123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231moduleMake(Literal:Literal.S)=structmoduleLiteralPair=structtypet=Literal.t*Literal.tletcompare(x0,y0)(x1,y1)=matchLiteral.comparex0x1with0->Literal.comparey0y1|c->cendmoduleMatrixMap=Map.Make(LiteralPair)moduleLiteralMap=Map.Make(Literal)type'am='aMatrixMap.tmoduleMake_SR(K:Algebra.Semiring_S)=structmoduleVector=Vector.Make(Literal)moduleVector_SR=Vector.Make_SR(K)letk_is_zero=K.(equalzero)letnone_to_zerox=Option.valuex~default:K.zeroletis_good_entryv1v2k=Literal.equalv1v2||not(k_is_zerok)(** We make sure the diagonal is never empty on the support of a matrix *)typet=K.tmletzero'=MatrixMap.emptyletzerosupport=List.fold_left(funaccs->MatrixMap.add(s,s)K.zeroacc)zero'supportletfor_allf=MatrixMap.for_all(fun(a,b)->fab)letis_zero=for_all(fun__->k_is_zero)letonesupport=List.fold_left(funaccs->MatrixMap.add(s,s)K.oneacc)zero'supportletdiagonalvect=Vector.fold(funskacc->MatrixMap.add(s,s)kacc)vectzero'letget_entryv1v2m=none_to_zero(MatrixMap.find_opt(v1,v2)m)letset_entryv1v2k=ifis_good_entryv1v2kthenMatrixMap.add(v1,v2)kelseMatrixMap.remove(v1,v2)letsingletonv1v2k=MatrixMap.singleton(v1,v1)K.zero|>MatrixMap.add(v2,v2)K.zero|>set_entryv1v2kletremovev1v2=MatrixMap.remove(v1,v2)letmergef=letg(v1,v2)xy=matchfv1v2xywith|None->ifLiteral.equalv1v2thenSomeK.zeroelseNone|Somes->ifis_good_entryv1v2sthenSomeselseNoneinMatrixMap.mergeg(** We keep the matrix as sparse as possible, while keeping the diagonal non-empty *)letunionf=letg(v1,v2)xy=matchfv1v2xywith|None->ifLiteral.equalv1v2thenSomeK.zeroelseNone|Somes->ifis_good_entryv1v2sthenSomeselseNoneinMatrixMap.uniongletequalm1m2=letp=MatrixMap.merge(fun_r1r2->match(r1,r2)with|(None,None)->None|(Somer,None)|(None,Somer)->Some(r,K.zero)|(Somer1,Somer2)->Some(r1,r2))m1m2inMatrixMap.for_all(fun_(a,b)->K.equalab)pletneqm1m2=not(equalm1m2)letiterf=MatrixMap.iter(fun(v1,v2)->fv1v2)letfoldf=MatrixMap.fold(fun(v1,v2)->fv1v2)letfilterf=MatrixMap.filter(fun(v1,v2)->fv1v2)letbindings=MatrixMap.bindingsletremove_zero_coeff=filteris_good_entryletmapfm=MatrixMap.mapfm|>remove_zero_coeffletmapifm=MatrixMap.mapi(fun(v1,v2)->fv1v2)m|>remove_zero_coeffletget_supportmat=fold(funab_acc->ifLiteral.equalabthena::accelseacc)mat[]letget_linevarmat=MatrixMap.to_seq(filter(funa__->Literal.equalavar)mat)|>Seq.map(fun((_,b),c)->(b,c))|>LiteralMap.of_seq|>Vector.of_map|>Vector.union(fun__x->Somex)(Vector_SR.zero(get_supportmat))letget_columnvarmat=MatrixMap.to_seq(filter(fun_b_->Literal.equalbvar)mat)|>Seq.map(fun((a,_),c)->(a,c))|>LiteralMap.of_seq|>Vector.of_map|>Vector.union(fun__x->Somex)(Vector_SR.zero(get_supportmat))letadd=union(fun__ab->Some(K.addab))letmulm1m2=letsupport_m1=get_supportm1inletsupport_m2=get_supportm2inletauxyaccx=letrf=Vector_SR.mul_dot(get_linexm1)(get_columnym2)inif(not(Literal.equalxy))&&k_is_zerorfthenaccelseMatrixMap.add(x,y)rfaccinletaux2acc2y=List.fold_left(auxy)acc2support_m1inList.fold_leftaux2zero'support_m2letpowmatk=letmoduleSt=structincludeStringletto_stringx=xendinletmoduleM=Monomial.Make(St)inletmoduleSMap=Map.Make(St)inletvar="m"inletmono=M.singletonvarkin(* We use [Monomial]'s fast exponentiation because why not *)let(res,_)=M.apply(modulestructtypet=K.tmletone=one(get_supportmat)letmul=mulletequal=equalletto_string_=""end)mono(SMap.singletonvarmat)inresletmul_vectmv=Vector.mapi(funvar_->Vector_SR.mul_dot(get_linevarm)v)vletis_nilpotentmat=powmat(List.length(get_supportmat))|>equalzero'letto_stringmat:string=(* It is a sparse matrix, only print the non-zero entries *)String.concat"\n"(List.map(fun((v1,v2),rf)->Printf.sprintf"( %s ; %s ) := %s"(Literal.to_stringv1)(Literal.to_stringv2)(K.to_stringrf))(bindingsmat))moduleInfix=structlet(+)=addlet(*)=mullet(*^)=powlet(*>)=mul_vectlet(=)=equallet(<>)=neqendendmoduleMake_R(K:Algebra.Ring_S)=structincludeMake_SR(K)letneg=mapK.negletsubm1m2=addm1(negm2)moduleInfix=structincludeInfixlet(~-)=neglet(-)=subendendletmake_semiring(typea)(moduleK:Algebra.Semiring_Swithtypet=a)l=(modulestructincludeMake_SR(K)letzero=zerolletone=onelend:Algebra.Semiring_Swithtypet=am)letmake_ring(typea)(moduleK:Algebra.Ring_Swithtypet=a)l=(modulestructincludeMake_R(K)letzero=zerolletone=onelend:Algebra.Ring_Swithtypet=am)end