Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non monomial basis #21

Merged
merged 134 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 119 commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
05dd9ed
remove CachedMTable
kalmarek Dec 5, 2023
c7669d4
introduce ImplicitBasis and ExplicitBasis
kalmarek Dec 5, 2023
1691ec7
rename TrivialMStructure → LazyMStructure
kalmarek Dec 5, 2023
1cf858a
remove baseless StarAlgebras
kalmarek Dec 5, 2023
769e8b4
AlgebraElement coefficients don't need to be vector
kalmarek Dec 5, 2023
9346178
first try on coefficients
kalmarek Dec 5, 2023
c8a8943
Fixes
blegat Dec 6, 2023
1ca4011
rename Basis → Fixed Basis
kalmarek Dec 6, 2023
023803b
introduce DiracBasis <: ImplicitBasis
kalmarek Dec 6, 2023
6ebdfd8
move mul! to mstructures
kalmarek Dec 6, 2023
5ddfa3b
fix the order {K,V} of params in AbstractCoefficients
kalmarek Dec 6, 2023
688583e
fix printing of LazyMStructure
kalmarek Dec 6, 2023
9eed650
add keytype, valtype for AbstractCoefficients
kalmarek Dec 6, 2023
fa98c01
add getindex for LazyMStructure over DiracBasis
kalmarek Dec 6, 2023
129bb41
add == for AbstractCoefficients
kalmarek Dec 6, 2023
765d98b
make DiracBasis threadsafe
kalmarek Dec 7, 2023
07c0cb4
give it a try with different parametrization of MStructures
kalmarek Dec 7, 2023
0e3d158
Fixes
blegat Dec 7, 2023
78f839a
move star_of to FixedBasis
kalmarek Dec 12, 2023
2c5386f
return DiracDeltas on indexing DiracBasis
kalmarek Dec 12, 2023
504f86a
dispatch star through star(basis, coeffs)
kalmarek Dec 12, 2023
5c2297e
move fmac! so that StarAlgebras actually load
kalmarek Dec 12, 2023
83d3219
implement basic canonicalize
kalmarek Dec 12, 2023
33b9466
more star dispatch
kalmarek Dec 12, 2023
0df1f2c
simplify AlgebraElement
kalmarek Dec 12, 2023
6e4a064
fix: define MA.operate!(zero, ::SparseVector)
kalmarek Dec 12, 2023
61a810c
fix show methods
kalmarek Dec 12, 2023
0316034
fix getindex for LazyMStructure
kalmarek Dec 12, 2023
644f98c
move coefficients to their separate files
kalmarek Dec 28, 2023
bb661ed
move Dirac/FixedBases to their separate files
kalmarek Dec 28, 2023
364960b
add (Dirac|Augmented)MStructure
kalmarek Dec 31, 2023
b77e698
reimplement MTables
kalmarek Dec 31, 2023
764b193
fix the definitions of of StarAlgebra/AlgebraElements
kalmarek Dec 31, 2023
5c32408
add a new implementation of star
kalmarek Dec 31, 2023
f639044
reimplement augmentation
kalmarek Dec 31, 2023
379203e
various small fixes
kalmarek Dec 31, 2023
086874a
add fmac! for AbstractVector
kalmarek Feb 22, 2024
7df6659
remove show for DiracMStructure now that it is basis free
kalmarek Feb 22, 2024
0a7e75c
quickly fix one
kalmarek Feb 22, 2024
10cb8c2
commit tmp.jl as an example of what works
kalmarek Feb 22, 2024
af08b35
move tmp.jl to test/perm_grp_algebra.jl
kalmarek Feb 22, 2024
5660ec7
turn demo perm_grp_algebra.jl into testset
kalmarek Feb 22, 2024
93933df
disable the old test for now
kalmarek Feb 23, 2024
7fe6a17
move compat section for Groups etc to test/Project.toml
kalmarek Feb 23, 2024
9cd7e19
Let AlgebraElement be an AbstractMutable
blegat Feb 26, 2024
79bbcf8
zero!(.) -> MA.operate!(zero, .)
blegat Feb 26, 2024
c40ae73
neg! -> operate_to!(-
blegat Feb 26, 2024
3c226f7
add! -> operate_to!(+
blegat Feb 26, 2024
b8faeb2
mul! -> MA.operate_to!
blegat Feb 26, 2024
55be591
mul! with mstruct to MA
blegat Feb 26, 2024
de56536
sub! -> MA
blegat Feb 26, 2024
59807e5
fmac -> MA
blegat Feb 26, 2024
6870eb2
Check for alias
blegat Feb 26, 2024
fa3c8ad
unsafe_add! -> UnsafeAddMul
blegat Feb 26, 2024
c92c229
Document UnsafeAddMul
blegat Feb 26, 2024
a0a7b90
Fixes for Chebyshev (#23)
blegat Mar 16, 2024
a89756f
replace keytype → key_type
kalmarek Mar 17, 2024
95aaed7
rename _nzpairs → nonzero_pairs
kalmarek Mar 17, 2024
9f7d357
implement canonicalization via MA.operate!!(canonical, ...)
kalmarek Mar 17, 2024
7346e7a
move the mutable API to coefficients
kalmarek Apr 2, 2024
ddf9e3d
remove Dirac and use GroupElements directly
kalmarek Apr 2, 2024
55d4174
rename AugmentedDirac to Augmented
kalmarek Apr 2, 2024
16e406f
fix: == for SparseCoefficients
kalmarek Apr 2, 2024
cd32a47
reorganize defs for star, aug and norm/dot
kalmarek Apr 2, 2024
8836dd2
implement MA API for SparseCoefficients
kalmarek Apr 2, 2024
513a748
add zero_coeffs(::Type, ::AbstractBasis)
kalmarek Apr 2, 2024
fa323d3
fix: use nonzero_pairs instead of pairs
kalmarek Apr 2, 2024
ca69382
fix: logic for canonical(::SparseCoefficients)
kalmarek Apr 2, 2024
87e2eb4
add getindex/setindex! for SparseCoefficients
kalmarek Apr 2, 2024
ed534c4
reshuffle definitions in types.jl
kalmarek Apr 2, 2024
9c9a43e
one/zero & isone/iszero are surprisingly hard...
kalmarek Apr 2, 2024
674a103
various small fixes/convenience additions
kalmarek Apr 2, 2024
be39b2d
fix: use getindex instead of broadcasting
kalmarek Apr 2, 2024
fe83753
[tests] implement iteration over free words
kalmarek Apr 2, 2024
4cf409d
[test] rewrite testset Arithmetic in group algebra
kalmarek Apr 2, 2024
5ba2061
[tests] rewrite tests with free monoid algebra
kalmarek Apr 2, 2024
c4d26ee
[tests] rewrite tests for chaching multiplication
kalmarek Apr 2, 2024
cdea07c
[tests] update constructors and sohs in group algebra
kalmarek Apr 2, 2024
b56a13e
[tests] reenable tests
kalmarek Apr 2, 2024
ce7653e
fix: test LinearAlgebra.dot
kalmarek Apr 2, 2024
888dc57
fix includes
kalmarek Apr 2, 2024
18a74d8
bump version to 0.3
kalmarek Apr 2, 2024
1632be4
[tests] fix: @allocations exist in julia ≥ 1.9
kalmarek Apr 2, 2024
f22b273
tidy up aug, star and adjoint
kalmarek Apr 14, 2024
ece736f
allow no cache in FixedBasis
kalmarek Apr 14, 2024
c707b89
document minimal AbstractCoefficients API
kalmarek Apr 14, 2024
e1a6a6e
de-randomize !isone test
kalmarek Apr 14, 2024
9c5368f
add default cache parameter (UInt32(0)) for FixedBasis
kalmarek Apr 17, 2024
3741eca
fix: compute hash on canonicalized coeffs
kalmarek Apr 17, 2024
3230c31
add Comparable to pass < for sorting in sparse coeffs
kalmarek Apr 17, 2024
654655e
caching for MTables does not work for isbits elements
kalmarek Apr 17, 2024
918c826
fix: use proper (double) indexing when evaluating AlgebraElement
kalmarek Apr 17, 2024
e9dceac
enable canonical for Vectors
kalmarek Apr 17, 2024
6081c5b
add += with MTable for AbstractVectors
kalmarek Apr 17, 2024
56475bf
fix: MA.operate!(zero, ...) failed for SparseVector{Rational...}
kalmarek Apr 17, 2024
f5cfbd0
remove old/unused functions
kalmarek Apr 17, 2024
3f098ff
add Base.keys(b::ExplicitBasis)
kalmarek Apr 17, 2024
d27c6e8
expand docstring for AbstractBasis
kalmarek Apr 17, 2024
e60f27b
inlining nonzero_pairs saves lots of allocations
kalmarek Apr 17, 2024
5c20325
test aug for Augmented basis
kalmarek Apr 17, 2024
91cec1b
reduce allocations by hinting size
kalmarek Apr 17, 2024
32bd4dc
unbreak tests with MutableArithmetics 1.4.3
kalmarek Apr 17, 2024
1a635c1
test allocations only on 1.10
kalmarek Apr 18, 2024
54de891
rearrange tests
kalmarek Apr 18, 2024
feca94e
lock complete! of MTable behind a SpinLock
kalmarek Apr 22, 2024
0a85747
Unbreak broken tests
blegat Apr 24, 2024
53a308d
Exclude on Julia latest
blegat Apr 24, 2024
719b7b9
Missing newline
blegat Apr 24, 2024
ce2a672
Merge pull request #29 from JuliaAlgebra/bl/unbroken_+
kalmarek Apr 24, 2024
83ecdbc
remove Comparable
kalmarek May 2, 2024
9f44cdc
update README with working examples
kalmarek May 2, 2024
ba2b8b8
fix (?) for multithreading access to MTable cache
kalmarek May 9, 2024
de054b2
make augmented stuff a self-contained file
kalmarek May 9, 2024
b204f99
don't export supp
kalmarek May 9, 2024
7438004
Merge pull request #26 from JuliaAlgebra/mk/changes_for_SW
kalmarek May 12, 2024
a9c0f89
fix nonzero_pairs for a vector
kalmarek May 15, 2024
48dd3cf
add tests for arithmetic on coeffs
kalmarek May 15, 2024
8fdf11e
add tests for using dense vector as coeffs
kalmarek May 15, 2024
05c2845
add test for abstract coeffs
kalmarek May 15, 2024
fa7d62c
add a bit of docs what AbstractCoefficients is
kalmarek May 15, 2024
cfaca65
formatting
kalmarek May 15, 2024
7f17590
increase coverage by removing old methods
kalmarek May 15, 2024
2cb891f
fix norm/dot and provide coverage
kalmarek May 15, 2024
74d8d1b
fix iteration on AugmentedBasis and add tests
kalmarek May 15, 2024
b9020b5
move the generic MA.operate! from ACoeffs to the lib
kalmarek May 16, 2024
06977b1
one more broken test
kalmarek May 16, 2024
66a53ad
Base._return_type -> MA.promote_operation
blegat May 21, 2024
5ebf6fa
Fix broken all tests but one
blegat May 21, 2024
6786870
Turn last broken test into a passable test
blegat May 21, 2024
344e773
Add eachindex back
blegat May 22, 2024
7901688
Merge pull request #30 from JuliaAlgebra/bl/return_type
kalmarek May 27, 2024
8255fe5
Merge pull request #33 from JuliaAlgebra/bl/eachindex
kalmarek May 27, 2024
69f107e
Assume mutability for canonical (#31)
blegat May 27, 2024
fc2e9b2
Merge pull request #32 from JuliaAlgebra/bl/broken_fixes
kalmarek May 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
name = "StarAlgebras"
uuid = "0c0c59c1-dc5f-42e9-9a8b-b5dc384a6cd1"
authors = ["Marek Kaluba <[email protected]>"]
version = "0.2.1"
version = "0.3.0"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[compat]
Groups = "0.8"
GroupsCore = "0.5"
PermutationGroups = "0.6"
MutableArithmetics = "1.4.3"
SparseArrays = "1"
julia = "1.6"

[extras]
Groups = "5d8bd718-bd84-11e8-3b40-ad14f4a32557"
GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120"
PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Pkg", "Groups", "GroupsCore", "PermutationGroups", "Random", "Test"]
226 changes: 107 additions & 119 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

----

The package implements `*`-algebras with basis. The prime example use is group/monoid algebras (or rings) (or their finite dimensional subspaces). An example usage can be as follows.
The package implements `*`-algebras with basis. The prime example use are group
or monoid algebras (or their finite dimensional subspaces).
An example usage can be as follows.

```julia
julia> using StarAlgebras
julia> using StarAlgebras; import StarAlgebras as SA

julia> using PermutationGroups

Expand All @@ -19,21 +21,15 @@ Permutation group on 2 generators generated by
(1,2)
(1,2,3)

julia> b = StarAlgebras.Basis{UInt8}(collect(G))
6-element StarAlgebras.Basis{Permutation{Int64, …}, UInt8, Vector{Permutation{Int64, …}}}:
()
(2,3)
(1,2)
(1,3,2)
(1,3)
(1,2,3)
julia> b = SA.DiracBasis{UInt32}(G);

julia> RG = StarAlgebra(G, b)
*-algebra of Permutation group on 2 generators of order 6
*-algebra of PermGroup( (1,2), (1,2,3) )

```

This creates the group algebra of the symmetric group. How do we compute inside the group algebra? There are a few ways to comstruct elements:
This creates the group algebra of the symmetric group. There are a few ways to
comstruct its elements:
```julia
julia> zero(RG)
0·()
Expand All @@ -48,98 +44,112 @@ julia> RG(-5.0) # coerce a scalar to the ring
-5.0·()

julia> RG(rand(G)) # the indicator function on a random element of G
1·(1,3,2)
1·()

julia> f = AlgebraElement(rand(-3:3, length(b)), RG) # an element given by vectors of coefficients in the basis
1·() -1·(2,3) +3·(1,2) -1·(1,3,2) -3·(1,3) +3·(1,2,3)
julia> f = sum(rand(-3:3)*RG(rand(G)) for _ in 1:12) # an element given by vectors of coefficients in the basis
-1·() +4·(1,2) +5·(1,2,3) -2·(1,3,2) -2·(1,3)

julia> SA.star(g::PermutationGroups.AbstractPermutation) = inv(g); star(f) # the star involution
-1·() +4·(1,2) +5·(1,3,2) -2·(1,2,3) -2·(1,3)

julia> f' # the same
-1·() +4·(1,2) +5·(1,3,2) -2·(1,2,3) -2·(1,3)

julia> f' == f
false

julia> f - f' # the alternating part
7·(1,2,3) -7·(1,3,2)

julia> StarAlgebras.aug(p::PermutationGroups.Permutation) = 1

julia> StarAlgebras.aug(f) # sum of coefficients
4

julia> StarAlgebras.aug(f - f') # sum of coefficients
0

julia> using LinearAlgebra; norm(f, 2) # 2-norm
25.0

```
One may work with such element using the following functions:
By default `f` here is stored as (sparse) coefficients against `basis(RG)`:
```julia
julia> StarAlgebras.coeffs(f)
6-element Vector{Int64}:
1
-1
3
-1
-3
3

julia> StarAlgebras.star(p::PermutationGroups.AbstractPerm) = inv(p); star(f) # the star involution
1·() -1·(2,3) +3·(1,2) +3·(1,3,2) -3·(1,3) -1·(1,2,3)
julia> coeffs(f) # same as SA.coeffs(f, basis(RG))
StarAlgebras.SparseCoefficients{...}(Permutation{...}[(), (1,2), (1,2,3), (1,3,2), (1,3)], [-1, 4, 5, -2, -2])
```

julia> f' # the same
1·() -1·(2,3) +3·(1,2) +3·(1,3,2) -3·(1,3) -1·(1,2,3)
Working directly with elements of `G` one can also write

julia> g = rand(G); g
```julia
julia> g = Permutation(perm"(1,2,3)", G)
(1,2,3)

julia> StarAlgebras.coeffs(RG(g)) # note the type of coefficients
6-element SparseArrays.SparseVector{Int64, UInt8} with 1 stored entry:
[6] = 1

julia> x = one(RG) - 3RG(g); supp(x) # support of the funtion
2-element Vector{Permutation{...}:
2-element Vector{Permutation{…}}:
()
(1,2,3)

julia> x(g) # value of x at g
-3

julia> x[g] += 3; x # modification of x in-place
1·()

julia> aug(f) # sum of coefficients
2

julia> using LinearAlgebra; norm(f, 2) # 2-norm
5.477225575051661
julia> x(inv(g))
0
```

Using this we can define e.g. a few projections in `RG` and check their orthogonality:
## Example: Projections in group algebra

Using these functions let's define a few projections in `RG` and check their
orthogonality:
```julia
julia> using Test

julia> Base.sign(p::PermutationGroups.Permutation) = sign(p.perm);

julia> l = length(b)
julia> l = length(basis(RG))
6

julia> P = sum(RG(g) for g in b) // l # projection to the subspace fixed by G
1//6·() +1//6·(2,3) +1//6·(1,2) +1//6·(1,3,2) +1//6·(1,3) +1//6·(1,2,3)
julia> P = sum(RG(g) for g in b) // l # projection to the subspace fixed by all elements of G
1//6·() +1//6·(2,3) +1//6·(1,2) +1//6·(1,2,3) +1//6·(1,3,2) +1//6·(1,3)

julia> @test P * P == P
Test Passed

julia> P3 = 2 * sum(RG(g) for g in b if sign(g) > 0) // l # projection to the subspace fixed by Alt(3) = C₃
1//3·() +1//3·(1,3,2) +1//3·(1,2,3)
1//3·() +1//3·(1,2,3) +1//3·(1,3,2)

julia> @test P3 * P3 == P3
Test Passed

julia> P2 = (RG(1) + RG(b[2])) // 2 # projection to the C₂-fixed subspace
1//2·() +1//2·(2,3)
julia> h = PermutationGroups.gens(G,1)
(1,2)

julia> P2 = (RG(one(G)) + RG(h)) // 2 # projection to the C₂-fixed subspace
1//2·() +1//2·(1,2)

julia> @test P2 * P2 == P2
Test Passed

julia> @test P2 * P3 == P3 * P2 == P # their intersection is precisely the same as the one for G
Test Passed

julia> P2m = (RG(1) - RG(b[2])) // 2 # orthogonal C₂-fixed subspace
1//2·() -1//2·(2,3)
julia> P2m = (RG(1) - RG(h)) // 2 # projection onto the subspace orthogonal to C₂-fixed subspace
1//2·() -1//2·(1,2)

julia> @test P2m * P2m == P2m
Test Passed

julia> @test iszero(P2m * P2) # indeed P2 and P2m are orthogonal
Test Passed

```

This package originated as a tool to compute sum of hermitian squares in `*`-algebras. These consist not of standard `f*f` summands, but rather `star(f)*f`. You may think of semi-definite matrices: their Cholesky decomposition determines `P = Q'·Q`, where `Q'` denotes transpose. Algebra of matrices with transpose is an (the?) example of a `*`-algebra. To compute such sums of squares one may either sprinkle the code with `star`s, or `'` (aka `Base.adjoint` postfix symbol):
This package originated as a tool to compute sum of hermitian squares in
`*`-algebras. These consist not of standard `f*f` summands, but rather
`star(f)*f`. You may think of semi-definite matrices: their Cholesky
decomposition determines `P = Q'·Q`, where `Q'` denotes (conjugate) transpose.
Algebra of matrices with transpose is an (the?) example of a `*`-algebra.
To compute such sums of squares one may either sprinkle the code with `star`s,
or `'` (aka `Base.adjoint` postfix symbol):
```julia
julia> x = RG(G(perm"(1,2,3)"))
julia> x = RG(Permutation(perm"(1,2,3)", G))
1·(1,2,3)

julia> X = one(RG) - x
Expand All @@ -149,99 +159,77 @@ julia> X'
1·() -1·(1,3,2)

julia> X'*X
2·() -1·(1,3,2) -1·(1,2,3)
2·() -1·(1,2,3) -1·(1,3,2)

julia> @test X'*X == star(X)*X == 2one(X) - x - star(x)
Test Passed

```

### More advanced use
## Fixed basis and translation between bases

`RG = StarAlgebra(G, b)` creates the algebra with `TrivialMStructure`, i.e. a multiplicative structure which computes product of basis elements every time it needs it. This of course may be wastefull, e.g. the computed products could be stored in a cache for future use. There are two options here:
```julia
julia> mt = StarAlgebras.MTable(b, table_size=(length(b), length(b)))
6×6 StarAlgebras.MTable{UInt8, false, Matrix{UInt8}}:
0x01 0x02 0x03 0x04 0x05 0x06
0x02 0x01 0x06 0x05 0x04 0x03
0x03 0x04 0x01 0x02 0x06 0x05
0x04 0x03 0x05 0x06 0x02 0x01
0x05 0x06 0x04 0x03 0x01 0x02
0x06 0x05 0x02 0x01 0x03 0x04
`b = SA.DiracBasis{UInt32}(G)` takes an iterator (in this case a finite
permutation group `G`) and creates a basis with Dirac multiplicative structure.
This means a basis of a linear space with the multiplicative structure where
multiplication of two basis elements results in a third one. This computation
does not depend on the finiteness of `G`, i.e. is fully lazy.

```
creates an eagerly computed multiplication table on elements of `b`. Keyword `table_size` is used to specify the table size (above: it's the whole multiplication table). Since `MTable<:AbstractMatrix`, one can use the indexing syntax `mt[i,j]` to compute the **index** of the product of `i`-th and `j`-th elements of the basis. For example
```julia
julia> g = G(perm"(1,2,3)"); h = G(perm"(2,3)");
When the basis is known a priori one can create an efficient `SA.FixedBasis`
which caches (memoizes) the results of multiplications. For example:

julia> i, j = b[g], b[h] # indices of g and h in basis b
(0x06, 0x02)

julia> k = mt[i,j] # the index of the product
0x05
```julia
julia> fb = let l = length(basis(RG))
StarAlgebras.FixedBasis(b; n=l, mt=l) # mt can be also smaller than l
end;

julia> @test b[k] == g*h
Test Passed
julia> fRG = StarAlgebra(G, fb)
*-algebra of PermGroup( (1,2), (1,2,3) )

```

The second option is
```julia
julia> cmt = StarAlgebras.CachedMTable(b, table_size=(length(b), length(b)));
```
This multiplication table is lazy, i.e. products will be computed and stored only when actually needed. Additionally, one may call
Since the length of the basis is known this time, algebra elements can be stored simply as (sparse) vectors:

```julia
julia> using SparseArrays
julia> coeffs(one(fRG))
6-element SparseArrays.SparseVector{Int64, Int64} with 1 stored entry:
[1] = 1

julia> StarAlgebras.CachedMTable(b, spzeros(UInt8, length(b), length(b)));
julia> AlgebraElement(ones(Int, length(basis(fRG)))//6, fRG)
1//6·() +1//6·(2,3) +1//6·(1,2) +1//6·(1,2,3) +1//6·(1,3,2) +1//6·(1,3)

```
to specify storage type of the matrix (by default it's a simple dense `Matrix`).
This may be advisable when a few products are computed repeatedly on a quite large basis.

```julia
julia> RGc = StarAlgebra(G, b, cmt)
*-algebra of Permutation group on 2 generators of order 6
To translate coefficients between bases one may call

```
should be functinally equivalent to `RG` above, however it will cache computation of products lazily. A word of caution is needed here though. Even though `RGc` and `RG` are functionally equivalent, they are not **comparable** in the sense that e.g.
```julia
julia> @test one(RGc) != one(RG)
Test Passed
julia> coeffs(P2, fb)
6-element SparseArrays.SparseVector{Rational{Int64}, Int64} with 2 stored entries:
[1] = 1//2
[3] = 1//2

```

This is a conscious decision on our part, as comparing algebraic structures is easier said than done ;) To avoid solving this conundrum (are bases equal? are multiplicative structures equal? are these permuted by a compatible permutation? or maybe a linear transformation was applied to the basis, resulting in a different, but equivalent multiplicative structure?), elements could be mixed together **only if their parents are identically** (i.e. `===`) **equal**.

Finally, if the group is infinite (or just too large), but we need specific products, we may reduce the table_size to the required size (it doesn't have to be `length(b) × length(b)`). Note that in such case asking for a product outside of multiplication table will rise `ProductNotDefined` exception.
julia> coeffs(coeffs(P2), b, fb) # same as above, from source basis to target basis
6-element SparseArrays.SparseVector{Rational{Int64}, Int64} with 2 stored entries:
[1] = 1//2
[3] = 1//2

### Even more advanced use (for experts only)
```

For low-level usage `MultiplicativeStructures` follow the sign convention:
```julia
julia> mt = StarAlgebras.CachedMTable(b, table_size=(length(b), length(b)));
Translation in the opposite direction is also possible

```julia
julia> k = mt[-i,j]
0x06
julia> fP2 = AlgebraElement(StarAlgebras.coeffs(P2,fb), fRG)
1//2·() +1//2·(1,2)

julia> @test star(b[i])*b[j] == b[k]
Test Passed
julia> StarAlgebras.coeffs(fP2, b)
StarAlgebras.SparseCoefficients{…}(Permutation{…}[(), (1,2)], Rational{Int64}[1//2, 1//2])

```
Note that this (minus-twisted) "product" is no longer associative! Observe:
```julia
julia> @test mt[mt[3, 5], 4] == mt[3, mt[5, 4]] # (b[3]*b[4])*b[5] == b[3]*(b[4]*b[5])
Test Passed
julia> P2_ = AlgebraElement(StarAlgebras.coeffs(fP2, b), RG)
1//2·() +1//2·(1,2)

julia> @test mt[-signed(mt[-3, 5]), 4] == 0x06 # star(star(b[3])*b[5])*b[4] = star(b[5])*b[3]*b[4]
julia> @test P2 == P2_
Test Passed

julia> @test mt[-3, mt[-5, 4]] == 0x01 # star(b[3])*star(b[5])*b[4]
Test Passed
```



-----
If you happen to use this package please cite either [1712.07167](https://arxiv.org/abs/1712.07167) or [1812.03456](https://arxiv.org/abs/1812.03456). This package superseeds [GroupRings.jl](https://github.com/kalmarek/GroupRings.jl) which was developed and used there. It served its purpose well. Let it rest peacefully.
Loading