Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/simpcomp/lib/   (GAP Algebra Version 4.15.1©)  Datei vom 18.2.2022 mit Größe 48 kB image not shown  

Quelle  homology.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

################################################################################
##
##  simpcomp / homology.gi
##
##  Homology related functions
##
##  $Id$
##
################################################################################

SCIntFunc.HomTransposeSparseMat:=function(A)
 local res,yind,i,j;
 res:=rec(n_row:=A.n_col, n_col:=A.n_row,M:=[]);
 for i in [1..res.n_col]do
  res.M[i]:=rec(n_entries:=0,inds:=[],vals:=[]);
 od;
 for i in [A.n_col,A.n_col-1..1] do
  for j in [1..A.M[i].n_entries] do
   yind:=A.M[i].inds[j];
   res.M[yind].n_entries:=res.M[yind].n_entries+1;
   Add(res.M[yind].inds,i);
   Add(res.M[yind].vals,A.M[i].vals[j]);
  od;
 od;
 return res;
end;;


SCIntFunc.HomSparseToDenseTMat:=function(A)
 local i,j,res;
 res:=NullMat(A.n_col,A.n_row);
 for i in [1..A.n_col] do
  for j in [1..A.M[i].n_entries] do
   res[i][A.M[i].inds[j]]:=A.M[i].vals[j];
  od;
 od;
 return res;
end;;

#=mult_a*a+mult_b*b
SCIntFunc.HomMult_add_mult_to_column:=function(mult_a, a, mult_b, b)
 local  i,j,res;
 res:=rec(n_entries:=0,inds:=[],vals:=[]);
 i:=1;
 j:=1;
 while(i<=a.n_entries and j <=b.n_entries)do
  if(a.inds[i]>b.inds[j]) then
   if ((mult_a*a.vals[i])<>0) then
    res.n_entries:=res.n_entries+1;
    Add(res.inds,a.inds[i]);
    Add(res.vals,(mult_a*a.vals[i]));
   fi;
   i:=i+1;
  elif (b.inds[j]>a.inds[i]) then
   if((mult_b*b.vals[j])<>0) then
    res.n_entries:=res.n_entries+1;
    Add(res.inds,b.inds[j]);
    Add(res.vals,(mult_b*b.vals[j]));
   fi;
   j:=j+1;
  else #b.inds[j]==a.inds[i]
   if ((mult_a*a.vals[i]+mult_b*b.vals[j])<>0) then
    res.n_entries:=res.n_entries+1;
    Add(res.inds,b.inds[j]);
    Add(res.vals,(mult_a*a.vals[i]+mult_b*b.vals[j]));
   fi;
   i:=i+1;
   j:=j+1;
  fi;
 od;
 while(i<=a.n_entries) do  
  #copy rest of a
  if ((mult_a*a.vals[i])<>0) then
   res.n_entries:=res.n_entries+1;
   Add(res.inds,a.inds[i]);
   Add(res.vals,(mult_a*a.vals[i]));
  fi;
  i:=i+1
 od;
 while(j <=b.n_entries) do
  #copy rest of b
  if((mult_b*b.vals[j])<>0) then
   res.n_entries:=res.n_entries+1;
   Add(res.inds,b.inds[j]);
   Add(res.vals,(mult_b*b.vals[j])); 
  fi;
  j:=j+1;
 od;
 return res;
end;;



SCIntFunc.HomInsert_col_to_sparse_mat:=function(matrix,vektor,col_ind)
 local i;
 matrix.M[col_ind].n_entries:=Length(vektor);
 matrix.M[col_ind].inds:=[];
 matrix.M[col_ind].vals:=[];
 
 
 for i in [Length(vektor),Length(vektor)-1..1] do
  Add(matrix.M[col_ind].inds,vektor[i][1]);
  Add(matrix.M[col_ind].vals,vektor[i][2]);
 od;

end;;



SCIntFunc.HomCopy_mat:=function(matrix)
 local i, res;
 res:=[];
 for i in [1..matrix.n_col] do
  res[i]:=rec(n_entries:=matrix.M[i].n_entries,inds:=ShallowCopy(matrix.M[i].inds),vals:=ShallowCopy(matrix.M[i].vals));
 od;
 return res;
end;;



SCIntFunc.HomIdentity_mat:=function(n_col)
 local i, res;
 res:=[];
 for i in [1..n_col] do
  res[i]:=rec(n_entries:=1,inds:=[i],vals:=[1]);
 od;
 return res;
end;;



SCIntFunc.HomGet_entry:=function(matrix,col_ind,row_ind)
 local i;
 i:=Position(matrix[col_ind].inds,row_ind);
 return matrix[col_ind].vals[i];
end;;




SCIntFunc.HomBoundaryOperatorMatrix:=function(A,B,d)
 local i,j,m,n, sign, help,dSimplex,pos,res, temp;
 n:=Size(A);
 m:=Size(B);
 
 res:=rec(n_row:=m, n_col:=n, M:=[]);
 for i in [1..res.n_col]do
  res.M[i]:=rec(n_entries:=0,inds:=[],vals:=[]);
 od;

 if (m=0) then 
  return res;
 elif (n=0) then
 
  return res;
 else
 
  for j in [1..n] do 
   sign:=1;
   temp:=[];
 
   dSimplex:=ShallowCopy(A[j]);
   for i in [1..d+1] do
    sign:=sign * (-1);
    help:=dSimplex[i];
    RemoveSet(dSimplex,help);
    pos:=Position(B,dSimplex);
    
    AddSet(temp,[pos,sign]);
    
    AddSet(dSimplex,help);
   od;
   SCIntFunc.HomInsert_col_to_sparse_mat(res,temp,j);
  od;
 
  return res;
 fi;

end;;


SCIntFunc.HomComputeBasis:=function(matrix, im, rowinvvalues) 
 local i,j,k,m,n,done,N,res,Mtemp,gcd,rs,a,b,Nhelp,Mtemphelp,AntModi, AntModj,rowinv,Mtemp_j_k;
 
 res:=rec( free:=[], torsion:=[]);
 m:=matrix.n_row;
 n:=matrix.n_col;
 N:=SCIntFunc.HomIdentity_mat(n);
 Mtemp:=matrix.M;
 
 rowinv:=0*[1..m];
 
 for i in [1..m] do 
  rowinvvalues[i]:=0;
 od;
 
 
 for i in [1..n] do
  
  done:=false;
  k:=m;
 
  while (not done) do
  
 
   if (Mtemp[i].n_entries>0) then
    k:=Mtemp[i].inds[1];
    j:=rowinv[k];
    if (j<>0) then 
 
      Mtemp_j_k:=SCIntFunc.HomGet_entry(Mtemp,j,k);
 
     AntModi:=Mtemp[i].vals[1];
     AntModj:=Mtemp_j_k;
     if (AntModi mod AntModj=0) then
      #no torsion
      b:=(Mtemp[i].vals[1])/AntModj;
      
 
      N[i]:=SCIntFunc.HomMult_add_mult_to_column((Mtemp_j_k /AntModj),N[i],-b,N[j]);
      Mtemp[i]:=SCIntFunc.HomMult_add_mult_to_column((Mtemp_j_k /AntModj),Mtemp[i],-b,Mtemp[j]);
 
     else
      #torsion
 
      gcd:=Gcd(AntModj,AntModi);
      a:=Mtemp_j_k/gcd;
      b:=-Mtemp[i].vals[1]/gcd;
      rs:=GcdRepresentation(AntModi,AntModj);
      Nhelp:=ShallowCopy(N[j]);
      Mtemphelp:=ShallowCopy(Mtemp[j]);
      rs[1]:=rs[1]*(Mtemp_j_k/AntModj);
      rs[2]:=rs[2]*(Mtemp[i].vals[1]/AntModi);
      
      
 
      N[j]:=SCIntFunc.HomMult_add_mult_to_column(rs[2],N[j],rs[1],N[i] ); 
      Mtemp[j]:=SCIntFunc.HomMult_add_mult_to_column(rs[2],Mtemp[j],rs[1],Mtemp[i] );
      
      N[i]:=SCIntFunc.HomMult_add_mult_to_column(a,N[i],b,Nhelp );
      Mtemp[i]:=SCIntFunc.HomMult_add_mult_to_column(a,Mtemp[i],b,Mtemphelp );
      
      rowinvvalues[k]:=AbsoluteValue(SCIntFunc.HomGet_entry(Mtemp,j,k));
 
     fi;
     k:=k-1;
    else   
     done:=true;
     rowinv[k]:=i;
     rowinvvalues[k]:=AbsoluteValue(SCIntFunc.HomGet_entry(Mtemp,i,k));
    fi;
   else
    gcd:=AbsoluteValue(SCIntFunc.HomGet_entry(N,i,i)) ;
    if (im[i] mod gcd<>0) then
     Info(InfoSimpcomp,1,"SCIntFunc.HomComputeBasis: DANGERWILLROBINSON -- entry not annulated. Please contact the authors/maintainers of simpcomp.");
     return fail;
    fi;
    if (im[i]=0) then
     
     AddSet(res.free,N[i]);

    elif (im[i] >gcd)then    

     AddSet(res.torsion,[im[i] /gcd,N[i]]);

    fi;
    done:=true;
   fi; 
  od;
 od;

 matrix.M:=Mtemp;
 return res;
end;;


SCIntFunc.HomCoHomologyD:=function(complex,d,mode)
 local i,s,simplices,boundaries,matrix1, matrix2, row,row2,basis, res, temp,min,smith,smith_base,tors_ord, tors_ord_test,dim;

 dim:=SCDim(complex);
 
 if(dim=fail) then
  return fail;
 fi;
 
 simplices:=[];
 simplices[1]:=[];
 for i in [d+1..d+3] do
  simplices[i]:=[];
  if(i-2>=0 and i-2<=dim) then
   simplices[i]:=SCSkelEx(complex,i-2);
  fi;
 od;

 #calculate boundary operator matrix
 if (mode=1) then #cohomology
  matrix1:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+2],simplices[d+1],d );
  matrix2:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+3],simplices[d+2],d+1 );
  matrix1:=SCIntFunc.HomTransposeSparseMat(matrix1);
  matrix2:=SCIntFunc.HomTransposeSparseMat(matrix2);
 else #homology
  matrix2:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+2],simplices[d+1],d );
  matrix1:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+3],simplices[d+2],d+1 );
 fi;

 row:=[];
 SCIntFunc.HomComputeBasis(matrix1, 0*[1..matrix1.n_col], row); #calculate image
 row2:=[];

 basis:=SCIntFunc.HomComputeBasis(matrix2, row, row2); #calculate kernel and kernel/image
 res:=[];

 for s in basis.free do
  temp:=[];
  for i in [1..s.n_entries]do   
   #Add(temp,[s.vals[i],simplices[d+2][s.inds[i]]]);
   Add(temp,[s.vals[i],s.inds[i]]);
  od;
  AddSet(res,[1,temp]);
 od;
 
 #check torsion with smith normal form
 if(basis.torsion<>[]) then
  tors_ord_test:=1;
  tors_ord:=1;
  for i in row do
   if i<>0 then
    tors_ord:=tors_ord*i;
   fi;
  od;
  
  smith:=SmithNormalFormIntegerMatTransforms(SCIntFunc.HomSparseToDenseTMat(matrix1));
  
  if (matrix1.n_col>matrix1.n_row) then
   min:=matrix1.n_row;
  else
   min:=matrix1.n_col;
  fi;
  
  #evaluate smith-normal-form
  for s in [1..min] do  
   if (AbsInt(smith.normal[s][s])>1) then
    tors_ord_test:=tors_ord_test*smith.normal[s][s];
    temp:=[];
    smith_base:=SolutionIntMat(smith.coltrans,smith.normal[s]/smith.normal[s][s]);
    
    for i in [1..matrix1.n_row] do 
     if (smith_base[i]<>0) then
      Add(temp,[smith_base[i],i]);
     fi;
    od;
    AddSet(res,[smith.normal[s][s],temp]);
   fi;
  od;
  if (AbsInt(tors_ord)<>AbsInt(tors_ord_test)) then
   Info(InfoSimpcomp,1,"SCIntFunc.HomCoHomologyD: inconsistent results, (co)homology computation failed. Please contact the authors/maintainers of simpcomp.");  
   return fail;
  fi;
 fi;
 
 return res;
end;

SCIntFunc.HomHomologyBaseD:=function(complex,d)
 return SCIntFunc.HomCoHomologyD(complex,d,0);
end;


SCIntFunc.HomCohomologyBaseD:=function(complex,d)
 return SCIntFunc.HomCoHomologyD(complex,d,1);
end;

SCIntFunc.HomSmithN:=function( basis, matrix1,i)
 local s, temp, smith, min;
 if (basis[i].torsion<>[]) then
  temp:=[];
  smith:=SmithNormalFormIntegerMat(SCIntFunc.HomSparseToDenseTMat(matrix1));
  if (matrix1.n_col>matrix1.n_row) then
   min:=matrix1.n_row;
  else
   min:=matrix1.n_col;
  fi;
  for s in [1..min] do
   if (AbsInt(smith[s][s])>1) then
    
    AddSet(temp,[smith[s][s],[]]);
   fi;
  od;
  basis[i].torsion:=temp;
 fi;
end;



SCIntFunc.HomCoHomology:=function(complex,mode)
 local i,j,d,s,simplices,boundaries,matrix1, matrix2, row,row2,basis, res, temp,min,smith,smith_base,tors_ord, tors_ord_test,dim,globres;

 dim:=SCDim(complex);
 
 if(dim=fail) then
  return fail;
 fi;

 simplices:=[];
 for i in [1..dim+3] do
  simplices[i]:=[];
  if(i-2>=0 and i-2<=dim) then
   simplices[i]:=SCSkelEx(complex,i-2);
  fi;
 od;

 globres:=[]; 
 for d in [0..dim] do
  #calculate boundary operator matrix
  if (mode=1) then #cohomology
   matrix1:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+2],simplices[d+1],d);
   matrix2:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+3],simplices[d+2],d+1);
   matrix1:=SCIntFunc.HomTransposeSparseMat(matrix1);
   matrix2:=SCIntFunc.HomTransposeSparseMat(matrix2);
  else #homology
   matrix1:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+3],simplices[d+2],d+1);
   matrix2:=SCIntFunc.HomBoundaryOperatorMatrix(simplices[d+2],simplices[d+1],d);
  fi;

  row:=[];
  SCIntFunc.HomComputeBasis(matrix1,ListWithIdenticalEntries(matrix1.n_col,0),row); #calculate image
  row2:=[];
 
  basis:=SCIntFunc.HomComputeBasis(matrix2, row, row2); #calculate kernel and kernel/image
  res:=[];
 
  for s in basis.free do
   temp:=[];
   for i in [1..s.n_entries]do   
    Add(temp,[s.vals[i],s.inds[i]]);
   od;
   AddSet(res,[1,temp]);
  od;
  
  #check torsion with smith normal form
  if(basis.torsion<>[]) then
   tors_ord_test:=1;
   tors_ord:=1;
   for i in row do
    if i<>0 then
     tors_ord:=tors_ord*i;
    fi;
   od;

   smith:=SmithNormalFormIntegerMatTransforms(SCIntFunc.HomSparseToDenseTMat(matrix1));
    
   if (matrix1.n_col>matrix1.n_row) then
    min:=matrix1.n_row;
   else
    min:=matrix1.n_col;
   fi;

   #evaluate smith-normal-form
   for s in [1..min] do  
    if (AbsInt(smith.normal[s][s])>1) then
     tors_ord_test:=tors_ord_test*smith.normal[s][s];
     temp:=[];
     smith_base:=SolutionIntMat(smith.coltrans,smith.normal[s]/smith.normal[s][s]);
     
     for i in [1..matrix1.n_row] do 
      if (smith_base[i]<>0) then
       #Add(temp,[smith_base[i],simplices[d+2][i]]);
       Add(temp,[smith_base[i],i]);
      fi;
     od;
     AddSet(res,[smith.normal[s][s],temp]);
    fi;
   od;
 
   if (AbsInt(tors_ord)<>AbsInt(tors_ord_test)) then
    Info(InfoSimpcomp,1,"SCIntFunc.HomCoHomologyD: inconsistent results, (co)homology computation failed. Please contact the authors/maintainers of simpcomp.");
    return fail;
   fi; 
  fi;
  Add(globres,res);
 od;
 
 res:=[];
 for i in [1..Length(globres)] do
  temp:=[];
  temp[1]:=0;
  temp[2]:=[];
  for j in globres[i] do
   if(j[1]=1) then
    temp[1]:=temp[1]+1;
   else
    Add(temp[2],j[1]);
   fi;
  od;

  if(i=1 and temp[1]>0 and mode=0) then
   temp[1]:=temp[1]-1;
  fi;
 
  Add(res, temp);
 od;
 return res;

end;


#calculate boundary of one simplex
#-- orientation flag=true: save orientation, false discard
SCIntFunc.boundaryOperator := function(simplex,orientation) 
 
 local b,cur,i,j,pos;

 b:=[];
 #all positions, i=kill entry
 for i in [1..Length(simplex)] do
  cur:=[];
  
  #reverse if i odd
  if((i mod 2)=1) then
   cur[1]:=-1;
   #pos:=Length(simplex)-1;
  else
   cur[1]:=1;
   #pos:=1;
  fi;
  pos:=1;
  cur[2]:=[];
  
  #extract one bounary face
  for j in [1..Length(simplex)] do
   if(i=j) then continue; fi;
   
   cur[2][pos]:=simplex[j];
   if((i mod 2)=1) then
    #pos:=pos-1;
    pos:=pos+1;
   else
    pos:=pos+1;
   fi;
  od;

  #add to list of boundary faces
  if(orientation=true) then
   Add(b,[ShallowCopy(cur[1]),ShallowCopy(cur[2])]);
  else
   Add(b,ShallowCopy(cur[2]));
  fi;
 od;
 
 return b;
end;

#calculate matrix of boundary operator mapping simplices to boundaries
#matrix: *-> d+1 simplices
#        |
#        V
#        d simplices
SCIntFunc.boundaryOperatorMatrix:=function(simplices, boundaries)
 local b,m,i,j,pos;
 
 if(boundaries=[]) then
  return [ListWithIdenticalEntries(Length(simplices),0)];
 fi;
 
 m:=[];
 for i in [1..Length(boundaries)] do
  m[i]:=[];
 od;
 
 for i in [1..Length(simplices)] do
  #get boundary of current simplex
  b:=SCIntFunc.boundaryOperator(simplices[i],true);
  
  #calculate matrix column
  for j in [1..Length(boundaries)] do
   m[j][i]:=0;
  od;

  for j in [1..Length(b)] do
   pos:=Position(boundaries,b[j][2]);
   if(pos<>fail) then
    m[pos][i]:=b[j][1];
   else
    Info(InfoSimpcomp,1,"SCIntFunc.boundaryOperatorMatrix: list of boundary simplices is not complete!");
    return fail;
   fi;
  od;
 od;
 
 return m;
end;







################################################################################
##<#GAPDoc Label="SCBoundarySimplex">
## <ManSection>
## <Func Name="SCBoundarySimplex" Arg="simplex, orientation"/>
## <Returns> a list upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates the boundary of a given <Arg>simplex</Arg>. If the flag <Arg>orientation</Arg> is set to <K>true</K>, the function returns the boundary as a list of oriented simplices of the form [ ORIENTATION, SIMPLEX ], where ORIENTATION is either +1 or -1 and a value of +1 means that SIMPLEX is positively oriented and a value of -1 that SIMPLEX is negatively oriented. If <Arg>orientation</Arg> is set to <K>false</K>, an unoriented list of simplices is returned. 
## <Example><![CDATA[
## gap> SCBoundarySimplex([1..5],true);
## [ [ -1, [ 2345 ] ], [ 1, [ 1345 ] ], [ -1, [ 1245 ] ], 
##   [ 1, [ 1235 ] ], [ -1, [ 1234 ] ] ]
## gap> SCBoundarySimplex([1..5],false);
## [ [ 2345 ], [ 1345 ], [ 1245 ], [ 1235 ], 
##   [ 1234 ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallGlobalFunction(SCBoundarySimplex,
function(simplex,orientation)
 if(not IsList(simplex) or not IsDuplicateFree(simplex) or not IsBool(orientation)) then
  Info(InfoSimpcomp,1,"SCBoundaryOperator: first argument must be a simplex (given as vertex tuple), second a boolean.");
  return fail;
 fi;

 return SCIntFunc.boundaryOperator(simplex,orientation);
end);



################################################################################
##<#GAPDoc Label="SCBoundaryOperatorMatrix">
## <ManSection>
## <Meth Name="SCBoundaryOperatorMatrix" Arg="complex,k"/>
## <Returns> a rectangular matrix  upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates the matrix of the boundary operator <M>\partial_{<Arg>k+1</Arg>}</M> of a simplicial complex <Arg>complex</Arg>. Note that each column contains the boundaries of a <Arg>k</Arg><M>+1</M>-simplex as a list of oriented <Arg>k</Arg>-simplices and that the matrix is stored as a list of row vectors (as usual in GAP).
## <Example><![CDATA[
## gap> c:=SCFromFacets([[1,2,3],[1,2,6],[1,3,5],[1,4,5],[1,4,6],\
##                       [2,3,4],[2,4,5],[2,5,6],[3,4,6],[3,5,6]]);;
## gap> mat:=SCBoundaryOperatorMatrix(c,1);
## [ [ 111110000000000 ], 
##   [ -100001111000000 ], 
##   [ 0, -1000, -1000111000 ], 
##   [ 00, -1000, -100, -100110 ], 
##   [ 000, -1000, -100, -10, -101 ], 
##   [ 0000, -1000, -100, -10, -1, -1 ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCBoundaryOperatorMatrixOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local d,bdm,s1,s2;
 
 if k < 0 then
  Info(InfoSimpcomp,1,"SCBoundaryOperatorMatrix: second argument must be an integer >=0.");
  return fail;
 fi;
 
 d:=SCDim(complex);
 if(d=fail) then
  return fail;
 fi;
 
 if(d < 0) then
   return [];
 fi;

 if(k>d) then
   return [[0]];
 fi;
 
 bdm:=[];
 
 s1:=SCSkelEx(complex,k);
 if(d>0) then
  s2:=SCSkelEx(complex,k-1);
 else
  s2:=[];
 fi;
 
 bdm:=SCIntFunc.boundaryOperatorMatrix(s1,s2);
 
 return bdm;
end);




################################################################################
##<#GAPDoc Label="SCCoboundaryOperatorMatrix">
## <ManSection>
## <Meth Name="SCCoboundaryOperatorMatrix" Arg="complex,k"/>
## <Returns> a rectangular matrix upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates the matrix of the coboundary operator <M>d^{<Arg>k+1</Arg>}</M> as a list of row vectors.
## <Example><![CDATA[
## gap> c:=SCFromFacets([[1,2,3],[1,2,6],[1,3,5],[1,4,5],[1,4,6],\
##                       [2,3,4],[2,4,5],[2,5,6],[3,4,6],[3,5,6]]);
## gap> mat:=SCCoboundaryOperatorMatrix(c,1);
## [ [ -11000, -1000000000 ], 
##   [ -10001000, -1000000 ], 
##   [ 0, -101000000, -10000 ], 
##   [ 00, -1100000000, -100 ], 
##   [ 00, -10100000000, -10 ], 
##   [ 00000, -1100, -100000 ], 
##   [ 000000, -110000, -100 ], 
##   [ 0000000, -1100000, -1 ], 
##   [ 000000000, -1010, -10 ], 
##   [ 0000000000, -1100, -1 ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCCoboundaryOperatorMatrixOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local bd;

 if k < 0 then
  Info(InfoSimpcomp,1,"SCCoboundaryOperatorMatrix: second argument must be an integer >=0.");
  return fail;
 fi;
 
 bd:=SCBoundaryOperatorMatrix(complex,k+1);
 
 if(bd=fail) then
  return fail;
 fi;
 
 return TransposedMat(bd);
end);


################################################################################
##<#GAPDoc Label="SCHomologyBasis">
## <ManSection>
## <Meth Name="SCHomologyBasis" Arg="complex,k"/>
## <Returns> a list of pairs of the form <C>[ integer, list of linear combinations of simplices ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates a set of basis elements for the <Arg>k</Arg>-dimensional homology group (with integer coefficients) of a simplicial complex <Arg>complex</Arg>. The entries of the returned list are of the form [ MODULUS, [ BASEELM1, BASEELM2, ...] ], where the value MODULUS is 1 for the basis elements of the free part of the <Arg>k</Arg>-th homology group and <M>q\geq 2</M> for the basis elements of the <M>q</M>-torsion part. In contrast to the function <Ref Meth="SCHomologyBasisAsSimplices" /> the basis elements are stored as lists of coefficient-index pairs referring to the simplices of the complex, i.e. a basis element of the form <M>[ [ \lambda_1, i], [\lambda_2, j], \dots ] \dots</M> encodes the linear combination of simplices of the form <M>\lambda_1*\Delta_1+\lambda_2*\Delta_2</M> with <M>\Delta_1</M>=<C>SCSkel(complex,k)[i]</C>, <M>\Delta_2</M>=<C>SCSkel(complex,k)[j]</C> and so on.
## <Example><![CDATA[
## gap> SCLib.SearchByName("(S^2xS^1)#RP^3");
## [ [ 237, "(S^2xS^1)#RP^3" ] ]
## gap> c:=SCLib.Load(last[1][1]);;
## gap> SCHomologyBasis(c,1);
## [ [ 1, [ [ 112 ], [ -17 ], [ 11 ] ] ], 
##   [ 2, [ [ 168 ], [ -169 ], [ -171 ], [ 272 ], [ -273 ] ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCHomologyBasisOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local hom,dhom,row,t,tmp,tmp2,bd1,bd2,d;

 if k < 0 then
  Info(InfoSimpcomp,1,"SCHomologyBasis: second argument must be an integer >=0.");
  return fail;
 fi;
 
 d:=SCDim(complex);
 if(d=fail) then
  return fail;
 fi;
 
 if(k>d) then
   return [];
 fi;
 
 hom:=SCIntFunc.HomHomologyBaseD(complex,k);
 
 return hom;  
end);




################################################################################
##<#GAPDoc Label="SCCohomologyBasis">
## <ManSection>
## <Meth Name="SCCohomologyBasis" Arg="complex,k"/>
## <Returns> a list of pairs of the form <C>[ integer, list of linear combinations of simplices ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates a set of basis elements for the <Arg>k</Arg>-dimensional cohomology group (with integer coefficients) of a simplicial complex <Arg>complex</Arg>. The entries of the returned list are of the form [ MODULUS, [ BASEELM1, BASEELM2, ...] ], where the value MODULUS is 1 for the basis elements of the free part of the <Arg>k</Arg>-th homology group and <M>q\geq 2</M> for the basis elements of the <M>q</M>-torsion part. In contrast to the function <Ref Meth="SCCohomologyBasisAsSimplices" /> the basis elements are stored as lists of coefficient-index pairs referring to the linear forms dual to the simplices in the <M>k</M>-th cochain complex of <Arg>complex</Arg>, i.e. a basis element of the form <M>[ [ \lambda_1, i], [\lambda_2, j], \dots ] \dots</M> encodes the linear combination of simplices (or their dual linear forms in the corresponding cochain complex) of the form <M>\lambda_1*\Delta_1+\lambda_2*\Delta_2</M> with <M>\Delta_1</M>=<C>SCSkel(complex,k)[i]</C>, <M>\Delta_2</M>=<C>SCSkel(complex,k)[j]</C> and so on.
## <Example><![CDATA[
## gap> SCLib.SearchByName("SU(3)/SO(3)");   
## [ [ 219, "SU(3)/SO(3) (VT)" ], [ 477, "SU(3)/SO(3) (VT)" ], 
##   [ 484, "SU(3)/SO(3) (VT)" ], [ 486, "SU(3)/SO(3) (VT)" ] ]
## gap> c:=SCLib.Load(last[1][1]);;
## gap> SCCohomologyBasis(c,3); 
## [ [ 2, [ [ -9259 ], [ 9262 ], [ 9263 ], [ -9270 ], [ 9271 ], 
##           [ -9273 ], [ -9274 ], [ -18275 ], [ -9276 ], [ 9278 ], 
##           [ -9279 ], [ -9280 ], [ 3283 ], [ -3285 ], [ 3289 ], 
##           [ -3294 ], [ 3310 ], [ -3313 ], [ 3316 ], [ -1317 ], 
##           [ -6318 ], [ 3319 ], [ -6320 ], [ 6321 ], [ 1322 ], 
##           [ 3325 ], [ -1328 ], [ 6330 ], [ -2331 ], [ 12332 ], 
##           [ 7333 ], [ -5334 ], [ 1345 ], [ 3355 ], [ -9357 ], 
##           [ 9358 ], [ 1363 ], [ 12365 ], [ -9366 ], [ -3370 ], 
##           [ -1371 ], [ -3372 ], [ 8373 ], [ -1374 ], [ 6375 ], 
##           [ 9376 ], [ 3377 ], [ 1380 ], [ 3383 ], [ -8385 ], 
##           [ -9386 ], [ -9388 ], [ -18404 ], [ 9410 ], [ -9425 ], 
##           [ -18426 ], [ -9427 ], [ 9428 ], [ -9429 ], [ 3433 ], 
##           [ -3435 ], [ -9437 ], [ 10442 ], [ 12445 ], [ 1447 ], 
##           [ -19448 ], [ 2449 ], [ -1450 ], [ -9451 ], [ 3453 ], 
##           [ 1455 ], [ 1457 ], [ -11458 ], [ -9459 ], [ 9461 ], 
##           [ 9462 ], [ -9468 ], [ 9469 ], [ -18471 ], [ -9472 ], 
##           [ 9474 ], [ -9475 ], [ 9488 ], [ 9495 ], [ -9500 ], 
##           [ -3504 ], [ 9505 ], [ 9512 ], [ 9515 ], [ 6519 ], 
##           [ 18521 ], [ -15523 ], [ 9524 ], [ -3525 ], [ 18527 ], 
##           [ -18528 ], [ 6529 ], [ 6531 ], [ 12532 ] ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCCohomologyBasisOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local hom,dhom,row,t,tmp,tmp2,bd1,bd2,d;

 if k < 0 then
  Info(InfoSimpcomp,1,"SCCohomologyBasis: second argument must be an integer >=0.");
  return fail;
 fi;

 d:=SCDim(complex);
 if(d=fail) then
  return fail;
 fi;
 
 if(k>d) then
   return [];
 fi;
 
 hom:=SCIntFunc.HomCohomologyBaseD(complex,k);
 
 return hom;
end);



SCIntFunc.CoHomBasisToSimplexList:=
function(hom,faces)
 if(hom=[]) then
  return [];
 fi;
 
 return List(hom,
  function(x)
   if(x=[]) then
    return [];
   fi;
   return [x[1],List(x[2],y->[y[1],faces[y[2]]])];
  end);
end;


################################################################################
##<#GAPDoc Label="SCHomologyBasisAsSimplices">
## <ManSection>
## <Meth Name="SCHomologyBasisAsSimplices" Arg="complex, k"/>
## <Returns> a list of pairs of the form <C>[ integer, list of linear combinations of simplices ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates a set of basis elements for the <Arg>k</Arg>-dimensional homology group (with integer coefficients) of a simplicial complex <Arg>complex</Arg>. The entries of the returned list are of the form [ MODULUS, [ BASEELM1, BASEELM2, ...] ], where the value MODULUS is 1 for the basis elements of the free part of the <Arg>k</Arg>-th homology group and <M>q\geq 2</M> for the basis elements of the <M>q</M>-torsion part. In contrast to the function <Ref Meth="SCHomologyBasis" /> the basis elements are stored as lists of coefficient-simplex pairs, i.e. a basis element of the form <M>[ [ \lambda_1, \Delta_1], [\lambda_2, \Delta_2], \dots ]</M> encodes the linear combination of simplices of the form <M>\lambda_1*\Delta_1+\lambda_2*\Delta_2 + \dots</M>.
## <Example><![CDATA[
## gap> SCLib.SearchByName("(S^2xS^1)#RP^3");
## [ [ 237, "(S^2xS^1)#RP^3" ] ]
## gap> c:=SCLib.Load(last[1][1]);;
## gap> SCHomologyBasisAsSimplices(c,1);
## [ [ 1, [ [ 1, [ 28 ] ], [ -1, [ 18 ] ], [ 1, [ 12 ] ] ] ], 
##   [ 2, [ [ 1, [ 1112 ] ], [ -1, [ 1113 ] ], [ -1, [ 1213 ] ], 
##          [ 2, [ 1214 ] ], [ -2, [ 1314 ] ] ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCHomologyBasisAsSimplicesOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local homsimp,hom,faces;

 if k < 0 then
  Info(InfoSimpcomp,1,"SCHomologyBasisAsSimplices: second argument must be an integer >=0.");
  return fail;
 fi;

 homsimp:=[];
 hom:=SCHomologyBasis(complex,k);
 faces:=SCSkelEx(complex,k);

 if(hom=fail or faces=fail) then
  return fail;
 fi;

 homsimp:=SCIntFunc.CoHomBasisToSimplexList(hom,faces);
 
 return homsimp;
end);

################################################################################
##<#GAPDoc Label="SCCohomologyBasisAsSimplices">
## <ManSection>
## <Meth Name="SCCohomologyBasisAsSimplices" Arg="complex, k"/>
## <Returns> a list of pars of the form <C>[ integer, linear combination of simplices ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Calculates a set of basis elements for the <Arg>k</Arg>-dimensional cohomology group (with integer coefficients) of a simplicial complex <Arg>complex</Arg>. The entries of the returned list are of the form [ MODULUS, [ BASEELM1, BASEELM2, ...] ], where the value MODULUS is 1 for the basis elements of the free part of the <Arg>k</Arg>-th homology group and <M>q\geq 2</M> for the basis elements of the <M>q</M>-torsion part. In contrast to the function <Ref Meth="SCCohomologyBasis" /> the basis elements are stored as lists of coefficient-simplex pairs referring to the linear forms dual to the simplices in the <M>k</M>-th cochain complex of <Arg>complex</Arg>, i.e. a basis element of the form <M>[ [ \lambda_1, \Delta_i], [\lambda_2, \Delta_j], \dots ] \dots</M> encodes the linear combination of simplices (or their dual linear forms in the corresponding cochain complex) of the form <M>\lambda_1*\Delta_1+\lambda_2*\Delta_2 + \dots</M>.
## <Example><![CDATA[
## gap> SCLib.SearchByName("SU(3)/SO(3)");   
## [ [ 219, "SU(3)/SO(3) (VT)" ], [ 477, "SU(3)/SO(3) (VT)" ], 
##   [ 484, "SU(3)/SO(3) (VT)" ], [ 486, "SU(3)/SO(3) (VT)" ] ]
## gap> c:=SCLib.Load(last[1][1]);;
## gap> SCCohomologyBasisAsSimplices(c,3);
## [ [ 2, [ [ -9, [ 2789 ] ], [ 9, [ 27812 ] ], [ 9, [ 27813 ] ], 
##          [ -9, [ 271112 ] ], [ 9, [ 271113 ] ], [ -9, [ 28910 ] ],
##          [ -9, [ 28911 ] ], [ -18, [ 28912 ] ], [ -9, [ 28913 ] ],
##          [ 9, [ 281012 ] ], [ -9, [ 281013 ] ], 
##          [ -9, [ 281112 ] ], [ 3, [ 291012 ] ], 
##          [ -3, [ 291112 ] ], [ 3, [ 3457 ] ], [ -3, [ 34512 ] ], 
##          [ 3, [ 341012 ] ], [ -3, [ 3567 ] ], [ 3, [ 35611 ] ], 
##          [ -1, [ 35613 ] ], [ -6, [ 3578 ] ], [ 3, [ 35710 ] ], 
##          [ -6, [ 35711 ] ], [ 6, [ 35712 ] ], [ 1, [ 35713 ] ], 
##          [ 3, [ 35812 ] ], [ -1, [ 35913 ] ], [ 6, [ 351012 ] ], 
##          [ -2, [ 351013 ] ], [ 12, [ 351112 ] ], 
##          [ 7, [ 351113 ] ], [ -5, [ 351213 ] ], [ 1, [ 36913 ] ], 
##          [ 3, [ 371012 ] ], [ -9, [ 371112 ] ], [ 9, [ 371113 ] ],
##          [ 1, [ 38913 ] ], [ 12, [ 381012 ] ], [ -9, [ 381013 ] ],
##          [ -3, [ 391012 ] ], [ -1, [ 391013 ] ], 
##          [ -3, [ 391112 ] ], [ 8, [ 391113 ] ], 
##          [ -1, [ 391213 ] ], [ 6, [ 3101112 ] ], 
##          [ 9, [ 3101113 ] ], [ 3, [ 3101213 ] ], [ 1, [ 4568 ] ], 
##          [ 3, [ 45611 ] ], [ -8, [ 45613 ] ], [ -9, [ 4578 ] ], 
##          [ -9, [ 45711 ] ], [ -18, [ 4689 ] ], [ 9, [ 46913 ] ], 
##          [ -9, [ 48910 ] ], [ -18, [ 48912 ] ], [ -9, [ 48913 ] ],
##          [ 9, [ 481012 ] ], [ -9, [ 481013 ] ], [ 3, [ 491012 ] ],
##          [ -3, [ 491112 ] ], [ -9, [ 491213 ] ], [ 10, [ 5678 ] ],
##          [ 12, [ 56711 ] ], [ 1, [ 56713 ] ], [ -19, [ 5689 ] ], 
##          [ 2, [ 56811 ] ], [ -1, [ 56812 ] ], [ -9, [ 56813 ] ], 
##          [ 3, [ 56911 ] ], [ 1, [ 56913 ] ], [ 1, [ 561013 ] ], 
##          [ -11, [ 561113 ] ], [ -9, [ 5789 ] ], [ 9, [ 57812 ] ], 
##          [ 9, [ 57813 ] ], [ -9, [ 571112 ] ], [ 9, [ 571113 ] ], 
##          [ -18, [ 58912 ] ], [ -9, [ 58913 ] ], [ 9, [ 581012 ] ],
##          [ -9, [ 581112 ] ], [ 9, [ 67813 ] ], [ 9, [ 671113 ] ], 
##          [ -9, [ 681013 ] ], [ -3, [ 691112 ] ], 
##          [ 9, [ 691113 ] ], [ 9, [ 78913 ] ], [ 9, [ 781112 ] ], 
##          [ 6, [ 791112 ] ], [ 18, [ 7111213 ] ], 
##          [ -15, [ 891012 ] ], [ 9, [ 891013 ] ], 
##          [ -3, [ 891112 ] ], [ 18, [ 8101112 ] ], 
##          [ -18, [ 8101213 ] ], [ 6, [ 9101112 ] ], 
##          [ 6, [ 9101213 ] ], [ 12, [ 9111213 ] ] ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCCohomologyBasisAsSimplicesOp,
"for SCSimplicialComplex and Int",
[SCIsSimplicialComplex,IsInt],
function(complex,k)
 local cohomsimp,cohom,faces;

 if k < 0 then
  Info(InfoSimpcomp,1,"SCCohomologyBasisAsSimplices: second argument must be an integer >=0.");
  return fail;
 fi;

 cohomsimp:=[];
 cohom:=SCCohomologyBasis(complex,k);
 faces:=SCSkelEx(complex,k);
 if(cohom=fail or faces=fail) then
  return fail;
 fi;

 cohomsimp:=SCIntFunc.CoHomBasisToSimplexList(cohom,faces);

 return cohomsimp;
end);


################################################################################
##<#GAPDoc Label="SCHomologyInternal">
## <ManSection>
## <Func Name="SCHomologyInternal" Arg="complex"/>
## <Returns> a list of pairs of the form <C>[ integer, list ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## This function computes the reduced simplicial homology with integer coefficients of a given simplicial complex <Arg>complex</Arg> with integer coefficients. It uses the algorithm described in <Cite Key="Desbrun08DiscDiffFormCompModel"/>. <P/>
## The output is a list of homology groups of the form <M>[H_0,....,H_d]</M>, where <M>d</M> is the dimension of <Arg>complex</Arg>. The format of the homology groups <M>H_i</M> is given in terms of their maximal cyclic subgroups, i.e. a homology group <M>H_i\cong \mathbb{Z}^f + \mathbb{Z} / t_1 \mathbb{Z} \times \dots \times \mathbb{Z} / t_n \mathbb{Z}</M> is returned in form of a list <M>[ f, [t_1,...,t_n] ]</M>, where <M>f</M> is the (integer) free part of <M>H_i</M> and <M>t_i</M> denotes the torsion parts of <M>H_i</M> ordered in weakly incresing size. See also <Ref Meth="SCHomology"/> and
## <Ref Func="SCHomologyClassic" />.
## <Example><![CDATA[
## gap> c:=SCSurface(1,false);;
## gap> SCHomologyInternal(c);
## [ [ 0, [  ] ], [ 0, [ 2 ] ], [ 0, [  ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallGlobalFunction(SCHomologyInternal,
function(complex)
 local d,hom;
 
 if(not SCIsSimplicialComplex(complex)) then
  Info(InfoSimpcomp,1,"SCHomologyInternal: argument must be a simplicial complex.");
  return fail;
 fi;
 
 d:=SCDim(complex);
 if(d=fail) then
  return fail;
 fi;
 
 if HasSCHomology(complex) then
  return SCHomology(complex);
 fi;

 hom:=SCIntFunc.HomCoHomology(complex,0);
 if(hom=fail) then
  return fail;
 fi;
 
 SetSCHomology(complex,hom);
 return hom;
end);


################################################################################
##<#GAPDoc Label="SCCohomology">
## <ManSection>
## <Meth Name="SCCohomology" Arg="complex"/>
## <Returns> a list of pairs of the form <C>[ integer, list ]</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## This function computes the simplicial cohomology groups of a given simplicial complex <Arg>complex</Arg> with integer coefficients. It uses the algorithm described in <Cite Key="Desbrun08DiscDiffFormCompModel"/>.<P/>
## The output is a list of cohomology groups of the form <M>[H^0,....,H^d]</M>, where <M>d</M> is the dimension of <Arg>complex</Arg>. The format of the cohomology groups <M>H^i</M> is given in terms of their maximal cyclic subgroups, i.e. a cohomology group <M>H^i\cong \mathbb{Z}^f + \mathbb{Z} / t_1 \mathbb{Z} \times \dots \times \mathbb{Z} / t_n \mathbb{Z}</M> is returned in form of a list <M>[ f, [t_1,...,t_n] ]</M>, where <M>f</M> is the (integer) free part of <M>H^i</M> and <M>t_i</M> denotes the torsion parts of <M>H^i</M> ordered in weakly increasing size.
## <Example><![CDATA[
## gap> c:=SCFromFacets([[1,2,3],[1,2,6],[1,3,5],[1,4,5],[1,4,6],
##                       [2,3,4],[2,4,5],[2,5,6],[3,4,6],[3,5,6]]);
## gap> SCCohomology(c);
## [ [ 1, [  ] ], [ 0, [  ] ], [ 0, [ 2 ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCCohomology,
"for SCSimplicialComplex",
[SCIsSimplicialComplex],
function(complex)
 local cohom;


 cohom:=SCIntFunc.HomCoHomology(complex,1);
 if(cohom=fail) then
  return fail;
 fi;

 return cohom;
end);


################################################################################
##<#GAPDoc Label="SCCupProduct">
## <ManSection>
## <Func Name="SCCupProduct" Arg="complex,cocycle1,cocycle2"/>
## <Returns> a list of pairs of the form <C>[ ORIENTATION, SIMPLEX ]</C> upon success, <K>fail</K> otherwise. </Returns>
## <Description>
## The cup product is a method of adjoining two cocycles of degree <M>p</M> and <M>q</M> to form a composite cocycle of degree <M>p + q</M>. It endows the cohomology groups of a simplicial complex with the structure of a ring. <P/>
## The construction of the cup product starts with a product of cochains: if <Arg>cocycle1</Arg> is a p-cochain and <Arg>cocylce2</Arg> is a q-cochain of a simplicial complex <Arg>complex</Arg> (given as list of oriented p- (q-)simplices), then<P/>
## <Arg>cocycle1</Arg> <M>\smile</M> <Arg>cocycle2</Arg><M>(\sigma) = </M><Arg>cocycle1</Arg><M>(\sigma \circ \iota_{0,1, ... p}) \cdot</M> <Arg>cocycle2</Arg><M>(\sigma \circ \iota_{p, p+1 ,..., p + q})</M><P/>
## where <M>\sigma</M> is a <M>p + q</M>-simplex and <M>\iota_S</M>, <M>S \subset \{0,1,...,p+q \}</M> is the canonical embedding of the simplex spanned by <M>S</M> into the <M>(p + q)</M>-standard simplex.<P/>
## <M>\sigma \circ \iota_{0,1, ..., p}</M> is called the <M>p</M>-th front face and <M>\sigma \circ \iota_{p, p+1, ..., p + q}</M> is the <M>q</M>-th back face of <M>\sigma</M>, respectively.<P/>
## Note that this function only computes the cup product in the case that <Arg>complex</Arg> is an orientable weak pseudomanifold of dimension <M>2k</M> and <M>p = q = k</M>. Furthermore, <Arg>complex</Arg> must be given in standard labeling, with sorted facet list and <Arg>cocylce1</Arg> and <Arg>cocylce2</Arg> must be given in simplex notation and labeled accordingly. Note that the latter condition is usually fulfilled in case the cocycles were computed using <Ref Meth="SCCohomologyBasisAsSimplices"/>.  
## <Example><![CDATA[
## gap> SCLib.SearchByName("K3");
## [ [ 520, "K3_16" ], [ 539, "K3_17" ] ]
## gap> c:=SCLib.Load(last[1][1]);;                                     
## gap> basis:=SCCohomologyBasisAsSimplices(c,2);;
## gap> SCCupProduct(c,basis[1][2],basis[1][2]);
## [ [ 1, [ 124711 ] ], [ 1, [ 23459 ] ] ]
## gap> SCCupProduct(c,basis[1][2],basis[2][2]);
## [ [ -1, [ 124711 ] ], [ -1, [ 124715 ] ], 
##   [ -1, [ 23459 ] ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallGlobalFunction(SCCupProduct,
 function(complex,cocycle1,cocycle2)

 local i, k, element, dim, cupProduct, product1, product2, 
  facets, facetsEx, frontface, backface, coeff, o;
 
 
 dim := SCDim(complex)/2;
 o := SCIsOrientable(complex);
 if o = fail then
  Info(InfoSimpcomp,1,"SCCupProduct: first argument must be an orientable simplicial complex.");
  return fail;
 fi;
 
  
 if(not IsInt(dim) or not SCIsSimplicialComplex(complex) or cocycle1 = [] or cocycle2 = [] or Size(cocycle1[1][2]) <> dim+1 or Size(cocycle2[1][2]) <> dim+1 or not o) then
  Info(InfoSimpcomp,1,"SCCupProduct: first argument must be an orientable 2k-dimensional simplicial complex, second and third argument must be non empty k-cochains.");
  return fail;
 fi;
 
 facets:=SCFacets(complex);
 facetsEx:=SCFacetsEx(complex);
 if facets = fail or facetsEx = fail then
  return fail;
 fi;
 
 if facets <> facetsEx or not IsSortedList(facets) or false in List(facets,x->IsSortedList(x)) then
  Info(InfoSimpcomp,1,"SCCupProduct: first argument must be a simplicial complex in standard labeling and with sorted facet list."); 
  return fail;
 fi;
 cupProduct:=[]; 
 
 for k in [1..Size(facets)] do
  element:=ShallowCopy(facets[k]);
  frontface:=element{[1..dim+1]};
  backface:=element{[dim+1..2*dim+1]};
  product1:=[];
  for i in cocycle1 do
   if frontface = i[2] then
    product1:=i;
    break;
   fi;    
  od;
  product2:=[];
  for i in cocycle2 do
   if backface = i[2] then
    product2:=i;
    break;
   fi;    
  od;
  if product1 <> [] and product2 <> [] then
   coeff:=product1[1]*product2[1];
   Add(cupProduct,[coeff,element]);
  fi;
  
 od;
 
 return cupProduct;
 
end);

################################################################################
##<#GAPDoc Label="SCIntersectionForm">
## <ManSection>
## <Meth Name="SCIntersectionForm" Arg="complex"/>
## <Returns> a square matrix of integer values upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## For <M>2k</M>-dimensional orientable manifolds <M>M</M> the cup product (see <Ref Meth="SCCupProduct"/>) defines a bilinear form <P/>
## H<M>^k ( M ) \times </M>H<M>^k ( M ) \to </M>H<M>^{2k} (M), (a,b) \mapsto a \cup b </M><P/>
## called the intersection form of <M>M</M>. This function returns the intersection form of an orientable combinatorial <M>2k</M>-manifold <Arg>complex</Arg> in form of a matrix <C>mat</C> with respect to the basis of  H<M>^k ( </M><Arg>complex</Arg>M<M>)</M> computed by <Ref Meth="SCCohomologyBasisAsSimplices"/>. The matrix entry <C>mat[i][j]</C> equals the intersection number of the <C>i</C>-th base element with the <C>j</C>-th base element of H<M>^k ( </M><Arg>complex</Arg>M<M>)</M>. 
## <Example><![CDATA[
## gap> SCLib.SearchByName("CP^2");       
## [ [ 16, "CP^2 (VT)" ], [ 96, "CP^2#-CP^2" ], 
##   [ 97, "CP^2#CP^2" ], [ 185, "CP^2#(S^2xS^2)" ], 
##   [ 397, "Gaifullin CP^2" ], 
##   [ 457, "(S^3~S^1)#(CP^2)^{#5} (VT)" ] ]
## gap> c:=SCLib.Load(last[1][1]);; 
## gap> c1:=SCConnectedSum(c,c);;
## gap> c2:=SCConnectedSumMinus(c,c);;
## gap> q1:=SCIntersectionForm(c1);;
## gap> q2:=SCIntersectionForm(c2);;
## gap> PrintArray(q1);
## [ [  1,  0 ],
##   [  0,  1 ] ]
## gap> PrintArray(q2);
## [ [   1,   0 ],
##   [   0,  -1 ] ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCIntersectionForm,
"for SCSimplicialComplex",
[SCIsSimplicialComplex],
function(complex)
 local i, j, idx1, idx2, idx, element, dim, cupProduct, product, 
  facets, frontface, backface, coeff, cocycles, orientation, sum, mat, labels,c;
 
  
 dim := SCDim(complex);
 if dim = fail then
  return fail;
 fi;
 if(dim mod 2 <> 0 or SCIsPseudoManifold(complex) <> true) then
  Info(InfoSimpcomp,1,"SCIntersectionForm: argument must be a orientable weak pseudomanifold of even dimension.");
  return fail;
 fi;
 
 facets:=SCIntFunc.DeepCopy(SCFacetsEx(complex));
 SCIntFunc.DeepSortList(facets);
 c:=SCFromFacets(facets);
 dim := dim/2;
 orientation:=SCOrientation(c);
 if orientation = fail then
  return fail;
 fi;
 if(SCIsOrientable(c) <> true) then
  Info(InfoSimpcomp,1,"SCIntersectionForm: argument must be orientable.");
  return fail;
 fi;
 
 cocycles:=SCCohomologyBasisAsSimplices(c,dim);
 if facets = fail or cocycles = fail then
  return fail;
 fi;
 
 if cocycles = [] then
   return [];
 fi;
 
 cupProduct:=[]; 
 mat:=[];
 for idx1 in [1..Size(cocycles)] do
  mat[idx1]:=[];
  for idx2 in [1..Size(cocycles)] do
   product:= SCCupProduct(c,cocycles[idx1][2],cocycles[idx2][2]);
   sum:=0;
   for j in [1..Size(product)] do
    idx:=Position(facets,product[j][2]);
    sum:=sum+orientation[idx]*product[j][1];
   od;
   mat[idx1][idx2]:=sum;
  od;
 od;
 
 return mat;
 
end);


################################################################################
##<#GAPDoc Label="SCIntersectionFormParity">
## <ManSection>
## <Meth Name="SCIntersectionFormParity" Arg="complex"/>
## <Returns> <C>0</C> or <C>1</C> upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Computes the parity of the intersection form of a combinatorial manifold <Arg>complex</Arg> (see <Ref Meth="SCIntersectionForm"/>). If the intersection for is even (i. e. all diagonal entries are even numbers) <C>0</C> is returned, otherwise <C>1</C> is returned.
## <Example><![CDATA[
## gap> SCLib.SearchByName("S^2xS^2");;
## gap> c:=SCLib.Load(last[1][1]);;    
## gap> SCIntersectionFormParity(c);
## 0
## gap> SCLib.SearchByName("CP^2");;     
## gap> c:=SCLib.Load(last[1][1]);; 
## gap> SCIntersectionFormParity(c);
## 1
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCIntersectionFormParity,
"for SCSimplicialComplex",
[SCIsSimplicialComplex],
function(complex)
 local parity, i, matrix, dim;
 
 
 dim:=SCDim(complex);
 if dim = fail then
  return fail;
 fi;
 if(dim mod 2 <> 0 or SCIsPseudoManifold(complex) <> true) then
  Info(InfoSimpcomp,1,"SCIntersectionFormParity: argument must be a pseudomanifold of even dimension.");
  return fail;
 fi;

 matrix:=SCIntersectionForm(complex);
 if matrix = fail then
  return fail;
 fi;
 
 parity := 0;  
 for i in [1..Size(matrix)] do 
  if matrix[i][i] mod 2 <> 0 then 
   parity:=1
   break; 
  fi; 
 od;
 
 return parity;
end);


################################################################################
##<#GAPDoc Label="SCIntersectionFormDimensionality">
## <ManSection>
## <Meth Name="SCIntersectionFormDimensionality" Arg="complex"/>
## <Returns> an integer upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Returns the dimensionality of the intersection form of a combinatorial manifold <Arg>complex</Arg>, i. e. the length of a minimal generating set of H<M>^k (M)</M> (where <M>2k</M> is the dimension of <Arg>complex</Arg>). See <Ref Meth="SCIntersectionForm"/> for further details.
## <Example><![CDATA[
## gap> SCLib.SearchByName("CP^2");;
## gap> c:=SCLib.Load(last[1][1]);; 
## gap> SCIntersectionFormParity(c);
## 1
## gap> SCCohomology(c);
## [ [ 1, [  ] ], [ 0, [  ] ], [ 1, [  ] ], [ 0, [  ] ], [ 1, [  ] ] ]
## gap> SCIntersectionFormDimensionality(c);
## 1
## gap> d:=SCConnectedProduct(c,10);;
## gap> SCIntersectionFormDimensionality(d);
## 10
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCIntersectionFormDimensionality,
"for SCSimplicialComplex",
[SCIsSimplicialComplex],
function(complex)
 local matrix, dim;

 
 dim:=SCDim(complex);
 if dim = fail then
  return fail;
 fi;
 if(dim mod 2 <> 0 or SCIsPseudoManifold(complex) <> true) then
  Info(InfoSimpcomp,1,"SCIntersectionFormDimensionality: argument must be a pseudomanifold of even dimension.");
  return fail;
 fi;

 matrix:=SCIntersectionForm(complex);
 if matrix = fail then
  return fail;
 fi;

 return Size(matrix);
end);


################################################################################
##<#GAPDoc Label="SCIntersectionFormSignature">
## <ManSection>
## <Meth Name="SCIntersectionFormSignature" Arg="complex"/>
## <Returns> a triple of integers upon success, <K>fail</K> otherwise.</Returns>
## <Description>
## Computes the dimensionality (see <Ref Meth="SCIntersectionFormDimensionality"/>) and the signature of the intersection form of a combinatorial manifold <Arg>complex</Arg> as a <M>3</M>-tuple that contains the dimensionality in the first entry and the number of positive / negative eigenvalues in the second and third entry. See <Ref Meth="SCIntersectionForm"/> for further details.<P/>
## Internally calls the &GAP;-functions <C>Matrix_CharacteristicPolynomialSameField</C> and <C>CoefficientsOfLaurentPolynomial</C> to compute the number of positive / negative eigenvalues of the intersection form. 
## <Example><![CDATA[
## gap> SCLib.SearchByName("CP^2");;
## gap> c:=SCLib.Load(last[1][1]);;
## gap> SCIntersectionFormParity(c);
## 1
## gap> SCCohomology(c);
## [ [ 1, [  ] ], [ 0, [  ] ], [ 1, [  ] ], [ 0, [  ] ], [ 1, [  ] ] ]
## gap> SCIntersectionFormSignature(c);
## [ 101 ]
## gap> d:=SCConnectedSum(c,c);                           
## gap> SCIntersectionFormSignature(d);
## [ 211 ]
## gap> d:=SCConnectedSumMinus(c,c);;
## gap> SCIntersectionFormSignature(d);
## [ 202 ]
## ]]></Example>
## </Description>
## </ManSection>
##<#/GAPDoc>
################################################################################
InstallMethod(SCIntersectionFormSignature,
"for SCSimplicialComplex",
[SCIsSimplicialComplex],
function(complex)
 local sign,matrix,charpol,coeff,dim,prod,old,idx;
 
 
 dim:=SCDim(complex);
 if dim = fail then
  return fail;
 fi;
 if(dim mod 2 <> 0 or SCIsPseudoManifold(complex) <> true) then
  Info(InfoSimpcomp,1,"SCIntersectionFormSignature: argument must be a pseudomanifold of even dimension.");
  return fail;
 fi;

 matrix:=SCIntersectionForm(complex);
 if matrix = fail then
  return fail;
 fi;
 
 dim:=Size(matrix);
 charpol:= Matrix_CharacteristicPolynomialSameField(Integers,matrix,1);
 coeff:=Reversed(CoefficientsOfLaurentPolynomial(charpol))[2];
 sign:=0;
 old:=0;
 
 for idx in [1..Size(coeff)] do 
  if coeff[idx] = 0 then continue; fi;
  
  if old = 0 then
   old := coeff[idx];
   continue;
  fi;
  
  prod:=old*coeff[idx];
  if prod = 0 then
   Info(InfoSimpcomp,1,"SCIntersectionFormSignature: Error, can not compute signature of intersection form.");
   return fail;
  fi;
  
  if not IsPosInt(Int(prod)) then
   sign := sign + 1;
  fi;
  
  old:=coeff[idx];
  
 od;

 return [dim,sign,dim-sign];
end);

[Dauer der Verarbeitung: 0.9 Sekunden, vorverarbeitet 2026-06-17]