"""
$TYPEDSIGNATURES

Constructing two block group algebra codes by specifying the group presentation.

Two block group algebra codes are constructed by choosing a group (and specific generators),
then choosing two polynomials made out of these generators,
then piping these two polynomials as the elements of `1×1` matrices to the
lifted product code constructors.

The Hecke library, for which we already have an extension, provides for a fairly easy way
to construct such polynomials for many abelian and small groups.
See [`two_block_group_algebra_code`](@ref) for those capabilities.

However, more esoteric groups are usually specified by a group presentation `⟨S | R⟩`,
where `S` is a set of generators and `R` is the relations those generators obey.
To support arbitrary group presentations we use Oscar, which builds upon Hecke.
We use `Oscar.free_group` and `quo` in order to first prepare the free group generated by `S`,
and then the group obeying also the relations `R`, i.e. the `⟨S | R⟩` [presentation](https://en.wikipedia.org/wiki/Presentation_of_a_group).

After that point we proceed as usual, creating two polynomials of generators and piping them
to [`two_block_group_algebra_code`](@ref).

This particular function is nothing more than a simple wrapper that takes care of argument conversions.
Of note, the polynomials here are given as lists of monomials.

Of course, if you are comfortable with Oscar, you can use [`two_block_group_algebra_code`](@ref) directly.

See also: [`two_block_group_algebra_code`](@ref), [`twobga_from_direct_product`](@ref)

## Examples

The [[96, 12, 10]] 2BGA code from Table I in [lin2024quantum](@cite) has the group presentation
`⟨r, s | s⁶ = r⁸ = r⁻¹srs = 1⟩` (the group `C₂ × (C₃ ⋉ C₈)`).

```jldoctest finitegrp
julia> import Oscar: free_group, small_group_identification, describe, order

julia> import Hecke: gens, quo, group_algebra, GF, one

julia> using QuantumClifford, QuantumClifford.ECC

julia> F = free_group(["r", "s"]);

julia> r, s = gens(F); # generators

julia> G, = quo(F, [s^6, r^8, r^(-1) * s * r * s]);  # relations

julia> GA = group_algebra(GF(2), G);

julia> r, s = gens(G);

julia> a = [one(G), r, s^3 * r^2, s^2 * r^3];

julia> b = [one(G), r, s^4 * r^6, s^5 * r^3];

julia> c = twobga_from_fp_group(a, b, GA);

julia> order(G)
48

julia> code_n(c), code_k(c)
(96, 12)

julia> describe(G), small_group_identification(G)
("C2 x (C3 : C8)", (48, 9))
```

### Cyclic Groups

Cyclic groups with specific group presentations, given by `Cₘ = ⟨x, s | xᵐ = s² = xsx⁻¹s⁻¹ = 1⟩`,
where the order is `2m` as seen in Table II of [lin2024quantum](@cite).

The [[56, 28, 2]] abelian 2BGA code from Appendix C, Table II in [lin2024quantum](@cite) is constructed using
the group presentation `⟨x, s | xs = sx, xᵐ = s² = 1⟩` (the cyclic group `C₂₈ = C₁₄ × C₂`).

```jldoctest finitegrp
julia> m = 14;

julia> F = free_group(["x", "s"]);

julia> x, s = gens(F); # generators

julia> G, = quo(F, [x^m, s^2, x * s * x^-1 * s^-1]); # relations

julia> GA = group_algebra(GF(2), G);

julia> x, s = gens(G);

julia> a = [one(G), x^7];

julia> b = [one(G), x^7, s, x^8, s * x^7, x];

julia> c = twobga_from_fp_group(a, b, GA);

julia> order(G)
28

julia> code_n(c), code_k(c)
(56, 28)

julia> describe(G), small_group_identification(G)
("C14 x C2", (28, 4))
```

### Dihedral Groups

Dihedral (non-abelian) groups with group presentations given by `Dₘ = ⟨r, s | rᵐ = s² = (rs)² = 1⟩`,
where the order is `2m`.

The [[24, 8, 3]] 2BGA code from Appendix C, Table III in [lin2024quantum](@cite) is constructed
by specifying a group presentation below (giving the group `D₆ = C₆ ⋉ C₂`).


```jldoctest finitegrp
julia> m = 6;

julia> F = free_group(["r", "s"]);

julia> r, s = gens(F); # generators

julia> G, = quo(F, [r^m, s^2, (r*s)^2]); # relations

julia> GA = group_algebra(GF(2), G);

julia> r, s = gens(G);

julia> a = [one(G), r^4];

julia> b = [one(G), s*r^4, r^3, r^4, s*r^2, r];

julia> c = twobga_from_fp_group(a, b, GA);

julia> order(G)
12

julia> code_n(c), code_k(c)
(24, 8)

julia> describe(G), small_group_identification(G)
("D12", (12, 4))
```

!!! note
    Notice how in all of these construction we are specifying a group presentation.
    We are explicitly **not** picking a group by name and getting its "canonical" generators,
    as we do not a priori know whether Oscar would give us the generating set we need (generating sets are not unique).
"""
function twobga_from_fp_group(a_elts::VectorFPGroupElem, b_elts::VectorFPGroupElem, F2G::FqFieldFPGroupAlgebra)
    a = sum(F2G(x) for x in a_elts)
    b = sum(F2G(x) for x in b_elts)
    c = two_block_group_algebra_code(a,b)
    return c
end
