Linear combinations

Types

LinearCombinations.AbstractLinearType
L(xc::Pair...; is_filtered = false; kw...) where L <: AbstractLinear
L(itr; is_filtered = false; kw...) where L <: AbstractLinear

AbstractLinear{T,R} is the supertype of all linear combinations with term type T and coefficient type R.

A constructor for a subtype L <: AbstractLinear constructs a linear combination of type L out of the given term-coefficient pairs of the form x => c where x is the term and c the coefficient, or out of the pairs provided by the iterator itr. It must be possible to convert all terms and coefficients to the chosen term type and coefficient type, respectively.

Neither the term type nor the coefficient type need to be concrete. (Of course, concrete types lead to better performance.) If the coefficient type and possibly also the term type are not specified, the constructor tries to determine them using promote_type (for coefficients) and promote_typejoin (for terms).

If two or more term-coefficient pairs are given with the same term, then the corresponding coefficients are added up. This is different from dictionaries, where any key-value pair overrides previous pairs with the same key. However, the implemented behavior is more useful for linear combinations.

For specialized applications, terms and coefficients can be processed with linear_filter and termcoeff before being stored in a linear combination. The keyword argument is_filtered controls whether linear_filter is called for each term.

See also Linear, DenseLinear, Linear1, linear_filter, LinearCombinations.termcoeff

Examples

julia> Linear('x' => 1, 'y' => 2)
x+2*y

julia> typeof(ans)
Linear{Char, Int64}

julia> Linear(x => c for (c, x) in enumerate('u':'z'))
3*w+2*v+4*x+u+5*y+6*z

julia> Linear{Char,Int}('x' => 1, 'y' => Int8(0), 'x' => 3.0)
4*x

julia> typeof(ans)
Linear{Char, Int64}

julia> a = Linear('x' => BigInt(1), "yz" => 2.0)
x+2.0*yz

julia> typeof(ans)
Linear{Any, BigFloat}

Iterating over a linear combination yields all non-zero term-coefficient pairs. Hence a linear combination can itself be used an argument to an AbstractLinear constructor.

julia> Linear{Union{Char,String}}(a)   # same a as before
x+2.0*yz

julia> typeof(ans)
Linear{Union{Char, String}, BigFloat}
source
LinearCombinations.LinearType
Linear{T,R} <: AbstractLinear{T,R}

Linear{T,R}(itr)

Construct a linear combination of type Linear with term type T and coefficient type R out of the term-coefficient pairs provided by the iterator itr.

Linear combinations of this type are sparse in the sense that terms and (non-zero) coefficients are internally stored in a dictionary.

Other ways to use this constructor are discussed under AbstractLinear.

See also AbstractLinear, DenseLinear, Linear1.

source
LinearCombinations.DenseLinearType
DenseLinear{T,R} <: AbstractLinear{T,R}

DenseLinear{T,R}(itr; basis::Basis)

Construct a linear combination of type DenseLinear with term type T and coefficient type R out of the term-coefficient pairs provided by the iterator itr.

Linear combinations of this type are internally stored as a Vector (or, more generally, an AbstractArray). The mandatory keyword argument basis is used to translate between terms and entries of the Vector (or Array). Operations involving two DenseLinear elements are much faster when the two bases are identical (in the sense of ===).

Other ways to use this constructor are discussed under AbstractLinear.

See also Basis, AbstractLinear, Linear, Linear1.

Examples

julia> azbasis = Basis('a':'z')
Basis('a':1:'z')

julia> a = DenseLinear('x' => 1, 'y' => 2; basis = azbasis)
x+2*y

julia> a + 'z'
x+2*y+z

julia> typeof(ans)
DenseLinear{Char, Int64, Basis{Char, 1, StepRange{Char, Int64}}, Vector{Int64}}

julia> a + 'X'
ERROR: KeyError: key 'X' not found
[...]

julia> b = DenseLinear('x' => -1, 'z' => 3; basis = azbasis)
-x+3*z

julia> a + b
2*y+3*z

julia> typeof(ans)
Linear{Char, Int64}

julia> c = DenseLinear('a' => 5; basis = Basis('a':'c'))
5*a

julia> add!(a, c)
5*a+x+2*y

julia> add!(c, a)
ERROR: KeyError: key 'x' not found
source
LinearCombinations.Linear1Type
Linear1{T,R} <: AbstractLinear{T,R}

Linear1{T,R}(itr)

Construct a linear combination of type Linear1 with term type T and coefficient type R out of the term-coefficient pairs provided by the iterator itr.

Linear combinations of this type can hold at most one non-zero term-coefficient pair at any time. There are often situations where this is sufficient, and in these cases Linear1 is much more efficient than Linear or DenseLinear.

Other ways to use this constructor are discussed under AbstractLinear.

See also AbstractLinear, Linear, DenseLinear.

Examples

julia> a = Linear1('x' => 1)
x

julia> add!(a, 'x')
2*x

julia> addmul!(a, 'x', -2)
0

julia> a + 'y'   # works because a is zero
y

julia> a + 'y' + 'z'
ERROR: Linear1 cannot store linear combinations of two or more elements
[...]

julia> a = Linear1('x' => 1); b = Linear1('y' => 2); a+b
x+2*y

julia> typeof(ans)
Linear{Char, Int64}
source

Basic methods

LinearCombinations.termtypeFunction
termtype(::Type{L}) where L <: AbstractLinear{T,R} = T
termtype(a::L) where L <: AbstractLinear{T,R} = T

Return the type of the terms (basis elements) in a linear combination.

See also coefftype.

source
LinearCombinations.coefftypeFunction
coefftype(::Type{L}) where L <: AbstractLinear{T,R} = R
coefftype(a::L) where L <: AbstractLinear{T,R} = R

Return the type of the coefficients in a linear combination.

See also termtype.

source
Base.inMethod
x in a::AbstractLinear -> Bool

Return true if the term x appears in the linear combination a with a non-zero coefficient, and false otherwise.

source
Base.lengthMethod
length(a::AbstractLinear) -> Int

Return the number of non-zero terms in a.

source
Base.iterateMethod
iterate(a::AbstractLinear [, state])

Iterating over a linear combination yields all non-zero term-coefficient pairs.

Examples

julia> a = Linear('x' => 1, 'y' => 2, 'z' => 0)
x+2*y

julia> collect(a)
2-element Vector{Pair{Char, Int64}}:
 'x' => 1
 'y' => 2

julia> Linear(x => c^2 for (x, c) in a)
x+4*y
source
Base.zeroFunction
zero(::Type{L}; kw...) where L <: AbstractLinear -> L
zero(a::L) where L <: AbstractLinear -> L

Return a zero linear combination of type L. If zero is called with a type L <: AbstractLinear as argument, then keyword arguments may be accepted or required.

See also zero!.

source
Base.copyFunction
copy(a::L) where L <: AbstractLinear -> L

Return a copy of a.

source
Base.copyto!Function
copyto!(a::AbstractLinear, b::AbstractLinear, c = 1) -> a
copyto!(a::AbstractLinear, x, c = 1) -> a

Set a equal to the c-fold multiple of the linear combination b or of the term x. If the scalar c is omitted, it is taken to be 1.

source
Base.sizehint!Function
sizehint!(a::AbstractLinear, n::Integer) -> a

Try to make room for in total n non-zero term-coefficient pairs in the linear combination a.

This can speed up computations. At present, sizehint! has an effect for elements of type Linear (which internally use a dictionary) and is ignored for all other subtypes of AbstractLinear.

See also Linear, LinearCombinations.has_sizehint, Base.sizehint!(d::AbstractDict).

source
Base.convertFunction
convert(::Type{L}, a::AbstractLinear; kw...) where L <: AbstractLinear -> L
convert(::Type{L}, x; kw...) where L <: AbstractLinear -> L

Convert the linear combination a or the term x to a linear combination of type L. Keyword arguments are passed to the constructor for L.

Examples

julia> a = Linear{AbstractChar,Int}('x' => 2)
2*x

julia> b = convert(Linear{Char,Float64}, a)
2.0*x

julia> typeof(b)
Linear{Char, Float64}

julia> convert(Linear{Char,Int}, 'x') == Linear('x' => 1)
true

julia> convert(DenseLinear, a; basis = Basis('a':'z'))
2*x

julia> typeof(ans)
DenseLinear{AbstractChar, Int64, Basis{Char, 1, StepRange{Char, Int64}}, Vector{Int64}}
source

Arithmetic

LinearCombinations.add!Function
add!(a::AbstractLinear, b::AbstractLinear) -> a
add!(a::AbstractLinear, x) -> a

Add the linear combination b or the term x to a. This function modifies a.

See also addmul!, sub!.

source
LinearCombinations.sub!Function
sub!(a::AbstractLinear, b::AbstractLinear) -> a
sub!(a::AbstractLinear, x) -> a

Subtract the linear combination b or the term x from a. This function modifies a.

See also addmul!, add!.

source
LinearCombinations.addmul!Function
addmul!(a::AbstractLinear, b::AbstractLinear, c) -> a
addmul!(a::AbstractLinear, x, c) -> a

Add the c-fold multiple of the linear combination b or of the term x to a, where c is a scalar. This function modifies a.

See also addmul, add!, sub!, mul!.

source
LinearCombinations.addmulFunction
addmul(a::AbstractLinear, b::AbstractLinear, c)
addmul(a::AbstractLinear, x, c)

Add the c-fold multiple of the linear combination b or of the term x to a, where c is a scalar.

See also addmul!.

source
LinearCombinations.degMethod
deg(a::AbstractLinear)

Return deg(x) where x is the first term appearing in a (as determined by first(a)).

The linear combination a must not be zero. If a is homogeneous, then deg(a) is the common degree of all terms in it.

source

Calling linear combinations

Calling objects is extended linearly. Here is an example:

julia> struct P{T} y::T end

julia> @linear p::P; (p::P)(x) = x * p.y

julia> p, q = P('p'), P('q')
(P{Char}('p'), P{Char}('q'))

julia> p('x')
"xp"

julia> a = Linear('x' => 1, 'y' => 2)
x+2*y

julia> p(a)
2*yp+xp

julia> u = Linear(p => -1, q => 3)
3*P{Char}('q')-P{Char}('p')

julia> u('x')
3*xq-xp

julia> u(a)
3*xq-2*yp+6*yq-xp

Broadcasting

Broadcasting is supported for AbstractLinear types. Broadcasted versions of +, -, *, = are converted to addmul!, mul! and copyto! as much as possible to avoid (or at least minimize) allocations. For example, for linear combinations a, b, c and d, the statement

   a .= b .+ 2 .* (c .- 3 .* d)

is translated to

    copyto!(a, b)
    addmul!(a, c, 2)
    addmul!(a, d, 2*(-3))

and the statement

    a .+= b .+ 2 .* (c .- 3 .* d)

to

    addmul!(a, b)
    addmul!(a, c, 2)
    addmul!(a, d, 2*(-3))

Broadcasted .* is always interpreted as scalar multiplication, with the scalar as the first argument. The only exception is a statement of the form a .*= c (that is, a .= a .* c) where the scalar is the second argument.

By default, only elements of types AbstractLinear and Number perticipate in broadcasting. To allow other scalar or term types, one has to use the macro @linear_broadcastable.

julia> @linear_broadcastable Char

julia> a, b = Linear('x' => 1), Linear('y' => 2)
(x, 2*y)

julia> a .+= b .+ 2 .* 'z'
x+2*y+2*z

julia> a
x+2*y+2*z

AbstractLinear interface