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


Quelle  affinespace.gi   Sprache: unbekannt

 
#############################################################################
##
##  affinespace.gi              FinInG package
##                                                              John Bamberg
##                                                              Anton Betten
##                                                              Jan De Beule
##                                                             Philippe Cara
##                                                            Michel Lavrauw
##                                                           Max Neunhoeffer
##
##  Copyright 2018 Colorado State University
##                  Sabancı Üniversitesi
##     Università degli Studi di Padova
##     Universiteit Gent
##     University of St. Andrews
##     University of Western Australia
##                  Vrije Universiteit Brussel
##
##
##  Implementation stuff for affine spaces
##
#############################################################################

#############################################################################
#
# Construction of affine spaces
#
#############################################################################

# CHECKED 12/03/12 jdb
#############################################################################
#O  AffineSpace( <d>, <f> )
# returns AG( <d>, <f> )
##
InstallMethod( AffineSpace, 
 "for a dimension and a field",
  [ IsPosInt, IsField ],
 function( d, f )
  local geo;
  geo := rec( dimension := d, basefield := f, 
                vectorspace := FullRowSpace(f, d) );
  Objectify( NewType( GeometriesFamily,
                        IsAffineSpace and IsAffineSpaceRep ), geo );
  SetAmbientSpace(geo,geo);
  SetRankAttr(geo,d); #this makes Rank applicable without adding more code in this file
  return geo;
 end );

# CHECKED 12/03/12 jdb
#############################################################################
#O  AffineSpace( <d>, <q> )
# returns AG( <d>, GF(<q>) )
##
InstallMethod( AffineSpace, 
 "for a dimension and a prime power",
 [ IsPosInt, IsPosInt ],
 function( d, q )
  return AffineSpace(d, GF(q));
 end );

############################################################################
#
# ViewObj/PrintObj for affine spaces
#
#############################################################################


InstallMethod( ViewObj, [ IsAffineSpace and IsAffineSpaceRep ],
  function( p )
    Print("AG(",p!.dimension,", ",Size(p!.basefield),")");
  end );

InstallMethod( PrintObj, [ IsAffineSpace and IsAffineSpaceRep ],
  function( p )
    Print("AffineSpace(",p!.dimension,",",p!.basefield,")");
  end );  

# ADDED 16/12/14 jdb, this is needed to make one check in ShadowOfElement
#############################################################################
#O  \=( <ag1>, <ag2> )
# Code taken from \= for projective spaces.
##
InstallMethod( \=, 
 "for two projective spaces",
 [IsAffineSpace, IsAffineSpace],
 function(ag1,ag2);
  return UnderlyingVectorSpace(ag1) = UnderlyingVectorSpace(ag2);
 end );

#############################################################################
#
# Attributes of affine spaces
#
#############################################################################

# CHECKED 20/03/11 jdb
#############################################################################
#A  Dimension( <as> )
# returns the projective dimension of <ps>
##
InstallMethod( Dimension, 
 "for an affine space",
 [ IsAffineSpace and IsAffineSpaceRep ],
 as -> as!.dimension
 );

# CHECKED 20/03/12 jdb
#############################################################################
#O  UnderlyingVectorSpace( <as> )
#returns the projective dimension of <ps>
##
InstallMethod( UnderlyingVectorSpace, 
 "for an affine space",
 [ IsAffineSpace and IsAffineSpaceRep ],
 as -> as!.vectorspace
 );
 
#############################################################################
#O  AmbientSpace( <subspace> ) returns the ambient space of <subspace>
##
InstallMethod( AmbientSpace,
 "for a subspace of an affine space",
 [IsSubspaceOfAffineSpace],
 function(subspace)
  return subspace!.geo;
 end );

# CHECKED 20/03/12 jdb
#############################################################################
#O  BaseField( <as> )
# returns the basefield of <as>
##
InstallMethod( BaseField, 
 "for an affine space", 
 [IsAffineSpace and IsAffineSpaceRep],
 ag -> ag!.basefield );

#############################################################################
#O  BaseField( <sub> )
# returns the basefield of an element of a projective space
##
InstallMethod( BaseField, 
 "for an element of a projective space", 
 [IsSubspaceOfAffineSpace],
 sub -> AmbientSpace(sub)!.basefield );

# CHECKED 12/03/12 jdb
#############################################################################
#O  TypesOfElementsOfIncidenceStructure( <ps> )
# returns the names of the types of the elements of the projective space <ps>
# the is a helper operation.
##
InstallMethod( TypesOfElementsOfIncidenceStructure, 
 "for an affine space", 
 [IsAffineSpace],
 function( as )
  local d,i,types;
  types := ["point"];
  d := Rank(as); #this line replaces next line, since next line assumes IsAffineSpaceRep
 #d := ps!.dimension;
  if d >= 2 then Add(types,"line"); fi;
  if d >= 3 then Add(types,"plane"); fi;
  if d >= 4 then Add(types,"solid"); fi;
  for i in [5..d] do
   Add(types,Concatenation("affine subspace of dim. ",String(i-1)));
  od;
  return types;
 end );

# CHECKED 12/03/12 jdb
#############################################################################
#O  TypesOfElementsOfIncidenceStructurePlural( <ps> )
# returns the plural of the names of the types of the elements of the projective space <ps>
# the is a helper operation.
##
InstallMethod( TypesOfElementsOfIncidenceStructurePlural, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  local d,i,types;
  types := ["points"];
      d := Rank(as); #this line replaces next line, since next line assumes IsAffineSpaceRep
 #d := ps!.dimension;
  if d >= 2 then Add(types,"lines"); fi;
  if d >= 3 then Add(types,"planes"); fi;
  if d >= 4 then Add(types,"solids"); fi;
  for i in [5..d] do
   Add(types,Concatenation("affine. subspaces of dim. ",String(i-1)));
  od;
  return types;
 end );

#############################################################################
# helper methods to construct affine subspacs.
#############################################################################

#############################################################################
#O  VectorSpaceTransversalElement( <space>, <subspace>, <v> )
# This is an internal subroutine which is not expected to be used by the user;
# Returns a canonical vector from <v>+<subspace>
##
InstallMethod( VectorSpaceTransversalElement,
 "for a vector space, a matric, a vector",
 [IsVectorSpace, IsFFECollColl, IsVector],
 function(space, subspace, v)
  local basis;
  basis := SemiEchelonBasis( Subspace(space, subspace) );
  return SiftedVector(basis, v);
 end );

#############################################################################
#O  VectorSpaceTransversal( <space>, <subspace> )
# This is an internal subroutine which is not expected to be used by the user;
# Returns a typed object containing a record with two components
# Note: IsVectorSpaceTransversal is a subfilter of IsSubspacesOfVectorSpace
##
InstallMethod( VectorSpaceTransversal, 
 "for a vector space, a matrix",
 [IsVectorSpace, IsFFECollColl],
 function(space, subspace)
  return Objectify(
               NewType( CollectionsFamily( FamilyObj( space ) ),
                    IsVectorSpaceTransversal and IsVectorSpaceTransversalRep),
           rec( vectorspace := space, subspace := subspace ) );    
 end );

#############################################################################
#O  ViewObj( <trans> )
InstallMethod( ViewObj, 
 "for a vector space transversal",
 [ IsVectorSpaceTransversal and IsVectorSpaceTransversalRep ],
 function( trans )
  Print("<vector space transversal of ", trans!.vectorspace,">");
 end );
 
#############################################################################
#O  PrintObj( <trans> )
InstallMethod( PrintObj, 
 "for a vector space transversal",
 [ IsVectorSpaceTransversal and IsVectorSpaceTransversalRep ],
 function( trans )
  Print("<vector space transversal of ", trans!.vectorspace," subspace spanned by ",trans!.subspace, ">");
 end );

#############################################################################
#
#  Methods for making subspaces
#
#  Affine subspaces can be constructed in the following ways:
#
# (1) from a vector v -> affine point v 
# (2) from a vector and a matrix [v, M] -> affine subspace v + <M>

# From these two options, we have the following list of 
# arguments for "AffineSubspace" (for now...)
#
# [ IsAffineSpace, IsRowVector ]
# [ IsAffineSpace, IsRowVector, IsPlistRep ]
# [ IsAffineSpace, IsRowVector, Is8BitMatrixRep ]
# [ IsAffineSpace, IsRowVector, IsGF2MatrixRep ]
#
# The treatment of the matrix representing the subspace at infinity, is similar to 
# the treatment in the methods for VectorSpaceToElement in projectivespace.gi
#
# 24/3/2014
# cvec/cmat changes lead to the methods for 
# [ IsAffineSpace, IsCVecRep ]
# [ IsAffineSpace, IsCVecRep, IsCMatRep ]
#
# more methods might be necessary in the future.
# Note that an affine point is represented by just one vector, while an affine 
# space by an object [v,m], where v is vector and m is a matrix. Currently we
# will change this into a cvec/cmat. 
#
#############################################################################

# CHECKED 12/03/12 jdb
# But I am unhappy with this code. It seems obsolete if you compare this with
# the method installed in geometry.gi for Wrap.
#############################################################################
#O  Wrap( <geo>, <type>, <o> )
# This is an internal subroutine which is not expected to be used by the user;
# they would be using AffineSubspace. Recall that Wrap is declared in 
# geometry.gd. 
##
InstallMethod( Wrap, 
 "for an affine space and an object",
 [IsAffineSpace, IsPosInt, IsObject],
 function( geo, type, o )
  local w;
  w := rec( geo := geo, type := type, obj := o );
  Objectify( NewType( SoASFamily, IsElementOfIncidenceStructure and
   IsElementOfIncidenceStructureRep and IsSubspaceOfAffineSpace ), w );
  return w;
 end );

#############################################################################
#
# ViewObj/PrintObjDisplay of subspaces of affine spaces
#
#############################################################################

InstallMethod( ViewObj, 
 [ IsSubspacesOfAffineSpace and IsSubspacesOfAffineSpaceRep ],
 function( vs )
  Print("<",TypesOfElementsOfIncidenceStructurePlural(vs!.geometry)[vs!.type]," of ");
  ViewObj(vs!.geometry);
  Print(">");
 end );

InstallMethod( PrintObj, 
 [ IsSubspacesOfAffineSpace and IsAllSubspacesOfProjectiveSpaceRep ],
 function( vs )
  Print("Elements( ",vs!.geometry," , ",vs!.type,")");
 end );

# special method to view an affine subspace as it is usually thought of

InstallMethod( Display, 
 [ IsSubspaceOfAffineSpace ],
 function( x )
  local u, t;
  u := x!.obj;
  if x!.type = 1 then
   Print("Affine point: ");
   Display( u );
  else
   if x!.type in [2, 3, 4] then
    Print("Affine ", TypesOfElementsOfIncidenceStructure(x!.geo)[x!.type], ":\n");
   else
    Print("Affine ", x!.type, "-space :\n");
   fi;
   Print("Coset representative: ", u[1], "\n" );
   Print("Coset (direction): ", u[2], "\n" );      
  fi;
 end );

#############################################################################
#
# User methods to construct subspaces of affine spaces.
#
#############################################################################

# CHECKED 12/03/12 jdb
# but I am unhappy with the fact that an empty v just returns [].
# 24/3/2014. I changed it now, entering [] gives an error.
# cvec/cmat change.
# changed 19/01/16 (jdb): by a change of IsPlistRep, this method gets also
# called when using a row vector, causing a problem with TriangulizeMat.
# a solution was to add IsMatrix.
#############################################################################
#O  AffineSubspace( <geom>, <v>, <m> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m>. 
##
InstallMethod( AffineSubspace, 
 "for a row vector and Plist",
    [IsAffineSpace, IsRowVector, IsPlistRep and IsMatrix],
 function( geom, v, m )
  local  x, n, i, gf, v2;
  gf := geom!.basefield;
  ## when v is empty... 
  #if IsEmpty(v) then
  # return [];
  #fi;
        ## dimension should be correct
        x := MutableCopyMat(m);
  if Length(v) <> geom!.dimension or Length(v) <> Length(x[1]) then
   Error("Dimensions are incompatible");
  fi;
  TriangulizeMat(x);

  ## Remove zero rows. It is possible the the user
  ## has inputted a matrix which does not have full rank
        n := Length(x);
  i := 0;
  while i < n and ForAll(x[n-i], IsZero) do
   i := i+1; 
  od;
  #if i = n then #this case corresponds simple with the "empty subspace at infinity", so a point must be returned.
  # return [];
  #fi;
  x := x{[1..n-i]};
  if Length(x) = geom!.dimension then
   return geom;
  fi;   
        ## It is possible that (a) the user has entered a
  ## matrix with one row, or that (b) the user has
  ## entered a matrix with rank 1 (thus at this stage
  ## we will have a matrix with one row).
        ## We must also compress our vector/matrix.
        ##note that IsZero([[]])=IsZero([])=true.
        if IsZero(x) then
  ## return an affine point
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v])[1];
   #ConvertToVectorRep(v2, gf); #useless now.
   return Wrap(geom, 1, v2);
  else
  ## find transversal element
   v2 := VectorSpaceTransversalElement( geom!.vectorspace, x, v );
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v2])[1];
   #ConvertToVectorRep(x, gf);
   #ConvertToMatrixRep(x, gf); #should have been ConvertToMatrixRep(v2,gf) ?
   x := NewMatrix(IsCMatRep,gf,geom!.dimension,x);
   return Wrap(geom, Length(x)+1, [v2,x]);
  fi;
 end );

# CHECKED 24/3/3014 jdb
#############################################################################
#O  AffineSubspace( <geom>, <v>  )
# returns the point in the affine space <geom> determined by <v> 
##
InstallMethod( AffineSubspace, 
 "for a row vector",
    [IsAffineSpace, IsRowVector],
 function( geom, v )
        if Length(v) <> geom!.dimension then
   Error("Dimensions are incompatible");
  fi;
  return Wrap(geom, 1, NewMatrix(IsCMatRep,geom!.basefield,geom!.dimension,[v])[1] );
 end );
 
# CHECKED 24/3/3014 jdb
#############################################################################
#O  AffineSubspace( <geom>, <v>  )
# returns the point in the affine space <geom> determined by <v> 
##
InstallMethod( AffineSubspace, 
 "for a row vector",
    [IsAffineSpace, IsCVecRep],
 function( geom, v )
        if Length(v) <> geom!.dimension then
   Error("Dimensions are incompatible");
  fi;
  return Wrap(geom, 1, v);
 end );

# CHECKED 24/3/3014 jdb
#############################################################################
#O  AffineSubspace( <geom>, <v>, <m> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m>. 
##
InstallMethod( AffineSubspace, 
 "for a row vector and 8-bit matrix",
    [IsAffineSpace, IsRowVector, Is8BitMatrixRep],
 function( geom, v, m )
  ## We have simply copied the code that was for IsPlistRep
  local  x, n, i, gf, v2;
  gf := geom!.basefield;
        x := MutableCopyMat(m);
  if Length(v) <> geom!.dimension or Length(v) <> Length(x[1]) then
   Error("Dimensions are incompatible");
  fi;
  TriangulizeMat(x);
        n := Length(x);
  i := 0;
  while i < n and ForAll(x[n-i], IsZero) do
   i := i+1; 
  od;
  x := x{[1..n-i]};
  if Length(x) = geom!.dimension then
   return geom;
  fi;   
        if IsZero(x) then
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v])[1];
   return Wrap(geom, 1, v2);
  else
   v2 := VectorSpaceTransversalElement( geom!.vectorspace, x, v );
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v2])[1];
   x := NewMatrix(IsCMatRep,gf,geom!.dimension,x);
   return Wrap(geom, Length(x)+1, [v2,x]);
  fi;
 end ); 
  
# CHECKED 24/3/3014 jdb
#############################################################################
#O  AffineSubspace( <geom>, <v>, <m> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m>. 
##
InstallMethod( AffineSubspace, 
 "for a row vector and 8-bit matrix",
    [IsAffineSpace, IsRowVector, IsGF2MatrixRep],
 function( geom, v, m )
    ## We have simply copied the code that was for IsPlistRep
  local  x, n, i, gf, v2;
  gf := geom!.basefield;
        x := MutableCopyMat(m);
  if Length(v) <> geom!.dimension or Length(v) <> Length(x[1]) then
   Error("Dimensions are incompatible");
  fi;
  TriangulizeMat(x);
        n := Length(x);
  i := 0;
  while i < n and ForAll(x[n-i], IsZero) do
   i := i+1; 
  od;
  x := x{[1..n-i]};
  if Length(x) = geom!.dimension then
   return geom;
  fi;   
        if IsZero(x) then
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v])[1];
   return Wrap(geom, 1, v2);
  else
   v2 := VectorSpaceTransversalElement( geom!.vectorspace, x, v );
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v2])[1];
   x := NewMatrix(IsCMatRep,gf,geom!.dimension,x);
   return Wrap(geom, Length(x)+1, [v2,x]);
  fi;
  end ); 
  
# ADDED 24/3/3014 jdb
#############################################################################
#O  AffineSubspace( <geom>, <v>, <m> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m>. 
##
InstallMethod( AffineSubspace, 
 "for a row vector and 8-bit matrix",
    [IsAffineSpace, IsCVecRep, IsCMatRep],
 function( geom, v, m )
  local  x, n, i, gf, v2;
  gf := geom!.basefield;
        x := MutableCopyMat(Unpack(m)); #cmat might give trouble with {}
  if Length(v) <> geom!.dimension or Length(v) <> Length(x[1]) then
   Error("Dimensions are incompatible");
  fi;
  TriangulizeMat(x);
        n := Length(x);
  i := 0;
  while i < n and ForAll(x[n-i], IsZero) do
   i := i+1; 
  od;
  x := x{[1..n-i]};
  if Length(x) = geom!.dimension then
   return geom;
  fi;   
        if IsZero(x) then
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v])[1];
   return Wrap(geom, 1, v2);
  else
   v2 := VectorSpaceTransversalElement( geom!.vectorspace, x, v );
   v2 := NewMatrix(IsCMatRep,gf,geom!.dimension,[v2])[1];
   x := NewMatrix(IsCMatRep,gf,geom!.dimension,x);
   return Wrap(geom, Length(x)+1, [v2,x]);
  fi;
  end ); 

# added 31/7/2014 for reasons of consistency jdb
#############################################################################
#O  ObjecToElement( <geom>, <obj> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m> if and only if <obj> is the list [v,m].
##
InstallMethod( ObjectToElement,
 "for an affine space and an object",
 [ IsAffineSpace, IsList],
 function(as, obj)
  if Length(obj) = 2 then
   return AffineSubspace(as, obj[1], obj[2]);
  else
   Error("<obj> does not determine a subspace of <as>");
  fi;
 end );
   
# added 31/7/2014 for reasons of consistency jdb
#############################################################################
#O  ObjecToElement( <geom>, <type>, <obj> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m> if and only if <obj> is the list [v,m].
##
InstallMethod( ObjectToElement,
 "for an affine space and an object",
 [ IsAffineSpace, IsPosInt, IsList],
 function(as, t, obj)
  local el;
  if Length(obj) = 2 then
   el :=  AffineSubspace(as, obj[1], obj[2]);
  else
   Error("<obj> does not determine a subspace of <as>");
  fi;
  if el!.type <> t then
   Error("<obj> does not determine a subspace of <as> of given type <t>");
  else
   return el;
  fi;
 end );

# CHECKED 13/03/12 jdb
#############################################################################
#O  RandomSubspace( <as>, <d> )
# returns an affine subspace of dimension <d> in the affine space <as>
##
InstallMethod( RandomSubspace, 
 "for an affine space and a dimension",
    [ IsAffineSpace, IsInt ],
 function(as, d)
  local vspace, w, sub;
        if d > RankAttr(as) then
   Error("The dimension of the subspace is larger than that of the affine space");
  fi;
  if IsNegInt(d) then
   Error("The dimension of the subspace must be at least 0!");
  fi;
  vspace := as!.vectorspace;
  w := Random(vspace);
  if d = 1 then
   return AffineSubspace( as, w );
  else
   sub := BasisVectors(  Basis( RandomSubspace( vspace, d-1 ) ) );
   return AffineSubspace( as, w, sub );
  fi;
 end );  
  
# CHECKED 13/03/12 jdb
#############################################################################
#O  Random( <subs> )
# returns a random element in the collection <subs>
##
InstallMethod( Random, 
 "for a collection of subspaces of an affine space",
    [ IsSubspacesOfAffineSpace ],
    # chooses a random element out of the collection of subspaces of given
    # dimension of an affine space
 function( subs )
  local x;
  x := RandomSubspace( subs!.geometry, subs!.type );
  return x;
 end );
  
#############################################################################
#
#  ElementsOfIncidenceStructure, enumerators, iterators
#
#############################################################################

# CHECKED 13/03/12 jdb
#############################################################################
#O  ElementsOfIncidenceStructure( <as> )
# returns the collection of all the elements of the affine space <as> 
## 
InstallMethod( ElementsOfIncidenceStructure, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return Objectify( NewType( ElementsCollFamily, IsAllElementsOfIncidenceStructure ),
   rec( geometry := as ) );
 end );

# CHECKED 20/03/12 jdb
#############################################################################
#O  ElementsOfIncidenceStructure( <as>, <j> )
# returns the collection of all the elements of type <j> of the affine space <as> 
## 
InstallMethod( ElementsOfIncidenceStructure, 
 "for an affine space and an integer",
 [ IsAffineSpace, IsPosInt],
 function( as, j )
  local r;
  r := Rank(as);
  if j > r then
   Error("<as> has no elements of type <j>");
  else
   return Objectify( NewType( ElementsCollFamily, IsElementsOfIncidenceStructure and
                                IsSubspacesOfAffineSpace and IsSubspacesOfAffineSpaceRep ),
        #IsAllSubspacesOfAffineSpace and IsAllSubspacesOfAffineSpaceRep),
   rec( geometry := as, type := j, size := Size(Subspaces(as!.vectorspace, j-1)) * 
                  Size(as!.basefield)^(as!.dimension - j + 1) ) );
  fi;
 end );

#############################################################################
# User friendly named operations for points, lines, planes, solids
# for affine spaces. These operations are not checking if the affine space
# really contains the elements of the asked type, since ElementsOfIncidenceStructure 
# does. 
#############################################################################

# CHECKED 13/03/12 jdb
#############################################################################
#O  Points( <as> )
# returns ElementsOfIncidenceStructure(as,1), <as> a an affine space
## 
InstallMethod( Points, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return ElementsOfIncidenceStructure(as, 1);
 end);

# CHECKED 13/03/12 jdb
#############################################################################
#O  Lines( <as> )
# returns ElementsOfIncidenceStructure(as,2), <as> a an affine space
## 
InstallMethod( Lines, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return ElementsOfIncidenceStructure(as, 2);
 end);

# CHECKED 13/03/12 jdb
#############################################################################
#O  Planes( <as> )
# returns ElementsOfIncidenceStructure(as,3), <as> a an affine space
## 
InstallMethod( Planes, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return ElementsOfIncidenceStructure(as, 3);
 end);

# CHECKED 13/03/12 jdb
#############################################################################
#O  Solids( <as> )
# returns ElementsOfIncidenceStructure(as,4), <as> a an affine space
## 
InstallMethod( Solids, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return ElementsOfIncidenceStructure(as, 4);
 end);

# CHECKED 20/03/12 jdb
#############################################################################
#O  Solids( <as> )
# returns ElementsOfIncidenceStructure(as,1), <as> a an affine space
## 
InstallMethod( Hyperplanes, 
 "for an affine space",
 [IsAffineSpace],
 function( as )
  return ElementsOfIncidenceStructure(as, as!.dimension);
 end);

# CHECKED 13/03/12 jdb
#############################################################################
#O  Size( <vs> )
# returns the number of elements in the collection <vs>
## 
InstallMethod(Size, 
 "for a collection of subspaces of an affine space",
    [IsSubspacesOfAffineSpace],
 function( vs ) 
  return vs!.size; 
 end );
    
#############################################################################
# Methods to create flags.
#############################################################################

#############################################################################
#O  FlagOfIncidenceStructure( <as>, <els> )
# returns the flag of the projective space <ps> with elements in <els>.
# the method checks whether the input really determines a flag.
##
InstallMethod( FlagOfIncidenceStructure,
 "for an affine space and list of subspaces of the affine space",
 [ IsAffineSpace, IsSubspaceOfAffineSpaceCollection ],
 function(as,els)
  local list,i,test,type,flag;
  list := Set(ShallowCopy(els));
  if Length(list) > Rank(as) then
    Error("A flag ca at most Rank(<as>) elements");
  fi;
        test := List(list,x->AmbientGeometry(x));
        if not ForAll(test,x->x=as) then
            Error("not all elements have <as> as ambient geometry");
        fi;
  test := Set(List([1..Length(list)-1],i -> IsIncident(list[i],list[i+1])));
  if (test <> [ true ] and test <> []) then
    Error("<els> does not determine a flag>");
  fi;
  flag := rec(geo := as, types := List(list,x->x!.type), els := list);
  ObjectifyWithAttributes(flag, IsFlagOfASType, IsEmptyFlag, false);
  return flag;
 end);

#############################################################################
#O  FlagOfIncidenceStructure( <as>, <els> )
# returns the empty flag of the projective space <ps>.
##
InstallMethod( FlagOfIncidenceStructure,
 "for an affine space and an empty list",
 [ IsAffineSpace, IsList and IsEmpty ],
 function(as,els)
  local flag;
  flag := rec(geo := as, types := [], els := []);
  ObjectifyWithAttributes(flag, IsFlagOfASType, IsEmptyFlag, true);
  return flag;
 end);

#############################################################################
# View/Print/Display methods for flags
#############################################################################

InstallMethod( ViewObj, 
 "for a flag of an affine space",
 [ IsFlagOfAffineSpace and IsFlagOfIncidenceStructureRep ],
 function( flag )
  Print("<a flag of AffineSpace(",flag!.geo!.dimension,", ",Size(flag!.geo!.basefield),")>");
 end );

InstallMethod( PrintObj,
 "for a flag of an affine space",
 [ IsFlagOfAffineSpace and IsFlagOfIncidenceStructureRep ],
 function( flag )
  PrintObj(flag!.els);
 end );

InstallMethod( Display, 
 "for a flag of an affine space",
 [ IsFlagOfAffineSpace and IsFlagOfIncidenceStructureRep ],
 function( flag )
  if IsEmptyFlag(flag) then
   Print("<empty flag of AffineSpace(",flag!.geo!.dimension,", ",Size(flag!.geo!.basefield),")>\n");
  else
   Print("<a flag of AffineSpace(",flag!.geo!.dimension,", ",Size(flag!.geo!.basefield),")> with elements of types ",flag!.types,"\n");
   Print("respectively spanned by\n");
   Display(flag!.els);
  fi;
 end );

#############################################################################
# Enumerator method(s)
#############################################################################

#############################################################################
#O  Enumerator( <trans> )
# return an Enumerator for a vector space transversal.
##
InstallMethod( Enumerator, 
 "for a vector space transversal", 
 [ IsVectorSpaceTransversal ],
 function( trans )  
    
    # returns an enumerator for the canonical elements of all cosets of 
    # <subspace> in <space>. 
    
    local complement, enumcomp, enum, space, subspace;
    space := trans!.vectorspace;
    subspace := trans!.subspace;
    complement := ComplementSpace( space, subspace );
    enumcomp := Enumerator( complement );
    enum := EnumeratorByFunctions( trans, rec(            
            ElementNumber := function(e, n)
    local v;
    v := enumcomp[n];
    return VectorSpaceTransversalElement(space, subspace, v);
            end,
            NumberElement := function(e,v)
    local n;
    n := Position(enumcomp,v);
    return n;
   end,
   #NumberElement := enumcomp!.NumberElement,
            #Length := e -> enumcomp!.Length ));   # silly enumerator of v.spaces doesn't always have "Length"
            Length := e -> Size(complement) ));
    return enum;
 end );

# 24/3/2014. cmat adapted.
#############################################################################
#O  Enumerator( <vs> )
# return an Enumerator for subspaces of an affine space of given type.
##
InstallMethod( Enumerator, 
 "for subspaces of an affine space",
    [ IsSubspacesOfAffineSpace ],  
 function( vs )
 ## An affine subspace will be represented by a pair (vector,direction).
 ## So for example, an affine plane x+<W> will be represented by
 ## (x', proj. line)  (where x' is the transversal rep corresponding to x).
    local as, j, vars, vec, subs, f, enum, enumV, classsize;
    as := vs!.geometry;
    j := vs!.type;
    vec := as!.vectorspace;
    f := as!.basefield;
    if j = 1 then 
       enumV := Enumerator( vec );
       enum := EnumeratorByFunctions( vs, rec(
            ElementNumber := function(e, n)
              local v;
              v := enumV[n]; 
              #ConvertToVectorRep(v, f);
              return Wrap(as, 1, NewMatrix(IsCMatRep,f,as!.dimension,[v])[1]); #looks ugly, avoids an extra call.
            end,
            NumberElement := function(e, x)
              local v;
              v := Unpack(x!.obj);
              return Position(enumV, v);
            end ));    
    else
       enumV := Enumerator( Subspaces( vec, j-1 ) ); 
       classsize := Size(f)^(Dimension(vec)-j+1);
       enum := EnumeratorByFunctions( vs, rec(
            ElementNumber := function(e, n)
               local l, k, enumtrans, v; 
               
               ## The way this works is that n is the position
               ## of the l-th coset incident with the k-th (j-1)-space
               ## of as.      
               l := n mod classsize;
               if l = 0 then l := classsize; fi;  
               k := (n-l) / classsize + 1;  
               v := NewMatrix(IsCMatRep,f,as!.dimension,BasisVectors(Basis(enumV[k])));
               enumtrans := Enumerator( VectorSpaceTransversal(vec, Unpack(v)) );
               return Wrap(as, j, [ NewMatrix(IsCMatRep,f,as!.dimension,[enumtrans[l]])[1], v ] );
            end,
            NumberElement := function( e, x )
              local w, vw, k, enumtrans, l;
              ## Here we must first find the unique direction of x
              ## incident with x, and then find its place in the ordering.
              w :=Unpack(x!.obj[2]); #x!.obj = [cvec,cmat]        
              vw := Subspace(vec,w);
     k := Position(enumV, vw);  
              enumtrans := Enumerator( VectorSpaceTransversal(vec, w) );
              l := Position(enumtrans, Unpack(x!.obj[1]));
              return (k-1)*classsize + l;
            end ) );
     fi;
    return enum;
 end );    

# cmat adapted.
#############################################################################
#O  Iterator( <vs> )
# iterator for affine subspaces of a given type.
##
InstallMethod( Iterator, 
 "for subspaces of an affine space",
    [IsSubspacesOfAffineSpace],  
 function( vs )
 ## An affine subspace will be represented by a pair (vector,direction).
 ## So for example, an affine plane x+<W> will be represented by
 ## (x', proj. line)  (where x' is the transversal rep corresponding to x).
  local ps, j, vars, vec, subs, f;
  ps := vs!.geometry;
  j := vs!.type;
  vec := ps!.vectorspace;
  f := ps!.basefield;
  if j = 1 then 
   vars := List(vec, x -> AffineSubspace(ps, x));
   return IteratorList( vars );
  else
 ## we need a transversal for each subspace
   if j = 2 then 
    subs := List(ElementsOfIncidenceStructure(ProjectiveSpace(ps!.dimension-1,f), 1), 
                     x -> [Unpack(x!.obj)]);
   else
    subs := List(ElementsOfIncidenceStructure(ProjectiveSpace(ps!.dimension-1,f), j-1), 
                     x -> Unpack(x!.obj));
   fi;
   vars := Union(List(subs, x -> 
                 List(VectorSpaceTransversal(vec, x), y -> AffineSubspace(ps,y,x))));
   return IteratorList( vars );
  fi;
  end );


#############################################################################
#
# Basic methods: \in (set theoretic containment for elements), 
# IsIncident, Span, Meet, IsParallel, ProjectiveCompletion
#
#############################################################################

# CHECKED 13/03/12 jdb
#############################################################################
#O  \in( <x>, <as> )
# returns true if <x> is an element of the affine space <as>
##
InstallMethod( \in, 
 "for an element of an affine space and an affine space",
 [IsSubspaceOfAffineSpace, IsAffineSpace],
 function( x, as )
  local s;
  s := x!.geo;
  return s!.dimension = as!.dimension and s!.basefield = as!.basefield;
 end );

#############################################################################
#O  \in( <x>, <y> )
# set theoretic containment for an affine space and a subspace. 
##
InstallOtherMethod( \in, 
 "for an affine space and an element of an affine space",
 [ IsAffineSpace, IsSubspaceOfAffineSpace ],
 function( x, y )
  if x = y!.geo then
   return false;
  else
   Error( "<x> is different from the ambient space of <y>" );
  fi;
 end );

# CREATED 20/3/2012 jdb
#############################################################################
#O  \in( <x>, <y> )
# returns true if <x> is contained in <y>, from the set theoretic point of view.
##
InstallMethod( \in,  
 "for two subspaces of an affine space",
 [IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace],
 function( x, y )
  local ambx, amby, typx, typy, mat, flag,
          zero, nrows, ncols, vectors, 
          nvectors, i, j, z, nzheads, row;
  ambx := x!.geo;
  amby := y!.geo;
  typx := x!.type;
  typy := y!.type;
  #set theoretic containment makes only sense if the dimension of x is at most the dimension of y.
  if typx > typy then
   return false;
  elif typx = typy then
   return x=y;
  fi;
   
  ## x + A in y + B iff y-x in B and A subset of B
  # x+a in y+B for all a => (y-x) in B and A subset of B 

  if ambx!.vectorspace = amby!.vectorspace then   

  ## First step: check that the translations are compatible,
  ## that is, that x!.obj[1] - y!.obj[1] is in the subspace
  ## spanned by "vectors"

   if typx = 1 and typy > 1 then
    return x!.obj - y!.obj[1] in Subspace(ambx!.vectorspace, y!.obj[2]);
   else 
    flag := x!.obj[1] - y!.obj[1] in Subspace(ambx!.vectorspace, y!.obj[2]);
   fi;
   if not flag then return false; fi;

  ## Second step: checking that the directions are compatible.
  ## Algorithm is the same as for projective spaces.
  ## Note that here we will have typx, typy > 1.

   vectors := y!.obj[2];
   nvectors := typy-1;
   mat := MutableCopyMat(x!.obj[2]);
   nrows := typx - 1;

   ncols:= amby!.dimension ;
   zero:= ZeroOfBaseDomain( mat );

  # here we are going to treat "vectors" as a list of basis vectors. first
  # figure out which column is the first nonzero column for each row
   nzheads := [];
   for i in [ 1 .. nvectors ] do
    row := vectors[i];
    j := PositionNonZero( row );
    Add(nzheads,j);
   od;

  # now try to reduce each row of "mat" with the basis vectors
   for i in [ 1 .. nrows ] do
    row := mat[i];
    for j in [ 1 .. Length(nzheads) ] do
     z := row[nzheads[j]];
     if z <> zero then
      AddRowVector( row, vectors[ j ], - z );
     fi;
    od;

  # if the row is now not zero then y is not a subspace of x
    j := PositionNonZero( row );
    if j <= ncols then
     flag := false; break;
    fi;
   od;
      
   return flag;
  else
   Error( "type is unknown or not implemented" );
  fi;
  return false;
  end );

# CREATED 20/3/2012 jdb
#############################################################################
#O  IsIncident( <x>, <y> )
# returns true if and only if <x> is incident with <y>. Relies on set theoretic
# containment.
##
InstallMethod( IsIncident,  
  [IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace],
        function(x,y)
                return x in y or y in x;
        end );


## An affine space is a complete lattice 
## (with the empty set as bottom element).

#############################################################################
#O  Span( <x>, <y> )
# cvec/cmat: I took no risk and unpacked everything to do linear algebra.
##
InstallMethod( Span,
 "for two affine subspaces",
 [IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace],
 function( x, y )  
  local ux1, uy1, ux2, uy2, ambx, amby, typx, typy, span, temp;
  ambx := AmbientSpace(x!.geo);
  amby := AmbientSpace(y!.geo);
  typx := x!.type;
  typy := y!.type;

  ## affine span of x + A and y + B is 
  ##  x + <y-x, A,B>

  if not (ambx!.vectorspace = amby!.vectorspace) then
   Error("Subspaces belong to different ambient spaces");
  fi;

  if typx = 1 then 
   ux1 := Unpack(x!.obj); 
   ux2 := [];
  else 
   ux1 := Unpack(x!.obj[1]); 
   ux2 := Unpack(x!.obj[2]);
  fi;
  if typy = 1  then 
   uy1 := Unpack(y!.obj); 
   uy2 := [];
  else 
   uy1 := Unpack(y!.obj[1]); 
   uy2 := Unpack(y!.obj[2]);
  fi;  
  span := MutableCopyMat(ux2);
  Append(span, uy2); #this is the reason to unpack everything, if span would be cmat, and uy2 e.g. [], this becomes very ugly.
  Append(span, [uy1-ux1]); 
  span := MutableCopyMat(SemiEchelonMat(span).vectors);
   
  # if the span is [], then x=y, so return x.
  
  if Length(span) = 0 then
   return x;
  fi;
   
  # if the span is the whole space, return that.
  if Length(span) = ambx!.dimension + 1 then
   return ambx;
  fi;      
  #TriangulizeMat(span); #AffineSubspace will do this now.
  return AffineSubspace(ambx, VectorSpaceTransversalElement(ambx!.vectorspace,span,ux1), span); #makes sure cvec/cmat is used.
  end );


#############################################################################
#O  Meet( <x>, <y> )
# cvec/cmat: I took no risk and unpacked everything to do linear algebra.
##
InstallMethod( Meet, 
 "for two affine subspaces",
 [IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace],
 function( x, y )
  local ag, ux1, uy1, ux2, uy2, typx, typy, int, 
          rep, t, f, vec, rk, trans, ambx, amby, m, mat;
  ag := x!.geo;
  ambx := AmbientSpace(x);
  amby := AmbientSpace(x);
  if not (ambx!.vectorspace = amby!.vectorspace) then
   Error("Subspaces belong to different ambient spaces");
  fi;

  typx := x!.type;
  typy := y!.type; 
  f := ag!.basefield; 
  vec := ag!.vectorspace;

  ## Cases for the intersection of x + A and y + B
  ## (i) A int B = 0 => (x+A) int (y+B) is a point or empty
  ## (ii) dim(A int B) = 1 => (x+A) int (y+B) is a point or empty
  ## (iii) dim(A int B) > 1 => (x+A) int (y+B) is subspace of 
  ## dimension dim(A int B), or empty
  ## (iv) A empty or B empty => equal or empty 

 ## redundant cases 
  if x = y then 
   return x;
  fi;
  # we can assume now that x<>y
  if typx = 1 and typy = 1 then
   return [];
  elif (typx = 1 or typy = 1) then
   if typx = 1 then
    ux1 := Unpack(x!.obj); 
   else
    ux1 := Unpack(x!.obj[1]); 
    mat := Unpack(x!.obj[2]);
   fi;
   if typy = 1 then
    uy1 := Unpack(y!.obj);
    mat := [ ]; 
   else
    uy1 := Unpack(y!.obj[1]); 
    mat := Unpack(y!.obj[2]);
   fi;
      
   if IsZero( VectorSpaceTransversalElement( vec, mat, ux1 - uy1) ) then
    return Minimum(x, y);
   else 
       return [];
   fi;
  fi;

  ux1 := Unpack(x!.obj[1]); 
  ux2 := Unpack(x!.obj[2]);
  uy1 := Unpack(y!.obj[1]); 
  uy2 := Unpack(y!.obj[2]);
 ## parallel spaces, case x=y is handled above.
  if ux2 = uy2 then 
   return []; 
  fi;
 
 ## find intersection of two spaces
  int := SumIntersectionMat(ux2, uy2)[2];
  
  if not IsEmpty(int) and Rank(int) > 0 then 
   int := MutableCopyMat(int);
   TriangulizeMat(int);
   rk := Rank(int) + 1;        
  ## Now check to see if the affine intersection
  ## is empty. We will need a representative anyway.
   trans := VectorSpaceTransversal(vec, int);
   rep := 0;
   for t in trans do
    if Rank(Union([t-ux1], ux2)) = Rank(ux2) and
     Rank(Union([t-uy1], uy2)) = Rank(uy2) then
     rep := t; break;
    fi;
   od;
   if rep = 0 then 
    return []; 
   elif rk = 1 then  
    return AffineSubspace( ag, rep);
   fi;
   return AffineSubspace( ag, rep, int);
  else   ## case (i)
   rep := 0;
   for t in vec do
    if not IsZero(t) and Rank(Union([t-ux1], ux2)) = Rank(ux2) and
     Rank(Union([t-uy1], uy2)) = Rank(uy2) then
     rep := t; break;
    fi;
   od;
   if rep = 0 then 
    return [];
   else
    return AffineSubspace( ag, rep);
   fi;
  fi;
 end );


# CHECKED 20/3/2012 jdb
#############################################################################
#O  IsParallel( <x>, <y> )
# returns true if and only if <x> is parallel with <y>. 
##
#InstallMethod( IsParallel, 
# "for two affine subspaces",
# [ IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace ],
# function( a, b );
#  if a!.type <> b!.type then
#   Error("Subspaces must be of the same dimension");
#  fi;
#  if a!.geo <> a!.geo then
#   Error("Ambient affine spaces must be the same");
#  fi;
#  if a!.type = 1 then
#   return true;
#  else
#   return a!.obj[2] = b!.obj[2];
#  fi;
# end );

# WRITTEN 12/9/2014 jb
# Two affine subspaces of possibly different dimensions are parallel if
# and only if the direction of one contains the direction of the other.

InstallMethod( IsParallel, 
 "for two affine subspaces",
 [ IsSubspaceOfAffineSpace, IsSubspaceOfAffineSpace ],
 function( a, b )
  local vectors, nvectors, mat, nrows, ncols, zero, row, i, j, nzheads, z, flag, x, y;
  if a!.geo <> b!.geo then
   Error("Ambient affine spaces must be the same");
  fi;
  if a!.type = 1 or b!.type = 1 then
   return true;
  fi;
  
  ## checking that the directions are incident.
  ## Algorithm is the same as for projective spaces.
  ## Note that here we will have typx, typy > 1.
  x := SortedList([a,b])[1];
  y := SortedList([a,b])[2];
  flag := true;
  vectors := y!.obj[2];
  nvectors := y!.type-1;
  mat := MutableCopyMat(x!.obj[2]);
  nrows := x!.type - 1;
  ncols:= y!.geo!.dimension ;
  zero:= ZeroOfBaseDomain( mat );

  # here we are going to treat "vectors" as a list of basis vectors. first
  # figure out which column is the first nonzero column for each row
  nzheads := [];
  for i in [ 1 .. nvectors ] do
   row := vectors[i];
   j := PositionNonZero( row );
   Add(nzheads,j);
  od;

  # now try to reduce each row of "mat" with the basis vectors
  for i in [ 1 .. nrows ] do
   row := mat[i];
   for j in [ 1 .. Length(nzheads) ] do
    z := row[nzheads[j]];
    if z <> zero then
     AddRowVector( row, vectors[ j ], - z );
    fi;
   od;

   # if the row is now not zero then y is not a subspace of x
   j := PositionNonZero( row );
   if j <= ncols then
    flag := false; break;
   fi;
  od;
      
  return flag;
 end );
 

#############################################################################
#O  ProjectiveCompletion( <x>, <y> )
# geometry morphism. Usual unpack to avoid potential problems.
# to be checked later.
##
InstallMethod( ProjectiveCompletion, 
 "for an affine space",
 [ IsAffineSpace ],
 function( as )
    # Returns an embedding of an affine space
    # into a projective space (its projective completion). 
    # For example, the point (x, y, z) goes to <(1, x, y, z)>    
    # An intertwiner is unnecessary, CollineationGroup(as) is 
    # subgroup of CollineationGroup(ps).

    local d, gf, ps, func, pre, map, morphism, vec, one, hom, infinity;
    d := as!.dimension;
    gf := as!.basefield;
    ps := ProjectiveSpace(d, gf);
    one := One(gf);    
    vec := as!.vectorspace;
  infinity := VectorSpaceToElement(ps,ShallowCopy(IdentityMat(d+1,gf)){[2..d+1]});
 func := function( x )
  local repx, subspace, n, trans, new, i, j;
  repx := x!.obj;
  n := x!.type;
  if not x in as then 
   Error("Subspace is not an element of the domain (affine space)");
  fi;
  if n > 1 then      
   subspace := Unpack(repx[2]);
   trans := Unpack(repx[1]);
   # simply put all vectors together and put 0's in the first column
   new := NullMat(n, d+1, gf);
   new{[1..n-1]}{[2..d+1]} := subspace;
   new[n][1] := one;
   new[n]{[2..d+1]} := trans; 
  else
   new := Concatenation([one], Unpack(repx)); 
  fi;
  return VectorSpaceToElement(ps, new);
    end;
 
    pre := function( y )
  local n, repy, subspace, trans, new, zerov, elm, hyp;
  if not y in ps then 
   Error("Subspace is not an element of the range (projective space)");
  fi;
  if y * infinity then
   Error("Subspace is an element at infinity");
  fi;
  n := y!.type;
  repy := y!.obj;
  if n > 1 then
   repy := List(repy,x->Unpack(x));
   zerov := NullMat(1,d,gf);
   hyp := TransposedMat(Concatenation(zerov, IdentityMat(d, gf)));
   subspace := SumIntersectionMat(hyp, repy)[2];
#   repy := SortedList(y!.obj);  ## JB: 11/09/2014 (found the bug here)
   repy := SortedList(repy);
   # Make use of lexicographic ordering
   # Zero at front gives the parallel class       
   trans := repy[n];
      
   # curtail
   trans := trans{[2..d+1]};
   subspace := subspace{[1..n-1]}{[2..d+1]}; 
   new := VectorSpaceTransversalElement(vec, subspace, trans);
   elm := AffineSubspace(as, new, subspace);
  else
   trans := repy{[2..d+1]};
   elm := AffineSubspace(as, trans);
  fi;
  return elm;
 end;

    map := GeometryMorphismByFunction(ElementsOfIncidenceStructure(as), 
                                      ElementsOfIncidenceStructure(ps), func, false, pre);
    SetIsInjective(map, true);  
    return map;
end );

#############################################################################
#
#  Methods for shadows and parallel classes
#
#  (We use the completion to the projective space)
#
#############################################################################


#############################################################################
#O  ShadowOfElement( <as>, <v>, <j> )
# Returns the elements of type j incidence with <v>, a usual shadow object 
# in FinInG.
##
InstallMethod( ShadowOfElement, 
 "for an affine space, an affine subspace, a positive integer",
 [IsAffineSpace, IsSubspaceOfAffineSpace, IsPosInt],
 function( as, v, j )   
        if not AmbientGeometry(v) = as then
            Error("Ambient geometry of <v> is not <as>");
        fi;
        return Objectify(
   NewType( ElementsCollFamily, IsElementsOfIncidenceStructure and
                                   IsShadowSubspacesOfAffineSpace and
                                   IsShadowSubspacesOfAffineSpaceRep),
     rec( geometry := as, type := j, list := [v] ) );
 end );
  

#############################################################################
#O  ShadowOfFlag( <as>, <v>, <j> )
# Returns the elements of type j incidence with a flag, a usual shadow object 
# in FinInG.
##
InstallMethod( ShadowOfFlag, 
 "for an affine space, a flag of affine elements, a positive integer",
 [IsAffineSpace, IsFlagOfIncidenceStructure, IsPosInt],
 function( as, flag, j )
        #   empty flag - return all subspaces of the right type
  if IsEmptyFlag(flag) then
   return ElementsOfIncidenceStructure(as, j);
  fi;
  return Objectify(
   NewType( ElementsCollFamily, IsElementsOfIncidenceStructure and
                                   IsShadowSubspacesOfAffineSpace and
                                   IsShadowSubspacesOfAffineSpaceRep),
    rec( geometry := as, type := j, list := flag!.els ) #JDB: added !.els here (flags used to be lists, are objects now).
     );
 end);
  
#############################################################################
#O  ParallelClass( <as>, <v> )
# returns the collection of elements parallel with <v>
##
InstallMethod( ParallelClass, 
 "for an affine space and subspace",
 [IsAffineSpace, IsSubspaceOfAffineSpace], 
 function( as, v )
  #if v!.type = 0 then
  # Error("Subspace must be nontrivial"); #this never occurs, it is not possible te constuct elements of type 0.
  if v!.type = 1 then
   return Points( as );     
  else
   return Objectify(
    NewType( ElementsCollFamily, IsElementsOfIncidenceStructure and
                                   IsParallelClassOfAffineSpace and
                                   IsParallelClassOfAffineSpaceRep),
      rec( geometry := as, element := v, type := v!.type ) );
                        # Added the type to the parallelclass 
                        # ml 12/09/2014
  fi;      
 end );
  
#############################################################################
#O  ParallelClass( <v> )
# returns the collection of elements parallel with <v>
##
InstallMethod( ParallelClass, 
 "for an affine subspace", 
 [ IsSubspaceOfAffineSpace ], 
 x -> ParallelClass( x!.geo, x ) );


#############################################################################
#O  Iterator( <pclass> )
# iterator for a parallel class of an element of an affine space.
##
InstallMethod( Iterator, 
 "for a parallel class of an affine space",
 [IsParallelClassOfAffineSpace and IsParallelClassOfAffineSpaceRep ],
 function( pclass )
  local as, v, type, direction, vec, elms;
  as := pclass!.geometry;
  v := pclass!.element;
  type := v!.type;
  direction := Unpack(v!.obj[2]); #a parallel class of a point is not in IsParallelClassOfAffineSpace(Rep)
  vec := as!.vectorspace;
        ## Do the trivial cases:
  #if type = 1 then #cannot occur
        ## it already has an iterator...
        #return Iterator( pclass );
        #fi;
  elms := List(VectorSpaceTransversal(vec, direction), y -> AffineSubspace(as, y,direction) );
  return IteratorList( elms ); 
 end );


#############################################################################
#O  Size( <vs> )
# number of elements in a shadow.
##
InstallMethod( Size, 
 "for a shadow of an element of an affine subspace",
 [IsShadowSubspacesOfAffineSpace and IsShadowSubspacesOfAffineSpaceRep ],
 function( vs )
  local ps, list, map, shad, j, as;
  as := vs!.geometry;
  j := vs!.type;
  map := ProjectiveCompletion(as);
  ps := Range(map)!.geometry;
  list := vs!.list;    
  if Size( list ) = 1 then
   shad := ShadowOfElement( ps, ImageElm(map, list[1]), j);
  else
   shad := ShadowOfFlag( ps, ImagesSet(map, list), j);
  fi;
  return Size( shad );
  end);


#############################################################################
#O  Iterator( <shadow> )
# iterator for a shadow of an element in an affine space.
##
InstallMethod( Iterator, 
 "for a shadow in an affine space",
 [IsShadowSubspacesOfAffineSpace and IsShadowSubspacesOfAffineSpaceRep ],
 function( vs )
  local as, i, j, ps, map, iter, list, dim, hyperplane, x, newfinish, assoc;
  as := vs!.geometry;
  j := vs!.type;
  map := ProjectiveCompletion(as);
  ps := Range(map)!.geometry;
  list := vs!.list;  
  dim := ps!.dimension+1;
  hyperplane := VectorSpaceToElement(ps, IdentityMat(dim,ps!.basefield){[2..dim]});
  if Size( list ) = 1 then
   x := list[1];
   i := x!.type;
   iter := StructuralCopy(Iterator( ShadowOfElement( ps, ImageElm(map, x), j) ));
   #
   #  We simple change the IsDoneIterator in iter.
   #  It took me ages to figure out how this all works!
   # 
   newfinish := Maximum(  [ Binomial(i-1,j-1), Binomial(dim-i,j-i) ] );   ##JB: Happy that this works!
   assoc := iter!.S!.associatedIterator;
   assoc!.choiceiter!.IsDoneIterator := 
    iter -> iter!.pos = newfinish and IsDoneIterator(assoc!.spaceiter);
  else
   # still need to truncate the iterator of this one ...
   Print("Iterators of shadows of flags in affine spaces are not complete in this version\n");
   iter := Iterator( ShadowOfFlag( ps, ImagesSet(map, list), j) );
  fi;
  return IteratorByFunctions( rec(
         NextIterator := function(iter)
          local x;
          repeat
           x := NextIterator(iter!.S);
          until not x in hyperplane;
          return PreImageElm(map, x);
         end,
         IsDoneIterator := iter -> IsDoneIterator(iter!.S),
         ShallowCopy := iter -> rec( S := ShallowCopy(iter!.S) ),
         S := iter )    
        );
 end);


#############################################################################
#
# Some view methods for shadows and parallel classes
#
#############################################################################


InstallMethod( ViewObj, 
 [ IsShadowSubspacesOfAffineSpace and IsShadowSubspacesOfAffineSpaceRep ],
 function( vs )
  Print("<shadow ",TypesOfElementsOfIncidenceStructurePlural(vs!.geometry)[vs!.type]," in ");
  ViewObj(vs!.geometry);
  Print(">");
 end );
  
InstallMethod( ViewObj, 
 [ IsParallelClassOfAffineSpace and IsParallelClassOfAffineSpaceRep ],
 function( vs )
  Print("<parallel class of ",
  TypesOfElementsOfIncidenceStructurePlural(vs!.geometry)[vs!.element!.type]," in ");
  ViewObj(vs!.geometry);
  Print(">");
 end );

#############################################################################
#
# Nice shorthand methods for shadows of elements
#
#############################################################################


InstallMethod( Points, [ IsSubspaceOfAffineSpace ],
  function( var )
    return ShadowOfElement(var!.geo, var, 1);
  end );

InstallMethod( Points, [ IsAffineSpace, IsSubspaceOfAffineSpace ],
  function( geo, var )
    return ShadowOfElement(geo, var, 1);
  end );

InstallMethod( Lines, [ IsSubspaceOfAffineSpace ],
  function( var )
    return ShadowOfElement(var!.geo, var, 2);
  end );

InstallMethod( Lines, [ IsAffineSpace, IsSubspaceOfAffineSpace ],
  function( geo, var )
    return ShadowOfElement(geo, var, 2);
  end );

InstallMethod( Planes, [ IsSubspaceOfAffineSpace ],
  function( var )
    return ShadowOfElement(var!.geo, var, 3);
  end );

InstallMethod( Planes, [ IsAffineSpace, IsSubspaceOfAffineSpace ],
  function( geo, var )
    return ShadowOfElement(geo, var, 3);
  end );

InstallMethod( Solids, [ IsSubspaceOfAffineSpace ],
  function( var )
    return ShadowOfElement(var!.geo, var, 4);
  end );

InstallMethod( Solids, [ IsAffineSpace, IsSubspaceOfAffineSpace ],
  function( geo, var )
    return ShadowOfElement(geo, var, 4);
  end );

#############################################################################
#O  IncidenceGraph( <gp> )
# Note that computing the collineation group of a projective space is zero
# computation time. So useless to print the warning here if the group is not
# yet computed.
###
InstallMethod( IncidenceGraph,
    "for a projective space",
    [ IsAffineSpace ],
    function( as )
        local elements, graph, adj, coll, sz;
  if IsBound(as!.IncidenceGraphAttr) then
            return as!.IncidenceGraphAttr;
        fi;
  coll := CollineationGroup(as);
  elements := Concatenation(List([1..Rank(as)], i -> List(AsList(ElementsOfIncidenceStructure(as,i)))));
        adj := function(x,y)
            if x!.type <> y!.type then
                return IsIncident(x,y);
            else
                return false;
            fi;
        end;
        graph := Graph(coll,elements,OnAffineSubspaces,adj,true);
        Setter( IncidenceGraphAttr )( as, graph );
        return graph;
    end );





[ Dauer der Verarbeitung: 0.35 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