aboutsummaryrefslogtreecommitdiff
path: root/src/algebra/mfinfact.spad.pamphlet
diff options
context:
space:
mode:
Diffstat (limited to 'src/algebra/mfinfact.spad.pamphlet')
-rw-r--r--src/algebra/mfinfact.spad.pamphlet547
1 files changed, 547 insertions, 0 deletions
diff --git a/src/algebra/mfinfact.spad.pamphlet b/src/algebra/mfinfact.spad.pamphlet
new file mode 100644
index 00000000..685afc57
--- /dev/null
+++ b/src/algebra/mfinfact.spad.pamphlet
@@ -0,0 +1,547 @@
+\documentclass{article}
+\usepackage{axiom}
+\begin{document}
+\title{\$SPAD/src/algebra mfinfact.spad}
+\author{Patrizia Gianni}
+\maketitle
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+\section{package MFINFACT MultFiniteFactorize}
+<<package MFINFACT MultFiniteFactorize>>=
+)abbrev package MFINFACT MultFiniteFactorize
+++ Author: P. Gianni
+++ Date Created: Summer 1990
+++ Date Last Updated: 19 March 1992
+++ Basic Functions:
+++ Related Constructors: PrimeField, FiniteField, Polynomial
+++ Also See:
+++ AMS Classifications:
+++ Keywords:
+++ References:
+++ Description: Package for factorization of multivariate polynomials
+++ over finite fields.
+
+
+MultFiniteFactorize(OV,E,F,PG) : C == T
+ where
+ F : FiniteFieldCategory
+ OV : OrderedSet
+ E : OrderedAbelianMonoidSup
+ PG : PolynomialCategory(F,E,OV)
+ SUP ==> SparseUnivariatePolynomial
+ R ==> SUP F
+ P ==> SparseMultivariatePolynomial(R,OV)
+ Z ==> Integer
+ FFPOLY ==> FiniteFieldPolynomialPackage(F)
+ MParFact ==> Record(irr:P,pow:Z)
+ MFinalFact ==> Record(contp:R,factors:List MParFact)
+ SUParFact ==> Record(irr:SUP P,pow:Z)
+ SUPFinalFact ==> Record(contp:R,factors:List SUParFact)
+
+ -- contp = content,
+ -- factors = List of irreducible factors with exponent
+
+ C == with
+
+ factor : PG -> Factored PG
+ ++ factor(p) produces the complete factorization of the multivariate
+ ++ polynomial p over a finite field.
+ factor : SUP PG -> Factored SUP PG
+ ++ factor(p) produces the complete factorization of the multivariate
+ ++ polynomial p over a finite field. p is represented as a univariate
+ ++ polynomial with multivariate coefficients over a finite field.
+
+ T == add
+
+ import LeadingCoefDetermination(OV,IndexedExponents OV,R,P)
+ import MultivariateLifting(IndexedExponents OV,OV,R,P)
+ import FactoringUtilities(IndexedExponents OV,OV,R,P)
+ import FactoringUtilities(E,OV,F,PG)
+ import GenExEuclid(R,SUP R)
+
+ NNI ==> NonNegativeInteger
+ L ==> List
+ UPCF2 ==> UnivariatePolynomialCategoryFunctions2
+ LeadFact ==> Record(polfac:L P,correct:R,corrfact:L SUP R)
+ ContPrim ==> Record(cont:P,prim:P)
+ ParFact ==> Record(irr:SUP R,pow:Z)
+ FinalFact ==> Record(contp:R,factors:L ParFact)
+ NewOrd ==> Record(npol:SUP P,nvar:L OV,newdeg:L NNI)
+ Valuf ==> Record(inval:L L R,unvfact:L SUP R,lu:R,complead:L R)
+
+ ---- Local Functions ----
+ ran : Z -> R
+ mFactor : (P,Z) -> MFinalFact
+ supFactor : (SUP P,Z) -> SUPFinalFact
+ mfconst : (SUP P,Z,L OV,L NNI) -> L SUP P
+ mfpol : (SUP P,Z,L OV,L NNI) -> L SUP P
+ varChoose : (P,L OV,L NNI) -> NewOrd
+ simplify : (P,Z,L OV,L NNI) -> MFinalFact
+ intChoose : (SUP P,L OV,R,L P,L L R) -> Valuf
+ pretest : (P,NNI,L OV,L R) -> FinalFact
+ checkzero : (SUP P,SUP R) -> Boolean
+ pushdcoef : PG -> P
+ pushdown : (PG,OV) -> P
+ pushupconst : (R,OV) -> PG
+ pushup : (P,OV) -> PG
+ norm : L SUP R -> Integer
+ constantCase : (P,L MParFact) -> MFinalFact
+ pM : L SUP R -> R
+ intfact : (SUP P,L OV,L NNI,MFinalFact,L L R) -> L SUP P
+
+ basicVar:OV:=NIL$Lisp pretend OV -- variable for the basic step
+
+
+ convertPUP(lfg:MFinalFact): SUPFinalFact ==
+ [lfg.contp,[[lff.irr ::SUP P,lff.pow]$SUParFact
+ for lff in lfg.factors]]$SUPFinalFact
+
+ supFactor(um:SUP P,dx:Z) : SUPFinalFact ==
+ degree(um)=0 => convertPUP(mFactor(ground um,dx))
+ lvar:L OV:= "setUnion"/[variables cf for cf in coefficients um]
+ lcont:SUP P
+ lf:L SUP P
+
+ flead : SUPFinalFact:=[0,empty()]$SUPFinalFact
+ factorlist:L SUParFact :=empty()
+
+ mdeg :=minimumDegree um ---- is the Mindeg > 0? ----
+ if mdeg>0 then
+ f1:SUP P:=monomial(1,mdeg)
+ um:=(um exquo f1)::SUP P
+ factorlist:=cons([monomial(1,1),mdeg],factorlist)
+ if degree um=0 then return
+ lfg:=convertPUP mFactor(ground um, dx)
+ [lfg.contp,append(factorlist,lfg.factors)]
+
+
+ om:=map(pushup(#1,basicVar),um)$UPCF2(P,SUP P,PG,SUP PG)
+ sqfacs:=squareFree(om)
+ lcont:=map(pushdown(#1,basicVar),unit sqfacs)$UPCF2(PG,SUP PG,P,SUP P)
+
+ ---- Factorize the content ----
+ if ground? lcont then
+ flead:=convertPUP constantCase(ground lcont,empty())
+ else
+ flead:=supFactor(lcont,dx)
+
+ factorlist:=flead.factors
+
+ ---- Make the polynomial square-free ----
+ sqqfact:=[[map(pushdown(#1,basicVar),ff.factor),ff.exponent]
+ for ff in factors sqfacs]
+
+ --- Factorize the primitive square-free terms ---
+ for fact in sqqfact repeat
+ ffactor:SUP P:=fact.irr
+ ffexp:=fact.pow
+ ffcont:=content ffactor
+ coefs := coefficients ffactor
+ ldeg:= ["max"/[degree(fc,xx) for fc in coefs] for xx in lvar]
+ if ground?(leadingCoefficient ffactor) then
+ lf:= mfconst(ffactor,dx,lvar,ldeg)
+ else lf:=mfpol(ffactor,dx,lvar,ldeg)
+ auxfl:=[[lfp,ffexp]$SUParFact for lfp in lf]
+ factorlist:=append(factorlist,auxfl)
+ lcfacs := */[leadingCoefficient leadingCoefficient(f.irr)**((f.pow)::NNI)
+ for f in factorlist]
+ [(leadingCoefficient leadingCoefficient(um) exquo lcfacs)::R,
+ factorlist]$SUPFinalFact
+
+ factor(um:SUP PG):Factored SUP PG ==
+ lv:List OV:=variables um
+ ld:=degree(um,lv)
+ dx:="min"/ld
+ basicVar:=lv.position(dx,ld)
+ cm:=map(pushdown(#1,basicVar),um)$UPCF2(PG,SUP PG,P,SUP P)
+ flist := supFactor(cm,dx)
+ pushupconst(flist.contp,basicVar)::SUP(PG) *
+ (*/[primeFactor(map(pushup(#1,basicVar),u.irr)$UPCF2(P,SUP P,PG,SUP PG),
+ u.pow) for u in flist.factors])
+
+
+
+ mFactor(m:P,dx:Z) : MFinalFact ==
+ ground?(m) => constantCase(m,empty())
+ lvar:L OV:= variables m
+ lcont:P
+ lf:L SUP P
+ flead : MFinalFact:=[1,empty()]$MFinalFact
+ factorlist:L MParFact :=empty()
+ ---- is the Mindeg > 0? ----
+ lmdeg :=minimumDegree(m,lvar)
+ or/[n>0 for n in lmdeg] => simplify(m,dx,lvar,lmdeg)
+ ---- Make the polynomial square-free ----
+ om:=pushup(m,basicVar)
+ sqfacs:=squareFree(om)
+ lcont := pushdown(unit sqfacs,basicVar)
+
+ ---- Factorize the content ----
+ if ground? lcont then
+ flead:=constantCase(lcont,empty())
+ else
+ flead:=mFactor(lcont,dx)
+ factorlist:=flead.factors
+ sqqfact:List Record(factor:P,exponent:Integer)
+ sqqfact:=[[pushdown(ff.factor,basicVar),ff.exponent]
+ for ff in factors sqfacs]
+ --- Factorize the primitive square-free terms ---
+ for fact in sqqfact repeat
+ ffactor:P:=fact.factor
+ ffexp := fact.exponent
+ ground? ffactor =>
+ for lterm in constantCase(ffactor,empty()).factors repeat
+ factorlist:=cons([lterm.irr,lterm.pow * ffexp], factorlist)
+ lvar := variables ffactor
+ x:OV:=lvar.1
+ ldeg:=degree(ffactor,lvar)
+ --- Is the polynomial linear in one of the variables ? ---
+ member?(1,ldeg) =>
+ x:OV:=lvar.position(1,ldeg)
+ lcont:= gcd coefficients(univariate(ffactor,x))
+ ffactor:=(ffactor exquo lcont)::P
+ factorlist:=cons([ffactor,ffexp]$MParFact,factorlist)
+ for lcterm in mFactor(lcont,dx).factors repeat
+ factorlist:=cons([lcterm.irr,lcterm.pow * ffexp], factorlist)
+
+ varch:=varChoose(ffactor,lvar,ldeg)
+ um:=varch.npol
+
+
+ ldeg:=ldeg.rest
+ lvar:=lvar.rest
+ if varch.nvar.1 ^= x then
+ lvar:= varch.nvar
+ x := lvar.1
+ lvar:=lvar.rest
+ pc:= gcd coefficients um
+ if pc^=1 then
+ um:=(um exquo pc)::SUP P
+ ffactor:=multivariate(um,x)
+ for lcterm in mFactor(pc,dx).factors repeat
+ factorlist:=cons([lcterm.irr,lcterm.pow*ffexp],factorlist)
+ ldeg:= degree(ffactor,lvar)
+
+ -- should be unitNormal if unified, but for now it is easier
+ lcum:F:= leadingCoefficient leadingCoefficient
+ leadingCoefficient um
+ if lcum ^=1 then
+ um:=((inv lcum)::R::P) * um
+ flead.contp := (lcum::R) *flead.contp
+
+ if ground?(leadingCoefficient um)
+ then lf:= mfconst(um,dx,lvar,ldeg)
+ else lf:=mfpol(um,dx,lvar,ldeg)
+ auxfl:=[[multivariate(lfp,x),ffexp]$MParFact for lfp in lf]
+ factorlist:=append(factorlist,auxfl)
+ flead.factors:= factorlist
+ flead
+
+
+ pM(lum:L SUP R) : R ==
+ x := monomial(1,1)$R
+ for i in 1..size()$F repeat
+ p := x + (index(i::PositiveInteger)$F) ::R
+ testModulus(p,lum) => return p
+ for e in 2.. repeat
+ p := (createIrreduciblePoly(e::PositiveInteger))$FFPOLY
+ testModulus(p,lum) => return p
+ while not((q := nextIrreduciblePoly(p)$FFPOLY) case "failed") repeat
+ p := q::SUP F
+ if testModulus(p, lum)$GenExEuclid(R, SUP R) then return p
+
+ ---- push x in the coefficient domain for a term ----
+ pushdcoef(t:PG):P ==
+ map(coerce(#1)$R,t)$MPolyCatFunctions2(OV,E,
+ IndexedExponents OV,F,R,PG,P)
+
+
+ ---- internal function, for testing bad cases ----
+ intfact(um:SUP P,lvar: L OV,ldeg:L NNI,
+ tleadpol:MFinalFact,ltry:L L R): L SUP P ==
+ polcase:Boolean:=(not empty? tleadpol.factors )
+ vfchoo:Valuf:=
+ polcase =>
+ leadpol:L P:=[ff.irr for ff in tleadpol.factors]
+ intChoose(um,lvar,tleadpol.contp,leadpol,ltry)
+ intChoose(um,lvar,1,empty(),empty())
+ unifact:List SUP R := vfchoo.unvfact
+ nfact:NNI := #unifact
+ nfact=1 => [um]
+ ltry:L L R:= vfchoo.inval
+ lval:L R:=first ltry
+ dd:= vfchoo.lu
+ lpol:List P:=empty()
+ leadval:List R:=empty()
+ if polcase then
+ leadval := vfchoo.complead
+ distf := distFact(vfchoo.lu,unifact,tleadpol,leadval,lvar,lval)
+ distf case "failed" =>
+ return intfact(um,lvar,ldeg,tleadpol,ltry)
+ dist := distf :: LeadFact
+ -- check the factorization of leading coefficient
+ lpol:= dist.polfac
+ dd := dist.correct
+ unifact:=dist.corrfact
+ if dd^=1 then
+ unifact := [dd*unifact.i for i in 1..nfact]
+ um := ((dd**(nfact-1)::NNI)::P)*um
+ (ffin:= lifting(um,lvar,unifact,lval,lpol,ldeg,pM(unifact)))
+ case "failed" => intfact(um,lvar,ldeg,tleadpol,ltry)
+ factfin: L SUP P:=ffin :: L SUP P
+ if dd^=1 then
+ factfin:=[primitivePart ff for ff in factfin]
+ factfin
+
+-- the following functions are used to "push" x in the coefficient ring -
+ ---- push back the variable ----
+ pushup(f:P,x:OV) :PG ==
+ ground? f => pushupconst((retract f)@R,x)
+ rr:PG:=0
+ while f^=0 repeat
+ lf:=leadingMonomial f
+ cf:=pushupconst(leadingCoefficient f,x)
+ lvf:=variables lf
+ rr:=rr+monomial(cf,lvf, degree(lf,lvf))$PG
+ f:=reductum f
+ rr
+
+ ---- push x in the coefficient domain for a polynomial ----
+ pushdown(g:PG,x:OV) : P ==
+ ground? g => ((retract g)@F)::R::P
+ rf:P:=0$P
+ ug:=univariate(g,x)
+ while ug^=0 repeat
+ cf:=monomial(1,degree ug)$R
+ rf:=rf+cf*pushdcoef(leadingCoefficient ug)
+ ug := reductum ug
+ rf
+
+ ---- push x back from the coefficient domain ----
+ pushupconst(r:R,x:OV):PG ==
+ ground? r => (retract r)@F ::PG
+ rr:PG:=0
+ while r^=0 repeat
+ rr:=rr+monomial((leadingCoefficient r)::PG,x,degree r)$PG
+ r:=reductum r
+ rr
+
+ -- This function has to be added to Eucliden domain
+ ran(k1:Z) : R ==
+ --if R case Integer then random()$R rem (2*k1)-k1
+ --else
+ +/[monomial(random()$F,i)$R for i in 0..k1]
+
+ checkzero(u:SUP P,um:SUP R) : Boolean ==
+ u=0 => um =0
+ um = 0 => false
+ degree u = degree um => checkzero(reductum u, reductum um)
+ false
+
+ --- Choose the variable of least degree ---
+ varChoose(m:P,lvar:L OV,ldeg:L NNI) : NewOrd ==
+ k:="min"/[d for d in ldeg]
+ k=degree(m,first lvar) =>
+ [univariate(m,first lvar),lvar,ldeg]$NewOrd
+ i:=position(k,ldeg)
+ x:OV:=lvar.i
+ ldeg:=cons(k,delete(ldeg,i))
+ lvar:=cons(x,delete(lvar,i))
+ [univariate(m,x),lvar,ldeg]$NewOrd
+
+
+ norm(lum: L SUP R): Integer == "max"/[degree lup for lup in lum]
+
+ --- Choose the values to reduce to the univariate case ---
+ intChoose(um:SUP P,lvar:L OV,clc:R,plist:L P,ltry:L L R) : Valuf ==
+ -- declarations
+ degum:NNI := degree um
+ nvar1:=#lvar
+ range:NNI:=0
+ unifact:L SUP R
+ ctf1 : R := 1
+ testp:Boolean := -- polynomial leading coefficient
+ plist = empty() => false
+ true
+ leadcomp,leadcomp1 : L R
+ leadcomp:=leadcomp1:=empty()
+ nfatt:NNI := degum+1
+ lffc:R:=1
+ lffc1:=lffc
+ newunifact : L SUP R:=empty()
+ leadtest:=true --- the lc test with polCase has to be performed
+ int:L R:=empty()
+
+ -- New sets of values are chosen until we find twice the
+ -- same number of "univariate" factors:the set smaller in modulo is
+ -- is chosen.
+ while true repeat
+ lval := [ ran(range) for i in 1..nvar1]
+ member?(lval,ltry) => range:=1+range
+ ltry := cons(lval,ltry)
+ leadcomp1:=[retract eval(pol,lvar,lval) for pol in plist]
+ testp and or/[unit? epl for epl in leadcomp1] => range:=range+1
+ newm:SUP R:=completeEval(um,lvar,lval)
+ degum ^= degree newm or minimumDegree newm ^=0 => range:=range+1
+ lffc1:=content newm
+ newm:=(newm exquo lffc1)::SUP R
+ testp and leadtest and ^ polCase(lffc1*clc,#plist,leadcomp1)
+ => range:=range+1
+ Dnewm := differentiate newm
+ D2newm := map(differentiate, newm)
+ degree(gcd [newm,Dnewm,D2newm])^=0 => range:=range+1
+ -- if R has Integer then luniv:=henselFact(newm,false)$
+ -- else
+ lcnm:F:=1
+ -- should be unitNormal if unified, but for now it is easier
+ if (lcnm:=leadingCoefficient leadingCoefficient newm)^=1 then
+ newm:=((inv lcnm)::R)*newm
+ dx:="max"/[degree uc for uc in coefficients newm]
+ luniv:=generalTwoFactor(newm)$TwoFactorize(F)
+ lunivf:= factors luniv
+ nf:= #lunivf
+
+ nf=0 or nf>nfatt => "next values" --- pretest failed ---
+
+ --- the univariate polynomial is irreducible ---
+ if nf=1 then leave (unifact:=[newm])
+
+ lffc1:=lcnm * retract(unit luniv)@R * lffc1
+
+ -- the new integer give the same number of factors
+ nfatt = nf =>
+ -- if this is the first univariate factorization with polCase=true
+ -- or if the last factorization has smaller norm and satisfies
+ -- polCase
+ if leadtest or
+ ((norm unifact > norm [ff.factor for ff in lunivf]) and
+ (^testp or polCase(lffc1*clc,#plist,leadcomp1))) then
+ unifact:=[uf.factor for uf in lunivf]
+ int:=lval
+ lffc:=lffc1
+ if testp then leadcomp:=leadcomp1
+ leave "foundit"
+
+ -- the first univariate factorization, inizialize
+ nfatt > degum =>
+ unifact:=[uf.factor for uf in lunivf]
+ lffc:=lffc1
+ if testp then leadcomp:=leadcomp1
+ int:=lval
+ leadtest := false
+ nfatt := nf
+
+ nfatt>nf => -- for the previous values there were more factors
+ if testp then leadtest:=^polCase(lffc*clc,#plist,leadcomp)
+ else leadtest:= false
+ -- if polCase=true we can consider the univariate decomposition
+ if ^leadtest then
+ unifact:=[uf.factor for uf in lunivf]
+ lffc:=lffc1
+ if testp then leadcomp:=leadcomp1
+ int:=lval
+ nfatt := nf
+ [cons(int,ltry),unifact,lffc,leadcomp]$Valuf
+
+
+ constantCase(m:P,factorlist:List MParFact) : MFinalFact ==
+ --if R case Integer then [const m,factorlist]$MFinalFact
+ --else
+ lunm:=distdfact((retract m)@R,false)$DistinctDegreeFactorize(F,R)
+ [(lunm.cont)::R, append(factorlist,
+ [[(pp.irr)::P,pp.pow] for pp in lunm.factors])]$MFinalFact
+
+ ---- The polynomial has mindeg>0 ----
+
+ simplify(m:P,dm:Z,lvar:L OV,lmdeg:L NNI):MFinalFact ==
+ factorlist:L MParFact:=empty()
+ pol1:P:= 1$P
+ for x in lvar repeat
+ i := lmdeg.(position(x,lvar))
+ i=0 => "next value"
+ pol1:=pol1*monomial(1$P,x,i)
+ factorlist:=cons([x::P,i]$MParFact,factorlist)
+ m := (m exquo pol1)::P
+ ground? m => constantCase(m,factorlist)
+ flead:=mFactor(m,dm)
+ flead.factors:=append(factorlist,flead.factors)
+ flead
+
+ ---- m square-free,primitive,lc constant ----
+ mfconst(um:SUP P,dm:Z,lvar:L OV,ldeg:L NNI):L SUP P ==
+ nsign:Boolean
+ factfin:L SUP P:=empty()
+ empty? lvar =>
+ um1:SUP R:=map(ground,
+ um)$UPCF2(P,SUP P,R,SUP R)
+ lum:= generalTwoFactor(um1)$TwoFactorize(F)
+ [map(coerce,lumf.factor)$UPCF2(R,SUP R,P,SUP P)
+ for lumf in factors lum]
+ intfact(um,lvar,ldeg,[0,empty()]$MFinalFact,empty())
+
+ --- m is square-free,primitive,lc is a polynomial ---
+ mfpol(um:SUP P,dm:Z,lvar:L OV,ldeg:L NNI):L SUP P ==
+ dist : LeadFact
+ tleadpol:=mFactor(leadingCoefficient um,dm)
+ intfact(um,lvar,ldeg,tleadpol,empty())
+
+ factor(m:PG):Factored PG ==
+ lv:=variables m
+ lv=empty() => makeFR(m,empty() )
+ -- reduce to multivariate over SUP
+ ld:=[degree(m,x) for x in lv]
+ dx:="min"/ld
+ basicVar:=lv(position(dx,ld))
+ cm:=pushdown(m,basicVar)
+ flist := mFactor(cm,dx)
+ pushupconst(flist.contp,basicVar) *
+ (*/[primeFactor(pushup(u.irr,basicVar),u.pow)
+ for u in flist.factors])
+
+@
+\section{License}
+<<license>>=
+--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+--All rights reserved.
+--
+--Redistribution and use in source and binary forms, with or without
+--modification, are permitted provided that the following conditions are
+--met:
+--
+-- - Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- - Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in
+-- the documentation and/or other materials provided with the
+-- distribution.
+--
+-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the
+-- names of its contributors may be used to endorse or promote products
+-- derived from this software without specific prior written permission.
+--
+--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+@
+<<*>>=
+<<license>>
+
+<<package MFINFACT MultFiniteFactorize>>
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}