<!--
  functionality.xml    Forms package documentation
                                                                   John Bamberg
                                                               and Jan De Beule
                                                           
  Copyright (C) 2007, Ghent University

This is the chapter of the documentation describing all of the functions of forms.
-->

<Chapter Label="functionality">
<Heading>Functionality</Heading>

<Section Label="creating_forms">
<Heading>Functions for creating forms</Heading>

<!--
<ManSection>
<Oper Name="FormByMatrix" Arg="m, f, string"/>
<Returns>a sesquilinear or quadratic form</Returns>
<Description>
The argument <A>m</A> must be a square matrix over
the finite field <A>f</A>. The field must be specified, as
only the characteristic of the underlying field can be determined
by the entries of <A>m</A>. The last argument is a string for the 
type of the prospective form: ``symplectic'', ``orthogonal'', ``elliptic'',
``hyperbolic'', ``parabolic'', or ``hermitian''. This is necessary since
the Gram matrix of a form does not determine the companion automorphism
or whether the form is sesquilinear or quadratic. The output will be
a record rec( matrix, basefield, type ), and will either be
a sesquilinear or quadratic form depending on the criteria set out
in Chapter <Ref Chap="theory"/>. In the case that <A>string</A> is 
``orthogonal'', the function will work out from <A>m</A> which of the three types
corresponds to the resulting form.
<Example>
gap> gf := GF(3^2);
GF(3^2)
gap> mat := IdentityMat(4, gf);
[ [ Z(3)^0, 0*Z(3), 0*Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0, 0*Z(3), 0*Z(3) ], 
  [ 0*Z(3), 0*Z(3), Z(3)^0, 0*Z(3) ], [ 0*Z(3), 0*Z(3), 0*Z(3), Z(3)^0 ] ]
gap> f := FormByMatrix( mat, gf, "hermitian" );
&lt; hermitian form &gt;
gap> ## Projective Points...
gap> projpoints := List(Subspaces( gf^4, 1 ), Representative);;
gap> ## Number of totally isotropic points
gap> Number(projpoints, t -> IsZero( [t, t]^f ));
280
</Example>
</Description>
</ManSection>
-->

<ManSection>
<Oper Name="BilinearFormByMatrix" Arg="m, f"/>
<Returns>a bilinear form</Returns>
<Description>
The argument <A>m</A> must be a square matrix over
the finite field <A>f</A>. The field must be specified, as
only the characteristic of the underlying field can be determined
by the entries of <A>m</A>. The output will be
a record rec( matrix, basefield, type ). 
<Example>
gap> gf := GF(3^2);
GF(3^2)
gap> mat := IdentityMat(4, gf);
[ [ Z(3)^0, 0*Z(3), 0*Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0, 0*Z(3), 0*Z(3) ], 
  [ 0*Z(3), 0*Z(3), Z(3)^0, 0*Z(3) ], [ 0*Z(3), 0*Z(3), 0*Z(3), Z(3)^0 ] ]
gap> f := BilinearFormByMatrix( mat, gf );
&lt; bilinear form &gt;
gap> Display(f);
Bilinear form
Gram Matrix:
 1 . . .
 . 1 . .
 . . 1 .
 . . . 1
</Example>
</Description>
</ManSection>

<ManSection>
<Oper Name="QuadraticFormByMatrix" Arg="m, f"/>
<Returns>a quadratic form</Returns>
<Description>
The argument <A>m</A> must be a square matrix over
the finite field <A>f</A>. The field must be specified, as
only the characteristic of the underlying field can be determined
by the entries of <A>m</A>. The output will be
a record rec( matrix, basefield, type ). 
<Example>
gap> gf := GF(2^2);
GF(2^2)
gap> mat := InvariantQuadraticForm( SO(-1, 4, 4) )!.matrix;
[ [ 0*Z(2), Z(2)^0, 0*Z(2), 0*Z(2) ], [ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ], 
  [ 0*Z(2), 0*Z(2), Z(2^2)^2, Z(2)^0 ], [ 0*Z(2), 0*Z(2), 0*Z(2), Z(2^2)^2 ] ]
gap> f := QuadraticFormByMatrix( mat, gf );
&lt; quadratic form &gt;
gap> Display(f);
Quadratic form
Gram Matrix:
z = Z(4)
   .   1   .   .
   .   .   .   .
   .   . z^2   1
   .   .   . z^2
</Example>
</Description>
</ManSection>

<ManSection>
<Oper Name="HermitianFormByMatrix" Arg="m, f"/>
<Returns>a quadratic form</Returns>
<Description>
The argument <A>m</A> must be a square matrix over
the finite field <A>f</A> of square order. The field must be specified, as
only the characteristic of the underlying field can be determined
by the entries of <A>m</A>. The output will be
a record rec( matrix, basefield, type ). 
<Example>
gap> gf := GF(3^2);
gap> mat := IdentityMat(4, gf);
gap> f := HermitianFormByMatrix( mat, gf );
&lt; hermitian form &gt;
gap> Display(f);
Hermitian form
Gram Matrix:
 1 . . .
 . 1 . .
 . . 1 .
 . . . 1
Witt Index: 2
</Example>
</Description>
</ManSection>

<!--
<ManSection>
<Oper Name="FormByPolynomial" Arg="poly, r, n, string"/>
<Returns>a sesquilinear or quadratic form</Returns>
<Description>.
The argument <A>poly</A> must be a polynomial in the polynomial
ring <A>r</A>. The third argument <A>n</A> is the dimension
for the underlying vector space of the resulting form, and the last argument is a string for the 
type of the prospective form: ``orthogonal'', ``quadratic'', or ``hermitian''. This is necessary since
the polynomial of a form does not determine the companion automorphism
or whether the form is sesquilinear or quadratic. Note that ``symplectic''
is invalid input as an alternating form can not arise from a polynomial
(in this way). The output will be
a record rec( poly, basefield, type ), and will either be
a sesquilinear or quadratic form depending on the criteria set out
in Chapter <Ref Chap="theory"/>. In the case that <A>string</A> is 
``orthogonal'', the function will work out from <A>poly</A> which of the three types
corresponds to the resulting form.
<Example>
gap> r := PolynomialRing(GF(4), 4);
GF(2^2)[x_1,x_2,x_3,x_4]
gap> z := Z(4);
Z(2^2)
gap> poly :=  r.1 * r.2 + r.3 * r.4 + z^2 * (r.3^2 + r.4^2);
x_1*x_2+Z(2^2)^2*x_3^2+x_3*x_4+Z(2^2)^2*x_4^2
gap> f := FormByPolynomial( poly, r, 4, "quadratic" ); 
&lt; quadratic form &gt;
gap> Display(f);
Quadratic form
Gram Matrix:
z = Z(4)
   .   1   .   .
   .   .   .   .
   .   . z^2   1
   .   .   . z^2
Polynomial: x_1*x_2+Z(2^2)^2*x_3^2+x_3*x_4+Z(2^2)^2*x_4^2
gap> ## Projective Points...
gap> projpoints := List(Subspaces( GF(4)^4, 1 ), Representative);;
gap> ## Number of totally isotropic points
gap> Number(projpoints, t -> IsZero( t^f ));
17
</Example>
</Description>
</ManSection>
-->

<ManSection>
<Oper Name="BilinearFormByPolynomial" Arg="poly, r, n"/>
<Oper Name="BilinearFormByPolynomial" Arg="poly, r"/>
<Returns>a bilinear form</Returns>
<Description>
The argument <A>poly</A> must be a polynomial in the polynomial
ring <A>r</A>. The (optional) last argument is the dimension
for the underlying vector space of the resulting form, which
by default is the number of indeterminates specified by <A>poly</A>.
<Example>
gap> r := PolynomialRing( GF(11), 4);
GF(11)[x_1,x_2,x_3,x_4]
gap> vars := IndeterminatesOfPolynomialRing( r );
[ x_1, x_2, x_3, x_4 ]
gap> pol := vars[1]*vars[2]+vars[3]*vars[4];
x_1*x_2+x_3*x_4
gap> form := BilinearFormByPolynomial(pol, r, 4);
&lt; bilinear form &gt;
gap> Display(form);
Bilinear form
Gram Matrix:
  .  6  .  .
  6  .  .  .
  .  .  .  6
  .  .  6  .
Polynomial: x_1*x_2+x_3*x_4
gap> ## Projective Points...
gap> projpoints := List(Subspaces( GF(11)^4, 1 ), Representative);;
gap> ## Number of totally isotropic points
gap> Number(projpoints, t -> IsZero( [t, t]^form ));
144
</Example>
</Description>
</ManSection>

<ManSection>
<Oper Name="QuadraticFormByPolynomial" Arg="poly, r, n"/>
<Oper Name="QuadraticFormByPolynomial" Arg="poly, r"/>
<Returns>a quadratic form</Returns>
<Description>
The argument <A>poly</A> must be a polynomial in the polynomial
ring <A>r</A>. The (optional) last argument is the dimension
for the underlying vector space of the resulting form, which
by default is the number of indeterminates specified by <A>poly</A>.
<Example>
gap> r := PolynomialRing( GF(8), 3);
GF(2^3)[x_1,x_2,x_3]
gap> poly := r.1^2 + r.2^2 + r.3^2;
x_1^2+x_2^2+x_3^2
gap> form := QuadraticFormByPolynomial(poly, r);
&lt; quadratic form &gt;
gap> RadicalOfForm(form);
&lt;vector space over GF(2^3), with 3 generators&gt;
</Example>
</Description>
</ManSection>

<ManSection>
<Oper Name="HermitianFormByPolynomial" Arg="poly, r, n"/>
<Oper Name="HermitianFormByPolynomial" Arg="poly, r"/>
<Returns>an hermitian form</Returns>
<Description>
The argument <A>poly</A> must be a polynomial in the polynomial
ring <A>r</A> (defined over a finite field of square order). 
The (optional) last argument is the dimension
for the underlying vector space of the resulting form, which
by default is the number of indeterminates specified by <A>poly</A>.
<Example>
gap> r := PolynomialRing( GF(9), 4);
GF(3^2)[x_1,x_2,x_3,x_4]
gap> vars := IndeterminatesOfPolynomialRing( r );
[ x_1, x_2, x_3, x_4 ]
gap> poly := vars[1]*vars[2]^3+vars[1]^3*vars[2]+vars[3]*vars[4]^3+vars[3]^3*vars[4];
x_1^3*x_2+x_1*x_2^3+x_3^3*x_4+x_3*x_4^3
gap> form := HermitianFormByPolynomial(poly,r);
&lt; hermitian form &gt;
gap> Display(form);
Hermitian form
Gram Matrix:
 . 1 . .
 1 . . .
 . . . 1
 . . 1 .
Polynomial: x_1^3*x_2+x_1*x_2^3+x_3^3*x_4+x_3*x_4^3
</Example>
</Description>
</ManSection>

</Section>


<!--
      ATTRIBUTES AND PROPERTIES 
-->


<Section Label="properties">
<Heading>Attributes and properties of forms</Heading>

<ManSection>
<Attr Name="IsReflexiveForm" Arg="f"/>
<Returns>true or false.</Returns>
<Description>
A sesquilinear form <M>f</M> is <E>reflexive</E> if whenever we
have <M>f(u,v)=0</M>, then we also have <M>f(v,u)=0</M>. This
operation simply returns <A>true</A> or <A>false</A>. 
</Description>
</ManSection>

<ManSection>
<Attr Name="IsAlternatingForm" Arg="f"/>
<Returns>true or false.</Returns>
<Description>
A bilinear form <M>f</M> is <E>alternating</E> if 
<M>f(v,v)=0</M> for all <M>v</M>. This
operation simply returns <A>true</A> or <A>false</A>. 
</Description>
</ManSection>

<ManSection>
<Attr Name="IsSymmetricForm" Arg="f"/>
<Returns>true or false.</Returns>
<Description>
A bilinear form <M>f</M> is <E>symmetric</E> if 
<M>f(u,v)=f(v,u)</M> for all pairs of vectors <M>u</M> and <M>v</M>.  This
operation simply returns <A>true</A> or <A>false</A>. 
</Description>
</ManSection>

<ManSection>
<Attr Name="IsDegenerateForm" Arg="f"/>
<Returns>true or false.</Returns>
<Description>
A sesquilinear form <M>f</M> is <E>degenerate</E> if there
exists a nonzero vector <M>v</M> which is orthogonal to every other vector.
That is, <M>f(v,w)=0</M> for all <M>w</M>. Likewise, a quadratic form <M>Q</M>
is degenerate if there is a nonzero vector <M>v</M> such that <M>Q(v)=0</M>.
This operation simply returns <A>true</A> or <A>false</A>.
</Description>
</ManSection>

<ManSection>
<Attr Name="BaseField" Arg="f"/>
<Returns>the underlying field of <A>f</A>.</Returns>
</ManSection>

<ManSection>
<Attr Name="GramMatrix" Arg="f"/>
<Returns>the associated Gram matrix of <A>f</A>.</Returns>
</ManSection>

<ManSection>
<Attr Name="WittIndex" Arg="f"/>
<Returns>the Witt index of <A>f</A>.</Returns>
<Description>
The Witt index is the maximum dimension of a totally singular 
subspace. So for example, if <A>f</A> is a symplectic form
and <M>d</M> is the dimension of its underlying vector space,
then the Witt index of <A>f</A> is <M>d/2</M>.
</Description>
</ManSection>

<ManSection>
<Attr Name="RadicalOfForm" Arg="f"/>
<Returns>a subspace, the radical, of the vectors space
associated with <A>f</A>.</Returns>
<Description>
<Example>
gap> r := PolynomialRing( GF(8), 3 );
GF(2^3)[x_1,x_2,x_3]
gap> poly := r.1^2 + r.2 * r.3;
x_1^2+x_2*x_3
gap> form := QuadraticFormByPolynomial( poly, r );
&lt; quadratic form &gt;
gap> RadicalOfForm( form );
&lt;vector space of dimension 1 over GF(2^3)&gt;
</Example>
</Description>
</ManSection>

<ManSection>
<Attr Name="PolynomialOfForm" Arg="f"/>
<Returns>the polynomial associated with <A>f</A>.</Returns>
<Description>
<Example> 
gap> mat := [ [ Z(8) , 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ], 
 [ 0*Z(2), Z(2)^0, Z(2^3)^5, 0*Z(2), 0*Z(2) ], 
 [ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ], 
 [ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), Z(2)^0 ], 
 [ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ] ];;
gap> form := QuadraticFormByMatrix(mat,GF(8));
&lt; quadratic form &gt;
gap> PolynomialOfForm(form);
Z(2^3)*x_1^2+x_2^2+Z(2^3)^5*x_2*x_3+x_4*x_5
</Example>
</Description>
</ManSection>

<ManSection>
<Attr Name="DiscriminantOfForm" Arg="f"/>
<Returns>a string</Returns>
<Description>
Given a quadratic or sesquilinear form <A>f</A>, this operation returns a string:
``square'' or ``nonsquare''. Discriminants can be used to delineate the isometry
type of an orthogonal form in even (algebraic) dimension.
<Example>
gap> gram := InvariantQuadraticForm(GO(-1,4,5))!.matrix;;
gap> f := QuadraticFormByMatrix(gram, GF(5));
&lt; quadratic form &gt;
gap> DiscriminantOfForm(f);
"nonsquare"
</Example>
</Description>
</ManSection>
</Section>

<!--
      CHANGING FORMS AND OTHER OPERATIONS
-->

<Section Label="changing_forms">
<Heading>Functions for changing forms</Heading>
<ManSection>
<Oper Name="BaseChangeToCanonical" Arg="f"/>
<Returns>a base-transition matrix</Returns>
<Description>
The argument <A>f</A> is a sesquilinear or quadratic form.
For every isometry class of forms, there is a canonical
representative, which is in block diagonal form. If <A>M</A> is
the Gram matrix of the form <A>f</A>, then <A>b * M * TransposedMat(b)</A>
is the Gram matrix of the canonical representative.
<Example>
gap> f := GF(3);
GF(3)
gap> gram := [
[0,0,0,1,0,0], 
[0,0,0,0,1,0],
[0,0,0,0,0,1],
[-1,0,0,0,0,0],
[0,-1,0,0,0,0],
[0,0,-1,0,0,0]] * One(f);;
gap> form := BilinearFormByMatrix( gram, f );
&lt; bilinear form &gt;
gap> b := BaseChangeToCanonical( form );;
gap> Display( b * gram * TransposedMat(b) );
 . 1 . . . .
 2 . . . . .
 . . . 1 . .
 . . 2 . . .
 . . . . . 1
 . . . . 2 .
</Example>
</Description>
</ManSection>

<ManSection>
<Attr  Name="IsometricCanonicalForm" Arg="f"/>
<Returns>the canonical form isometric to the
sesquilinear or quadratic form <A>f</A>.</Returns>
<Description>
For every isometry type of sesquilinear or quadratic form,
there is a canonical one. In <Package>Forms</Package>,
the canonical form of each class is that which preserves
the natural hyperbolic line decomposition (see Secton
<Ref Sect="canonical"/>).
<Example>
gap> mat := [ [ Z(8) , 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ], 
[ 0*Z(2), Z(2)^0, Z(2^3)^5, 0*Z(2), 0*Z(2) ], 
[ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ], 
[ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), Z(2)^0 ], 
[ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ] ];;
gap> form := QuadraticFormByMatrix(mat,GF(8));
&lt; quadratic form &gt;
gap> iso := IsometricCanonicalForm(form);
&lt; quadratic form &gt;
gap> Display(form);
Quadratic form
Gram Matrix:
z = Z(8)
 z^1   .   .   .   .
   .   1 z^5   .   .
   .   .   .   .   .
   .   .   .   .   1
   .   .   .   .   .
Witt Index: 2
gap> Display(iso);
Quadratic form
Gram Matrix:
 1 . . . .
 . . 1 . .
 . . . . .
 . . . . 1
 . . . . .
Witt Index: 2
</Example>
</Description>
</ManSection>
</Section>

<Section Label="operations">
<Heading>Operations on forms</Heading>

<ManSection>
<Oper Name="BaseChangeHomomorphism" Arg="b, gf"/>
<Returns>the inner automorphism of GL(d,q) associated
to the base-transition <A>b</A>.</Returns>
<Description>
The argument <A>b</A> must be an invertible matrix over
the finite field <A>gf</A>.
<Example>
gap> gl:=GL(3,3);
GL(3,3)
gap> go:=GO(3,3);
GO(0,3,3)
gap> gram:=InvariantBilinearForm(go)!.matrix;
[ [ 0*Z(3), Z(3)^0, 0*Z(3) ], [ Z(3)^0, 0*Z(3), 0*Z(3) ], [ 0*Z(3), 0*Z(3), Z(3) ] ]
gap> f:=FormByMatrix(gram,GF(3),"parabolic");
&lt; bilinear form &gt;
gap> b:=BaseChangeToCanonical(f);;
gap> hom := BaseChangeHomomorphism(b, GF(3));
^[ [ 0*Z(3), 0*Z(3), Z(3) ], [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ] ]
gap> newgo := Image(hom, go); 
Group(
[ [ [ Z(3)^0, 0*Z(3), Z(3) ], [ Z(3)^0, Z(3), Z(3)^0 ], [ 0*Z(3), 0*Z(3), Z(3) ] ], 
  [ [ Z(3), Z(3)^0, 0*Z(3) ], [ 0*Z(3), Z(3), 0*Z(3) ], [ Z(3)^0, Z(3)^0, Z(3) ] ] ])
gap> gens:=GeneratorsOfGroup(newgo);;
gap> canonical := b * gram * TransposedMat(b);
[ [ Z(3), 0*Z(3), 0*Z(3) ], [ 0*Z(3), 0*Z(3), Z(3)^0 ], [ 0*Z(3), Z(3)^0, 0*Z(3) ] ]
gap> ForAll(gens, y -> y * canonical * TransposedMat(y) = canonical);
true
</Example>
</Description>
</ManSection>

<ManSection>
<Oper Name="EvaluateForm" Arg="f, u, v"/>
<Oper Name="EvaluateForm" Arg="f, u"/>
<Returns>a finite field element</Returns>
<Description>
The argument <A>f</A> is either a sesquilinear or quadratic form
defined over a finite field <M>GF(q)</M>. The other argument is
a pair of vectors or matrices, or a single vector or matrix, which represent
the bases of given subspaces of <M>GF(q)^d</M>. There is also an overloading
of the operation <A>\^</A> which we show in the following example:
<Example>
gap> mat := [[Z(8),0,0,0],[0,0,Z(8)^4,0],[0,0,0,1],[0,0,0,0]]*Z(8)^0;;
gap> form := QuadraticFormByMatrix(mat,GF(8));
&lt; quadratic form &gt;
gap> u := [ Z(2^3)^4, Z(2^3)^4, Z(2)^0, Z(2^3)^3 ];
[ Z(2^3)^4, Z(2^3)^4, Z(2)^0, Z(2^3)^3 ]
gap> EvaluateForm( form, u );
Z(2^3)^6
gap> u^form;
Z(2^3)^6
</Example>
Here is an example using sesquilinear forms...
<Example>
gap> gram := [[0,0,0,0,0,2],[0,0,0,0,2,0],[0,0,0,1,0,0],[0,0,1,0,0,0],
 [0,2,0,0,0,0],[2,0,0,0,0,0]]*Z(3)^0;;
gap> form := BilinearFormByMatrix(gram,GF(3));
&lt; bilinear form &gt;
gap> u := [ [ Z(3)^0, 0*Z(3), 0*Z(3), Z(3)^0, 0*Z(3), Z(3)^0 ], 
  [ 0*Z(3), 0*Z(3), Z(3)^0, Z(3)^0, Z(3), 0*Z(3) ] ];;
gap> v := [ [ Z(3)^0, 0*Z(3), Z(3)^0, Z(3), 0*Z(3), Z(3) ], 
  [ 0*Z(3), Z(3)^0, 0*Z(3), Z(3), Z(3), Z(3) ] ];;
gap> EvaluateForm( form, u, v);
[ [ Z(3)^0, Z(3)^0 ], [ 0*Z(3), 0*Z(3) ] ]
gap> [u,v]^form;
[ [ Z(3)^0, Z(3)^0 ], [ 0*Z(3), 0*Z(3) ] ]
</Example>
</Description>
</ManSection>

</Section>

</Chapter>
