1#######################################################################
2##
3#O  PushOut(<f>, <g>)
4##
5##  This function finds the pushout of the homomorphisms
6##                    f
7##              A ---------> B
8##              |            |
9##              | g          | g'
10##              |            |
11##              V    f'      V
12##              C ---------> E
13##  in that it returns the homomorphisms  [f', g'].
14##
15InstallMethod( PushOut,
16   "for two homomorphisms starting in a common module over a path algebra",
17   [ IsPathAlgebraMatModuleHomomorphism, IsPathAlgebraMatModuleHomomorphism ], 0,
18   function( f, g )
19
20   local B, C, CplusB, inclusions, projections, h;
21
22   if Source(f) = Source(g) then
23      B := Range(f);
24      C := Range(g);
25      CplusB := DirectSumOfQPAModules([C,B]);
26      inclusions := DirectSumInclusions(CplusB);
27      h := f*inclusions[2]-g*inclusions[1];
28      h := CoKernelProjection(h);
29
30      return [inclusions[1]*h,inclusions[2]*h];
31   else
32      Print("Error: The two maps entered don't start in the same module.\n");
33      return fail;
34   fi;
35end
36);
37
38#######################################################################
39##
40#O  PullBack(<f>, <g>)
41##
42##  This function finds the pullback of the homomorphisms
43##                    f'
44##              E ---------> C
45##              |            |
46##              | g'         | g
47##              |            |
48##              V     f      V
49##              A ---------> B
50##  in that it returns the homomorphisms  [f', g'].
51##
52InstallMethod( PullBack,
53   "for two homomorphisms ending in a common module over a path algebra",
54   [ IsPathAlgebraMatModuleHomomorphism, IsPathAlgebraMatModuleHomomorphism ], 0,
55   function( f, g )
56
57   local A, C, AplusC, projections, h;
58
59   if Range(f) = Range(g) then
60      A := Source(f);
61      C := Source(g);
62      AplusC := DirectSumOfQPAModules([A,C]);
63      projections := DirectSumProjections(AplusC);
64      h := projections[1]*f-projections[2]*g;
65      h := KernelInclusion(h);
66
67      return [h*projections[2],h*projections[1]];
68   else
69      Print("Error: The two maps entered don't end in the same module.\n");
70      return fail;
71   fi;
72end
73);
74
75#######################################################################
76##
77#O  IsOmegaPeriodic( <M>, <n> )
78##
79##  This function tests if the module  <M>  is \Omega-periodic, that is,
80##  if  M \simeq \Omega^i(M)  when  i  ranges over the set {1,2,...,n}.
81##  Otherwise it returns false.
82##
83InstallMethod( IsOmegaPeriodic,
84   "for a path algebra matmodule and an integer",
85   [ IsPathAlgebraMatModule, IS_INT  ], 0,
86   function( M, n )
87
88   local N0, N1, i;
89
90   N0 := M;
91   for i in [1..n] do
92      Print("Computing syzygy number: ",i,"\n");
93      N1 := 1stSyzygy(N0);
94      if IsomorphicModules(M,N1) then
95         return i;
96      else
97         N0 := N1;
98      fi;
99   od;
100   return false;
101end
102);
103
104#######################################################################
105##
106#O  IsTauPeriodic( <M>, <n> )
107##
108##  This function tests if the module  <M>  is \tau-periodic, that is,
109##  if  M \simeq \tau^i(M)  when  i  ranges over the set {1,2,...,n}.
110##  Otherwise it returns false.
111##
112InstallMethod( IsTauPeriodic,
113   "for a path algebra matmodule and an integer",
114   [ IsPathAlgebraMatModule, IS_INT  ], 0,
115   function( M, n )
116
117   local N0, N1, i;
118
119   N0 := M;
120   for i in [1..n] do
121      N1 := DTr(N0);
122      if IsomorphicModules(M,N1) then
123         return i;
124      else
125         N0 := N1;
126      fi;
127   od;
128   return false;
129end
130);
131
132#######################################################################
133##
134#O  1stSyzygy( <M> )
135##
136##  This function computes the first syzygy of the module  <M>  by first
137##  finding a minimal set of generators for  <M>, then finding the
138##  projective cover and computing the first syzygy as a submodule of
139##  this module.
140##
141InstallMethod( 1stSyzygy,
142   "for a path algebra",
143   [ IsPathAlgebraMatModule ], 0,
144   function( M )
145
146   local A, Q, K, num_vert, vertices, verticesinalg, arrows, B, BB, B_M,
147         G, MM, r, test, projective_cover, s, projective_vector, Solutions,
148         syzygy, zero_in_P, big_mat, mat, a, arrow, arrows_of_quiver, dom_a,
149	 im_a, pd, pi, dim_vect, first_syzygy, V, BV, m, v,
150         cycle_list, i, j, b,
151         pos, commutators, center, zero_count, c, x, cycles, matrix,
152         data, coeffs, fam, elms, solutions, gbb, run_time, BU, FlatBasisSyzygy,
153         partial,temp,V_list,B_list;
154
155   A:= RightActingAlgebra(M);
156   if Dimension(M) = 0 then
157       return ZeroModule(A);
158   fi;
159   B := CanonicalBasis(A);
160   Q := QuiverOfPathAlgebra(A);
161   K := LeftActingDomain(A);
162   num_vert := NumberOfVertices(Q);
163   vertices := VerticesOfQuiver(Q);
164   if IsPathAlgebra(A) then
165      verticesinalg := GeneratorsOfAlgebra(A){[1..num_vert]};
166      arrows   := GeneratorsOfAlgebra(A){[1+num_vert..num_vert+NumberOfArrows(Q)]};
167   else
168      verticesinalg := GeneratorsOfAlgebra(A){[2..1+num_vert]};
169      arrows   := GeneratorsOfAlgebra(A){[2+num_vert..1+num_vert+NumberOfArrows(Q)]};
170   fi;
171#
172#  Finding a basis of each indecomposable right projective A-module
173#
174   BB := [];
175   for i in [1..num_vert] do
176      BB[i] := [];
177   od;
178   for i in [1..num_vert] do
179      for j in [1..Length(B)] do
180         if verticesinalg[i]*B[j] <> Zero(A) then
181            Add(BB[i],B[j]);
182         fi;
183      od;
184   od;
185#
186# Finding a basis for the module M and a set of minimal generators
187#
188   B_M := CanonicalBasis(M);
189   G   := MinimalGeneratingSetOfModule(M);
190#
191#  Assuming that the generators G of M is uniform.
192#  Finding generators multiplied with all basis elements of A.
193#
194   MM := [];
195   projective_cover := [];
196   for i in [1..Length(G)] do
197      r := 0;
198      repeat
199         r := r + 1;
200         test := G[i]^verticesinalg[r] <> Zero(M);
201      until test;
202      projective_cover[i] := r;
203       for j in [1..Length(BB[r])] do
204         Add(MM,G[i]^BB[r][j]);
205      od;
206   od;
207#
208# Finding the matrix with the rows being the generators of M times the
209# the basis of the corresponding projective.
210#
211   matrix := NullMat(Length(MM),Dimension(M),K);
212   for i in [1..Length(MM)] do
213      matrix[i] := Flat(ExtRepOfObj(MM[i])![1]);
214   od;
215#
216#  Finding the kernel of the projective cover as a vectorspace
217#
218   solutions := NullspaceMat(matrix);
219#
220# Finding the kernel as a submodule of the projective cover.
221#
222   Solutions := [];
223   for i in [1..Length(solutions)] do
224      projective_vector := [];
225      s := 0;
226      for j in [1..Length(projective_cover)] do
227         a := Zero(A);
228         for r in [1..Length(BB[projective_cover[j]])] do
229            a := a + BB[projective_cover[j]][r]*solutions[i][r+s];
230         od;
231         Add(projective_vector,a);
232         s := s + Length(BB[projective_cover[j]]);
233      od;
234      Add(Solutions,projective_vector);
235   od;
236#
237# Finding a uniform basis for the syzygy.
238#
239   syzygy := [];
240   for i in [1..num_vert] do
241      syzygy[i] := [];
242   od;
243   zero_in_P := [];
244   for i in [1..Length(G)] do
245      Add(zero_in_P,Zero(A));
246   od;
247   for i in [1..num_vert] do
248      for j in [1..Length(Solutions)] do
249         if Solutions[j]*verticesinalg[i] <> zero_in_P then
250            Add(syzygy[i],Solutions[j]*verticesinalg[i]);
251         fi;
252      od;
253   od;
254
255   for i in [1..num_vert] do
256      if Length(syzygy[i]) > 0 then
257         syzygy[i] := TipReduceVectors(A,syzygy[i]);
258      fi;
259   od;
260
261   arrows_of_quiver := GeneratorsOfQuiver(Q){[1+num_vert..num_vert+Length(ArrowsOfQuiver(Q))]};
262#
263# Finding the dimension vector of the syzygy.
264#
265   dim_vect := List(syzygy,x->Length(x));
266#
267# Finding a basis for the vectorspace in each vertex for the syzygy.
268#
269   BU := Basis(UnderlyingLeftModule(B));
270   FlatBasisSyzygy := [];
271   for i in [1..num_vert] do
272      if dim_vect[i] > 0 then
273         partial := [];
274         for j in [1..dim_vect[i]] do
275            Add(partial,Flat(List(syzygy[i][j],x->Coefficients(BU,x))));
276         od;
277         Add(FlatBasisSyzygy,partial);
278      else
279         Add(FlatBasisSyzygy,[]);
280      fi;
281   od;
282#
283# Constructing the vectorspace in each vertex in the syzygy and
284# saying that the basis is the generators we have found.
285#
286  V_list := [];
287  for i in [1..num_vert] do
288     if FlatBasisSyzygy[i] <> [] then
289        Add(V_list,VectorSpace(K,FlatBasisSyzygy[i],"basis"));
290     else
291        Add(V_list,Subspace(K,[]));
292     fi;
293   od;
294   B_list := [];
295   for i in [1..num_vert] do
296      Add(B_list,Basis(V_list[i],FlatBasisSyzygy[i]));
297   od;
298#
299#  Finding the 1st syzygy as a representation of the quiver.
300#
301   big_mat:=[];
302   for a in arrows do
303      mat := [];
304      for v in verticesinalg do
305         if v*a <> Zero(A) then
306              dom_a := v;
307         fi;
308      od;
309      for v in verticesinalg do
310         if a*v <> Zero(A) then
311            im_a := v;
312         fi;
313      od;
314
315      pd := Position(verticesinalg,dom_a);
316      pi := Position(verticesinalg,im_a);
317
318      arrow := arrows_of_quiver[Position(arrows,a)];
319      if ( dim_vect[pd] = 0 ) or ( dim_vect[pi] = 0 ) then
320         mat := [dim_vect[pd],dim_vect[pi]];
321      else
322         for m in syzygy[pd] do
323            temp := Flat(List(m*a,x->Coefficients(BU,x)));
324            temp := Coefficients(B_list[pi],temp);
325            Add(mat,temp);
326         od;
327      fi;
328      Add(big_mat,[arrow,mat]);
329   od;
330#
331# Creating the syzygy as a representation of the quiver.
332#
333   if IsPathAlgebra(A) then
334      first_syzygy := RightModuleOverPathAlgebra(A,big_mat);
335   else
336      first_syzygy := RightModuleOverPathAlgebra(A,big_mat);
337   fi;
338
339   return first_syzygy;
340end
341);
342
343#######################################################################
344##
345#O  NthSyzygy( <M>, <n> )
346##
347##  This function computes the <n>-th syzygy of the module <M>.
348##
349InstallMethod( NthSyzygy,
350   "for a path algebra module and a positive integer",
351   [ IsPathAlgebraMatModule, IsPosInt ], 0,
352   function( M, n )
353
354  local projres, diff;
355
356  projres := ProjectiveResolution( M );
357  diff := DifferentialOfComplex( projres, n - 1 );
358
359  return Kernel( diff );
360end
361  );
362
363#######################################################################
364##
365#O  RightApproximationByAddM( <M>, <C> )
366##
367##  This function computes a right add<M>-approximation of the module
368##  <C>, and the approximation is not necessarily minimal.
369##
370InstallMethod ( RightApproximationByAddM,
371   "for two PathAlgebraMatModules",
372   true,
373   [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
374   0,
375   function( M, C )
376
377   local K, HomMC, EndM, radEndM, radHomMC, i, j, FlatHomMC,
378         FlatradHomMC, V, BB, W, f, VoverW, B, gens, approx, approxmap;
379
380   if RightActingAlgebra(M) <> RightActingAlgebra(C) then
381       Error(" the two modules entered into MinimalRightApproximation are not modules over the same algebra.");
382       return fail;
383   fi;
384   if Dimension(C) = 0 then
385       return ZeroMapping(ZeroModule(RightActingAlgebra(M)),C);
386   fi;
387   K := LeftActingDomain(M);
388   HomMC := HomOverAlgebra(M,C);
389   if Length(HomMC) = 0 then
390       return ZeroMapping(ZeroModule(RightActingAlgebra(M)),C);
391   else
392       EndM  := EndOverAlgebra(M);
393       radEndM := RadicalOfAlgebra(EndM);
394       radEndM := BasisVectors(Basis(radEndM));
395       radEndM := List(radEndM, x -> FromEndMToHomMM(M,x));
396       radHomMC := [];
397       for i in [1..Length(HomMC)] do
398           for j in [1..Length(radEndM)] do
399               Add(radHomMC,radEndM[j]*HomMC[i]);
400           od;
401       od;
402       FlatHomMC := List(HomMC, x -> Flat(x!.maps));
403       FlatradHomMC := List(radHomMC, x -> Flat(x!.maps));
404       V := VectorSpace(K,FlatHomMC,"basis");
405       BB := Basis(V,FlatHomMC);
406       W := Subspace(V,FlatradHomMC);
407       f := NaturalHomomorphismBySubspace( V, W );
408       VoverW := Range(f);
409       B := BasisVectors(Basis(VoverW));
410       gens := List(B, x -> PreImagesRepresentative(f,x));
411       gens := List(gens, x -> Coefficients(BB,x));
412       gens := List(gens, x -> LinearCombination(HomMC,x));
413       approx := List(gens, x -> Source(x));
414       approx := DirectSumOfQPAModules(approx);
415       approxmap := ShallowCopy(DirectSumProjections(approx));
416       approxmap := List([1..Length(approxmap)], x -> approxmap[x]*gens[x]);
417
418       approxmap := Sum(approxmap);
419       return approxmap;
420   fi;
421end
422);
423
424#######################################################################
425##
426#O  MinimalRightApproximation( <M>, <C> )
427##
428##  This function computes the minimal right add<M>-approximation of the
429##  module  <C>.  TODO/CHECK: If one can modify the algorithm as indicated
430##  below with ####.
431##
432InstallMethod ( MinimalRightApproximation,
433   "for two PathAlgebraMatModules",
434   true,
435   [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
436   0,
437   function( M, C )
438
439    local   f;
440
441   f := RightApproximationByAddM( M, C );
442
443   return RightMinimalVersion( f )[ 1 ];
444end
445);
446
447#######################################################################
448##
449#O   LeftApproximationByAddM( <C>, <M> )
450##
451##  This function computes a left add<M>-approximation of the module
452##  <C>.
453##
454InstallMethod ( LeftApproximationByAddM,
455   "for two PathAlgebraMatModules",
456   true,
457   [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
458   0,
459   function( C, M )
460
461    local   K,  HomCM,  EndM,  radEndM,  radHomCM,  i,  j,  FlatHomCM,
462            FlatradHomCM,  V,  BB,  W,  f,  VoverW,  B,  gens,
463            approx,  approxmap;
464
465   if RightActingAlgebra(M) <> RightActingAlgebra(C) then
466       Error(" the two modules entered into LeftApproximationByAddM are not modules over the same algebra.");
467       return fail;
468   fi;
469   if Dimension(C) = 0 then
470       return ZeroMapping(C, ZeroModule(RightActingAlgebra(M)));
471   fi;
472   K := LeftActingDomain(M);
473   HomCM := HomOverAlgebra(C,M);
474   if Length(HomCM) = 0 then
475       return ZeroMapping(C,ZeroModule(RightActingAlgebra(M)));
476   else
477       EndM  := EndOverAlgebra(M);
478       radEndM := RadicalOfAlgebra(EndM);
479       radEndM := BasisVectors(Basis(radEndM));
480       radEndM := List(radEndM, x -> FromEndMToHomMM(M,x));
481       radHomCM := [];
482       for i in [1..Length(HomCM)] do
483           for j in [1..Length(radEndM)] do
484               Add(radHomCM,HomCM[i]*radEndM[j]);
485           od;
486       od;
487       FlatHomCM := List(HomCM, x -> Flat(x!.maps));
488       FlatradHomCM := List(radHomCM, x -> Flat(x!.maps));
489       V := VectorSpace(K,FlatHomCM,"basis");
490       BB := Basis(V,FlatHomCM);
491       W := Subspace(V,FlatradHomCM);
492       f := NaturalHomomorphismBySubspace( V, W );
493       VoverW := Range(f);
494       B := BasisVectors(Basis(VoverW));
495       gens := List(B, x -> PreImagesRepresentative(f,x));
496       gens := List(gens, x -> Coefficients(BB,x));
497       gens := List(gens, x -> LinearCombination(HomCM,x));
498       approx := List(gens, x -> Range(x));
499       approx := DirectSumOfQPAModules(approx);
500       approxmap := ShallowCopy(DirectSumInclusions(approx));
501       for i in [1..Length(approxmap)] do
502           approxmap[i] := gens[i]*approxmap[i];
503       od;
504       approxmap := Sum(approxmap);
505
506       return approxmap;
507   fi;
508end
509  );
510
511
512
513#######################################################################
514##
515#O   MinimalLeftApproximation( <C>, <M> )
516##
517##  This function computes the minimal left add<M>-approximation of the
518##  module  <C>.
519##
520InstallMethod ( MinimalLeftApproximation,
521   "for two PathAlgebraMatModules",
522   true,
523   [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
524   0,
525   function( C, M )
526
527    local   f;
528
529   f := LeftApproximationByAddM( C, M );
530
531   return LeftMinimalVersion( f )[ 1 ];
532end
533  );
534
535
536#######################################################################
537##
538#O  ProjectiveCover(<M>)
539##
540##  This function finds the projective cover P(M) of the module  <M>
541##  in that it returns the map from P(M) ---> M.
542##
543InstallMethod ( ProjectiveCover,
544   "for a PathAlgebraMatModule",
545   true,
546   [ IsPathAlgebraMatModule ],
547   0,
548   function( M )
549
550   local mingen, maps, PN, projections;
551
552   if Dimension(M) = 0 then
553      return ZeroMapping(ZeroModule(RightActingAlgebra(M)), M);
554   else
555      mingen := MinimalGeneratingSetOfModule(M);
556      maps := List(mingen, x -> HomFromProjective(x,M));
557      PN := List(maps, x -> Source(x));
558      PN := DirectSumOfQPAModules(PN);
559      projections := DirectSumProjections(PN);
560
561      return projections*maps;;
562   fi;
563end
564);
565
566#######################################################################
567##
568#A  InjectiveEnvelope(< M >)
569##
570##  This function finds the injective envelope I(M) of the module  <M>
571##  in that it returns the map from M ---> I(M).
572##
573InstallMethod ( InjectiveEnvelope,
574    "for a PathAlgebraMatModule",
575    true,
576    [ IsPathAlgebraMatModule ],
577    0,
578    function( M );
579
580    return DualOfModuleHomomorphism( ProjectiveCover( DualOfModule( M ) ) );
581end
582);
583
584#######################################################################
585##
586#O  ExtOverAlgebra(<M>,<N>)
587##
588##  This function returns a list of three elements: (1) the kernel of
589##  the projective cover  Omega(<M>) --> P(M), (2) a basis of
590##  Ext^1(<M>,<N>)  inside  Hom(Omega(<M>),<N>)  and (3) a function
591##  that takes as an argument a homomorphism in  Hom(Omega(<M>),<N>)
592##  and returns the coefficients of this element when written in
593##  terms of the basis of  Ext^1(<M>,<N>), if the group is non-zero.
594##  Otherwise it returns an empty list.
595##
596InstallMethod( ExtOverAlgebra,
597   "for two PathAlgebraMatModule's",
598   true,
599   [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
600   function( M, N )
601
602   local index, fromflatHomToHom, K, f, g, PM, syzygy, G, H, Img1, zero,
603         genssyzygyN, VsyzygyN, Img, gensImg, VImg, pi, ext, preimages,
604         homvecs, dimsyz, dimN, vec, t, l, i, H2, coefficients;
605#
606# Defining functions for later use.
607#
608    index := function( n )
609   	if n = 0 then
610            return 1;
611        else
612            return n;
613        fi;
614    end;
615
616    fromflatHomToHom := function( flat, dim, dim2 )
617        local totalmat, matrix, i, start, j, d, d2;
618
619        d := List(dim, index);
620        d2 := List(dim2, index);
621    	start := 0;
622    	totalmat := [];
623    	for i in [1..Length(dim)] do
624            matrix := [];
625            for j in [1..d[i]] do
626            	Add(matrix, flat{[start+1..start+d2[i]]});
627            	start := start+d2[i];
628            od;
629            Add(totalmat,matrix);
630    	od;
631        return totalmat;
632    end;
633#
634# Test of input.
635#
636   if RightActingAlgebra(M) <> RightActingAlgebra(N) then
637      Error(" the two modules entered are not modules over the same algebra.\n");
638   else
639      K := LeftActingDomain(M);
640#
641# creating a short exact sequence 0 -> Syz(M) -> P(M) -> M -> 0
642# f: P(M) -> M, g: Syz(M) -> P(M)
643#
644      f := ProjectiveCover(M);
645      g := KernelInclusion(f);
646      PM := Source(f);
647      syzygy := Source(g);
648#
649# using Hom(-,N) on the s.e.s. above
650#
651      G := HomOverAlgebra(PM,N);
652      H := HomOverAlgebra(syzygy,N);
653#
654# Making a vector space of Hom(Syz(M),N)
655# by first rewriting the maps as vectors
656#
657      genssyzygyN := List(H, x -> Flat(x!.maps));
658      if Length(genssyzygyN) = 0 then
659         return [[],[],[]];
660      else
661         VsyzygyN := VectorSpace(K, genssyzygyN);
662#
663# finding a basis for im(g*)
664# first, find a generating set of im(g*)
665#
666         Img1 := g*G;
667#
668# removing 0 maps by comparing to zero = Zeromap(syzygy,N)
669#
670         zero := ZeroMapping(syzygy,N);
671         Img  := Filtered(Img1, x -> x <> zero);
672#
673# Rewriting the maps as vectors
674#
675         gensImg := List(Img, x -> Flat(x!.maps));
676#
677# Making a vector space of <Im g*>
678         VImg := Subspace(VsyzygyN, gensImg);
679#
680# Making the vector space Ext1(M,N)
681#
682         pi := NaturalHomomorphismBySubspace(VsyzygyN, VImg);
683         ext := Range(pi);
684         if Dimension(Range(pi)) = 0 then
685            return [g,[],[]];
686         else
687#
688# Sending elements of ext back to Hom(Syz(M),N)
689#
690            preimages := List(BasisVectors(Basis(ext)), x -> PreImagesRepresentative(pi,x));
691#
692# need to put the parentheses back in place
693#
694            homvecs := []; # to store all lists of matrices, one list for each element (homomorphism)
695            dimsyz := DimensionVector(syzygy);
696            dimN := DimensionVector(N);
697            homvecs := List(preimages, x -> fromflatHomToHom(x,dimsyz,dimN));
698#
699# Making homomorphisms of the elements
700#
701            H2 := List(homvecs, x -> RightModuleHomOverAlgebra(syzygy,N,x));
702
703            coefficients := function( map )
704               local vector, B;
705
706               vector := ImageElm(pi,Flat(map!.maps));
707               B := Basis(Range(pi));
708
709               return Coefficients(B,vector);
710            end;
711
712            return [g,H2,coefficients];
713         fi;
714      fi;
715   fi;
716end
717);
718
719#######################################################################
720##
721#O  ExtAlgebraGenerators(<M>,<n>)
722##
723##  This function computes a set of generators of the Ext-algebra Ext^*(M,M)
724##  up to degree  <n>. It returns a list of three elements, where the
725##  first element is the dimensions of Ext^[0..n](M,M), the second element
726##  is the number of a set generators in the degrees [0..n], and the
727##  third element is the generators in these degrees. TODO: Create a
728##  minimal set of generators. Needs to take the radical of the degree
729##  zero part into account.
730##
731InstallMethod( ExtAlgebraGenerators,
732    "for a module over a quotient of a path algebra",
733    [ IsPathAlgebraMatModule, IS_INT ], 0,
734    function( M, n )
735
736    local N, projcovers, f, i, EndM, J, gens, extgroups, dim_ext_groups,
737          generators, productelements, j, induced, k, liftings, products,
738          l, m, productsinbasis, W, V, K, extalggenerators, p, tempgens,
739          I, g, templist, idealsquare;
740
741    K := LeftActingDomain(M);
742    N := M;
743    projcovers := [];
744    for i in [1..n] do
745        f := ProjectiveCover(N);
746        Add(projcovers,f);
747        N := Kernel(f);
748    od;
749    extgroups := [];
750    #
751    #   Computing Ext^i(M,M) for i = 0, 1, 2,...., n.
752    #
753    for i in [0..n] do
754        if i = 0 then
755            EndM := EndOverAlgebra(M);
756            J := RadicalOfAlgebra(EndM);
757            gens := GeneratorsOfAlgebra(J);
758            Add(extgroups, [[],List(gens, x -> FromEndMToHomMM(M,x))]);
759        elif i = 1 then
760            Add(extgroups, ExtOverAlgebra(M,M));
761        else
762            Add(extgroups, ExtOverAlgebra(Kernel(projcovers[i-1]),M));
763        fi;
764    od;
765    dim_ext_groups := List(extgroups, x -> Length(x[2]));
766#    Print(Dimension(EndM) - Dimension(J)," generators in degree 0.\n");
767    #
768    #   Computing Ext^j(M,M) x Ext^(i-j)(M,M) for j = 1..i-1 and i = 2..n.
769    #
770    generators := List([1..n + 1], x -> 0);
771    extalggenerators := List([1..n + 1], x -> []);
772    for i in [1..n] do
773        productelements := [];
774        for j in [0..i] do
775            if ( dim_ext_groups[i+1] <> 0 ) and ( dim_ext_groups[j+1] <> 0 ) and ( dim_ext_groups[i-j+1] <> 0 ) then
776                induced := ShallowCopy(extgroups[i-j+1][2]);
777                for k in [1..j] do
778                    liftings := List([1..dim_ext_groups[i-j+1]], x -> projcovers[i-j+k]*induced[x]);
779                    liftings := List([1..dim_ext_groups[i-j+1]], x -> LiftingMorphismFromProjective(projcovers[k],liftings[x]));
780                    induced  := List([1..dim_ext_groups[i-j+1]], x -> MorphismOnKernel(projcovers[i-j+k],projcovers[k],liftings[x],induced[x]));
781                od;
782                products := [];
783                for l in [1..dim_ext_groups[j+1]] do
784                    for m in [1..dim_ext_groups[i-j+1]] do
785                        Add(products,induced[m]*extgroups[j+1][2][l]);
786                    od;
787                od;
788                productsinbasis := List(products, x -> extgroups[i+1][3](x));
789                productsinbasis := Filtered(productsinbasis, x -> x <> Zero(x));
790                if Length(productsinbasis) <> 0 then
791                    Append(productelements,productsinbasis);
792                fi;
793            fi;
794        od;
795        if Length(productelements) <> 0 then
796            W := FullRowSpace(K,Length(extgroups[i+1][2]));
797            V := Subspace(W,productelements);
798            if dim_ext_groups[i+1] > Dimension(V) then
799                generators[i+1] := Length(extgroups[i+1][2]) - Dimension(V);
800                p := NaturalHomomorphismBySubspace(W,V);
801                tempgens := List(BasisVectors(Basis(Range(p))), x -> PreImagesRepresentative(p,x));
802                extalggenerators[i+1] := List(tempgens, x -> LinearCombination(extgroups[i+1][2],x));
803#                Print(Length(extgroups[i+1][2]) - Dimension(V)," new generator(s) in degree ",i,".\n");
804            fi;
805        elif dim_ext_groups[i+1] <> 0 then
806            generators[i+1] := Length(extgroups[i+1][2]);
807            extalggenerators[i+1] := extgroups[i+1][2];
808#            Print(Length(extgroups[i+1][2])," new generator(s) in degree ",i,".\n");
809        fi;
810    od;
811    dim_ext_groups[1] := Dimension(EndM);
812    templist := [];
813    for i in [1..Length(gens)] do
814        for j in [1..Dimension(EndM)] do
815            Add(templist,BasisVectors(Basis(EndM))[j]*gens[i]);
816        od;
817    od;
818    templist := Filtered(templist, x -> x <> Zero(x));
819    idealsquare := [];
820    for i in [1..Length(templist)] do
821        for j in [1..Length(gens)] do
822            Add(idealsquare,gens[j]*templist[i]);
823        od;
824    od;
825    I := Ideal(EndM,idealsquare);
826    g := NaturalHomomorphismByIdeal(EndM,I);
827    extalggenerators[1] := List(BasisVectors(Basis(Range(g))), x -> FromEndMToHomMM(M,PreImagesRepresentative(g,x)));
828    generators[1] := Length(extalggenerators[1]);
829    return [dim_ext_groups,generators,extalggenerators];
830end
831);
832
833#######################################################################
834##
835#O  PartialIyamaGenerator( <M> )
836##
837##  Given a module  <M>  this function returns the submodule of  <M>
838##  given by the radical of the endomorphism ring of  <M>  times <M>.
839##  If  <M>  is zero, then  <M>  is returned.
840##
841InstallMethod( PartialIyamaGenerator,
842    "for a path algebra",
843    [ IsPathAlgebraMatModule ], 0,
844    function( M )
845
846    local B, EndM, radEndM, Brad, subgens, b, r;
847
848    if Dimension(M) = 0 then
849        return M;
850    fi;
851    B := CanonicalBasis(M);
852    EndM := EndOverAlgebra(M);
853    radEndM := RadicalOfAlgebra(EndM);
854    Brad := BasisVectors(Basis(radEndM));
855    Brad := List(Brad, x -> FromEndMToHomMM(M,x));
856    subgens := [];
857    for b in B do
858        for r in Brad do
859            Add(subgens, ImageElm(r,b));
860        od;
861    od;
862
863    return SubRepresentation(M,subgens);
864end
865);
866
867#######################################################################
868##
869#O  IyamaGenerator( <M> )
870##
871##  Given a module  <M> this function returns a module  N  such that
872##  <M>  is a direct summand of  N  and such that the global dimension
873##  of the endomorphism ring of  N  is finite.
874##
875InstallMethod( IyamaGenerator,
876    "for a path algebra",
877    [ IsPathAlgebraMatModule ], 0,
878    function( M )
879
880    local iyamagen, N, IG, L;
881
882    iyamagen := [];
883    N := M;
884    repeat
885        Add(iyamagen,N);
886        N := PartialIyamaGenerator(N);
887    until
888        Dimension(N) = 0;
889
890    IG := DirectSumOfQPAModules(iyamagen);
891    if IsFinite(LeftActingDomain(M)) then
892        L := DecomposeModuleWithMultiplicities(IG);
893        IG := DirectSumOfQPAModules(L[1]);
894    fi;
895
896    return IG;
897end
898);
899
900#######################################################################
901##
902#O  GlobalDimensionOfAlgebra( <A>, <n> )
903##
904##  Returns the global dimension of the algebra  <A>  if it is less or
905##  equal to  <n>, otherwise it returns false.
906##
907InstallMethod ( GlobalDimensionOfAlgebra,
908    "for a finite dimensional quotient of a path algebra",
909    true,
910    [ IsQuiverAlgebra, IS_INT ],
911    0,
912    function( A, n )
913
914    local simples, S, projres, dimension, j;
915
916    if not IsFiniteDimensional(A) then
917        TryNextMethod();
918    fi;
919    if HasGlobalDimension(A) then
920        return GlobalDimension(A);
921    fi;
922    if Trace(AdjacencyMatrixOfQuiver(QuiverOfPathAlgebra(A))) > 0 then
923        SetGlobalDimension(A,infinity);
924        return infinity;
925    fi;
926    simples := SimpleModules(A);
927    dimension := 0;
928    for S in simples do
929        projres := ProjectiveResolution(S);
930        j := 0;
931        while ( j < n + 1 ) and ( Dimension(ObjectOfComplex(projres,j)) <> 0 ) do
932            j := j + 1;
933        od;
934        if ( j < n + 1 ) then
935            dimension := Maximum(dimension, j - 1 );
936        else
937            if ( Dimension(ObjectOfComplex(projres,n + 1)) <> 0 ) then
938                return false;
939            else
940                dimension := Maximum(dimension, n );
941            fi;
942        fi;
943    od;
944
945    SetGlobalDimension(A,dimension);
946    return dimension;
947end
948);
949
950#######################################################################
951##
952#O  DominantDimensionOfModule( <M>, <n> )
953##
954##  Returns the dominant dimension of the module  <M>  if it is less or
955##  equal to  <n>. If the module  <M>  is injectiv and projective, then
956##  it returns infinity. Otherwise it returns false.
957##
958InstallMethod ( DominantDimensionOfModule,
959    "for a finite dimensional quotient of a path algebra",
960    true,
961    [ IsPathAlgebraMatModule, IS_INT ],
962    0,
963    function( M, n )
964
965    local A, Mop, resop, dimension, j;
966
967    A := RightActingAlgebra(M);
968    #
969    # If the algebra  A  is not a finite dimensional, try another method.
970    #
971    if not IsFiniteDimensional(A) then
972        TryNextMethod();
973    fi;
974    #
975    # If the module  <M>  is injective and projective, then the dominant dimension of
976    # <M>  is infinite.
977    if IsInjectiveModule(M) and IsProjectiveModule(M) then
978        return infinity;
979    fi;
980    Mop := DualOfModule(M);
981    #
982    # Compute the minimal projective resolution of the module  Mop.
983    #
984    resop := ProjectiveResolution(Mop);
985    dimension := 0;
986    # Check how far out the modules in the minimal projective resolution of Mop
987    # is injective.
988    if IsInjectiveModule(ObjectOfComplex(resop,0)) then
989        if Dimension(ObjectOfComplex(resop,1)) = 0 then
990            return infinity;
991        else
992            j := 1;
993            while ( j < n + 1 ) and ( IsInjectiveModule(ObjectOfComplex(resop,j)) ) do
994                    j := j + 1;
995            od;
996            if ( j < n + 1 ) then # if this happens, then j-th projective is not injective and domdim equal to j for <M>.
997                dimension := Maximum(dimension, j);
998            else                    # if this happens, then j = n + 1.
999                if not IsInjectiveModule(ObjectOfComplex(resop,n + 1)) then # then domdim is  n  of  <M>.
1000                    dimension := Maximum(dimension, n);
1001                else                                                      # then domdim is > n  for  <M>.
1002                    return false;
1003                fi;
1004            fi;
1005        fi;
1006    fi;
1007
1008#    SetDominantDimension(M,dimension);
1009    return dimension;
1010end
1011);
1012
1013
1014#######################################################################
1015##
1016#O  DominantDimensionOfAlgebra( <A>, <n> )
1017##
1018##  Returns the dominant dimension of the algebra  <A>  if it is less or
1019##  equal to  <n>. If the algebra  <A>  is selfinjectiv, then it returns
1020##  infinity. Otherwise it returns false.
1021##
1022InstallMethod ( DominantDimensionOfAlgebra,
1023    "for a finite dimensional quotient of a path algebra",
1024    true,
1025    [ IsQuiverAlgebra, IS_INT ],
1026    0,
1027    function( A, n )
1028
1029    local P, domdimlist, M, test, pos, finite_ones;
1030
1031    #
1032    # If the algebra  <A>  is not a finite dimensional, try another method.
1033    #
1034    if not IsFiniteDimensional(A) then
1035        TryNextMethod();
1036    fi;
1037    #
1038    # If the algebra  <A>  is selfinjective, then the dominant dimension of
1039    # <A>  is infinite.
1040    if IsSelfinjectiveAlgebra(A) then
1041        return infinity;
1042    fi;
1043    P := IndecProjectiveModules(A);
1044    domdimlist := [];
1045    for M in P do
1046        test := DominantDimensionOfModule(M,n);   # Checking the dominant dimension of each indec. projective module.
1047        if test = false then
1048            return false;
1049        fi;
1050        Add(domdimlist,test);
1051    od;
1052    pos := Positions(domdimlist,infinity); # positions of the indec. projective modules with infinite domdim.
1053    finite_ones := [1..Length(P)];
1054    SubtractSet(finite_ones,pos); # positions of the indec. projective modules with finite domdim.
1055
1056    return Minimum(domdimlist{finite_ones});
1057end
1058  );
1059
1060#######################################################################
1061##
1062#O  ProjDimensionOfModule( <M>, <n> )
1063##
1064##  Returns the projective dimension of the module  <M>  if it is less
1065##  or equal to  <n>, otherwise it returns false.
1066##
1067InstallMethod ( ProjDimensionOfModule,
1068    "for a PathAlgebraMatModule",
1069    true,
1070    [ IsPathAlgebraMatModule, IS_INT ],
1071    0,
1072    function( M, n )
1073
1074    local projres, i;
1075
1076    if HasProjDimension(M) then
1077        if ProjDimension(M) > n then
1078            return false;
1079        else
1080            return ProjDimension(M);
1081        fi;
1082    fi;
1083    projres := ProjectiveResolution(M);
1084    i := 1;
1085    while i < n + 2 do
1086        if Dimension(ObjectOfComplex(projres,i)) = 0 then # the projective dimension is  i - 1.
1087            SetProjDimension(M, i - 1);
1088            return i-1;
1089        fi;
1090        i := i + 1;
1091    od;
1092
1093    return false;
1094end
1095  );
1096
1097#######################################################################
1098##
1099#O  GorensteinDimensionOfAlgebra( <A>, <n> )
1100##
1101##  Returns the Gorenstein dimension of the algebra  <A>  if it is less
1102##  or equal to  <n>, otherwise it returns false.
1103##
1104InstallMethod ( GorensteinDimensionOfAlgebra,
1105    "for a quiver algebra",
1106    true,
1107    [ IsQuiverAlgebra, IS_INT ],
1108    0,
1109    function( A, n )
1110
1111    local Ilist, dimension_right, I, projdim, Ilistop, dimension_left;
1112
1113    #
1114    #  If  <A>  has finite global dimension, then the Gorenstein
1115    #  dimension of  <A>  is equal to the global dimension of  <A>.
1116    #
1117    if HasGlobalDimension(A) then
1118        if GlobalDimension(A) <> infinity then
1119            SetGorensteinDimension(A, GlobalDimension(A));
1120            return GlobalDimension(A);
1121        fi;
1122    fi;
1123    if HasGorensteinDimension(A) then
1124        return GorensteinDimension(A);
1125    fi;
1126    #
1127    #  First checking the injective dimension of the indecomposable
1128    #  projective left  <A>-modules.
1129    #
1130    Ilist := IndecInjectiveModules(A);
1131    dimension_right := 0;
1132    for I in Ilist do
1133        projdim := ProjDimensionOfModule(I,n);
1134        if projdim = false then   # projective dimension of  I  is bigger than  n.
1135            return false;
1136        else                      # projective dimension of  I  is less or equal to  n.
1137            dimension_right := Maximum(dimension_right, projdim );
1138        fi;
1139    od;
1140    #
1141    #  Secondly checking the injective dimension of the indecomposable
1142    #  projective right  <A>-modules.
1143    #
1144    Ilistop := IndecInjectiveModules(OppositeAlgebra(A));
1145    dimension_left := 0;
1146    for I in Ilistop do
1147        projdim := ProjDimensionOfModule(I,n);
1148        if projdim = false then   # projective dimension of  I  is bigger than  n.
1149            return false;
1150        else                      # projective dimension of  I  is less or equal to  n.
1151            dimension_left := Maximum(dimension_left, projdim );
1152        fi;
1153    od;
1154    if dimension_left <> dimension_right then
1155        Print("You have a counterexample to the Gorenstein conjecture!\n\n");
1156    fi;
1157
1158    SetGorensteinDimension(A, Maximum(dimension_left, dimension_right));
1159    return Maximum(dimension_left, dimension_right);
1160end
1161  );
1162
1163#######################################################################
1164##
1165#O  N_RigidModule( <M>, <n> )
1166##
1167##  Returns true if the module  <M>  is n-rigid, otherwise false.
1168##
1169InstallMethod ( N_RigidModule,
1170    "for a PathAlgebraMatModule",
1171    true,
1172    [ IsPathAlgebraMatModule, IS_INT ],
1173    0,
1174    function( M, n )
1175
1176    local i, N;
1177
1178    i := 1;
1179    N := M;
1180    while i < n + 1 do
1181        if Length(ExtOverAlgebra(N,M)[2]) > 0 then # Ext^i(M,M) <> 0.
1182            return false;
1183        else                                       # Ext^i(M,M) = 0.
1184            i := i + 1;
1185            N := NthSyzygy(N,1);
1186        fi;
1187    od;
1188
1189    return true;
1190end
1191  );
1192
1193#######################################################################
1194##
1195#O  LeftFacMApproximation( <C>, <M> )
1196##
1197##  This function computes a left, not necessarily left minimal,
1198##  Fac<M>-approximation of the module  <C>  by doing the following:
1199##                  p
1200##           P(C) -------> C  (projective cover)
1201##             |           |
1202##           f |           | g - the returned homomorphism
1203##             V           V
1204##          M^{P(C)} ----> E
1205##
1206InstallMethod( LeftFacMApproximation,
1207    "for a representations of a quiver",
1208    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
1209    function( C, M )
1210
1211    local p, f;
1212    #
1213    # Checking if the modules  <C>  and  <M>  are modules over the same algebra.
1214    #
1215    if RightActingAlgebra(C) <> RightActingAlgebra(M) then
1216        Error("the entered modules are not modules over the same algebra,\n");
1217    fi;
1218    p := ProjectiveCover(C);
1219    f := MinimalLeftAddMApproximation(Source(p),M);
1220
1221    return PushOut(p,f)[2];
1222end
1223  );
1224
1225
1226#######################################################################
1227##
1228#O  MinimalLeftFacMApproximation( <C>, <M> )
1229##
1230##  This function computes a minimal left Fac<M>-approximation of the
1231##  module  <C>.
1232##
1233InstallMethod( MinimalLeftFacMApproximation,
1234    "for a representations of a quiver",
1235    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
1236    function( C, M );
1237
1238    return LeftMinimalVersion(LeftFacMApproximation(C,M))[1];
1239end
1240  );
1241
1242
1243#######################################################################
1244##
1245#O  RightSubMApproximation( <M>, <C> )
1246##
1247##  This function computes a right, not necessarily a right minimal,
1248##  Sub<M>-approximation of the module  <C>  by doing the following:
1249##
1250##             E -----> M^{I(C)}  (minimal right Add<M>-approximation)
1251##             |           |
1252##           g |           | f     g - the returned homomorphism
1253##             V    i      V
1254##             C -------> I(C)  (injective envelope)
1255##
1256InstallMethod( RightSubMApproximation,
1257    "for a representations of a quiver",
1258    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
1259    function( M, C )
1260
1261    local iop, i, f;
1262    #
1263    # Checking if the modules  <M>  and  <C>  are modules over the same algebra.
1264    #
1265    if RightActingAlgebra(M) <> RightActingAlgebra(C) then
1266        Error("the entered modules are not modules over the same algebra,\n");
1267    fi;
1268    iop := ProjectiveCover(DualOfModule(C));
1269    i := DualOfModuleHomomorphism(iop);
1270    f := MinimalRightAddMApproximation(M, Range(i));
1271
1272    return PullBack(i,f)[2];
1273end
1274  );
1275
1276
1277#######################################################################
1278##
1279#O  MinimalRightSubMApproximation( <M>, <C> )
1280##
1281##  This function computes a minimal right Sub<M>-approximation of the module
1282##  <C>.
1283##
1284InstallMethod( MinimalRightSubMApproximation,
1285    "for a representations of a quiver",
1286    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
1287    function( M, C );
1288
1289    return RightMinimalVersion(RightSubMApproximation(M,C))[1];
1290end
1291  );
1292
1293
1294#######################################################################
1295##
1296#O  LeftSubMApproximation( <C>, <M> )
1297##
1298##  This function computes a minimal left Sub<M>-approximation of the
1299##  module  <C>  by doing the following:
1300##            f
1301##       C -------> M^{C} = the minimal left Add<M>-approxiamtion
1302##
1303##   Returns the natural projection  C --------> Im(f).
1304##
1305InstallMethod( LeftSubMApproximation,
1306    "for a representations of a quiver",
1307    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ], 0,
1308    function( C, M )
1309
1310    local f;
1311    #
1312    # Checking if the modules  <C>  and  <M>  are modules over the same algebra.
1313    #
1314    if RightActingAlgebra(C) <> RightActingAlgebra(M) then
1315        Error("the entered modules are not modules over the same algebra,\n");
1316    fi;
1317    f := MinimalLeftAddMApproximation(C,M);
1318
1319    return ImageProjection(f);
1320end
1321  );
1322
1323#######################################################################
1324##
1325#O  InjDimensionOfModule( <M>, <n> )
1326##
1327##  Returns the injective dimension of the module  <M>  if it is less
1328##  or equal to  <n>, otherwise it returns false.
1329##
1330InstallMethod ( InjDimensionOfModule,
1331    "for a PathAlgebraMatModule and a positive integer",
1332    true,
1333    [ IsPathAlgebraMatModule, IS_INT ],
1334    0,
1335    function( M, n )
1336
1337    local DM, projresop, i;
1338
1339    if HasInjDimension(M) then
1340        if InjDimension(M) > n then
1341            return false;
1342        else
1343            return InjDimension(M);
1344        fi;
1345    fi;
1346    DM := DualOfModule(M);
1347    if HasProjDimension(DM) then
1348        return ProjDimension(DM);
1349    fi;
1350    projresop := ProjectiveResolution(DM);
1351    i := 1;
1352    while i < n + 2 do
1353        if Dimension(ObjectOfComplex(projresop,i)) = 0 then # the projective dimension of DM is  i - 1.
1354            SetInjDimension(M, i - 1);
1355            return i-1;
1356        fi;
1357        i := i + 1;
1358    od;
1359
1360    return false;
1361end
1362  );
1363
1364#######################################################################
1365##
1366#O  HaveFiniteCoresolutionInAddM( <N>, <M>, <n> )
1367##
1368##  This function checks if the module  <N>  has a finite coresolution
1369##  in  add<M>  of length at most  <n>.  If it does, then this
1370##  coresoultion is returned, otherwise false is returned.
1371##
1372InstallMethod( HaveFiniteCoresolutionInAddM,
1373    "for two PathAlgebraMatModules and a positive integer",
1374    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule, IS_INT ],
1375
1376    function( N, M, n )
1377    local U, differentials, g, f, i, cat, coresolution;
1378    #
1379    # Checking if  <N>  and  <M>  are modules over the same algebra.
1380    #
1381    if RightActingAlgebra(M) <> RightActingAlgebra(N) then
1382        Error("the entered modules are not modules over the same algebra,\n");
1383    fi;
1384    #
1385    # If n = 0, then this is the same as N being in add M.
1386    #
1387    # Computing successive minimal left add<M>-approximation to produce
1388    # a coresolution of  <N>  in  add<M>.
1389    #
1390    cat := CatOfRightAlgebraModules(RightActingAlgebra(M));
1391    U := N;
1392    differentials := [];
1393    g := IdentityMapping(U);
1394    f := MinimalLeftAddMApproximation(U,M);
1395    if n = 0 then
1396      if IsIsomorphism( f ) then
1397        return FiniteComplex(cat, 0, [ f ] );
1398      else
1399        return false;
1400      fi;
1401    fi;
1402    for i in [0..n] do
1403        if not IsInjective(f) then
1404            return false;
1405        fi;
1406        Add(differentials, g*f);
1407        g := CoKernelProjection(f);
1408        if Dimension(Range(g)) = 0 then
1409            break;
1410        fi;
1411        f := MinimalLeftAddMApproximation(Range(g),M);
1412    od;
1413    differentials := Reversed(differentials);
1414    coresolution := FiniteComplex(cat, -Length(differentials) + 1, differentials);
1415    return coresolution;
1416end
1417  );
1418
1419
1420#######################################################################
1421##
1422#O  TiltingModule( <M>, <n> )
1423##
1424##  This function checks if the module  <M>  is a tilting module of
1425##  projective dimension at most  <n>.
1426##
1427InstallMethod( TiltingModule,
1428    "for a PathAlgebraMatModule and a positive integer",
1429    [ IsPathAlgebraMatModule, IS_INT ],
1430
1431    function( M, n )
1432    local m, N, i, P, t, coresolution, temp;
1433    #
1434    # Checking if the module has projective dimension at most  <n>.
1435    #
1436    if HasProjDimension(M) then
1437        if ProjDimension(M) > n then
1438            return false;
1439        fi;
1440    else
1441        if not IS_INT(ProjDimensionOfModule(M,n)) then
1442            return false;
1443        fi;
1444    fi;
1445    #
1446    # Now we know that the projective dimension of  <M>  is at most  <n>.
1447    # Next we check if the module  <M>  is selforthogonal.
1448    #
1449    m := ProjDimension(M);
1450    N := M;
1451    i := 0;
1452    repeat
1453        if Length(ExtOverAlgebra(N,M)[2]) <> 0 then
1454            return false;
1455        fi;
1456        i := i + 1;
1457        if i < m then
1458            N := NthSyzygy(N,1);
1459        fi;
1460    until i = m + 1;
1461    #
1462    # Now we know that the projective dimension of  <M>  is at most  <n>,
1463    # and that the module  <M>  is selforthogonal.  Next we check if all the
1464    # indecomposable projectives can be coresolved in  add<M>.
1465    #
1466    P := IndecProjectiveModules(RightActingAlgebra(M));
1467    t := Length(P);
1468    coresolution := [];
1469    for i in [1..t] do
1470        temp := HaveFiniteCoresolutionInAddM(P[i], M, m);
1471        if temp = false then
1472            return false;
1473        fi;
1474        Add(coresolution, temp);
1475    od;
1476    #
1477    # Now we know that the module  <M>  is a tilting module of projective
1478    # dimension  m.
1479    #
1480    SetIsTiltingModule(M, true);
1481    return [m, coresolution];
1482end
1483  );
1484
1485#######################################################################
1486##
1487#O  HaveFiniteResolutionInAddM( <N>, <M>, <n> )
1488##
1489##  This function checks if the module  <N>  has a finite resolution
1490##  in  add<M>  of length at most  <n>.  If it does, then this
1491##  resoultion is returned, otherwise false is returned.
1492##
1493InstallMethod( HaveFiniteResolutionInAddM,
1494    "for two PathAlgebraMatModules and a positive integer",
1495    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule, IS_INT ],
1496
1497    function( N, M, n )
1498    local U, differentials, g, f, i, cat, resolution;
1499    #
1500    # Checking if  <N>  and  <M>  are modules over the same algebra.
1501    #
1502    if RightActingAlgebra(M) <> RightActingAlgebra(N) then
1503        Error("the entered modules are not modules over the same algebra,\n");
1504    fi;
1505    #
1506    # If n = 0, then this is the same as N being in add M.
1507    #
1508    # Computing successive minimal right add<M>-approximation to produce
1509    # a resolution of  <N>  in  add<M>.
1510    #
1511    U := N;
1512    differentials := [];
1513    g := IdentityMapping(U);
1514    f := MinimalRightAddMApproximation(M,U);
1515    if n = 0 then
1516      if IsIsomorphism( f ) then
1517        return true;
1518      else
1519        return false;
1520      fi;
1521    fi;
1522    for i in [0..n] do
1523        if not IsSurjective(f) then
1524            return false;
1525        fi;
1526        Add(differentials, f*g);
1527        g := KernelInclusion(f);
1528        if Dimension(Source(g)) = 0 then
1529            break;
1530        fi;
1531        f := MinimalRightAddMApproximation(M, Source(g));
1532    od;
1533    cat := CatOfRightAlgebraModules(RightActingAlgebra(M));
1534    resolution := FiniteComplex(cat, 1, differentials);
1535    return resolution;
1536end
1537  );
1538
1539
1540#######################################################################
1541##
1542#O  CotiltingModule( <M>, <n> )
1543##
1544##  This function checks if the module  <M>  is a cotilting module of
1545##  projective dimension at most  <n>.
1546##
1547InstallMethod( CotiltingModule,
1548    "for a PathAlgebraMatModule and a positive integer",
1549    [ IsPathAlgebraMatModule, IS_INT ],
1550
1551    function( M, n )
1552    local m, N, i, I, t, resolution, temp;
1553    #
1554    # Checking if the module has injective dimension at most  <n>.
1555    #
1556    if HasInjDimension(M) then
1557        if InjDimension(M) > n then
1558            return false;
1559        fi;
1560    else
1561        if not IS_INT(InjDimensionOfModule(M,n)) then
1562            return false;
1563        fi;
1564    fi;
1565    #
1566    # Now we know that the injective dimension of  <M>  is at most  <n>.
1567    # Next we check if the module  <M>  is selforthogonal.
1568    #
1569    m := InjDimension(M);
1570    N := M;
1571    i := 0;
1572    repeat
1573        if Length(ExtOverAlgebra(N,M)[2]) <> 0 then
1574	    SetIsCotiltingModule(M, false);
1575            return false;
1576        fi;
1577        i := i + 1;
1578        if i < m then
1579            N := NthSyzygy(N,1);
1580        fi;
1581    until i = m + 1;
1582    #
1583    # Now we know that the injective dimension of  <M>  is at most  <n>,
1584    # and that the module  <M>  is selforthogonal.  Next we check if all the
1585    # indecomposable injectives can be resolved in  add<M>.
1586    #
1587    I := IndecInjectiveModules(RightActingAlgebra(M));
1588    t := Length(I);
1589    resolution := [];
1590    for i in [1..t] do
1591        temp := HaveFiniteResolutionInAddM(I[i], M, m);
1592        if temp = false then
1593            return false;
1594        fi;
1595        Add(resolution, temp);
1596    od;
1597    #
1598    # Now we know that the module  <M>  is a cotilting module of injective
1599    # dimension  <M>.
1600    #
1601    SetIsCotiltingModule(M, true);
1602    return [m, resolution];
1603end
1604  );
1605
1606
1607#######################################################################
1608##
1609#O  AllComplementsOfAlmostCompleteTiltingModule( <M>, <X> )
1610##
1611##  This function constructs all complements of an almost complete
1612##  tilting module  <M>  given a complement  <X>  of  <M>.  The
1613##  complements are returned as a long exact sequence (whenever possible)
1614##  of minimal left and minimal right  add<M>-approximations.
1615##
1616InstallMethod( AllComplementsOfAlmostCompleteTiltingModule,
1617    "for two PathAlgebraMatModules",
1618    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
1619
1620    function( M, X)
1621    local U, leftdifferentials, g, f, cat, resolution,
1622          rightdifferentials, coresolution;
1623    #
1624    # Checking if  <M>  and  <X>  are modules over the same algebra.
1625    #
1626    if RightActingAlgebra(M) <> RightActingAlgebra(X) then
1627        Error("the entered modules are not modules over the same algebra,\n");
1628    fi;
1629    #
1630    # Computing successive minimal right add<M>-approximation to produce
1631    # a resolution of  <X>  in  add<M>.
1632    #
1633    U := X;
1634    leftdifferentials := [];
1635    g := IdentityMapping(U);
1636    f := MinimalRightAddMApproximation(M,U);
1637    while IsSurjective(f) do
1638        Add(leftdifferentials, f*g);
1639        g := KernelInclusion(f);
1640        if Dimension(Source(g)) = 0 then
1641            break;
1642        fi;
1643        f := MinimalRightAddMApproximation(M, Source(g));
1644    od;
1645    cat := CatOfRightAlgebraModules(RightActingAlgebra(M));
1646    if Length(leftdifferentials) = 0 then
1647        resolution := [];
1648    else
1649        Add(leftdifferentials, KernelInclusion(leftdifferentials[Length(leftdifferentials)]));
1650        resolution := FiniteComplex(cat, 1, leftdifferentials);
1651    fi;
1652    #
1653    # Computing successive minimal left add<M>-approximation to produce
1654    # a coresolution of  <X>  in  add<M>.
1655    #
1656    U := X;
1657    rightdifferentials := [];
1658    g := IdentityMapping(U);
1659    f := MinimalLeftAddMApproximation(U,M);
1660    while IsInjective(f) do
1661        Add(rightdifferentials, g*f);
1662        g := CoKernelProjection(f);
1663        f := MinimalLeftAddMApproximation(Range(g),M);
1664    od;
1665
1666    if Length(rightdifferentials) = 0 then
1667        coresolution := [];
1668    else
1669        Add(rightdifferentials, CoKernelProjection(rightdifferentials[Length(rightdifferentials)]));
1670        rightdifferentials := Reversed(rightdifferentials);
1671        coresolution := FiniteComplex(cat, -Length(rightdifferentials) + 1, rightdifferentials);
1672    fi;
1673
1674    return [resolution,coresolution];
1675end
1676  );
1677
1678#######################################################################
1679##
1680#A  FaithfulDimension( <M> )
1681##
1682##  This function computes the faithful dimension of a module  <M>.
1683##
1684InstallMethod( FaithfulDimension,
1685    "for a PathAlgebraMatModules",
1686    [ IsPathAlgebraMatModule ],
1687
1688    function( M )
1689    local P, lengths, p, tempdim, U, g, f;
1690
1691    P := IndecProjectiveModules(RightActingAlgebra(M));
1692    #
1693    # For all indecomposable projective  A-modules computing successive
1694    # minimal left add<M>-approximation to produce find the faithful
1695    # dimension  <M>  has with respect to that indecomposable
1696    # projective.
1697    #
1698    lengths := [];
1699    for p in P do
1700        tempdim := 0;
1701        U := p;
1702        f := MinimalLeftAddMApproximation( U, M );
1703	if not IsInjective( f ) then
1704	   return 0;
1705	fi;
1706        while IsInjective( f ) do
1707            tempdim := tempdim + 1;
1708            g := CoKernelProjection( f );
1709            if Dimension( Range( g ) ) = 0 then
1710                Add( lengths, infinity );
1711                break;
1712            else
1713                f := MinimalLeftAddMApproximation( Range( g ), M );
1714            fi;
1715        od;
1716        if Dimension( Range( g ) ) <> 0 then
1717            Add( lengths, tempdim );
1718        fi;
1719    od;
1720
1721    return Minimum( lengths );
1722end
1723  );
1724
1725#######################################################################
1726##
1727#O  NumberOfComplementsOfAlmostCompleteTiltingModule( <M> )
1728##
1729##  This function computes the number complements of an almost
1730##  complete tilting/cotilting module  <M>, assuming that  <M>
1731##  is an almost complete tilting module.
1732##
1733InstallMethod( NumberOfComplementsOfAlmostCompleteTiltingModule,
1734    "for a PathAlgebraMatModules",
1735    [ IsPathAlgebraMatModule ],
1736
1737    function( M );
1738
1739    return FaithfulDimension(M) + 1;
1740end
1741  );
1742
1743#######################################################################
1744##
1745#O  LeftMutationOfTiltingModuleComplement( <M>, <N> )
1746##
1747##  This function computes the left mutation of a complement  <N>  of
1748##  an almost complete tilting module  <M>, assuming that  <M>  is an
1749##  almost complete tilting module.  If it doesn't exist, then the
1750##  function returns false.
1751##
1752InstallMethod( LeftMutationOfTiltingModuleComplement,
1753    "for a PathAlgebraMatModules",
1754    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
1755
1756    function( M, N )
1757
1758    local f;
1759
1760    f := MinimalLeftAddMApproximation(N, M);
1761    if IsInjective(f) then
1762        return CoKernel(f);
1763    else
1764        return false;
1765    fi;
1766end
1767  );
1768
1769#######################################################################
1770##
1771#O  RightMutationOfTiltingModuleComplement( <M>, <N> )
1772##
1773##  This function computes the right mutation of a complement  <N>  of
1774##  an almost complete tilting module  <M>, assuming that  <M>  is an
1775##  almost complete tilting module.  If it doesn't exist, then the
1776##  function returns false.
1777##
1778InstallMethod( RightMutationOfTiltingModuleComplement,
1779    "for a PathAlgebraMatModules",
1780    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
1781
1782    function( M, N )
1783
1784    local f;
1785
1786    f := MinimalRightAddMApproximation(M, N);
1787    if IsSurjective(f) then
1788        return Kernel(f);
1789    else
1790        return false;
1791    fi;
1792end
1793  );
1794
1795##########################################################################
1796##
1797#P DeclareProperty( "IsHereditaryAlgebra", [ A ] )
1798##
1799## The function is defined for an admissible quotient  <A>  of a path
1800## algebra, and it returns true if  <A>  is a hereditary algebra and
1801## false otherwise.
1802##
1803InstallMethod( IsHereditaryAlgebra,
1804    "for an algebra",
1805    [ IsAdmissibleQuotientOfPathAlgebra ],
1806
1807    function( A )
1808    local test;
1809
1810    if HasGlobalDimension(A) then
1811        return GlobalDimension(A) < 2;
1812    fi;
1813
1814    test := GlobalDimensionOfAlgebra(A, 1);
1815    #
1816    # test = false => gldim(A) > 1
1817    # test = infinity => gldim(A) = infinity
1818    # test = integer > 1 => gldim(A) > 1
1819    # if all these are not true, then gldim(A) < 1, and  A  is hereditary.
1820    #
1821    if IsBool(test) or ( test = infinity ) or ( IS_INT(test) and test > 1 ) then
1822        return false;
1823    else
1824        return true;
1825    fi;
1826end
1827  );
1828
1829#######################################################################
1830##
1831#O  RightApproximationByPerpT( <T>, <M> )
1832##
1833##  Returns the minimal rightt $\widehat{\add T}$-approximation of the
1834##  module  <M>.  It checks if  <T>  is a cotilting module, and if not
1835##  it returns an error message.
1836##
1837InstallMethod ( RightApproximationByPerpT,
1838    "for a cotilting PathAlgebraMatModule and a PathAlgebraMatModule",
1839    true,
1840    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
1841    0,
1842    function( T, M )
1843
1844    local   n,  projres,  exactsequences,  currentsequences,  f,  i,  g,
1845            h,  alpha,  t, fprime;
1846
1847    if not IsCotiltingModule( T ) then
1848        Error("the first argument is not a cotilting module,\n");
1849    fi;
1850    if IsZero( M ) then
1851      return ZeroMapping( ZeroModule( RightActingAlgebra( M ) ), M );
1852    fi;
1853    n := InjDimension( T );
1854    projres := ProjectiveResolution( M );
1855    ObjectOfComplex( projres, n);
1856    exactsequences := List( [ 0..n - 1 ], i -> [ KernelInclusion(DifferentialOfComplex(projres, i)),
1857                              ImageProjection(DifferentialOfComplex(projres, i)) ]);
1858    f := MinimalLeftApproximation( Source( exactsequences[ n ][ 1 ] ), T );
1859    for i in [ 1..n ] do
1860      g := PushOut( exactsequences[ n + 1 - i ][ 1 ], f )[ 1 ];
1861      h := CoKernelProjection( g );
1862      alpha := IsomorphismOfModules( Range( h ), Range( exactsequences[ n + 1 - i ][ 2 ] ) );
1863      h := h * alpha;
1864      if i < n then
1865        fprime := MinimalLeftApproximation( Source( h ), T );
1866        f := PushOut( fprime, h )[ 1 ];
1867      fi;
1868    od;
1869
1870    return RightMinimalVersion( h )[ 1 ];
1871end
1872);
1873
1874
1875#######################################################################
1876##
1877#O  LeftApproximationByAddTHat( <T>, <M> )
1878##
1879##  Returns the minimal left $\widehat{\add T}$-approximation of the
1880##  module  <M>.  It checks if  <T>  is a cotilting module, and if not
1881##  it returns an error message.
1882##
1883InstallMethod ( LeftApproximationByAddTHat,
1884    "for a cotilting PathAlgebraMatModule and a PathAlgebraMatModule",
1885    true,
1886    [ IsPathAlgebraMatModule, IsPathAlgebraMatModule ],
1887    0,
1888    function( T, M )
1889
1890    local   n,  projres,  exactsequences,  currentsequences,  f,  i,  g,
1891            h,  alpha,  t, fprime;
1892
1893    if not IsCotiltingModule( T ) then
1894        Error("the first argument is not a cotilting module,\n");
1895    fi;
1896    if IsZero( M ) then
1897      return ZeroMapping( M, ZeroModule( RightActingAlgebra( M ) ) );
1898    fi;
1899    n := InjDimension( T );
1900    projres := ProjectiveResolution( M );
1901    ObjectOfComplex( projres, n);
1902    exactsequences := List( [ 0..n - 1 ], i -> [ KernelInclusion(DifferentialOfComplex(projres, i)),
1903                              ImageProjection(DifferentialOfComplex(projres, i)) ]);
1904    f := MinimalLeftApproximation( Source( exactsequences[ n ][ 1 ] ), T );
1905    for i in [ 1..n ] do
1906      g := PushOut( exactsequences[ n + 1 - i ][ 1 ], f )[ 1 ];
1907      h := CoKernelProjection( g );
1908      alpha := IsomorphismOfModules( Range( h ), Range( exactsequences[ n + 1 - i ][ 2 ] ) );
1909      h := h * alpha;
1910      fprime := MinimalLeftApproximation( Source( h ), T );
1911      f := PushOut( fprime, h )[ 1 ];
1912    od;
1913
1914    return LeftMinimalVersion( f )[ 1 ];
1915end
1916  );
1917
1918InstallMethod( IsNthSyzygy,
1919    "for a PathAlgebraMatModule",
1920    true,
1921    [ IsPathAlgebraMatModule, IS_INT ],
1922    0,
1923    function( M, n )
1924
1925    local N;
1926
1927    N := NthSyzygy( DualOfModule( NthSyzygy( DualOfModule( M ), n ) ), n );
1928    N := DirectSumOfQPAModules( [ N, Source( ProjectiveCover( M ) ) ] );
1929
1930    return IsDirectSummand( M, N );
1931end
1932  );