Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  alco.gi   Sprache: unbekannt

 
#     This file belongs to ALCO: Tools for Algebraic Combinatorics.
#     Copyright (C) 2024, Benjamin Nasmith

#     This program is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 3 of the License, or
#     (at your option) any later version.

#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.

#     You should have received a copy of the GNU General Public License
#     along with this program.  If not, see <https://www.gnu.org/licenses/>.

# Cyclotomic tools

BindGlobal( "EisensteinIntegers", Objectify( NewType(
    CollectionsFamily(CyclotomicsFamily),
    IsEisensteinIntegers and IsAttributeStoringRep ),
    rec() ) );

SetLeftActingDomain( EisensteinIntegers, Integers );
SetName( EisensteinIntegers, "EisensteinIntegers" );
SetString( EisensteinIntegers, "EisensteinIntegers" );
SetIsLeftActedOnByDivisionRing( EisensteinIntegers, false );
SetSize( EisensteinIntegers, infinity );
SetGeneratorsOfRing( EisensteinIntegers, [ E(3) ] );
SetGeneratorsOfLeftModule( EisensteinIntegers, [ 1, E(3) ] );
SetIsFinitelyGeneratedMagma( EisensteinIntegers, false );
SetUnits( EisensteinIntegers, Set([ -1, 1, -E(3), E(3), -E(3)^2, E(3)^2 ] ));
SetIsWholeFamily( EisensteinIntegers, false );

InstallMethod( \in,
    "for Eisenstein integers",
    IsElmsColls,
    [ IsCyc, IsEisensteinIntegers ],
    function( cyc, EisensteinIntegers )
    return IsCycInt( cyc ) and 3 mod Conductor( cyc ) = 0;
    end );

InstallMethod( IsEisenInt, 
    "for cyclotomics", 
    [ IsCyc ],
    function(x) 
        return x in EisensteinIntegers;
    end);

InstallMethod( Basis,
    "for Eisenstein integers (delegate to `CanonicalBasis')",
    [ IsEisensteinIntegers ], CANONICAL_BASIS_FLAGS,
    CanonicalBasis );

InstallMethod( CanonicalBasis,
    "for Eisenstein integers",
    [ IsEisensteinIntegers ],
    function( EisensteinIntegers )
    local B;

    B:= Objectify( NewType( FamilyObj( EisensteinIntegers ),
                                IsFiniteBasisDefault
                            and IsCanonicalBasis
                            and IsCanonicalBasisEisensteinIntegersRep ),
                   rec() );
    SetUnderlyingLeftModule( B, EisensteinIntegers );
    SetIsIntegralBasis( B, true );
    SetBasisVectors( B, Immutable( [ 1, E(3) ] ) );
    B!.conductor:= 3;
    B!.zumbroichbase := [ 0, 1 ];

    # Return the basis.
    return B;
    end );

InstallMethod( Coefficients,
    "for the canonical basis of Eisenstein integers",
    [ IsCanonicalBasisEisensteinIntegersRep,
      IsCyc ], 0,
    function( B, v )
        return Coefficients(Basis(CF(3), BasisVectors(B)), v);
    end );

BindGlobal( "KleinianIntegers", Objectify( NewType(
    CollectionsFamily(CyclotomicsFamily),
    IsKleinianIntegers and IsAttributeStoringRep ),
    rec() ) );

SetLeftActingDomain( KleinianIntegers, Integers );
SetName( KleinianIntegers, "KleinianIntegers" );
SetString( KleinianIntegers, "KleinianIntegers" );
SetIsLeftActedOnByDivisionRing( KleinianIntegers, false );
SetSize( KleinianIntegers, infinity );
SetGeneratorsOfRing( KleinianIntegers, [ 1, EB(7) ] );
SetGeneratorsOfLeftModule( KleinianIntegers, [ 1, EB(7) ] );
SetIsFinitelyGeneratedMagma( KleinianIntegers, false );
SetUnits( KleinianIntegers, Set([ -1, 1 ] ));
SetIsWholeFamily( KleinianIntegers, false );

InstallMethod( IsKleinInt, 
    "for cyclotomics", 
    [ IsCyc ],
    function(x)
        if DegreeOverPrimeField(Field(Union(Basis(KleinianIntegers), [x]))) > 2 then 
            return false;
        fi; 
        return ForAll(Coefficients(Basis(KleinianIntegers), x), IsInt);
    end);

InstallMethod( \in,
    "for Kleinian integers",
    IsElmsColls,
    [ IsCyc, IsKleinianIntegers ],
    function( cyc, KleinianIntegers )
        return IsKleinInt( cyc );
    end );

InstallMethod( Basis,
    "for Kleinian integers (delegate to `CanonicalBasis')",
    [ IsKleinianIntegers ], CANONICAL_BASIS_FLAGS,
    CanonicalBasis );

InstallMethod( CanonicalBasis,
    "for Kleinian integers",
    [ IsKleinianIntegers ],
    function( KleinianIntegers )
    local B;

    B:= Objectify( NewType( FamilyObj( KleinianIntegers ),
                                IsFiniteBasisDefault
                            and IsCanonicalBasis
                            and IsCanonicalBasisKleinianIntegersRep ),
                   rec() );
    SetUnderlyingLeftModule( B, KleinianIntegers );
    SetIsIntegralBasis( B, true );
    SetBasisVectors( B, Immutable( [ 1, EB(7) ] ) );
    return B;
    end );

InstallMethod( Coefficients,
    "for the canonical basis of IcosianRing",
    [ IsCanonicalBasisKleinianIntegersRep,
      IsCyc ], 0,
    function( B, v )
        return Coefficients(Basis(Field(EB(7)), BasisVectors(B)), v);
    end );


# Quaternion tools

InstallMethod( Trace, 
    "for a quaternion",
    [ IsQuaternion and IsSCAlgebraObj ],
    quat -> ExtRepOfObj(quat + ComplexConjugate(quat))[1]
    );

InstallMethod( Norm, 
    "for a quaternion",
    [ IsQuaternion and IsSCAlgebraObj ],
    quat -> ExtRepOfObj(quat*ComplexConjugate(quat))[1]
    );

BindGlobal( "QuaternionD4Basis", Basis(QuaternionAlgebra(Rationals),
    List([  [  -1/2,  -1/2,  -1/2,   1/2 ],
            [  -1/2,  -1/2,   1/2,  -1/2 ],
            [  -1/2,   1/2,  -1/2,  -1/2 ],
            [     1,     0,     0,     0 ] ], x -> ObjByExtRep(FamilyObj(One(QuaternionAlgebra(Rationals))),x)
        )) );

BindGlobal( "HurwitzIntegers", Objectify( NewType(
    CollectionsFamily(FamilyObj(QuaternionAlgebra(Rationals))),
    IsHurwitzIntegers and IsRingWithOne and IsQuaternionCollection and IsAttributeStoringRep ),
    rec() ) );

SetLeftActingDomain( HurwitzIntegers, Integers );
SetName( HurwitzIntegers, "HurwitzIntegers" );
SetString( HurwitzIntegers, "HurwitzIntegers" );
SetIsLeftActedOnByDivisionRing( HurwitzIntegers, false );
SetSize( HurwitzIntegers, infinity );
SetGeneratorsOfRing( HurwitzIntegers, AsList(QuaternionD4Basis));
SetGeneratorsOfLeftModule( HurwitzIntegers, AsList(QuaternionD4Basis) );
SetIsWholeFamily( HurwitzIntegers, false );
SetIsAssociative( HurwitzIntegers, false );

InstallMethod( Units, 
    "For Hurwitz integers", 
    [ IsHurwitzIntegers ],
    function(O)
        return Closure(Basis(O), \*);
    end);

InstallMethod( IsHurwitzInt, 
    "for Quaternions", 
    [ IsQuaternion ],
    function(x) 
        return ForAll(Coefficients(Basis(HurwitzIntegers), x), IsInt);
    end);

InstallMethod( \in,
    "for integers",
    [ IsQuaternion, IsHurwitzIntegers ], 10000,
    function( n, Integers )
    return IsHurwitzInt( n );
    end );

InstallMethod( Basis,
    "for Hurwitz integers (delegate to `CanonicalBasis')",
    [ IsHurwitzIntegers ], CANONICAL_BASIS_FLAGS,
    CanonicalBasis );


InstallMethod( CanonicalBasis,
    "for Hurwitz integers",
    [ IsHurwitzIntegers ],
    function( HurwitzIntegers )
    local B;
    B:= Objectify( NewType( FamilyObj( HurwitzIntegers ),
                                IsFiniteBasisDefault
                            and IsCanonicalBasis
                            and IsQuaternionCollection
                            and IsCanonicalBasisHurwitzIntegersRep ),
                   rec() );
    SetUnderlyingLeftModule( B, HurwitzIntegers );
    SetIsIntegralBasis( B, true );
    SetBasisVectors( B, Immutable( BasisVectors(QuaternionD4Basis)));
    # Return the basis.
    return B;
    end );

InstallMethod( Coefficients,
    "for the canonical basis of HurwitzIntegers",
    [ IsCanonicalBasisHurwitzIntegersRep,
      IsQuaternion ], 0,
    function( B, v )
        return SolutionMat(List(B, ExtRepOfObj), ExtRepOfObj(v));
    end );

# Icosian and Golden Field Tools

InstallGlobalFunction( GoldenModSigma, function(q)
    # Check that q belongs to the quadratic field containing Sqrt(5).
    if not q in NF(5,[1,4]) then return fail; fi;
    # Compute the coefficients in the basis [1,(1-Sqrt(5))/2] and return the 1 coefficient.
    return Coefficients(Basis(NF(5,[1,4]), [1, (1-Sqrt(5))/2]), q)[1];
end );

BindGlobal( "IcosianH4Generators", Basis(QuaternionAlgebra(Field(Sqrt(5))),
    List([  [ 0, -1, 0, 0 ], 
            [ 0, -1/2*E(5)^2-1/2*E(5)^3, 1/2, -1/2*E(5)-1/2*E(5)^4 ],
            [ 0, 0, -1, 0 ], 
            [ -1/2*E(5)-1/2*E(5)^4, 0, 1/2, -1/2*E(5)^2-1/2*E(5)^3 ] ], 
        x -> ObjByExtRep(FamilyObj(One(QuaternionAlgebra(Field(Sqrt(5))))),x)
        )) );


BindGlobal( "IcosianRing", Objectify( NewType(
    CollectionsFamily(FamilyObj(QuaternionAlgebra(Rationals))),
    IsIcosianRing and IsRingWithOne and IsQuaternionCollection and IsAttributeStoringRep ),
    rec() ) );

SetLeftActingDomain( IcosianRing, Integers );
SetName( IcosianRing, "IcosianRing" );
SetString( IcosianRing, "IcosianRing" );
SetIsLeftActedOnByDivisionRing( IcosianRing, false );
SetSize( IcosianRing, infinity );
SetGeneratorsOfRing( IcosianRing, AsList(IcosianH4Generators));
SetGeneratorsOfLeftModule( IcosianRing, AsList(IcosianH4Generators) );
SetIsWholeFamily( IcosianRing, false );
SetIsAssociative( IcosianRing, false );

InstallMethod( Units, 
    "For Icosians", 
    [ IsIcosianRing ],
    function(O)
        return Closure(Basis(O), \*);
    end);

InstallMethod( IsIcosian, 
    "for Quaternions", 
    [ IsQuaternion ],
    function(x) 
        return ForAll(Coefficients(Basis(IcosianRing), x), y -> 
                    ForAll(Coefficients(Basis(NF(5,[1,4]), [1, (1-Sqrt(5))/2]), y), IsInt)
            );
    end);

InstallMethod( \in,
    "for integers",
    [ IsQuaternion, IsIcosianRing ], 10000,
    function( n, Integers )
    return IsIcosian( n );
    end );

InstallMethod( Basis,
    "for Icosians (delegate to `CanonicalBasis')",
    [ IsIcosianRing ], CANONICAL_BASIS_FLAGS,
    CanonicalBasis );


InstallMethod( CanonicalBasis,
    "for Icosians",
    [ IsIcosianRing ],
    function( IcosianRing )
    local B;
    B:= Objectify( NewType( FamilyObj( IcosianRing ),
                                IsFiniteBasisDefault
                            and IsCanonicalBasis
                            and IsQuaternionCollection
                            and IsCanonicalBasisIcosianRingRep ),
                   rec() );
    SetUnderlyingLeftModule( B, IcosianRing );
    SetIsIntegralBasis( B, true );
    SetBasisVectors( B, Immutable( BasisVectors(IcosianH4Generators)));
    # Return the basis.
    return B;
    end );

InstallMethod( Coefficients,
    "for the canonical basis of IcosianRing",
    [ IsCanonicalBasisIcosianRingRep,
      IsQuaternion ], 0,
    function( B, v )
        return SolutionMat(List(B, ExtRepOfObj), ExtRepOfObj(v));
    end );

# Function to construct an octonion algebra in a standard basis (i.e. e[1]*e[2] = e[4], and cycle indices). 
InstallGlobalFunction( OctonionAlgebra, function( F )
    local e, stored, filter, T, A;
    # Arguments checking
    if not IsField(F) then 
        Error( "usage: OctonionAlgebra( <F> ) for a field <F>." );
    fi;
    e:= One( F );
    if e = fail then
      Error( "<F> must have an identity element" );
    fi;
    # Generators in the right family may be already available.
    stored := GET_FROM_SORTED_CACHE( OctonionAlgebraData, [ Characteristic(F), FamilyObj( F ) ],
        function()
            # Construct a filter describing element properties,
            # which will be stored in the family.
            filter:= IsSCAlgebraObj and IsOctonion;
            # if HasIsAssociative( F ) and IsAssociative( F ) then
            #     filter:= filter and IsAssociativeElement;
            # fi;
            T := [ [ [ [ 8 ], [ -1 ] ], [ [ 4 ], [ 1 ] ], [ [ 7 ], [ 1 ] ], [ [ 2 ], [ -1 ] ], [ [ 6 ], [ 1 ] ], 
                    [ [ 5 ], [ -1 ] ], [ [ 3 ], [ -1 ] ], [ [ 1 ], [ 1 ] ] ], 
                [ [ [ 4 ], [ -1 ] ], [ [ 8 ], [ -1 ] ], [ [ 5 ], [ 1 ] ], [ [ 1 ], [ 1 ] ], [ [ 3 ], [ -1 ] ], 
                    [ [ 7 ], [ 1 ] ], [ [ 6 ], [ -1 ] ], [ [ 2 ], [ 1 ] ] ], 
                [ [ [ 7 ], [ -1 ] ], [ [ 5 ], [ -1 ] ], [ [ 8 ], [ -1 ] ], [ [ 6 ], [ 1 ] ], [ [ 2 ], [ 1 ] ], 
                    [ [ 4 ], [ -1 ] ], [ [ 1 ], [ 1 ] ], [ [ 3 ], [ 1 ] ] ], 
                [ [ [ 2 ], [ 1 ] ], [ [ 1 ], [ -1 ] ], [ [ 6 ], [ -1 ] ], [ [ 8 ], [ -1 ] ], [ [ 7 ], [ 1 ] ], 
                    [ [ 3 ], [ 1 ] ], [ [ 5 ], [ -1 ] ], [ [ 4 ], [ 1 ] ] ], 
                [ [ [ 6 ], [ -1 ] ], [ [ 3 ], [ 1 ] ], [ [ 2 ], [ -1 ] ], [ [ 7 ], [ -1 ] ], [ [ 8 ], [ -1 ] ], 
                    [ [ 1 ], [ 1 ] ], [ [ 4 ], [ 1 ] ], [ [ 5 ], [ 1 ] ] ], 
                [ [ [ 5 ], [ 1 ] ], [ [ 7 ], [ -1 ] ], [ [ 4 ], [ 1 ] ], [ [ 3 ], [ -1 ] ], [ [ 1 ], [ -1 ] ], 
                    [ [ 8 ], [ -1 ] ], [ [ 2 ], [ 1 ] ], [ [ 6 ], [ 1 ] ] ], 
                [ [ [ 3 ], [ 1 ] ], [ [ 6 ], [ 1 ] ], [ [ 1 ], [ -1 ] ], [ [ 5 ], [ 1 ] ], [ [ 4 ], [ -1 ] ], 
                    [ [ 2 ], [ -1 ] ], [ [ 8 ], [ -1 ] ], [ [ 7 ], [ 1 ] ] ], 
                [ [ [ 1 ], [ 1 ] ], [ [ 2 ], [ 1 ] ], [ [ 3 ], [ 1 ] ], [ [ 4 ], [ 1 ] ], [ [ 5 ], [ 1 ] ], 
                    [ [ 6 ], [ 1 ] ], [ [ 7 ], [ 1 ] ], [ [ 8 ], [ 1 ] ] ], 0, Zero(F) ];
            # Construct the algebra.
            A:= AlgebraByStructureConstantsArg([ F, T, "e" ], filter );
            SetFilterObj( A, IsAlgebraWithOne );
            SetFilterObj( A, IsOctonionAlgebra );
            return A;
        end );
        A:= AlgebraWithOne( F, CanonicalBasis( stored ), "basis" );
        SetGeneratorsOfAlgebra( A, GeneratorsOfAlgebraWithOne( A ) );
        SetIsFullSCAlgebra( A, true );
        SetFilterObj( A, IsOctonionAlgebra );
    # Return the octonion algebra.
    return A;
    end );

InstallMethod( Trace,
    "for an octonion",
    [ IsOctonion and IsSCAlgebraObj ],
    oct -> 2*ExtRepOfObj(oct)[8] 
    );

InstallMethod( Norm,
    "for an octonion",
    [ IsOctonion and IsSCAlgebraObj ],
    oct -> ExtRepOfObj(oct)*ExtRepOfObj(oct) 
    );

InstallMethod( Norm,
    "for an octonion list",
    [ IsOctonionCollection ],
    function(vec)
        return Sum(List(vec, Norm) );
    end );

InstallMethod( ComplexConjugate,
    "for an octonion",
    [ IsOctonion and IsSCAlgebraObj ],
    oct -> One(oct)*Trace(oct) - oct
    );  

InstallMethod( RealPart,
    "for an octonion",
    [ IsOctonion and IsSCAlgebraObj ],
    oct -> (1/2)*Trace(oct)*One(oct)
    );

# Avoiding use of ImaginaryPart for octonions since the built in GAP quaternion version of this command is easily misunderstood. 

# InstallMethod( ImaginaryPart,
#     "for an octonion",
#     [ IsOctonion and IsSCAlgebraObj ],
#     oct -> oct - RealPart(oct)
#     );

# Octonion arithmetic tools

BindGlobal( "OctonionE8Basis", Basis(OctonionAlgebra(Rationals),
    List(
        [[ -1/2, 0, 0, 0, 1/2, 1/2, 1/2, 0 ], 
    [ -1/2, -1/2, 0, -1/2, 0, 0, -1/2, 0 ], 
    [ 0, 1/2, 1/2, 0, -1/2, 0, -1/2, 0 ], 
    [ 1/2, 0, -1/2, 1/2, 1/2, 0, 0, 0 ],
    [ 0, -1/2, 1/2, 0, -1/2, 0, 1/2, 0 ], 
    [ 0, 1/2, 0, -1/2, 1/2, -1/2, 0, 0 ], 
    [ -1/2, 0, -1/2, 1/2, -1/2, 0, 0, 0 ], 
    [ 1/2, 0, 0, -1/2, 0, 1/2, 0, -1/2 ] ], 
        x -> ObjByExtRep(FamilyObj(One(OctonionAlgebra(Rationals))),x)
        )) );       

BindGlobal( "OctavianIntegers", Objectify( NewType(
    CollectionsFamily(FamilyObj(OctonionAlgebra(Rationals))),
    IsOctavianIntegers and IsRingWithOne and IsOctonionCollection and IsAttributeStoringRep ),
    rec() ) );

SetLeftActingDomain( OctavianIntegers, Integers );
SetName( OctavianIntegers, "OctavianIntegers" );
SetString( OctavianIntegers, "OctavianIntegers" );
SetIsLeftActedOnByDivisionRing( OctavianIntegers, false );
SetSize( OctavianIntegers, infinity );
SetGeneratorsOfRing( OctavianIntegers, AsList(OctonionE8Basis));
SetGeneratorsOfLeftModule( OctavianIntegers, AsList(OctonionE8Basis) );
SetIsWholeFamily( OctavianIntegers, false );
SetIsAssociative( OctavianIntegers, false );

InstallMethod( Units, 
    "For octavian integers", 
    [ IsOctavianIntegers ],
    function(O)
        return Closure(Basis(O), \*);
    end);

InstallMethod( IsOctavianInt, 
    "for Octonions", 
    [ IsOctonion ],
    function(x) 
        return ForAll(Coefficients(Basis(OctavianIntegers), x), IsInt);
    end);

InstallMethod( \in,
    "for integers",
    [ IsOctonion, IsOctavianIntegers ], 10000,
    function( n, Integers )
    return IsOctavianInt( n );
    end );

InstallMethod( Basis,
    "for Octavian integers (delegate to `CanonicalBasis')",
    [ IsOctavianIntegers ], CANONICAL_BASIS_FLAGS,
    CanonicalBasis );


InstallMethod( CanonicalBasis,
    "for Octavian integers",
    [ IsOctavianIntegers ],
    function( OctavianIntegers )
    local B;
    B:= Objectify( NewType( FamilyObj( OctavianIntegers ),
                                IsFiniteBasisDefault
                            and IsCanonicalBasis
                            and IsOctonionCollection
                            and IsCanonicalBasisOctavianIntegersRep ),
                   rec() );
    SetUnderlyingLeftModule( B, OctavianIntegers );
    SetIsIntegralBasis( B, true );
    SetBasisVectors( B, Immutable( BasisVectors(OctonionE8Basis)));
    # Return the basis.
    return B;
    end );

InstallMethod( Coefficients,
    "for the canonical basis of OctavianIntegers",
    [ IsCanonicalBasisOctavianIntegersRep,
      IsOctonion ], 0,
    function( B, v )
        return SolutionMat(List(B, ExtRepOfObj), ExtRepOfObj(v));
    end );

InstallMethod( \mod, 
    "For an octonion integer", 
    [IsOctonion, IsPosInt], 0,
    function(a,m)
        local coeffs;
        coeffs := Coefficients(Basis(OctavianIntegers), a); 
        if not ForAll(coeffs, IsInt) then 
            return fail;
        fi; 
        return LinearCombination(Basis(OctavianIntegers),  coeffs mod m);
    end );

# Potentially replace the function below with a method.

# InstallMethod( OctonionToRealVector, 
#     "For an octonion basis and vector",
#     [ IsBasis, IsRowVector ], 0,
#     function(basis, x)
#         if IsHomogeneousList(Flat(AsList(Basis), x)) and 
#             IsOctonionCollection(x) 
#         then 
#             return Flat(List(x, y -> Coefficients(basis, y)) );
#         fi;
#         return fail;
#     end );

InstallGlobalFunction( OctonionToRealVector,
    function(arg, x) 
    # In the case of an octonion basis return the concatenated octonion basis expansion.
    if IsBasis(arg) and IsOctonionCollection(UnderlyingLeftModule(arg)) and IsOctonionCollection(x) then 
        return Concatenation(List(x, y -> Coefficients(arg, y)) );
    fi;
    return fail;
    end );

InstallMethod( Coefficients, 
    "For an octonion lattice basis and an octonion vector",
    [ IsOctonionLatticeBasis, IsOctonionCollection ], 0,
    function(basis, x)
        local L;
        L := UnderlyingLeftModule(basis);
        if x in L then 
            # return OctonionToRealVector(UnderlyingLeftModule(basis), x);
            return SolutionMat(LLLReducedBasisCoefficients(L),
            OctonionToRealVector((UnderlyingOctonionRingBasis(L)), x));
        fi;
        return fail;
    end );

InstallGlobalFunction( RealToOctonionVector,
    function(arg, x)
        local n, temp;
        # In the case of an octonion basis convert each length of 8 into an octonion,
        # Check length of coefficient vector.
        if IsBasis(arg) and IsOctonionCollection(UnderlyingLeftModule(arg)) then
            if Length(x) mod 8 = 0 and IsHomogeneousList(x) then 
                n := Length(x)/8;
                temp := List([1..n], m -> x{[(m-1)*8+1 .. m*8]} );;
                return List(temp, y -> LinearCombination(arg, y) );
            fi;
        fi;
        return fail;
    end );

InstallGlobalFunction( VectorToIdempotentMatrix, 
    function(x)
        local temp;
        if not IsHomogeneousList(x) or not IsAssociative(x) or not (IsCyc(x[1]) or IsQuaternion(x[1]) or IsOctonion(x[1])) then 
            return fail;
        fi;
        if IsAssociative(x) then 
            temp := TransposedMat([ComplexConjugate(x)])*[x];
            return temp/Trace(temp );
        fi; 
        return fail;
    end );

InstallGlobalFunction( WeylReflection, 
    function(r,x)
        local R;
        R := VectorToIdempotentMatrix(r );
        if R = fail or not IsHomogeneousList(Flat([r,x])) then 
            return fail; 
        fi;
        return x - 2*x*R;
    end );


# Jordan Algebra Tools

InstallMethod( Rank, 
    "for a Jordan Algebra",
    [ IsJordanAlgebra ],
    J -> JordanRank(J)
    );

InstallMethod( JordanRank, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    j -> JordanRank(FamilyObj(j)!.fullSCAlgebra)
    );

InstallMethod( Rank, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    j -> JordanRank(j)
    );

InstallMethod( JordanDegree, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    j -> JordanDegree(FamilyObj(j)!.fullSCAlgebra)
    );

InstallMethod( Degree, 
    "for a Jordan Algebra",
    [ IsJordanAlgebra ],
    J -> JordanDegree(J)
    );

InstallMethod( Degree, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    j -> JordanDegree(j)
    );

InstallMethod( Trace,
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj and IsSCAlgebraObj ],
    # j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j))
    j -> ExtRepOfObj(j)*JordanBasisTraces(FamilyObj(j)!.fullSCAlgebra) 
    );

InstallMethod( Norm,
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj and IsSCAlgebraObj ],
    j -> Trace(j^2)/2
    );

InstallGlobalFunction( GenericMinimalPolynomial, 
    function(x)
        local p, prx, p1xr, r, j, qjx;
        p := [-Trace(x)];
        p1xr := [-Trace(x)];
        r := 1;
        repeat 
            r := r + 1;
            Append(p1xr, [-Trace(x^r)] ); 
            prx := (1/r)*(p1xr[r] + Sum(List([1..r-1], j -> 
                p1xr[r-j]*p[j]
            )) );
            Append(p, [prx] );
        until r = Rank(x );
        p := Reversed(p );
        Append(p, [1] );
        return p;
    end );

InstallMethod( Determinant,
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj and IsSCAlgebraObj ],
    j -> ValuePol(GenericMinimalPolynomial(j), 0)*(-1)^Rank(j) 
    );

InstallMethod( JordanAdjugate, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    function(j) return (-1)^(1+Rank(j))*ValuePol(ShiftedCoeffs(GenericMinimalPolynomial(j), -1), j ); end
    );

InstallMethod( IsPositiveDefinite, 
    "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    function(j) local temp; 
        temp := GenericMinimalPolynomial(j ); 
        if 0 in temp then return false; fi;
        temp := Reversed(temp );
        temp := List([0..Rank(j)], n -> temp[n+1]*(-1)^n > 0 );
        if Set(temp) = [true] then return true; fi;
        return false;
    end );

# Function to construct basis matrices for a Hermitian simple Euclidean Jordan algebra.
InstallGlobalFunction( HermitianJordanAlgebraBasis, function(rho, comp_alg_basis)
    local d, C, F, peirce, conj, mat, frame, realbasis;
    # Ensure that the rank and degree are correct.
    if not (IsInt(rho) and rho > 1 and IsBasis(comp_alg_basis)) then 
        return fail; 
    fi;
    d := Length(comp_alg_basis);
    if (not d in [1,2,4,8]) or (d = 8 and rho > 3) then 
        return fail; 
    fi;
    # Record the composition algebra over F.
    C := UnderlyingLeftModule(comp_alg_basis);
    F := LeftActingDomain(C);
    # Require that F is either integers or a field of characteristic zero.
    if not (IsIntegers(F) or (IsField(F) and Characteristic(F) = 0)) then 
        return fail;
    fi;
    # It is possible that the d = 1 or 2 cases do not involve quaternions or octonion SCAlgebra objects
    if not (IsOctonionCollection(C) or IsQuaternionCollection(C)) then 
        # Only real and complex cases remain, which must be quadratic extensions of some number field. 
        if d > 2 then 
            return fail; 
        fi;
        # Rule out subfields of the rationals for d = 2:
        if d = 2 and Set(comp_alg_basis, x -> RealPart(x) = x ) = [true]
            then return fail;
        fi;
    fi;
    # Define a function to construct a single entry Hermitian matrix.
    mat := function(n,x)
        local temp; 
        if Length(n) <> 2 then return fail; fi;
        temp := Zero(x)*IdentityMat( rho );
        temp[n[1]][n[2]] := x;
        temp[n[2]][n[1]] := ComplexConjugate( x );
        return temp;
    end;
    # Construct the diagonal matrices. 
    frame := Concatenation(List(IdentityMat(rho), x -> List([One(C)], r -> DiagonalMat(x)*r)) );
    # Construct the off-diagonal matrices.
    peirce := List(Combinations([1..rho],2), n -> List(comp_alg_basis, x -> mat(n,x)) );
    # Return the matrices. 
    return Concatenation(frame, Concatenation(peirce) );
end );

# Function to convert a Hermitian matrix to a vector, or coefficients of a vector, in a Jordan algebra. 
InstallGlobalFunction( HermitianMatrixToJordanCoefficients, function(mat, comp_alg_basis)
    local temp, rho, d, i, basis;
    # Verify that the input is a Hermitian matrix.
    if not IsMatrix(mat) and mat = TransposedMat(ComplexConjugate(mat)) then return fail; fi;
    # Ensure that the second input is a basis. 
    if not IsBasis(comp_alg_basis) then return fail; fi;
    # Record basic parameters. 
    basis := comp_alg_basis;
    rho := Length(DiagonalOfMat(mat) );
    d := Size(basis); 
    # Define a temporary list of coefficients.
    temp := []; 
    # Determine the coefficients due to the diagonal components of the matrix.
    for i in [1..rho] do 
        if IsQuaternionCollection(comp_alg_basis) or IsOctonionCollection(comp_alg_basis) then  
            Append(temp, [Trace(mat[i][i])/2] );
        elif IsCyclotomicCollection(comp_alg_basis) then 
            Append(temp, [RealPart(mat[i][i])]);
        else
            Display("Here"); 
            return fail;
        fi;
    od;
    # Find the off-diagonal coefficients next.
    for i in Combinations([1..rho],2) do
        # if not (IsQuaternionCollection(comp_alg_basis) or IsOctonionCollection(comp_alg_basis) ) and LeftActingDomain(UnderlyingLeftModule(comp_alg_basis)) = Integers then     
        #     Append(temp, Coefficients(Basis(Rationals,[1]), mat[i[1]][i[2]]) );
        # else 
        #     Append(temp, Coefficients(basis, mat[i[1]][i[2]]) );
        # fi;
        Append(temp, Coefficients(basis, mat[i[1]][i[2]]) );
    od;
    # Return the coefficients.
    return temp;
end );

# Function to convert a Hermitian matrix into a Jordan algebra vector. 
InstallGlobalFunction( HermitianMatrixToJordanVector, function(mat, J)
    local temp;
    # Verify that the second argument is a Jordan algebra with an off-diagonal basis defined. 
    if not (IsJordanAlgebra(J) and HasJordanOffDiagonalBasis(J)) then 
        return fail; 
    fi;
    # Verify that the matrix entries belong to the algebra spanned by the off-diagonal basis. 
    if not IsHomogeneousList(Flat([mat, JordanOffDiagonalBasis(J)])) then return fail; fi;
    # Compute the coefficients, if possible.
    temp := HermitianMatrixToJordanCoefficients(mat, JordanOffDiagonalBasis(J) );
    if temp = fail then return temp; fi;
    # Return the coefficients in J-vector form.
    return LinearCombination(Basis(J), temp );
end );

# Function to construct Jordan algebra of Hermitian type.
InstallGlobalFunction( HermitianSimpleJordanAlgebra, function(rho, comp_alg_basis, F...)
    local jordan_basis, C, K, T, temp, coeffs, algebra, filter, n, m, z, l;
    # Ensure inputs are correct by computing basis vectors:
    if Length(F) > 1 then 
        return fail; 
    fi;
    jordan_basis := HermitianJordanAlgebraBasis(rho, comp_alg_basis );
    if jordan_basis = fail then 
        return jordan_basis; 
    fi;
    # Record the composition algebra over F.
    C := UnderlyingLeftModule(comp_alg_basis);
    K := LeftActingDomain(C);
    if Length(F) = 0 and IsSubset(Rationals, K) then 
        K := Rationals;
    fi;
    # Ensure that the optional field argument contains the left acting domain of the basis. 
    if Length(F) = 1 then
        F := F[1]; 
        if not (IsField(F) or IsIntegers(F)) then 
            return fail;  
        elif IsField(F) and not IsSubset(F, K) then 
            return fail;
        fi;
        K := F;
    fi;
    # Define an empty structure constants table.
    T := EmptySCTable(Size(jordan_basis), Zero(K) );
    # Compute the structure constants.
    for n in [1..Size(jordan_basis)] do 
        for m in [1..Size(jordan_basis)] do 
            z := (1/2)*(jordan_basis[n]*jordan_basis[m] + jordan_basis[m]*jordan_basis[n] );
            # z := (jordan_basis[n]*jordan_basis[m] + jordan_basis[m]*jordan_basis[n] );
            temp := HermitianMatrixToJordanCoefficients(z, comp_alg_basis );
            coeffs := [];
            for l in [1..Size(jordan_basis)] do 
                if temp[l] <> 0 then 
                    Append(coeffs, [temp[l], l] );
                fi;
            od;
            SetEntrySCTable( T, n, m, coeffs );
        od;
    od;
    # Construct the algebra.
    filter:= IsSCAlgebraObj and IsJordanAlgebraObj;
    algebra := AlgebraByStructureConstantsArg([K, T], filter );
    SetFilterObj( algebra, IsJordanAlgebra );
    SetFilterObj( algebra, IsAlgebraWithOne);
    # Assign various attributes to the algebra.
    SetJordanRank( algebra, rho );
    SetJordanDegree( algebra, Length(comp_alg_basis) );
    SetJordanMatrixBasis( algebra, jordan_basis );
    SetJordanOffDiagonalBasis( algebra, comp_alg_basis );
    SetJordanHomotopeVector( algebra, One(algebra) );
    SetJordanBasisTraces( algebra, List(Basis(algebra), 
        j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j)))
        );
    return algebra;
end );

InstallGlobalFunction( JordanSpinFactor,  function(gram_mat)
    local result, T, n, m, z, temp, coeffs, filter;
    if not IsMatrix(gram_mat) or Inverse(gram_mat) = fail or gram_mat <> TransposedMat(gram_mat) then 
        Display("Usage: JordanSpinFactor(G) requires <G> to be a positive definite symmetric matrix.");
        return fail; 
    fi;
    result := rec( );
    result.F := Field(Flat(gram_mat) );
    result.rho := 2;
    result.d := DimensionsMat(gram_mat)[1]-1;
    # Construct the algebra.
    T := EmptySCTable(result.d + 2, Zero(0) );
    SetEntrySCTable(T, 1, 1, [1, 1] );
    for m in [2..result.d + 2] do 
        SetEntrySCTable(T, m, 1, [1, m] );
        SetEntrySCTable(T, 1, m, [1, m] );
    od;
    for n in [2..result.d + 2] do 
        for m in [2..result.d + 2] do
            SetEntrySCTable( T, n, m, [gram_mat[n-1][m-1], 1] );
        od;
    od;
    filter:= IsSCAlgebraObj and IsJordanAlgebraObj;
    result.algebra := AlgebraByStructureConstantsArg([result.F, T], filter );
    SetFilterObj( result.algebra, IsJordanAlgebra );
    SetFilterObj( result.algebra, IsAlgebraWithOne);
    SetJordanRank( result.algebra, result.rho );
    SetJordanDegree( result.algebra, result.d );
    SetJordanHomotopeVector( result.algebra, One(result.algebra) );
    SetJordanBasisTraces( result.algebra, List(Basis(result.algebra), 
        j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j)))
        );
    return result.algebra;
end );

InstallMethod( JordanAlgebraGramMatrix, 
    "for a Jordan algebra",
    [ IsJordanAlgebra ],
    j -> List(Basis(j), x -> List(Basis(j), y -> Trace(x*y)))
    );

InstallGlobalFunction( JordanHomotope , function(ring, u, label...)
    local result, temp, filter, T, n, m, z, l, coeffs;
    if not IsJordanAlgebra(ring) then return fail; fi;
    result := rec( );
    result.rho := Rank(ring );
    result.d := Degree(ring );
    result.F := LeftActingDomain(ring );
    T := EmptySCTable(Dimension(ring), Zero(result.F) );
    for n in Basis(ring) do 
        for m in Basis(ring) do 
            z := n*(u*m) + (n*u)*m - u*(n*m );
            temp := Coefficients(Basis(ring), z );
            coeffs := [];
            for l in [1..Dimension(ring)] do 
                if temp[l] <> Zero(temp[l]) then 
                    Append(coeffs, [temp[l], l] );
                fi;
            od;
            SetEntrySCTable( T, Position(Basis(ring), n), Position(Basis(ring), m), coeffs );
        od;
    od;
    filter:= IsSCAlgebraObj and IsJordanAlgebraObj;
    if Length(label) > 0 and IsString(label[1]) then 
        result.algebra := AlgebraByStructureConstantsArg([result.F, T, label[1]], filter );
    else 
        result.algebra := AlgebraByStructureConstantsArg([result.F, T], filter );
    fi;
    SetFilterObj( result.algebra, IsJordanAlgebra );
    if Inverse(u) <> fail then 
        SetFilterObj( result.algebra, IsAlgebraWithOne);
    fi;
    SetJordanRank( result.algebra, result.rho );
    SetJordanDegree( result.algebra, result.d );
    if HasJordanMatrixBasis( result.algebra) then 
        SetJordanMatrixBasis( result.algebra, JordanMatrixBasis(ring) );
    fi;
    if HasJordanOffDiagonalBasis(result.algebra) then 
        SetJordanOffDiagonalBasis( result.algebra, JordanOffDiagonalBasis(ring) );
    fi;
    SetJordanHomotopeVector( result.algebra, u );
    SetJordanBasisTraces( result.algebra, List(Basis(result.algebra), 
        j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j)))
        );
    return result.algebra;
end );

InstallGlobalFunction( SimpleEuclideanJordanAlgebra, function(rho, d, args...)
    local temp, F;
    temp := rec( );
    if not (IsInt(d) and IsInt(rho)) then return fail; fi;
    if rho < 2 then return fail; fi; 
    if rho > 2 and not d in [1,2,4,8] then return fail; fi;
    if d = 8 and rho > 3 then return fail; fi;
    if rho = 2 then 
        if Length(args) = 0 then 
            return JordanSpinFactor(IdentityMat(d+1) );
            elif IsMatrix(args[1]) and DimensionsMat(args[1]) = [d+1, d+1] and TransposedMat(args[1]) = args[1] and Inverse(args[1]) <> fail then 
                return JordanSpinFactor(args[1] );
        elif d in [1,2,4,8] and IsBasis(args[1]) and Size(args[1]) = d then 
            return HermitianSimpleJordanAlgebra(rho, args[1] );
        else
            Display("Usage: SimpleEuclideanJordanAlgebra(2, d [, args]) where <args> is either empty, a symmetric invertible matrix, or when <d> = 1,2,4,8 <args> can also be a basis for a composition algebra."); 
            return fail;
        fi;
    fi;

    if Length(args) = 0 then
        if d = 8 then 
            return HermitianSimpleJordanAlgebra(rho, Basis(OctonionAlgebra(Rationals)) );
        elif d = 4 then 
            return HermitianSimpleJordanAlgebra(rho, Basis(QuaternionAlgebra(Rationals)) );
        elif d = 2 then 
            return HermitianSimpleJordanAlgebra(rho, Basis(CF(4), [1, E(4)]) );
        elif d = 1 then 
            return HermitianSimpleJordanAlgebra(rho, Basis(Rationals, [1]) );
        fi;
    elif IsBasis(args[1]) and Size(args[1]) = d then 
        return HermitianSimpleJordanAlgebra(rho, args[1] );
    else 
        return fail;
    fi;
end );

# Albert Algebra tools

InstallGlobalFunction( AlbertAlgebra, function( F )
    local e, i, j, k, jordan_basis, stored, filter, T, A;
    # Arguments checking
    if not IsField(F) then 
        Error( "usage: AlbertAlgebra( <F> ) for a field <F>." );
    fi;
    e:= One( F );
    if e = fail then
      Error( "<F> must have an identity element" );
    fi;
    # Generators in the right family may be already available.
    stored := GET_FROM_SORTED_CACHE( AlbertAlgebraData, [ Characteristic(F), FamilyObj( F ) ],
        function()
            filter:= IsSCAlgebraObj and IsJordanAlgebraObj and IsAlbertAlgebraObj;
            T := [ [ [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 24 ], [ -1/2 ] ], [ [ 20 ], [ -1/2 ] ], 
      [ [ 23 ], [ -1/2 ] ], [ [ 18 ], [ 1/2 ] ], [ [ 22 ], [ -1/2 ] ], [ [ 21 ], [ 1/2 ] ], 
      [ [ 19 ], [ 1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 12 ], [ 1/2 ] ], 
      [ [ 15 ], [ 1/2 ] ], [ [ 10 ], [ -1/2 ] ], [ [ 14 ], [ 1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 11 ], [ -1/2 ] ], [ [ 9 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 1 ], [ 1/2 ] ], 
      [ [ 1 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 20 ], [ 1/2 ] ], [ [ 24 ], [ -1/2 ] ], 
      [ [ 21 ], [ -1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 19 ], [ 1/2 ] ], [ [ 23 ], [ -1/2 ] ], 
      [ [ 22 ], [ 1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], [ [ 16 ], [ -1/2 ] ], 
      [ [ 13 ], [ 1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 15 ], [ 1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 10 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 2 ], [ 1/2 ] ], 
      [ [ 2 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 23 ], [ 1/2 ] ], [ [ 21 ], [ 1/2 ] ], 
      [ [ 24 ], [ -1/2 ] ], [ [ 22 ], [ -1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 20 ], [ 1/2 ] ], 
      [ [ 17 ], [ -1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 16 ], [ -1/2 ] ], [ [ 14 ], [ 1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 12 ], [ -1/2 ] ], 
      [ [ 9 ], [ 1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 3 ], [ 1/2 ] ], 
      [ [ 3 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 18 ], [ -1/2 ] ], [ [ 17 ], [ 1/2 ] ], 
      [ [ 22 ], [ 1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], [ [ 19 ], [ -1/2 ] ], 
      [ [ 21 ], [ 1/2 ] ], [ [ 20 ], [ -1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 9 ], [ -1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 15 ], [ 1/2 ] ], [ [ 11 ], [ 1/2 ] ], 
      [ [ 13 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 4 ], [ 1/2 ] ] ], [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 22 ], [ 1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 18 ], [ 1/2 ] ], [ [ 23 ], [ 1/2 ] ], 
      [ [ 24 ], [ -1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 20 ], [ -1/2 ] ], [ [ 21 ], [ -1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 11 ], [ 1/2 ] ], [ [ 10 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], 
      [ [ 16 ], [ -1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [ 12 ], [ 1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [ 5 ], [ 1/2 ] ], [ [ 5 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 21 ], [ -1/2 ] ], 
      [ [ 23 ], [ 1/2 ] ], [ [ 20 ], [ -1/2 ] ], [ [ 19 ], [ 1/2 ] ], [ [ 17 ], [ 1/2 ] ], 
      [ [ 24 ], [ -1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 22 ], [ -1/2 ] ], [ [ 13 ], [ 1/2 ] ], 
      [ [ 15 ], [ -1/2 ] ], [ [ 12 ], [ 1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 9 ], [ -1/2 ] ], 
      [ [ 16 ], [ -1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 14 ], [ -1/2 ] ], [ [  ], [  ] ], 
      [ [ 6 ], [ 1/2 ] ], [ [ 6 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [ 26, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [ 19 ], [ -1/2 ] ], 
      [ [ 22 ], [ -1/2 ] ], [ [ 17 ], [ 1/2 ] ], [ [ 21 ], [ -1/2 ] ], [ [ 20 ], [ 1/2 ] ], 
      [ [ 18 ], [ 1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], [ [ 11 ], [ 1/2 ] ], 
      [ [ 14 ], [ 1/2 ] ], [ [ 9 ], [ -1/2 ] ], [ [ 13 ], [ 1/2 ] ], [ [ 12 ], [ -1/2 ] ], 
      [ [ 10 ], [ -1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [  ], [  ] ], 
      [ [ 7 ], [ 1/2 ] ], [ [ 7 ], [ 1/2 ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [ 26, 27 ], [ 1, 1 ] ], [ [ 17 ], [ -1/2 ] ], 
      [ [ 18 ], [ -1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 20 ], [ -1/2 ] ], [ [ 21 ], [ -1/2 ] ], 
      [ [ 22 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], [ [ 24 ], [ 1/2 ] ], [ [ 9 ], [ -1/2 ] ], 
      [ [ 10 ], [ -1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 16 ], [ 1/2 ] ], [ [  ], [  ] ], 
      [ [ 8 ], [ 1/2 ] ], [ [ 8 ], [ 1/2 ] ] ], 
  [ [ [ 24 ], [ -1/2 ] ], [ [ 20 ], [ 1/2 ] ], [ [ 23 ], [ 1/2 ] ], [ [ 18 ], [ -1/2 ] ], 
      [ [ 22 ], [ 1/2 ] ], [ [ 21 ], [ -1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 17 ], [ -1/2 ] ], 
      [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 8 ], [ -1/2 ] ], [ [ 4 ], [ -1/2 ] ], 
      [ [ 7 ], [ -1/2 ] ], [ [ 2 ], [ 1/2 ] ], [ [ 6 ], [ -1/2 ] ], [ [ 5 ], [ 1/2 ] ], 
      [ [ 3 ], [ 1/2 ] ], [ [ 1 ], [ -1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [  ], [  ] ], 
      [ [ 9 ], [ 1/2 ] ] ], [ [ [ 20 ], [ -1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 21 ], [ 1/2 ] ], 
      [ [ 17 ], [ 1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 23 ], [ 1/2 ] ], [ [ 22 ], [ -1/2 ] ], 
      [ [ 18 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 4 ], [ 1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 5 ], [ -1/2 ] ], [ [ 1 ], [ -1/2 ] ], 
      [ [ 3 ], [ 1/2 ] ], [ [ 7 ], [ -1/2 ] ], [ [ 6 ], [ 1/2 ] ], [ [ 2 ], [ -1/2 ] ], 
      [ [ 10 ], [ 1/2 ] ], [ [  ], [  ] ], [ [ 10 ], [ 1/2 ] ] ], 
  [ [ [ 23 ], [ -1/2 ] ], [ [ 21 ], [ -1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 22 ], [ 1/2 ] ], 
      [ [ 18 ], [ 1/2 ] ], [ [ 20 ], [ -1/2 ] ], [ [ 17 ], [ 1/2 ] ], [ [ 19 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 7 ], [ 1/2 ] ], [ [ 5 ], [ 1/2 ] ], 
      [ [ 8 ], [ -1/2 ] ], [ [ 6 ], [ -1/2 ] ], [ [ 2 ], [ -1/2 ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 1 ], [ -1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 11 ], [ 1/2 ] ], [ [  ], [  ] ], 
      [ [ 11 ], [ 1/2 ] ] ], [ [ [ 18 ], [ 1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 22 ], [ -1/2 ] ], 
      [ [ 24 ], [ -1/2 ] ], [ [ 23 ], [ 1/2 ] ], [ [ 19 ], [ 1/2 ] ], [ [ 21 ], [ -1/2 ] ], 
      [ [ 20 ], [ -1/2 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 2 ], [ -1/2 ] ], [ [ 1 ], [ 1/2 ] ], [ [ 6 ], [ 1/2 ] ], [ [ 8 ], [ -1/2 ] ], 
      [ [ 7 ], [ -1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 5 ], [ 1/2 ] ], [ [ 4 ], [ -1/2 ] ], 
      [ [ 12 ], [ 1/2 ] ], [ [  ], [  ] ], [ [ 12 ], [ 1/2 ] ] ], 
  [ [ [ 22 ], [ -1/2 ] ], [ [ 19 ], [ 1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], 
      [ [ 24 ], [ -1/2 ] ], [ [ 17 ], [ 1/2 ] ], [ [ 20 ], [ 1/2 ] ], [ [ 21 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 6 ], [ 1/2 ] ], [ [ 3 ], [ -1/2 ] ], 
      [ [ 2 ], [ 1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 1 ], [ -1/2 ] ], 
      [ [ 4 ], [ -1/2 ] ], [ [ 5 ], [ -1/2 ] ], [ [ 13 ], [ 1/2 ] ], [ [  ], [  ] ], 
      [ [ 13 ], [ 1/2 ] ] ], [ [ [ 21 ], [ 1/2 ] ], [ [ 23 ], [ -1/2 ] ], [ [ 20 ], [ 1/2 ] ], 
      [ [ 19 ], [ -1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 18 ], [ 1/2 ] ], 
      [ [ 22 ], [ -1/2 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 5 ], [ -1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 4 ], [ -1/2 ] ], [ [ 3 ], [ 1/2 ] ], 
      [ [ 1 ], [ 1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 2 ], [ -1/2 ] ], [ [ 6 ], [ -1/2 ] ], 
      [ [ 14 ], [ 1/2 ] ], [ [  ], [  ] ], [ [ 14 ], [ 1/2 ] ] ], 
  [ [ [ 19 ], [ 1/2 ] ], [ [ 22 ], [ 1/2 ] ], [ [ 17 ], [ -1/2 ] ], [ [ 21 ], [ 1/2 ] ], 
      [ [ 20 ], [ -1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 24 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [ 3 ], [ -1/2 ] ], 
      [ [ 6 ], [ -1/2 ] ], [ [ 1 ], [ 1/2 ] ], [ [ 5 ], [ -1/2 ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 2 ], [ 1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 7 ], [ -1/2 ] ], [ [ 15 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [ 15 ], [ 1/2 ] ] ], 
  [ [ [ 17 ], [ -1/2 ] ], [ [ 18 ], [ -1/2 ] ], [ [ 19 ], [ -1/2 ] ], [ [ 20 ], [ -1/2 ] ], 
      [ [ 21 ], [ -1/2 ] ], [ [ 22 ], [ -1/2 ] ], [ [ 23 ], [ -1/2 ] ], [ [ 24 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 27 ], [ 1, 1 ] ], [ [ 1 ], [ -1/2 ] ], 
      [ [ 2 ], [ -1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 4 ], [ -1/2 ] ], [ [ 5 ], [ -1/2 ] ], 
      [ [ 6 ], [ -1/2 ] ], [ [ 7 ], [ -1/2 ] ], [ [ 8 ], [ 1/2 ] ], [ [ 16 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [ 16 ], [ 1/2 ] ] ], 
  [ [ [ 16 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 10 ], [ 1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 13 ], [ 1/2 ] ], [ [ 11 ], [ 1/2 ] ], [ [ 9 ], [ -1/2 ] ], 
      [ [ 8 ], [ -1/2 ] ], [ [ 4 ], [ 1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 2 ], [ -1/2 ] ], 
      [ [ 6 ], [ 1/2 ] ], [ [ 5 ], [ -1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 1 ], [ -1/2 ] ], 
      [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 17 ], [ 1/2 ] ], [ [ 17 ], [ 1/2 ] ], 
      [ [  ], [  ] ] ], [ [ [ 12 ], [ 1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 9 ], [ -1/2 ] ], [ [ 11 ], [ 1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 14 ], [ 1/2 ] ], 
      [ [ 10 ], [ -1/2 ] ], [ [ 4 ], [ -1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 5 ], [ 1/2 ] ], 
      [ [ 1 ], [ 1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 6 ], [ -1/2 ] ], 
      [ [ 2 ], [ -1/2 ] ], [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 18 ], [ 1/2 ] ], [ [ 18 ], [ 1/2 ] ], [ [  ], [  ] ] ], 
  [ [ [ 15 ], [ 1/2 ] ], [ [ 13 ], [ 1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 14 ], [ -1/2 ] ], 
      [ [ 10 ], [ -1/2 ] ], [ [ 12 ], [ 1/2 ] ], [ [ 9 ], [ -1/2 ] ], [ [ 11 ], [ -1/2 ] ], 
      [ [ 7 ], [ -1/2 ] ], [ [ 5 ], [ -1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 6 ], [ 1/2 ] ], 
      [ [ 2 ], [ 1/2 ] ], [ [ 4 ], [ -1/2 ] ], [ [ 1 ], [ 1/2 ] ], [ [ 3 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 19 ], [ 1/2 ] ], [ [ 19 ], [ 1/2 ] ], 
      [ [  ], [  ] ] ], [ [ [ 10 ], [ -1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [ 14 ], [ 1/2 ] ], 
      [ [ 16 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 13 ], [ 1/2 ] ], 
      [ [ 12 ], [ -1/2 ] ], [ [ 2 ], [ 1/2 ] ], [ [ 1 ], [ -1/2 ] ], [ [ 6 ], [ -1/2 ] ], 
      [ [ 8 ], [ -1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 3 ], [ 1/2 ] ], [ [ 5 ], [ -1/2 ] ], 
      [ [ 4 ], [ -1/2 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 20 ], [ 1/2 ] ], [ [ 20 ], [ 1/2 ] ], [ [  ], [  ] ] ], 
  [ [ [ 14 ], [ 1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 15 ], [ 1/2 ] ], 
      [ [ 16 ], [ -1/2 ] ], [ [ 9 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 6 ], [ -1/2 ] ], [ [ 3 ], [ 1/2 ] ], [ [ 2 ], [ -1/2 ] ], [ [ 7 ], [ -1/2 ] ], 
      [ [ 8 ], [ -1/2 ] ], [ [ 1 ], [ 1/2 ] ], [ [ 4 ], [ 1/2 ] ], [ [ 5 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 21 ], [ 1/2 ] ], [ [ 21 ], [ 1/2 ] ], 
      [ [  ], [  ] ] ], [ [ [ 13 ], [ -1/2 ] ], [ [ 15 ], [ 1/2 ] ], [ [ 12 ], [ -1/2 ] ], 
      [ [ 11 ], [ 1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 10 ], [ -1/2 ] ], 
      [ [ 14 ], [ -1/2 ] ], [ [ 5 ], [ 1/2 ] ], [ [ 7 ], [ -1/2 ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 3 ], [ -1/2 ] ], [ [ 1 ], [ -1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 2 ], [ 1/2 ] ], 
      [ [ 6 ], [ -1/2 ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 22 ], [ 1/2 ] ], [ [ 22 ], [ 1/2 ] ], [ [  ], [  ] ] ], 
  [ [ [ 11 ], [ -1/2 ] ], [ [ 14 ], [ -1/2 ] ], [ [ 9 ], [ 1/2 ] ], [ [ 13 ], [ -1/2 ] ], 
      [ [ 12 ], [ 1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 16 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], 
      [ [ 3 ], [ 1/2 ] ], [ [ 6 ], [ 1/2 ] ], [ [ 1 ], [ -1/2 ] ], [ [ 5 ], [ 1/2 ] ], 
      [ [ 4 ], [ -1/2 ] ], [ [ 2 ], [ -1/2 ] ], [ [ 8 ], [ -1/2 ] ], [ [ 7 ], [ -1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], [ [  ], [  ] ], [ [ 23 ], [ 1/2 ] ], 
      [ [ 23 ], [ 1/2 ] ], [ [  ], [  ] ] ], 
  [ [ [ 9 ], [ -1/2 ] ], [ [ 10 ], [ -1/2 ] ], [ [ 11 ], [ -1/2 ] ], [ [ 12 ], [ -1/2 ] ], 
      [ [ 13 ], [ -1/2 ] ], [ [ 14 ], [ -1/2 ] ], [ [ 15 ], [ -1/2 ] ], [ [ 16 ], [ 1/2 ] ], 
      [ [ 1 ], [ -1/2 ] ], [ [ 2 ], [ -1/2 ] ], [ [ 3 ], [ -1/2 ] ], [ [ 4 ], [ -1/2 ] ], 
      [ [ 5 ], [ -1/2 ] ], [ [ 6 ], [ -1/2 ] ], [ [ 7 ], [ -1/2 ] ], [ [ 8 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [ 25, 26 ], [ 1, 1 ] ], [ [ 24 ], [ 1/2 ] ], 
      [ [ 24 ], [ 1/2 ] ], [ [  ], [  ] ] ], 
  [ [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 9 ], [ 1/2 ] ], [ [ 10 ], [ 1/2 ] ], 
      [ [ 11 ], [ 1/2 ] ], [ [ 12 ], [ 1/2 ] ], [ [ 13 ], [ 1/2 ] ], [ [ 14 ], [ 1/2 ] ], 
      [ [ 15 ], [ 1/2 ] ], [ [ 16 ], [ 1/2 ] ], [ [ 17 ], [ 1/2 ] ], [ [ 18 ], [ 1/2 ] ], 
      [ [ 19 ], [ 1/2 ] ], [ [ 20 ], [ 1/2 ] ], [ [ 21 ], [ 1/2 ] ], [ [ 22 ], [ 1/2 ] ], 
      [ [ 23 ], [ 1/2 ] ], [ [ 24 ], [ 1/2 ] ], [ [ 25 ], [ 1 ] ], [ [  ], [  ] ], [ [  ], [  ] ] 
     ], [ [ [ 1 ], [ 1/2 ] ], [ [ 2 ], [ 1/2 ] ], [ [ 3 ], [ 1/2 ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 5 ], [ 1/2 ] ], [ [ 6 ], [ 1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 8 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [ 17 ], [ 1/2 ] ], [ [ 18 ], [ 1/2 ] ], 
      [ [ 19 ], [ 1/2 ] ], [ [ 20 ], [ 1/2 ] ], [ [ 21 ], [ 1/2 ] ], [ [ 22 ], [ 1/2 ] ], 
      [ [ 23 ], [ 1/2 ] ], [ [ 24 ], [ 1/2 ] ], [ [  ], [  ] ], [ [ 26 ], [ 1 ] ], [ [  ], [  ] ] 
     ], [ [ [ 1 ], [ 1/2 ] ], [ [ 2 ], [ 1/2 ] ], [ [ 3 ], [ 1/2 ] ], [ [ 4 ], [ 1/2 ] ], 
      [ [ 5 ], [ 1/2 ] ], [ [ 6 ], [ 1/2 ] ], [ [ 7 ], [ 1/2 ] ], [ [ 8 ], [ 1/2 ] ], 
      [ [ 9 ], [ 1/2 ] ], [ [ 10 ], [ 1/2 ] ], [ [ 11 ], [ 1/2 ] ], [ [ 12 ], [ 1/2 ] ], 
      [ [ 13 ], [ 1/2 ] ], [ [ 14 ], [ 1/2 ] ], [ [ 15 ], [ 1/2 ] ], [ [ 16 ], [ 1/2 ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], [ [  ], [  ] ], 
      [ [ 27 ], [ 1 ] ] ], 1, Zero(F) ]; 
            # Construct the algebra.
            A:= AlgebraByStructureConstantsArg([F, T, "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", 
            "j1", "j2", "j3", "j4", "j5", "j6", "j7", "j8", 
            "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", 
            "ei", "ej", "ek"], filter );
            SetFilterObj( A, IsAlgebraWithOne );
            SetFilterObj( A, IsJordanAlgebra );
            SetJordanRank( A, 3 );
            SetJordanDegree( A, 8 );
            SetJordanOffDiagonalBasis( A, Basis(OctonionAlgebra(Rationals)) );
            SetJordanHomotopeVector( A, One(A) );
            SetJordanBasisTraces( A, List(Basis(A), 
                j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j)))
            );
            return A;
        end );
        A:= AlgebraWithOne( F, CanonicalBasis( stored ), "basis" );
        SetGeneratorsOfAlgebra( A, GeneratorsOfAlgebraWithOne( A ) );
        SetIsFullSCAlgebra( A, true );
        SetFilterObj( A, IsJordanAlgebra );
        SetFilterObj( A, IsAlgebraWithOne);
        SetJordanRank( A, 3 );
        SetJordanDegree( A, 8 );
        SetJordanOffDiagonalBasis( A, Basis(OctonionAlgebra(Rationals)) );
        SetJordanHomotopeVector( A, One(A) );
        SetJordanBasisTraces( A, List(Basis(A), 
            j -> (Rank(j)/Dimension(FamilyObj(j)!.fullSCAlgebra))*Trace(AdjointMatrix(Basis(FamilyObj(j)!.fullSCAlgebra), j)))
        );
        jordan_basis := HermitianJordanAlgebraBasis(3, CanonicalBasis(OctonionAlgebra(Rationals)) );
        e := jordan_basis{[1..3]};
        i := jordan_basis{[20..27]};
        j := ComplexConjugate(jordan_basis{[12..19]});
        k := jordan_basis{[4..11]};
        jordan_basis := Concatenation([i,j,k,e]);
        SetJordanMatrixBasis( A, jordan_basis );
        return A;
    end );

InstallGlobalFunction( HermitianMatrixToAlbertVector, 
    function(mat)
        local temp;
        if not IsMatrix(mat) or not DimensionsMat(mat) = [3,3] or not IsSubset(OctonionAlgebra(Rationals), Flat(mat)) then 
            return fail;
        fi;
        if ComplexConjugate(TransposedMat(mat)) <> mat then 
            return fail;
        fi;
        temp := HermitianMatrixToJordanCoefficients(mat, Basis(OctonionAlgebra(Rationals)));
        temp := Concatenation([temp{[20..27]}, -temp{[12..18]}, temp{[19]}, temp{[4..11]}, temp{[1..3]}]);
        return LinearCombination(Basis(AlbertAlgebra(Rationals)), temp);
    end);

InstallGlobalFunction( AlbertVectorToHermitianMatrix, 
    function(vec)
        if not IsAlbertAlgebraObj(vec) then return fail; fi;
        return LinearCombination(JordanMatrixBasis(AlbertAlgebra(Rationals)), ExtRepOfObj(vec));
    end);



# See Faraut and Koranyi p. 32
InstallMethod( JordanQuadraticOperator, 
     "for a Jordan algebra element",
    [ IsJordanAlgebraObj ],
    function(j)
        return 2*AdjointMatrix(CanonicalBasis(FamilyObj(j)!.fullSCAlgebra), j)^2 - AdjointMatrix(CanonicalBasis(FamilyObj(j)!.fullSCAlgebra), j^2); 
    end);

InstallMethod( JordanQuadraticOperator, 
     "for a pair of Jordan algebra elements",
    [ IsJordanAlgebraObj, IsJordanAlgebraObj ],
    function(j, k)
        return 2*j*(j*k) - (j^2)*k; 
    end);

InstallMethod( JordanTripleSystem,
    "for three Jordan algebra elements",
    [IsJordanAlgebraObj, IsJordanAlgebraObj, IsJordanAlgebraObj],
    {x,y,z} -> x*(y*z) + (x*y)*z - (x*z)*y
    );

# T-Design Tools

InstallGlobalFunction( JacobiPolynomial, function(k, a, b)
    local temp, a1, a2, a3, a4, n, x;
    if not IsInt(k) and k > -1 then 
        return fail;
    fi; 
    if not (IsPolynomial(a) or (IsRat(a) and a > -1)) then 
        return fail;
    fi;
    if not (IsPolynomial(b) or (IsRat(b) and a > -1)) then 
        return fail;
    fi;  
    n := k - 1;
    a1 := 2*(n+1)*(n+a+b+1)*(2*n+a+b );
    a2 := (2*n+a+b+1)*(a^2 - b^2 );
    a3 := (2*n + a + b)*(2*n + a + b + 1)*(2*n + a + b + 2 );
    a4 := 2*(n+a)*(n+b)*(2*n+a+b+2 );
    x := [0,1];
    if k = 0 then 
        return [1];
    elif k = -1 then 
        return [0];
    elif k = 1 then 
        return (1/2)*[a-b,(a+b+2)];
    fi;
    return ProductCoeffs([a2/a1, a3/a1], JacobiPolynomial(k-1,a,b))-(a4/a1)*JacobiPolynomial(k-2,a,b );
end );

InstallGlobalFunction( Q_k_epsilon, function(k, epsilon, rank, degree, x) 
    local temp, p, poch, N, m;
    if k = 0 and epsilon = 0 then return 1+0*x; fi;
    m := degree/2;
    N := rank*m;
    p := ValuePol(JacobiPolynomial(k, N-m-1, m-1+epsilon), 2*x - 1 );
    poch := function(a,n)
        if n = 1 then return a;
        elif n =  0 then return 1;
        elif n < 0 then return 0;
        fi;
        return Product(List([1..n], b -> a + b -1) );
    end;
    temp := poch(N, k + epsilon - 1)*poch(N-m, k)*(2*k + N + epsilon - 1 );
    temp := temp/(Factorial(k)*poch(m,k+epsilon) );
    return temp*p/Value(p, [x], [1] );
end );

InstallGlobalFunction( R_k_epsilon, function(k, epsilon, rank, degree, x)
    local temp, n;
    temp := 0*x;
    for n in [0..k] do 
        temp := temp + Q_k_epsilon(n, epsilon, rank, degree, x );
    od;
    return temp;
end );

InstallGlobalFunction( JordanDesignByParameters, function(rank, degree)
    local obj, F, x;
    # Check that the inputs match a Jordan primitive idempotent space    
    if not IsInt(rank) or rank < 2 then return fail; fi;
    if rank > 2 and not degree in [1,2,4,8] then return fail; fi;
    if degree = 8 and rank > 3 then return fail; fi; 
    # Create the object
    obj := Objectify(NewType(NewFamily( "Design"), IsJordanDesign and IsComponentObjectRep, rec()), rec() );
    SetFilterObj(obj, IsAttributeStoringRep );
    # Assign rank and degree attributes.
    SetJordanDesignRank(obj, rank );
    SetJordanDesignDegree(obj, degree );
    # Assign Spherical or Projective filters.
    if rank = 2 then 
        SetFilterObj(obj, IsSphericalJordanDesign );
    fi;
    if degree in [1,2,4,8] then 
        SetFilterObj(obj, IsProjectiveJordanDesign );
    fi;
    return obj;
end );

InstallMethod( PrintObj,
    "for a design",
    [ IsJordanDesign ],
    function(x)
    local text;
    Print( "<design with rank ", JordanDesignRank(x), " and degree ", JordanDesignDegree(x), ">" );
   end );

InstallMethod(JordanDesignQPolynomials,
    "Generic method for designs",
    [ IsJordanDesign ],
    function(D)
        local x, temp;
        x := Indeterminate(Rationals, "x" );
        temp := function(k)
            if IsInt(k) and k > -1 then 
                return CoefficientsOfUnivariatePolynomial((Q_k_epsilon(k, 0, JordanDesignRank(D), JordanDesignDegree(D), x)) );
            fi;
            return fail;
        end;
        return temp;
    end );

InstallMethod( JordanDesignConnectionCoefficients,
    "Generic method for designs",
    [ IsJordanDesign ],
    function(D)
        local temp;
        temp := function(s)
            local x, Q, V, basis, mat, k, i;
            x := Indeterminate(Rationals, "x" );
            Q := List([0..s], i -> Q_k_epsilon(i,0, JordanDesignRank(D), JordanDesignDegree(D), x) );
            V := VectorSpace(Rationals, Q );
            basis := Basis(V, Q );
            mat := [];
            for k in [0..s] do 
                Append(mat, [
                    Coefficients(basis, x^k)
                ] );
            od;
            return mat;
        end;
        return temp; 
    end );

InstallMethod( JordanDesignAddAngleSet, 
    "for designs",
    [ IsJordanDesign, IsList ],
    function(D, A)
        if not (ForAll(A, IsCyc) and 
            ForAll(A, x -> ComplexConjugate(x) = x) and
            ForAll(A, x -> not IsRat(x) or (x < 1 and x >= 0)))
        then 
            return fail;
        fi;  
        SetJordanDesignAngleSet(D, Set(A) );
        SetFilterObj(D, IsJordanDesignWithAngleSet );
        # Assign Positive Indicator Coefficients filter if applicable.
        if [true] = Set(JordanDesignNormalizedIndicatorCoefficients(D), x -> x > 0) then 
            SetFilterObj(D, IsJordanDesignWithPositiveIndicatorCoefficients );
        fi;
        return D; 
    end );

InstallGlobalFunction( JordanDesignByAngleSet,  function(rank, degree, A)
    local obj, F, x;
    obj := JordanDesignByParameters(rank, degree );
    if obj = fail then return obj; fi;
    # Test the angle set:
    if not (ForAll(A, IsCyc) and 
            ForAll(A, x -> ComplexConjugate(x) = x) and
            ForAll(A, x -> not IsRat(x) or (x < 1 and x >= 0)))
    then 
            return fail;
    fi; 
    # Assign angle set.
    SetJordanDesignAngleSet(obj, Set(A) );
    SetFilterObj(obj, IsJordanDesignWithAngleSet ); 
    # Assign Positive Indicator Coefficients filter if applicable.
    if [true] = Set(JordanDesignNormalizedIndicatorCoefficients(obj), x -> x > 0) then 
        SetFilterObj(obj, IsJordanDesignWithPositiveIndicatorCoefficients );
    fi;
    return obj;
end );

InstallMethod( PrintObj,
    "for a design with angle set",
    [ IsJordanDesignWithAngleSet ],
    function(x)
    local text;
    Print( "<design with rank ", JordanDesignRank(x), ", degree ", JordanDesignDegree(x), ", and angle set ", JordanDesignAngleSet(x), ">" );
   end );

InstallMethod( JordanDesignNormalizedAnnihilatorPolynomial,
    "generic method for designs",
    [ IsJordanDesignWithAngleSet ],
    function(D)
    local x, F, A;
    A := JordanDesignAngleSet(D );
    x := Indeterminate(Field(A), "x" );
    F := Product(List(A, a -> (x - a)/(1-a)) );
    return CoefficientsOfUnivariatePolynomial(F );
    end );

InstallMethod( JordanDesignNormalizedIndicatorCoefficients,
    "generic method for designs",
    [ IsJordanDesignWithAngleSet ],
    function(D)
    local x, r, d, Q, F, V, basis;
    r := JordanDesignRank(D );
    d := JordanDesignDegree(D );
    x := Indeterminate(Field(JordanDesignAngleSet(D)), "x" );
    Q := k -> Q_k_epsilon(k, 0, r, d, x );
    F := ValuePol(JordanDesignNormalizedAnnihilatorPolynomial(D), x );
    V := VectorSpace(Field(JordanDesignAngleSet(D)), List([0..Degree(F)], Q) );
    basis := Basis(V, List([0..Degree(F)], Q) );  
    return Coefficients(basis, F );
    end );

InstallMethod( JordanDesignSpecialBound,
    "generic method for designs",
    [ IsJordanDesignWithAngleSet and IsJordanDesignWithPositiveIndicatorCoefficients ],
    function(D)
    if Filtered(JordanDesignNormalizedIndicatorCoefficients(D), x -> x < 0) <> [] then 
        return fail; 
    fi;
    return 1/JordanDesignNormalizedIndicatorCoefficients(D)[1];
    end );

InstallMethod( JordanDesignAddCardinality, 
    "for designs with angle sets",
    [ IsJordanDesignWithAngleSet, IsInt ],
    function(D, v)
        local obj;
        SetJordanDesignCardinality(D, v );
        SetFilterObj(D, IsJordanDesignWithCardinality );
        if JordanDesignSpecialBound(D) = JordanDesignCardinality(D) then 
            SetFilterObj(D, IsSpecialBoundJordanDesign );
            JordanDesignStrength(D );
        fi;
        return D; 
    end );

InstallMethod( PrintObj,
    "for a design with cardinality",
    [ IsJordanDesignWithCardinality ],
    function(x)
        Print( "<design with rank ", JordanDesignRank(x), ", degree ", JordanDesignDegree(x), ", cardinality ", JordanDesignCardinality(x), ", and angle set ", JordanDesignAngleSet(x), ">" );
   end );

InstallMethod( JordanDesignStrength, 
    "method for designs with positive indicator coefficients",
    [ IsJordanDesignWithPositiveIndicatorCoefficients and IsJordanDesignWithCardinality and IsSpecialBoundJordanDesign ],
    function(D)
        local s, i, t, e;
        s := Size(JordanDesignAngleSet(D) );
        for i in [0..s] do 
            if JordanDesignIndicatorCoefficients(D)[i+1] = 1 then 
                t := s + i;
            fi;
        od;
        SetFilterObj(D, IsJordanDesignWithStrength );
        if 0 in JordanDesignAngleSet(D) then 
            e := 1;
        else 
            e := 0;
        fi;
        # Check for tightness, etc
        if t = 2*s - e then
            SetFilterObj(D, IsTightJordanDesign );
            return t;
        fi;
        if t >= 2*s - 2 then
            SetFilterObj(D, IsAssociationSchemeJordanDesign );
            return t;
        fi;
        return t;
    end );

InstallMethod( JordanDesignAnnihilatorPolynomial, 
    "generic method for designs",
    [ IsJordanDesignWithAngleSet and IsJordanDesignWithCardinality ],
    function(D)
        return JordanDesignCardinality(D)*JordanDesignNormalizedAnnihilatorPolynomial(D );
    end );

InstallMethod( JordanDesignIndicatorCoefficients, 
    "generic method for designs",
    [ IsJordanDesignWithAngleSet and IsJordanDesignWithCardinality ],
    function(D)
        return JordanDesignCardinality(D)*JordanDesignNormalizedIndicatorCoefficients(D );
    end );

InstallMethod( PrintObj,
    "for a design with angle set and strength",
    [IsJordanDesignWithAngleSet and IsJordanDesignWithStrength],
    function(x)
    local text;
    Print( "<", JordanDesignStrength(x), "-design with rank ", JordanDesignRank(x), ", degree ", JordanDesignDegree(x), ", cardinality ", JordanDesignCardinality(x), ", and angle set ", JordanDesignAngleSet(x), ">" );
   end );

InstallMethod( PrintObj,
    "for a tight design",
    [IsTightJordanDesign],
    function(x)
        Print( "<Tight ", JordanDesignStrength(x), "-design with rank ", JordanDesignRank(x), ", degree ", JordanDesignDegree(x), ", cardinality ", JordanDesignCardinality(x), ", and angle set ", JordanDesignAngleSet(x), ">" );
   end );

InstallMethod( JordanDesignSubdegrees, 
    "method for a regular scheme design",
    [ IsRegularSchemeJordanDesign and IsJordanDesignWithCardinality and IsJordanDesignWithAngleSet ],
    function(D)
        local rank, degree, v, A, f, s, mat, vec, i;
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.61 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge