Skip to content

Commit 56f1ad3

Browse files
committed
added possibility of noncommutative coefficients
1 parent 6864a7a commit 56f1ad3

File tree

7 files changed

+192
-607
lines changed

7 files changed

+192
-607
lines changed

Manifest.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModuleElts"
22
uuid = "4249f315-58d4-4c46-b324-3577fc7dfca0"
33
authors = ["Jean Michel <jean.michel@imj-prg.fr>"]
4-
version = "0.1.0"
4+
version = "0.1.1"
55

66
[compat]
77
julia = "1"

README.md

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
Module Elements –- elements of free modules.
77

8-
A `ModuleElt{K,V}` represents an element of a free module where basis elements are of type `K` and coefficients of type `V`. Usually you want objects of type `V` to be elements of a ring, but it could also be useful if they just belong to an abelian group. This is similar to the SageMath CombinatorialFreeModule. You can also see them as `SparseVector`s where keys can be type `K` instead of integers.
8+
A `ModuleElt{K,V}` represents an element of a free module where basis elements are of type `K` and coefficients of type `V`. Usually you want objects of type `V` to be elements of a (non-necessarily commutative) ring, but it could also be useful if they just belong to an abelian group. This is similar to the SageMath CombinatorialFreeModule. You can also see them as `SparseVector`s where keys can be of type `K` instead of integers.
99

1010
This basic data structure is used in my packages as an efficient representation at many places. For example, the `Monomial` type representing multivariate monomials is a `ModuleElt{Symbol,Int}`:
1111

@@ -25,17 +25,17 @@ We provide two implementations:
2525

2626
This requires that the type `K` is hashable. It is a very simple implementation since the interface of the type is close to that of dicts; the only difference is weeding out keys which have a zero cofficient –- which is necessary since for testing equality of module elements one needs a canonical form for each element.
2727

28-
* `ModuleElt`, a faster implementation which keeps a list of pairs sorted by key.
28+
* `ModuleElt`, a faster implementation by a vector of pairs sorted by key.
2929

30-
This demands that the type `K` has a `isless` method. This implementation is two to four times faster than the `Dict` one and requires half the memory.
30+
This requires that the type `K` has a `isless` method. This implementation is two to four times faster than the `Dict` one and requires half the memory.
3131

3232
Both implementations have the same methods, which are mostly the same methods as a `Dict` (`haskey`, `getindex`, `setindex`, `keys`, `values`. `pairs`, `first`, `iterate`, `length`, `eltype`, `copy`), with some exceptions. Adding elements is implemented as `merge(+,...)` which is a variation on `merge` for `Dict`s where keys with zero value are deleted after the operation (here `+` can be replaced by any operation `op` with the property that `op(0,x)=op(x,0)=x`).
3333

34-
A module element can also be negated, or multiplied or divided (`/`or `//`) by some element (acting on coefficients) if the method is defined between type `V` and that element; there are also `zero` and `iszero` methods.
34+
A module element can also be negated, or multiplied or divided (`/`or `//` or `\`) by some element (acting on coefficients) if the method is defined between type `V` and that element; the order of the arguments is respected, which allows to implement left and right modules when multiplication for `V` is non-commutative. There are also `zero` and `iszero` methods.
3535

36-
`ModuleElt`s have methods `cmp` and `isless` which `HModuleElt`s don't have. There is also `ModuleElts.merge2` which does the same as merge but is valid for more general operations (I use it with `min` and `max` which implement `gcd` and `lcm` for `Monomial`s and `CycPol`s).
36+
`ModuleElt`s have methods `cmp` and `isless` which `HModuleElt`s don't have (the definition is lexicographic order). There is also `ModuleElts.merge2` which does the same as merge but is valid for more general operations – thus is more expensive since it needs more checks for zero results (I use it with `min` and `max` which implement `gcd` and `lcm` for `Monomial`s and `CycPol`s).
3737

38-
Here is an example where basis elements are `Symbol`s and coefficients are `Int`. As you can see in the examples, at the REPL (or in Jupyter or Pluto, when `IO` has the `:limit` attribute) the `show` method shows the coefficients (bracketed if necessary, which is when they have inner occurences of `+-*/`), followed by showing the basis elements. The `repr` method gives a representation which can be read back in julia:
38+
We show now an an example; here basis elements are `Symbol`s and coefficients are `Int`. As you can see in the examples, at the REPL (or in Jupyter or Pluto, when `IO` has the `:limit` attribute) the `show` method gives a nice display where the coefficients (bracketed if necessary, which is when they have inner occurences of `+-*/`) preced the keys. The `repr` method gives a representation which can be read back in julia:
3939

4040
```julia-repl
4141
julia> a=ModuleElt(:xy=>1,:yx=>-1)
@@ -51,7 +51,7 @@ julia> ModuleElt([:xy=>1//2,:yx=>-1])
5151
Setting the `IO` property `:showbasis` to a custom printing function changes how the basis elements are printed.
5252

5353
```julia-rep1
54-
julia> show(IOContext(stdout,:showbasis=>(io,s)->string("<",s,">")),a)
54+
julia> show(IOContext(stdout,:limit=>true,:showbasis=>(io,s)->string("<",s,">")),a)
5555
3<xy>+2<yx>
5656
```
5757

@@ -61,7 +61,7 @@ We illustrate basic operations on `ModuleElt`s:
6161
julia> a-a
6262
0
6363
64-
julia> a*99
64+
julia> a*99 # Ints commute so same as 99*a
6565
99:xy-99:yx
6666
6767
julia> a//2
@@ -79,29 +79,35 @@ julia> a[:xy] # indexing by a basis element finds the coefficient
7979
julia> a[:xx] # the coefficient of an absent basis element is zero.
8080
0
8181
82-
julia> haskey(a,:xx)
82+
julia> haskey(a,:xx) # same as !iszero(a[:xx])
8383
false
8484
85+
julia> a[:xx]=1 # this does an insertion
86+
1
87+
8588
julia> first(a)
86-
:xy => 1
89+
:xx => 1
8790
8891
julia> collect(a)
89-
2-element Vector{Pair{Symbol, Int64}}:
92+
3-element Vector{Pair{Symbol, Int64}}:
93+
:xx => 1
9094
:xy => 1
9195
:yx => -1
9296
9397
julia> collect(keys(a))
94-
2-element Vector{Symbol}:
98+
3-element Vector{Symbol}:
99+
:xx
95100
:xy
96101
:yx
97102
98103
julia> collect(values(a))
99-
2-element Vector{Int64}:
104+
3-element Vector{Int64}:
105+
1
100106
1
101107
-1
102108
103109
julia> length(a)
104-
2
110+
3
105111
106112
julia> eltype(a)
107113
Pair{Symbol, Int64}
@@ -125,7 +131,39 @@ julia> a+ModuleElt([:z=>1.0])
125131
```
126132

127133

128-
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/e699813afe72977ac1a21d7a432b9470142d41ac/src/ModuleElts.jl#L1-L162' class='documenter-source'>source</a><br>
134+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L1-L171' class='documenter-source'>source</a><br>
135+
136+
<a id='ModuleElts.ModuleElt' href='#ModuleElts.ModuleElt'>#</a>
137+
**`ModuleElts.ModuleElt`** &mdash; *Type*.
138+
139+
140+
141+
`ModuleElt{K,V}` has a similar interface to `Dict{K,V}`, but instead of assuming that `K` is hashable, it assumes that `K` is sortable. It also has the advantage that ModuleElts are naturally sortable.
142+
143+
The only field, a `Vector{Pair{K,V}}`, is kept sorted by `K`; the constructor by default checks sorting, adds values with same key, and suppresses keys with zero value. This can be bypassed by the keyword `check=false`.
144+
145+
146+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L215-L224' class='documenter-source'>source</a><br>
147+
148+
<a id='Base.merge-Tuple{Function, ModuleElt, ModuleElt}' href='#Base.merge-Tuple{Function, ModuleElt, ModuleElt}'>#</a>
149+
**`Base.merge`** &mdash; *Method*.
150+
151+
152+
153+
`merge(op::Function,a::ModuleElt,b::ModuleElt)`
154+
155+
is like `merge(op,a,b)` for `Dict`s, except that keys with value `0` are deleted after the operation is done.
156+
157+
The code is only valid for `op`s such that `op(0,x)=op(x,0)=x` otherwise the result is wrong. You can use `ModuleElts.merge2` for a (more expensive) function which always works.
158+
159+
`merge(op,m::ModuleElt,b)` does `v->op(v,b)` on the values of `m`.
160+
161+
`merge(op,b,m::ModuleElt)` does `v->op(b,v)` on the values of `m`.
162+
163+
`merge(op,m::ModuleElt)` does `v->op(v)` on the values of `m`.
164+
165+
166+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L253-L268' class='documenter-source'>source</a><br>
129167

130168
<a id='ModuleElts.merge2' href='#ModuleElts.merge2'>#</a>
131169
**`ModuleElts.merge2`** &mdash; *Function*.
@@ -137,5 +175,25 @@ julia> a+ModuleElt([:z=>1.0])
137175
does `op` between coefficients of the same basis element in `a` and `b`. This version works for general ops (not necessarily commutative or which need not satisfy op(0,x)=op(x,0)=x), but has too much overhead currently to replace `merge` for + or other ops such that op(0,x)==op(x,0)=x. It is useful for max or min which do lcm and gcd of `Monomial`s or `CycPol`s.
138176

139177

140-
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/e699813afe72977ac1a21d7a432b9470142d41ac/src/ModuleElts.jl#L273-L281' class='documenter-source'>source</a><br>
178+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L291-L299' class='documenter-source'>source</a><br>
179+
180+
<a id='Base.getindex-Tuple{ModuleElt, Any}' href='#Base.getindex-Tuple{ModuleElt, Any}'>#</a>
181+
**`Base.getindex`** &mdash; *Method*.
182+
183+
184+
185+
`getindex(x::ModuleElt,key)` returns the value associated to the given `key` in `x`. It returns zero if the key does not occur in `x`.
186+
187+
188+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L340-L343' class='documenter-source'>source</a><br>
189+
190+
<a id='Base.setindex!-Tuple{ModuleElt, Any, Any}' href='#Base.setindex!-Tuple{ModuleElt, Any, Any}'>#</a>
191+
**`Base.setindex!`** &mdash; *Method*.
192+
193+
194+
195+
`setindex!(x::ModuleElt,v,key)` sets `v` as the value associated to the given `key` in `x`. Setting a value to zero or for a new key is expensive.
196+
197+
198+
<a target='_blank' href='https://github.com/jmichel7/ModuleElts.jl/blob/6864a7ae33c8167bec30dd4f058e1cceab6d7536/src/ModuleElts.jl#L350-L353' class='documenter-source'>source</a><br>
141199

docs/src/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
```@docs
22
ModuleElts
3+
ModuleElt
4+
merge(::Function,::ModuleElt,::ModuleElt)
35
ModuleElts.merge2
6+
getindex(::ModuleElt,Any)
7+
setindex!(::ModuleElt,Any,Any)
48
```

0 commit comments

Comments
 (0)