# \[ANN\] LinearCombinations.jl: formal linear combinations + (multi)linear maps

**URL:** https://discourse.julialang.org/t/ann-linearcombinations-jl-formal-linear-combinations-multi-linear-maps/129031
**Category:** Package Announcements
**Tags:** linearalgebra, symbolic, tensors
**Created:** [May 15, 2025, 11:30am UTC](https://discourse.julialang.org/t/ann-linearcombinations-jl-formal-linear-combinations-multi-linear-maps/129031 "2025-05-15T11:30:59Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)
#### Post date: [May 15, 2025, 11:30am UTC](https://discourse.julialang.org/t/ann-linearcombinations-jl-formal-linear-combinations-multi-linear-maps/129031/1 "2025-05-15T11:30:59Z")

</div>

# LinearCombinations.jl

This package addresses a very specific part of symbolic computation: formal linear combinations and linear maps between them. Multilinear maps and tensors are also supported. Formal linear combinations come up in many parts of (pure) mathematics, for example as elements of the [group ring](https://en.wikipedia.org/wiki/Group_ring) of a group or as [simplicial chains](https://en.wikipedia.org/wiki/Simplicial_homology#Chains) in a simplicial complex.

The overall aim of the package is to provide functions that are easy to use and at the same time fast enough to deal with large linear combinations having millions of terms. The terms can be of any type, and coefficients can be in any commutative ring with unit. In the examples below we use `Char` and `String` for terms together with integer coefficients.

LinearCombinations.jl comes with an extensive [documentation](https://matthias314.github.io/LinearCombinations.jl/stable/). For a use case, see the package [SimplicialSets.jl](https://github.com/matthias314/SimplicialSets.jl).

## Linear combinations

The type [`Linear`](https://matthias314.github.io/LinearCombinations.jl/stable/linear/#LinearCombinations.Linear) can store any number of term-coefficient pairs. Term type and coefficient type are automatically determined if possible.

```julia
julia> a = Linear('x' => 1, 'y' => 2)
Linear{Char, Int64} with 2 terms:
'x'+2*'y'

julia> b = Linear('z' => 3, 'w' => -1)
Linear{Char, Int64} with 2 terms:
-'w'+3*'z'

julia> c = a + 2*b - 'v'
Linear{Char, Int64} with 5 terms:
-2*'w'+'x'+2*'y'-'v'+6*'z'

julia> c .-= 2 .* b # in-place modification
Linear{Char, Int64} with 3 terms:
'x'+2*'y'-'v'

```

Linear combinations with non-concrete types are also possible. For `Linear`, the terms and coefficients are internally stored in a dictionary. In contrast, the type [`DenseLinear`](https://matthias314.github.io/LinearCombinations.jl/stable/linear/#LinearCombinations.DenseLinear) uses a coordinate vector with respect to a chosen basis.

## Linear maps

The following linear function maps terms to terms. Linearity is achieved via the macro [`@linear`](https://matthias314.github.io/LinearCombinations.jl/stable/extensions/#LinearCombinations.@linear).

```julia
julia> @linear f; f(x::Char) = uppercase(x);

julia> f(a)
Linear{Char, Int64} with 2 terms:
2*'Y'+'X'

```

Here is another linear function, this time mapping terms to linear combinations.

```julia
julia> @linear g; g(x::Char) = Linear(f(x) => 1, x => -1);

julia> g(a)
Linear{Char, Int64} with 4 terms:
2*'Y'-'x'-2*'y'+'X'

```

(A more efficient implementation of `g` would use the keyword arguments `addto` and `coeff`, see [`@linear_kw`](https://matthias314.github.io/LinearCombinations.jl/stable/extensions/#LinearCombinations.@linear_kw).)

## Multilinear maps

Multiplication is bilinear by default. Recall that multiplying `Char` or `String` values in Julia means concatenation.

```julia
julia> a * 'w'
Linear{String, Int64} with 2 terms:
"xw"+2*"yw"

julia> a * b
Linear{String, Int64} with 4 terms:
-"xw"+6*"yz"-2*"yw"+3*"xz"

```

For a user-defined function, bilinearity (or higher multilinearity) is achieved with the macro [`@multilinear`](https://matthias314.github.io/LinearCombinations.jl/stable/extensions/#LinearCombinations.@multilinear).

```julia
julia> @multilinear h; h(x, y) = x*y*x
h (generic function with 2 methods)

julia> h(a, b)
Linear{String, Int64} with 8 terms:
-"xwx"+3*"xzx"+12*"yzy"+6*"xzy"+6*"yzx"-2*"ywx"-2*"xwy"-4*"ywy"

```

Multilinear function with a variable number of arguments are also possible.

## Tensors

We use the [intrinsic definition](https://en.wikipedia.org/wiki/Tensor_(intrinsic_definition)) of a tensor. The ones appearing in physics are their coordinate representations.

We define a tensor and swap the two components of each term.

```julia
julia> a⊗b
Linear{Tensor{Tuple{Char, Char}}, Int64} with 4 terms:
-'x'⊗'w'-2*'y'⊗'w'+3*'x'⊗'z'+6*'y'⊗'z'

julia> swap(a⊗b)
Linear{Tensor{Tuple{Char, Char}}, Int64} with 4 terms:
-'w'⊗'x'+3*'z'⊗'x'+6*'z'⊗'y'-2*'w'⊗'y'

```

We finally take the tensor product of the functions `f` and `g` and apply it to a pure tensor and to `a⊗b`.

```julia
julia> f⊗g
Linear{Tensor{Tuple{typeof(f), typeof(g)}}, Int64} with 1 term:
f⊗g

julia> (f⊗g)('x'⊗'z')
Linear{Tensor{Tuple{Char, Char}}, Int64} with 2 terms:
-'X'⊗'z'+'X'⊗'Z'

julia> (f⊗g)(a⊗b)
Linear{Tensor{Tuple{Char, Char}}, Int64} with 8 terms:
-3*'X'⊗'z'+2*'Y'⊗'w'+3*'X'⊗'Z'+'X'⊗'w'-'X'⊗'W'-2*'Y'⊗'W'-6*'Y'⊗'z'+6*'Y'⊗'Z'

```

One can assign degrees to terms and maps. In this case tensor operations observe the usual sign rule. See [`deg`](https://matthias314.github.io/LinearCombinations.jl/stable/basics/#LinearCombinations.deg-Tuple%7BAny%7D), and [`swap`](https://matthias314.github.io/LinearCombinations.jl/stable/tensor/#LinearCombinations.swap) for an example.
