DIRECTORY Rope, Basics, Atom, Ascii, Convert, IO, RemoteAlgebra, MathExpr, MathConstructors, AlgebraClasses, Structures, Variables, Sets, Ints, Sequences, VariableSequences, DistribPolys, Matrices, Polynomials; PolynomialsImpl: CEDAR PROGRAM IMPORTS Rope, Convert, IO, RemoteAlgebra, MathConstructors, AlgebraClasses, Structures, Variables, Sets, Ints, Sequences, VariableSequences, DistribPolys, Matrices EXPORTS Polynomials = BEGIN OPEN AC: AlgebraClasses, VARS: Variables, VARSEQ: VariableSequences, SEQ: Sequences, DP: DistribPolys, MAT: Matrices, Polynomials; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Object: TYPE = AC.Object; Method: TYPE = AC.Method; SyntaxError: PUBLIC ERROR [reason: ATOM] = CODE; BadElementStructure: PUBLIC ERROR [elementStructure: Object] = CODE; CantInvertError: PUBLIC ERROR [elementStructure: Object] = CODE; TypeError: PUBLIC ERROR [message: ATOM _ $Unspecified] = CODE; OperationError: PUBLIC ERROR [message: ATOM _ $Unspecified] = CODE; MakePolynomialStructure: PUBLIC AC.PolynomialStructureConstructor ~ { baseCoeffRing, strictCoeffRing: Object; strictVariable: VARS.Variable; allVariables: VARSEQ.VariableSequence; polynomialRingData: PolynomialRingData; vData: SEQ.SequenceData _ NARROW[variableSeq.data]; IF vData.lengthPlus1 - 1 > 1 THEN { strictCoeffRing _ MakePolynomialStructure[coeffRing, SEQ.DeleteLast[variableSeq] ]; strictVariable _ SEQ.Last[variableSeq]; } ELSE { strictCoeffRing _ coeffRing; strictVariable _ SEQ.First[variableSeq]; }; IF IsPolynomialStructure[strictCoeffRing] THEN { -- polynomials over polynomials, or not? data: PolynomialRingData _ NARROW[strictCoeffRing.data]; baseCoeffRing _ data.baseCoeffRing; allVariables _ SEQ.Append[data.allVariables, strictVariable] } ELSE { baseCoeffRing _ strictCoeffRing; allVariables _ SEQ.MakeSequence[LIST[strictVariable], VARSEQ.VariableSequences]; }; polynomialRingData _ NEW[PolynomialRingDataRec _ [ coeffRing: strictCoeffRing, variable: strictVariable, baseCoeffRing: baseCoeffRing, allVariables: allVariables ] ]; polynomialStructure _ NEW[AC.ObjectRec _ [ flavor: Structure, class: NIL, data: polynomialRingData ] ]; polynomialStructure.name _ ShortPrintName[polynomialStructure]; SELECT TRUE FROM AC.IsCategory[strictCoeffRing, ring] => polynomialStructure.class _ polynomialsOverCommRingClass; AC.IsCategory[strictCoeffRing, algebra] => polynomialStructure.class _ polynomialsOverCommRingClass; AC.IsCategory[strictCoeffRing, field] => polynomialStructure.class _ polynomialsOverOrderedCommFieldClass; AC.IsCategory[strictCoeffRing, divisionAlgebra] => polynomialStructure.class _ polynomialsOverOrderedCommFieldClass; -- probably wrong, since probably the divisionAlgebra is noncommutative ENDCASE => polynomialStructure.class _ polynomialClass; }; ShortPrintName: PUBLIC AC.PrintNameProc = { data: PolynomialRingData _ NARROW[structure.data]; shortPrintNameMethod: Method _ AC.LookupMethodInStructure[$shortPrintName, data.baseCoeffRing]; RETURN[Rope.Concat[ NARROW[AC.ApplyNoLkpNoRecastRef[shortPrintNameMethod,LIST[data.baseCoeffRing] ] ], Sequences.ToRope[data.allVariables] ] ]; }; IsPolynomialStructure: PUBLIC AC.UnaryPredicate = { IF ~arg.flavor = Structure THEN RETURN[FALSE]; RETURN[ AC.LookupMethodInStructure[$polynomialStructure, arg]#NIL ] }; Recast: PUBLIC AC.BinaryOp = { destPolyRing: Object _ secondArg; destPolyRingData: PolynomialRingData _ NARROW[destPolyRing.data]; destFromRopeMethod: Method _ AC.LookupMethodInStructure[$fromRope, destPolyRing]; destBaseCoeffRing: Object _ destPolyRingData.baseCoeffRing; destBaseCanRecastMethod: Method _ AC.LookupMethodInStructure[$canRecast, destBaseCoeffRing]; destBaseRecastMethod: Method _ AC.LookupMethodInStructure[$recast, destBaseCoeffRing]; refBOOL: REF BOOL; sourceStructure: Object _ firstArg.class; variable: Object _ firstArg; sourceRope: ROPE; IF AC.StructureEqual[sourceStructure, destPolyRing] THEN RETURN[firstArg]; IF Sets.IsVariable[firstArg] THEN { -- recast as an element of Variables Structure variable _ Sets.UnderlyingSetUniverseEltFromSSSElt[firstArg]; sourceStructure _ variable.class; }; IF VARS.IsVariables[sourceStructure] THEN { sourceVarsSubset: BOOL _ SEQ.IsSubset[SEQ.MakeSequence[LIST[variable], VARSEQ.VariableSequences], destPolyRingData.allVariables]; IF NOT sourceVarsSubset THEN RETURN[NIL]; sourceRope _ NARROW[AC.ApplyLkpNoRecastRef[$toRope, sourceStructure, LIST[variable]]]; RETURN[AC.ApplyFromRopeMethod[destFromRopeMethod, sourceRope, destPolyRing] ]; }; IF IsPolynomialStructure[sourceStructure] THEN { sourcePolyRingData: PolynomialRingData _ NARROW[sourceStructure.data]; sourceBaseCoeffRing: Object _ sourcePolyRingData.baseCoeffRing; sourceVarsSubset: BOOL _ Sequences.IsSubset[sourcePolyRingData.allVariables, destPolyRingData.allVariables]; IF NOT sourceVarsSubset THEN RETURN[NIL]; refBOOL _ NARROW[AC.ApplyNoLkpNoRecastRef[destBaseCanRecastMethod, LIST[sourceBaseCoeffRing, destBaseCoeffRing] ] ]; IF NOT refBOOL^ THEN RETURN[NIL]; sourceRope _ NARROW[AC.ApplyLkpNoRecastRef[$toRope, sourceStructure, LIST[firstArg]]]; RETURN[AC.ApplyFromRopeMethod[destFromRopeMethod, sourceRope, destPolyRing] ]; }; refBOOL _ NARROW[AC.ApplyNoLkpNoRecastRef[destBaseCanRecastMethod, LIST[sourceStructure, destBaseCoeffRing] ] ]; IF refBOOL^ THEN { sourceRope _ NARROW[AC.ApplyLkpNoRecastRef[$toRope, sourceStructure, LIST[firstArg]]]; RETURN[AC.ApplyFromRopeMethod[destFromRopeMethod, sourceRope, destPolyRing] ]; }; RETURN[NIL]; }; CanRecast: PUBLIC AC.BinaryPredicate = { destPolyRing: Object _ secondArg; destPolyRingData: PolynomialRingData _ NARROW[destPolyRing.data]; destBaseCoeffRing: Object _ destPolyRingData.baseCoeffRing; destBaseCanRecastMethod: Method _ AC.LookupMethodInStructure[$canRecast, destBaseCoeffRing]; refBOOL: REF BOOL; sourceStructure: Object _ IF firstArg.flavor = StructureElement THEN firstArg.class ELSE IF firstArg.flavor = Structure THEN firstArg ELSE ERROR; variable: Object _ firstArg; variableList: LIST OF Object _ NIL; IF AC.StructureEqual[sourceStructure, destPolyRing] THEN RETURN[TRUE]; -- nothing to do IF firstArg.flavor=StructureElement AND Sets.IsVariable[firstArg] THEN { -- recast as an element of Variables Structure variable _ Sets.UnderlyingSetUniverseEltFromSSSElt[firstArg]; sourceStructure _ variable.class; variableList_ LIST[variable]; } ELSE IF firstArg.flavor=Structure AND Sets.IsSingleSetStructure[firstArg] THEN { thisSetStructureData: Sets.SingleSetStructureData _ NARROW[firstArg.data]; thisSetStructureUnderlyingSet: Object _ thisSetStructureData.underlyingSet; underlyingSetData: Sets.SetData; IF NOT AC.StructureEqual[thisSetStructureUnderlyingSet.class, Sets.VariableSets] THEN RETURN[FALSE]; underlyingSetData _ NARROW[thisSetStructureUnderlyingSet.data]; variableList_ underlyingSetData; variable _ underlyingSetData.first; sourceStructure _ variable.class; }; IF VARS.IsVariables[sourceStructure] THEN { sourceVarsSubset: BOOL; IF variable.flavor # StructureElement THEN RETURN[FALSE]; -- can't check since don't have any concrete variables, i.e.VARS.Variables is not recastable to a particular poly ring IF variableList=NIL THEN variableList _ LIST[variable]; sourceVarsSubset _ Sequences.IsSubset[SEQ.MakeSequence[variableList, VARSEQ.VariableSequences], destPolyRingData.allVariables]; RETURN[sourceVarsSubset]; }; IF IsPolynomialStructure[sourceStructure] THEN { sourcePolyRingData: PolynomialRingData _ NARROW[sourceStructure.data]; sourceBaseCoeffRing: Object _ sourcePolyRingData.baseCoeffRing; sourceVarsSubset: BOOL _ Sequences.IsSubset[sourcePolyRingData.allVariables, destPolyRingData.allVariables]; IF NOT sourceVarsSubset THEN RETURN[FALSE]; refBOOL _ NARROW[AC.ApplyNoLkpNoRecastRef[destBaseCanRecastMethod, LIST[sourceBaseCoeffRing, destBaseCoeffRing] ] ]; RETURN[refBOOL^]; }; refBOOL _ NARROW[AC.ApplyNoLkpNoRecastRef[destBaseCanRecastMethod, LIST[sourceStructure, destBaseCoeffRing] ] ]; RETURN[refBOOL^]; }; ToExpr: PUBLIC AC.ToExprOp = { data: PolynomialRingData _ NARROW[in.class.data]; dIn: DP.DPolynomial _ DPolyFromPoly[in]; addend, sum: MathExpr.EXPR; V: VARSEQ.VariableSequence _ data.allVariables; coeffRing: Object _ data.baseCoeffRing; firstTerm: BOOL _ TRUE; trivialMonomial, firstOccurringVar: BOOL; thisVar: MathExpr.EXPR; coeff, coeffAbs: AC.Object; degreeVec: DP.DegreeVector; coeffSign: Basics.Comparison; exponent, index: CARDINAL; one: AC.Object _ AC.ApplyLkpNoRecastObject[$one, coeffRing, LIST[coeffRing] ]; equalMethod: Method _ AC.LookupMethodInStructure[$eqFormula, coeffRing]; toExprMethod: Method _ AC.LookupMethodInStructure[$toExpr, coeffRing]; isOrdered: BOOL _ AC.HasProperty[coeffRing, $ordered]; signMethod, absMethod: Method; CreateDTerm: PROC[firstTerm: BOOL] ~ { [coeff, degreeVec] _ dIn.first; IF isOrdered THEN { coeffSign _ AC.ApplyCompareToZeroMethod[signMethod, coeff]; coeffAbs _ AC.ApplyNoLkpNoRecastObject[absMethod, LIST[coeff] ] } ELSE { -- for unordered coeffRing, act as though coeff is positive coeffSign _ greater; coeffAbs _ coeff; }; trivialMonomial _ TRUE; firstOccurringVar _ TRUE; degreeVec _ DP.DVReverse[degreeVec]; WHILE degreeVec#NIL DO trivialMonomial _ FALSE; exponent _ degreeVec.first; degreeVec _ degreeVec.rest; index _ degreeVec.first; degreeVec _ degreeVec.rest; IF exponent>1 THEN thisVar _ MathConstructors.MakePow[ VARS.ToExpr[SEQ.Select[V, Ints.FromINT[index] ] ], MathConstructors.MakeInt[Convert.RopeFromCard[exponent]] ] ELSE thisVar _ VARS.ToExpr[SEQ.Select[V, Ints.FromINT[index] ] ]; IF firstOccurringVar THEN addend _ thisVar ELSE addend _ MathConstructors.MakeProduct[addend, thisVar]; firstOccurringVar _ FALSE; ENDLOOP; IF NOT trivialMonomial THEN { IF NOT AC.ApplyPredNoLkpNoRecast[equalMethod, LIST[coeffAbs, one] ] THEN addend _ MathConstructors.MakeProduct[NARROW[AC.ApplyNoLkpNoRecastRef[toExprMethod, LIST[coeffAbs] ] ], addend] } ELSE addend _ NARROW[AC.ApplyNoLkpNoRecastRef[toExprMethod, LIST[coeffAbs] ] ]; IF firstTerm AND coeffSign = less THEN addend _ MathConstructors.MakeNegation[addend]; }; IF isOrdered THEN { signMethod _ AC.LookupMethodInStructure[$sign, coeffRing]; absMethod _ AC.LookupMethodInStructure[$abs, coeffRing]; }; IF dIn = DP.ZeroDPoly THEN RETURN[MathConstructors.MakeInt["0"] ]; CreateDTerm[TRUE]; -- first term sum _ addend; dIn _ dIn.rest; WHILE dIn # NIL DO CreateDTerm[FALSE]; -- not first term IF coeffSign = greater THEN sum _ MathConstructors.MakeSum[sum, addend] -- (((a+b)+c)+d)+ ... ELSE sum _ MathConstructors.MakeDifference[sum, addend]; dIn _ dIn.rest; ENDLOOP; RETURN[sum]; }; LegalFirstChar: PUBLIC AC.LegalFirstCharOp = { data: PolynomialRingData _ NARROW[structure.data]; firstCharMethod: Method _ AC.LookupMethodInStructure[$legalFirstChar, data.baseCoeffRing]; IF AC.ApplyLegalFirstCharMethod[firstCharMethod, char, data.baseCoeffRing] THEN RETURN[TRUE]; RETURN[VARSEQ.VariableFirstChar[char, data.allVariables] ]; }; Read: PUBLIC AC.ReadOp = { data: PolynomialRingData _ NARROW[structure.data]; dPoly: DP.DPolynomial; termChar: CHAR; [dPoly, termChar] _ DP.ReadDPoly[in, data.allVariables, data.baseCoeffRing]; RETURN[ PolyFromDPoly[dPoly, structure] ]; }; FromRope: PUBLIC AC.FromRopeOp = { stream: IO.STREAM _ IO.RIS[in]; out _ Read[stream, structure]; }; ToRope: PUBLIC AC.ToRopeOp ~ { data: PolynomialRingData _ NARROW[in.class.data]; out _ DP.DPolyToRope[DPolyFromPoly[in], data.allVariables, data.baseCoeffRing, NIL]; }; Write: PUBLIC AC.WriteOp ~ { IO.PutRope[ stream, ToRope[in] ] }; PolyToRope: PUBLIC PROC [in: Polynomial, termRope: Rope.ROPE _ NIL] RETURNS [out: Rope.ROPE] = { data: PolynomialRingData _ NARROW[in.class.data]; out _ DP.DPolyToRope[DPolyFromPoly[in], data.allVariables, data.baseCoeffRing, termRope]; }; WritePoly: PUBLIC PROC [in: Polynomial, out: IO.STREAM, termRope: Rope.ROPE _ NIL] = { out.PutF["\n %g \n", IO.rope[PolyToRope[in, termRope]] ]; }; PolyFromDPoly: PUBLIC PROC [in: DP.DPolynomial, polynomialRing: Object] RETURNS [out: Polynomial] = { polyRingData: PolynomialRingData _ NARROW[polynomialRing.data]; coeffRing: Object _ polyRingData.coeffRing; zero: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, polynomialRing, LIST[polynomialRing] ]; allVarsData: SEQ.SequenceData _ NARROW[polyRingData.allVariables.data]; numVars: CARDINAL = allVarsData.lengthPlus1 - 1; termDegree: CARDINAL; -- degree in main variable of current (output) term outTermDCoefficient: DP.DPolynomial; -- output term coefficient, still in DP rep outTermCoefficient: AC.Object; -- output term coefficient, converted to P rep outTerm: Term; -- completed output term outTerms, outTermsPointer: LIST OF Term _ NIL; IF in = DP.ZeroDPoly THEN RETURN[zero]; WHILE in#NIL DO termDegree _ DP.DVDegree[in.first.degreeVector, numVars]; -- degree in main variable IF numVars > 1 THEN { outTermDCoefficient _ LIST[ [in.first.coefficient, DP.DVRemoveMainVariablePower[in.first.degreeVector, numVars] ] ]; in _ in.rest; WHILE in#NIL AND DP.DVDegree[in.first.degreeVector, numVars] = termDegree DO outTermDCoefficient _ CONS[ [in.first.coefficient, DP.DVRemoveMainVariablePower[in.first.degreeVector, numVars] ], outTermDCoefficient]; in _ in.rest; ENDLOOP; outTermDCoefficient _ DP.DPReverse[ outTermDCoefficient ]; outTermCoefficient _ PolyFromDPoly[ outTermDCoefficient, coeffRing ]; } ELSE { outTermCoefficient _ in.first.coefficient; in _ in.rest; }; outTerm _ NEW[TermRec _ [ exponent: termDegree, coefficient: outTermCoefficient ] ]; IF outTerms # NIL THEN outTermsPointer _ outTermsPointer.rest _ LIST[outTerm] ELSE outTerms _ outTermsPointer _ LIST[outTerm]; ENDLOOP; RETURN[ NEW[AC.ObjectRec _ [flavor: StructureElement, class: polynomialRing, data: outTerms]] ] }; DPolyFromPoly: PUBLIC PROC [in: Polynomial] RETURNS [out: DP.DPolynomial] ~ { polyRingData: PolynomialRingData _ NARROW[in.class.data]; allVarsData: SEQ.SequenceData _ NARROW[polyRingData.allVariables.data]; numVars: CARDINAL = allVarsData.lengthPlus1 - 1; inTerms: LIST OF Term _ NARROW[in.data]; inTermDegree: CARDINAL; -- degree in main variable of current (input) term inTermDPolynomial: DP.DPolynomial; singleVariableIndex: CARDINAL = 1; ok: BOOL; degreeVec: DP.DegreeVector; IF IsZero[in] THEN RETURN[DP.ZeroDPoly]; out _ DP.ZeroDPoly; WHILE inTerms # NIL DO inTermDegree _ inTerms.first.exponent; IF numVars > 1 THEN { inTermDPolynomial _ DPolyFromPoly[NARROW[inTerms.first.coefficient, Polynomial]]; WHILE inTermDPolynomial#NIL DO out _ CONS[ [ inTermDPolynomial.first.coefficient, DP.DVAddMainVariablePower[inTermDPolynomial.first.degreeVector, numVars, inTermDegree] ], out]; inTermDPolynomial _ inTermDPolynomial.rest; ENDLOOP; } ELSE { [ok, degreeVec] _ DP.DVInsertVariablePower[singleVariableIndex, inTermDegree, NIL]; IF NOT ok THEN ERROR; out _ CONS[ [inTerms.first.coefficient, degreeVec], out]; }; inTerms _ inTerms.rest; ENDLOOP; out _ DP.DPReverse[out]; }; Monomial: PUBLIC AC.BinaryImbedOp = { structureData: PolynomialRingData _ NARROW[structure.data]; coeffRing: Object _ structureData.coeffRing; refExp: REF CARDINAL _ NARROW[data2]; exp: CARDINAL _ refExp^; equalMethod: Method _ AC.LookupMethodInStructure[$eqFormula, coeffRing]; zero: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, coeffRing, LIST[coeffRing] ]; IF NOT AC.StructureEqual[data1.class, coeffRing] THEN TypeError[]; -- check that we really are constructing an element of polynomialRing IF AC.ApplyPredNoLkpNoRecast[equalMethod, LIST[data1, zero] ] THEN -- check for zero coeff RETURN[ NEW[AC.ObjectRec _ [ flavor: StructureElement, class: structure, data: NIL ] ] ] ELSE { outTerm: Term _ NEW[TermRec _ [exponent: exp, coefficient: data1] ]; outTerms: LIST OF Term _ LIST[outTerm]; RETURN[ NEW[AC.ObjectRec _ [ flavor: StructureElement, class: structure, data: outTerms ] ] ]; }; }; LeadingCoefficient: PUBLIC AC.UnaryOp ~ { data: PolynomialRingData _ NARROW[arg.class.data]; coeffRing: Object _ data.coeffRing; polyData: PolynomialData; IF IsZero[arg] THEN RETURN[AC.ApplyLkpNoRecastObject[$zero, coeffRing, LIST[coeffRing] ]]; polyData _ NARROW[arg.data]; RETURN[polyData.first.coefficient]; }; Degree: PUBLIC AC.ElementRankOp ~ { polyData: PolynomialData; IF IsZero[arg] THEN RETURN[0]; polyData _ NARROW[arg.data]; RETURN[polyData.first.exponent]; }; Reductum: PUBLIC AC.UnaryOp ~ { polyData: PolynomialData; IF IsZero[arg] THEN RETURN[arg]; polyData _ NARROW[arg.data]; RETURN[ NEW[AC.ObjectRec _ [flavor: StructureElement, class: arg.class, data: polyData.rest] ] ]; }; Zero: PUBLIC AC.NullaryOp = { RETURN[ NEW[ AC.ObjectRec _ [flavor: StructureElement, class: structure, data: NIL]] ] }; One: PUBLIC AC.NullaryOp = { data: PolynomialRingData _ NARROW[structure.data]; RETURN[ Monomial[AC.ApplyLkpNoRecastObject[$one, data.coeffRing, LIST[data.coeffRing] ], NEW[CARDINAL _ 0], structure] ]; }; Add: PUBLIC AC.BinaryOp ~ { data: PolynomialRingData _ NARROW[firstArg.class.data]; coeffRing: Object _ data.coeffRing; zero: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, coeffRing, LIST[coeffRing] ]; addMethod: Method _ AC.LookupMethodInStructure[$sum, coeffRing]; equalMethod: Method _ AC.LookupMethodInStructure[$eqFormula, coeffRing]; inTerms1: LIST OF Term _ NARROW[firstArg.data]; inTerms2: LIST OF Term _ NARROW[secondArg.data]; outTerms, outTermsPointer, tail: LIST OF Term _ NIL; outTerm: Term; termToAdd: BOOL; IF IsZero[firstArg] THEN RETURN[secondArg]; IF IsZero[secondArg] THEN RETURN[firstArg]; WHILE inTerms1 # NIL AND inTerms2 # NIL DO termToAdd _ TRUE; SELECT inTerms1.first.exponent FROM < inTerms2.first.exponent => { outTerm _ inTerms2.first; inTerms2 _ inTerms2.rest; }; > inTerms2.first.exponent => { outTerm _ inTerms1.first; inTerms1 _ inTerms1.rest; }; = inTerms2.first.exponent => { coeff: AC.Object _ AC.ApplyNoLkpNoRecastObject[addMethod, LIST[inTerms1.first.coefficient, inTerms2.first.coefficient] ]; IF NOT AC.ApplyPredNoLkpNoRecast[equalMethod,LIST[coeff, zero] ] THEN outTerm _ NEW[TermRec _ [ exponent: inTerms2.first.exponent, coefficient: coeff ] ] ELSE termToAdd _ FALSE; inTerms1 _ inTerms1.rest; inTerms2 _ inTerms2.rest; }; ENDCASE; IF termToAdd THEN { IF outTerms # NIL THEN outTermsPointer _ outTermsPointer.rest _ LIST[outTerm] ELSE outTerms _ outTermsPointer _ LIST[outTerm]; }; ENDLOOP; IF inTerms1 = NIL THEN tail _ inTerms2 ELSE tail _ inTerms1; IF outTerms # NIL THEN outTermsPointer.rest _ tail ELSE outTerms _ tail; RETURN[ NEW[AC.ObjectRec _ [flavor: StructureElement, class: firstArg.class, data: outTerms] ] ]; }; Negate: PUBLIC AC.UnaryOp ~ { data: PolynomialRingData _ NARROW[arg.class.data]; coeffRing: Object _ data.coeffRing; negateMethod: Method _ AC.LookupMethodInStructure[$negation, coeffRing]; inTerms: LIST OF Term _ NARROW[arg.data]; outTerms, outTermsPointer: LIST OF Term _ NIL; outTerm: Term; IF IsZero[arg] THEN RETURN[arg]; WHILE inTerms # NIL DO outTerm _ NEW[TermRec _ [ exponent: inTerms.first.exponent, coefficient: AC.ApplyNoLkpNoRecastObject[negateMethod, LIST[inTerms.first.coefficient] ] ] ]; IF outTerms # NIL THEN outTermsPointer _ outTermsPointer.rest _ LIST[outTerm] ELSE outTerms _ outTermsPointer _ LIST[outTerm]; inTerms _ inTerms.rest; ENDLOOP; RETURN[ NEW[AC.ObjectRec _ [flavor: StructureElement, class: arg.class, data: outTerms] ] ]; }; Subtract: PUBLIC AC.BinaryOp ~ { RETURN[ Add[ firstArg, Negate[ secondArg] ] ]; }; Multiply: PUBLIC AC.BinaryOp ~ { data: PolynomialRingData _ NARROW[firstArg.class.data]; coeffRing: Object _ data.coeffRing; zeroPoly: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, firstArg.class, LIST[firstArg.class] ]; productMethod: Method _ AC.LookupMethodInStructure[$product, coeffRing]; inTerms1: LIST OF Term _ NARROW[firstArg.data]; inTerms2: LIST OF Term _ NARROW[secondArg.data]; outSummand: Polynomial; outSummandTerms, outSummandTermsPointer: LIST OF Term; outSummandTerm: Term; scratchInTerms1: LIST OF Term; result _ zeroPoly; IF IsZero[firstArg] OR IsZero[secondArg] THEN RETURN[result]; WHILE inTerms2 # NIL DO outSummandTerms _ outSummandTermsPointer _ NIL; scratchInTerms1 _ inTerms1; WHILE scratchInTerms1 # NIL DO coeff: AC.Object _ AC.ApplyNoLkpNoRecastObject[productMethod, LIST[ scratchInTerms1.first.coefficient, inTerms2.first.coefficient ] ]; outSummandTerm _ NEW[TermRec _ [ exponent: scratchInTerms1.first.exponent + inTerms2.first.exponent, coefficient: coeff ] ]; IF outSummandTerms # NIL THEN outSummandTermsPointer _ outSummandTermsPointer.rest _ LIST[outSummandTerm] ELSE outSummandTerms _ outSummandTermsPointer _ LIST[outSummandTerm]; scratchInTerms1 _ scratchInTerms1.rest; ENDLOOP; outSummand _ NEW[AC.ObjectRec _ [flavor: StructureElement, class: firstArg.class, data: outSummandTerms]]; result _ Add[result, outSummand]; inTerms2 _ inTerms2.rest; ENDLOOP; }; ObjectAndIntDesired: PUBLIC AC.UnaryToListOp ~ { RETURN[ LIST[arg, Ints.Ints] ]; -- arg assumed to be a Structure }; Power: PUBLIC AC.BinaryOp ~ { -- this simple algorithm is Structure independent power: INT _ Ints.ToINT[secondArg]; structure: Object _ firstArg.class; one: Object _ AC.ApplyLkpNoRecastObject[$one, structure, LIST[structure] ]; productMethod: Method _ AC.LookupMethodInStructure[$product, structure]; IF power < 0 THEN { invertMethod: Method _ AC.LookupMethodInStructure[$invert, structure]; temp: Object; IF invertMethod = NIL THEN ERROR; temp _ Power[firstArg, Ints.FromINT[ABS[power] ] ]; RETURN[AC.ApplyNoLkpNoRecastObject[invertMethod, LIST[temp] ] ]; }; IF power = 0 THEN RETURN[one]; result _ firstArg; FOR i:INT IN [2..power] DO result _ AC.ApplyNoLkpNoRecastObject[productMethod, LIST[firstArg, result] ]; ENDLOOP; }; Differentiate: PUBLIC AC.BinaryOp ~ { reorderedArg: Object _ NewMainVariable[firstArg, secondArg]; data: PolynomialRingData _ NARROW[reorderedArg.class.data]; coeffRing: Object _ data.coeffRing; fromRopeMethod: Method _ AC.LookupMethodInStructure[$fromRope, coeffRing]; productMethod: Method _ AC.LookupMethodInStructure[$product, coeffRing]; inTerms: LIST OF Term _ NARROW[reorderedArg.data]; outTerms, outTermsPointer: LIST OF Term _ NIL; outTerm: Term; reorderedResult: Object; IF Degree[reorderedArg] = 0 THEN RETURN[Zero[firstArg.class] ]; WHILE inTerms # NIL AND inTerms.first.exponent > 0 DO imbeddedExp: AC.Object _ AC.ApplyFromRopeMethod[fromRopeMethod, Convert.RopeFromCard[inTerms.first.exponent,10, FALSE], coeffRing]; newCoeff: AC.Object _ AC.ApplyNoLkpNoRecastObject[productMethod, LIST[imbeddedExp, inTerms.first.coefficient] ]; outTerm _ NEW[TermRec _ [exponent: inTerms.first.exponent-1, coefficient: newCoeff] ]; IF outTerms # NIL THEN outTermsPointer _ outTermsPointer.rest _ LIST[outTerm] ELSE outTerms _ outTermsPointer _ LIST[outTerm]; inTerms _ inTerms.rest; ENDLOOP; reorderedResult _ NEW[AC.ObjectRec _ [flavor: StructureElement, class: reorderedArg.class, data: outTerms] ]; RETURN[ Recast[reorderedResult, firstArg.class] ]; }; IndefIntegrate: PUBLIC AC.BinaryOp ~ { reorderedArg: Object _ NewMainVariable[firstArg, secondArg]; data: PolynomialRingData _ NARROW[reorderedArg.class.data]; coeffRing: Object _ data.coeffRing; variable: Object _ data.variable; fromRopeMethod: Method _ AC.LookupMethodInStructure[$fromRope, coeffRing]; fractionMethod: Method _ AC.LookupMethodInStructure[$fraction, coeffRing]; inTerms: LIST OF Term _ NARROW[reorderedArg.data]; outTerms, outTermsPointer: LIST OF Term _ NIL; newCoeff: AC.Object; outTerm: Term; reorderedResult: Object; IF Degree[reorderedArg] = 0 THEN RETURN[Zero[firstArg.class] ]; IF fractionMethod=NIL THEN RETURN[firstArg]; -- do nothing if no fraction method WHILE inTerms # NIL AND (inTerms.first.exponent > 0 OR inTerms.first.exponent = 0) DO imbeddedExp: AC.Object _ AC.ApplyFromRopeMethod[fromRopeMethod, Convert.RopeFromCard[inTerms.first.exponent+1,10, FALSE], coeffRing]; newCoeff _ AC.ApplyNoLkpRecastObject[fractionMethod, coeffRing, LIST[inTerms.first.coefficient, imbeddedExp] ]; -- Recast since fraction method may be coming from superClass; if so, coeffRing arg will be bogus, but need the placeholder outTerm _ NEW[TermRec _ [exponent: inTerms.first.exponent+1, coefficient: newCoeff] ]; IF outTerms # NIL THEN outTermsPointer _ outTermsPointer.rest _ LIST[outTerm] ELSE outTerms _ outTermsPointer _ LIST[outTerm]; inTerms _ inTerms.rest; ENDLOOP; reorderedResult _ NEW[AC.ObjectRec _ [ flavor: StructureElement, class: MakePolynomialStructure[newCoeff.class, SEQ.MakeSequence[LIST[variable], VARSEQ.VariableSequences] ], data: outTerms ] ]; -- pick up possible new quotient structure for (new) coefficients RETURN[ reorderedResult ]; -- return with possibly reordered variables }; MainVarEval: PUBLIC AC.BinaryOp ~ { data: PolynomialRingData _ NARROW[firstArg.class.data]; productMethod: Method _ AC.LookupMethodInStructure[$product, coeffRing]; sumMethod: Method _ AC.LookupMethodInStructure[$sum, coeffRing]; coeffRing: Object _ data.coeffRing; zero: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, coeffRing, LIST[coeffRing] ]; inTerms: LIST OF Term _ NARROW[firstArg.data]; IF NOT AC.StructureEqual[secondArg.class, coeffRing] THEN TypeError[]; IF IsZero[firstArg] THEN RETURN[zero]; result _ inTerms.first.coefficient; WHILE inTerms.rest # NIL DO degreeDelta: CARDINAL _ DegreeDelta[inTerms]; newAddend: AC.Object _ AC.ApplyNoLkpNoRecastObject[productMethod, LIST[result, Power[secondArg, Ints.FromINT[degreeDelta] ] ] ]; inTerms _ inTerms.rest; result _ AC.ApplyNoLkpNoRecastObject[sumMethod, LIST[newAddend, inTerms.first.coefficient] ]; ENDLOOP; result _ AC.ApplyNoLkpNoRecastObject[productMethod, LIST[result, Power[secondArg, Ints.FromINT[inTerms.first.exponent] ] ] ]; RETURN[ result ]; }; DegreeDelta: PUBLIC PROC [terms: LIST OF Term] RETURNS [CARDINAL] ~ { IF terms = NIL THEN RETURN[0]; IF terms.rest = NIL THEN RETURN[terms.first.exponent]; RETURN[terms.first.exponent - terms.rest.first.exponent]; }; SylvesterMatrix: PUBLIC AC.BinaryOp ~ { data: PolynomialRingData _ NARROW[firstArg.class.data]; coeffRing: Object _ data.coeffRing; degree1: CARDINAL _ Degree[firstArg]; degree2: CARDINAL _ Degree[secondArg]; size: CARDINAL _ degree1 + degree2; rows: MAT.RowSeq _ NEW[MAT.RowSeqRec[size]]; zero: AC.Object _ AC.ApplyLkpNoRecastObject[$zero, coeffRing, LIST[coeffRing] ]; matrixStructure: Object _ MAT.MakeMatrixStructure[coeffRing, size, size]; IF degree1 = 0 AND degree2 = 0 THEN RETURN[NIL]; -- undefined in this case IF degree1 = 0 THEN { IF IsZero[firstArg] THEN RETURN[NARROW[MAT.DiagonalMatrix[zero, matrixStructure] ] ] ELSE { polyData: PolynomialData _ NARROW[firstArg.data]; RETURN[NARROW[MAT.DiagonalMatrix[polyData.first.coefficient, matrixStructure] ] ]; }; }; IF degree2 = 0 THEN { IF IsZero[secondArg] THEN RETURN[NARROW[MAT.DiagonalMatrix[zero, matrixStructure] ] ] ELSE { polyData: PolynomialData _ NARROW[secondArg.data]; RETURN[NARROW[MAT.DiagonalMatrix[polyData.first.coefficient, matrixStructure] ] ]; }; }; FOR i:NAT IN [1..degree2] DO row: Matrices.Row _ NEW[Matrices.RowRec[size]]; in1Terms: LIST OF Term _ NARROW[firstArg.data]; FOR j:NAT IN [1..i-1] DO row[j] _ zero; ENDLOOP; row[i] _ in1Terms.first.coefficient; WHILE in1Terms.rest # NIL DO degreeDelta: CARDINAL _ DegreeDelta[in1Terms]; FOR j: NAT IN [1..degreeDelta-1] DO row[i+degree1-in1Terms.first.exponent+j] _ zero; ENDLOOP; in1Terms _ in1Terms.rest; row[i+degree1-in1Terms.first.exponent] _ in1Terms.first.coefficient; ENDLOOP; FOR j: NAT IN [1..in1Terms.first.exponent+(degree2-i)] DO row[size+1-j] _ zero; ENDLOOP; rows[i] _ row; ENDLOOP; FOR i:NAT IN [1..degree1] DO row: Matrices.Row _ NEW[Matrices.RowRec[size]]; in2Terms: LIST OF Term _ NARROW[secondArg.data]; FOR j:NAT IN [1..i-1] DO row[j] _ zero; ENDLOOP; row[i] _ in2Terms.first.coefficient; WHILE in2Terms.rest # NIL DO degreeDelta: CARDINAL _ DegreeDelta[in2Terms]; FOR j: NAT IN [1..degreeDelta-1] DO row[i+degree2-in2Terms.first.exponent+j] _ zero; ENDLOOP; in2Terms _ in2Terms.rest; row[i+degree2-in2Terms.first.exponent] _ in2Terms.first.coefficient; ENDLOOP; FOR j: NAT IN [1..in2Terms.first.exponent+(degree1-i)] DO row[size+1-j] _ zero; ENDLOOP; rows[degree2+i] _ row; ENDLOOP; result _ NEW[AC.ObjectRec _ [flavor: StructureElement, class: matrixStructure, data: rows] ]; }; Resultant: PUBLIC AC.BinaryOp ~ { sylvesterMatrix: MAT.Matrix _ SylvesterMatrix[firstArg, secondArg]; RETURN[MAT.Determinant[sylvesterMatrix] ]; }; GCD: PUBLIC AC.BinaryOp ~ { polyRingData: PolynomialRingData _ NARROW[firstArg.class.data]; allVariables: Object _ polyRingData.allVariables; varRope: ROPE _ NARROW[AC.ApplyLkpNoRecastRef[$toRope, allVariables.class, LIST[allVariables] ] ]; resultStream: IO.STREAM _ RemoteAlgebra.SAC2PolynomialBinaryOp[varRope, ToRope[firstArg], ToRope[secondArg] ]; RETURN[Read[resultStream, firstArg.class] ]; }; Remainder: PUBLIC AC.BinaryOp ~ { newDividend: Polynomial _ firstArg; polyRingData: PolynomialRingData _ NARROW[firstArg.class.data]; coeffRing: Object _ polyRingData.coeffRing; fractionMethod: Method _ AC.LookupMethodInStructure[$fraction, coeffRing]; IF NOT AC.IsCategory[coeffRing, field] AND AC.IsCategory[coeffRing, divisionAlgebra] THEN TypeError[]; WHILE Degree[newDividend] >= Degree[secondArg] DO coeff: AC.Object _ AC.ApplyNoLkpNoRecastObject[fractionMethod, LIST[LeadingCoefficient[newDividend], LeadingCoefficient[secondArg] ] ]; degreeDelta: CARDINAL _ Degree[newDividend] - Degree[secondArg]; multiplier: Polynomial _ Monomial[coeff, NEW[CARDINAL _ degreeDelta], firstArg.class]; product: Polynomial _ Multiply[multiplier, secondArg]; newDividend _ Subtract[newDividend, product]; ENDLOOP; RETURN[newDividend]; }; Equal: PUBLIC AC.EqualityOp ~ { RETURN[IsZero[Subtract[firstArg, secondArg] ] ]; }; IsZero: PUBLIC AC.UnaryPredicate ~ { RETURN[AC.HasProperty[arg.class, $polynomialStructure] AND arg.data = NIL] }; ObjectAndVariableDesired: PUBLIC AC.UnaryToListOp ~ { RETURN[ LIST[arg, Variables.Variables] ]; -- arg assumed to be a polynomial Structure }; NewMainVariable: PUBLIC AC.BinaryOp ~ { polyRingData: PolynomialRingData _ NARROW[firstArg.class.data]; allVars: VARSEQ.VariableSequence _ polyRingData.allVariables; reorderedVars: VARSEQ.VariableSequence _ VARSEQ.NewMainVariable[allVars, secondArg]; newStruct: Object _ MakePolynomialStructure[polyRingData.baseCoeffRing, reorderedVars]; RETURN[ Recast[firstArg, newStruct] ]; }; polynomialClass: AC.Object _ AC.MakeClass["polynomialClass", NIL, NIL]; polynomialsOverCommRingClass: AC.Object _ AC.MakeClass["polynomialsOverCommRingClass", polynomialClass, NIL]; polynomialsOverOrderedCommRingClass: AC.Object _ AC.MakeClass["polynomialsOverOrderedCommRingClass", polynomialsOverCommRingClass, NIL]; polynomialsOverOrderedCommFieldClass: AC.Object _ AC.MakeClass["polynomialsOverOrderedCommFieldClass", polynomialsOverOrderedCommRingClass, NIL]; polynomialsOverNonCommRingClass: AC.Object _ AC.MakeClass["polynomialsOverNonCommRingClass", polynomialClass, NIL]; polynomialStructureMethod: Method _ AC.MakeMethod[Value, FALSE, NIL, NIL, "polynomialStructure"]; groupCategoryMethod: Method _ AC.MakeMethod[Value, FALSE, NEW[AC.Category _ group], NIL, "group"]; ringCategoryMethod: Method _ AC.MakeMethod[Value, FALSE, NEW[AC.Category _ ring], NIL, "ring"]; euclideanDomainMethod: Method _ AC.MakeMethod[Value, FALSE, NIL, NIL, "euclideanDomain"]; orderedMethod: Method _ AC.MakeMethod[Value, FALSE, NIL, NIL, "ordered"]; commutativeMethod: Method _ AC.MakeMethod[Value, FALSE, NIL, NIL, "commutative"]; shortPrintNameMethod: Method _ AC.MakeMethod[ToRopeOp, FALSE, NEW[AC.ToRopeOp _ ShortPrintName], NIL, "shortPrintName"]; recastMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Recast], NIL, "recast"]; canRecastMethod: Method _ AC.MakeMethod[BinaryPredicate, TRUE, NEW[AC.BinaryPredicate _ CanRecast], NIL, "canRecast"]; toExprMethod: Method _ AC.MakeMethod[ToExprOp, FALSE, NEW[AC.ToExprOp _ ToExpr], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "toExpr"]; fromRopeMethod: Method _ AC.MakeMethod[FromRopeOp, TRUE, NEW[AC.FromRopeOp _ FromRope], NIL, "fromRope"]; readMethod: Method _ AC.MakeMethod[ReadOp, FALSE, NEW[AC.ReadOp _ Read], NIL, "read"]; toRopeMethod: Method _ AC.MakeMethod[ToRopeOp, FALSE, NEW[AC.ToRopeOp _ ToRope], NIL, "toRope"]; monomialMethod: Method _ AC.MakeMethod[BinaryImbedOp, FALSE, NEW[AC.BinaryImbedOp _ Monomial], NIL, "monomial"]; leadingCoeffMethod: Method _ AC.MakeMethod[UnaryOp, TRUE, NEW[AC.UnaryOp _ LeadingCoefficient], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "leadingCoeff"]; degreeMethod: Method _ AC.MakeMethod[ElementRankOp, TRUE, NEW[AC.ElementRankOp _ Degree], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "degree"]; reductumMethod: Method _ AC.MakeMethod[UnaryOp, TRUE, NEW[AC.UnaryOp _ Reductum], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "reductum"]; parenMethod: Method _ AC.MakeMethod[UnaryOp, FALSE, NEW[AC.UnaryOp _ AC.Copy], NIL, "paren"]; zeroMethod: Method _ AC.MakeMethod[NullaryOp, FALSE, NEW[AC.NullaryOp _ Zero], NIL, "zero"]; oneMethod: Method _ AC.MakeMethod[NullaryOp, FALSE, NEW[AC.NullaryOp _ One], NIL, "one"]; sumMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Add], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "sum"]; negationMethod: Method _ AC.MakeMethod[UnaryOp, TRUE, NEW[AC.UnaryOp _ Negate], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "negation"]; differenceMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Subtract], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "difference"]; productMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Multiply], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "product"]; powerMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Power], NEW[AC.UnaryToListOp _ ObjectAndIntDesired], "power"]; derivativeMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Differentiate], NEW[AC.UnaryToListOp _ ObjectAndVariableDesired], "derivative"]; partialDerivativeMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Differentiate], NEW[AC.UnaryToListOp _ ObjectAndVariableDesired], "partialDerivative"]; indefIntMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ IndefIntegrate], NEW[AC.UnaryToListOp _ ObjectAndVariableDesired], "indefiniteIntegrate"]; newMainVariableMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ NewMainVariable], NEW[AC.UnaryToListOp _ ObjectAndVariableDesired], "newMainVarialbe"]; mainVarEvalMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ MainVarEval], NIL, "mainVarEval"]; sylvesterMatrixMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ SylvesterMatrix], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "sylvesterMatrix"]; resultantMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Resultant], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "resultant"]; gcdMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ GCD], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "gcd"]; remainderMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Remainder], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "remainder"]; equalMethod: Method _ AC.MakeMethod[BinaryPredicate, TRUE, NEW[AC.BinaryPredicate _ Equal], NEW[AC.UnaryToListOp _ AC.DefaultDesiredArgStructures], "equals"]; makePolynomialStructureMethod: Method _ AC.MakeMethod[PolynomialStructureConstructor, FALSE, NEW[AC.PolynomialStructureConstructor _ MakePolynomialStructure], NIL, "makePolynomialStructure"]; AC.AddMethodToClass[$polynomialStructure, polynomialStructureMethod, polynomialClass]; AC.AddMethodToClass[$category, groupCategoryMethod, polynomialClass]; AC.AddMethodToClass[$shortPrintName, shortPrintNameMethod, polynomialClass]; AC.AddMethodToClass[$recast, recastMethod, polynomialClass]; AC.AddMethodToClass[$canRecast, canRecastMethod, polynomialClass]; AC.AddMethodToClass[$toExpr, toExprMethod, polynomialClass]; AC.AddMethodToClass[$fromRope, fromRopeMethod, polynomialClass]; AC.AddMethodToClass[$read, readMethod, polynomialClass]; AC.AddMethodToClass[$toRope, toRopeMethod, polynomialClass]; AC.AddMethodToClass[$monomial, monomialMethod, polynomialClass]; AC.AddMethodToClass[$leadingCoeff, leadingCoeffMethod, polynomialClass]; AC.AddMethodToClass[$degree, degreeMethod, polynomialClass]; AC.AddMethodToClass[$reductum, reductumMethod, polynomialClass]; AC.AddMethodToClass[$paren, parenMethod, polynomialClass]; AC.AddMethodToClass[$zero, zeroMethod, polynomialClass]; AC.AddMethodToClass[$one, oneMethod, polynomialClass]; AC.AddMethodToClass[$sum, sumMethod, polynomialClass]; AC.AddMethodToClass[$negation, negationMethod, polynomialClass]; AC.AddMethodToClass[$difference, differenceMethod, polynomialClass]; AC.AddMethodToClass[$eqFormula, equalMethod, polynomialClass]; AC.AddMethodToClass[$newMainVariable, newMainVariableMethod, polynomialClass]; AC.AddMethodToClass[$category, ringCategoryMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$commutative, commutativeMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$product, productMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$pow, powerMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$dDx, derivativeMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$partialDeriv, partialDerivativeMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$indefInt, indefIntMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$mainVarEval, mainVarEvalMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$sylvesterMatrix, sylvesterMatrixMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$resultant, resultantMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$gcd, gcdMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$ordered, orderedMethod, polynomialsOverOrderedCommRingClass]; AC.AddMethodToClass[$euclideanDomain, euclideanDomainMethod, polynomialsOverOrderedCommFieldClass]; AC.AddMethodToClass[$remainder, remainderMethod, polynomialsOverOrderedCommFieldClass]; AC.AddMethodToClass[$makePolynomialStructure, makePolynomialStructureMethod, Structures.StructuresClass]; AC.AddMethodToClass[$Polynomials, makePolynomialStructureMethod, Structures.StructuresClass]; END. \PolynomialsImpl.mesa Last Edited by: Arnon, June 10, 1985 4:19:22 pm PDT Points, Types Errors Polynomial Structure Ops PrintName: PUBLIC AC.PrintNameProc = { data: PolynomialRingData _ NARROW[structure.data]; RETURN[Rope.Cat[ "Polynomials in ", VARSEQ.VariableSequenceToRope[data.variable], " over ", data.coeffRing.class.printName[data.coeffRing] ] ]; }; Characteristic: PUBLIC AC.StructureRankOp = { data: PolynomialRingData _ NARROW[structure.data]; RETURN[ data.coeffRing.class.characteristic[data.coeffRing] ] }; Conversion and IO Args are a StructureElement and a Structure reCastSource: Object; Already in this structure Source Object to recast is a variable as an elt of a SingleSetStructure Source Object to recast is a variable as an elt of VARS.IsVariables Check that variable occurs in destination Structure's allVars Do secondArg.class.FromRope[firstArg.class.ToRope[firstArg] ]; avoids having to get into firstArg's internals and possibly introduce new variables Object to recast is a polynomial Check that sourceStructure's allVars are a subset of destination Structure's allVars Check that canRecast source baseCoeffRing to dest baseCoeffRing Do secondArg.class.FromRope[firstArg.class.ToRope[firstArg] ]; avoids having to get into firstArg's internals and possibly reorder, possibly introduce new variables Source Object to recast NOT a polynomial; Check if canRecast sourceStructure to dest baseCoeffRing; If so, do it, and return as a constant monomial -- This way works for univariate, but not multivariate, polynomials reCastSource _ AC.ApplyNoLkpNoRecastObject[destBaseRecastMethod, LIST[firstArg, destBaseCoeffRing] ]; RETURN[ Monomial[reCastSource, NEW[CARDINAL _ 0], destPolyRing] ]; -- Can't do it Args are either [Structure, Structure] or [StructureElement, Structure] Source Object to recast is a variable as an elt of a SingleSetStructure Source Object to recast is a SingleSetStructure; check whether underlying set consists of a single variable; if so, make it the arg Source Object to recast is one or more variables Check that variable occurs in destination Structure's allVars Source Object to recast is a polynomial Check that source Structure's allVars are a subset of destination Structure's allVars Check that canRecast source baseCoeffRing to dest baseCoeffRing Source Object to recast NOT a polynomial; Check if canRecast sourceStructure to dest baseCoeffRing Legal first char of polynomial is either legal first char of coefficient, or first char of some variable (this all with reference to distributed rep) ToIndexRope: PUBLIC AC.ToRopeOp ~ { out _ "Pol"; }; Constructors Selectors Arithmetic Does not assume that coefficient multiplication is commutative Simple or partial differentiation. firstArg is polynomial, secondArg is variable. firstArg is reordered to make secondArg its main variable, then partially differentiated, then result reordered back to original firstArg Structure. Assumes that CARDINAL exponent values can be imbedded in coeffRing, in particular, that coeffRing.class.fromRope[Convert.RopeFromCard[arg.data.first.exponent]] works. If we are here, variable of diff occurs in both firstArg and reorderedArg, result of diff will be nonzero, and we know we can recast back into firstArg Structure Indefinite integration. firstArg is polynomial, secondArg is variable. firstArg is reordered to make secondArg its main variable, then integrated, then result reordered back to original firstArg Structure. Constant of integration set to zero. Currently (some superClass of) coeffRing must have a fraction method, i.e. be a field, and its DesiredArgStructures proc must be able to recast elements of coeffRing. I.e. current proc won't work for multivariate integrands. Assumes that CARDINAL exponent values can be imbedded in coeffRing, in particular, that coeffRing.class.fromRope[Convert.RopeFromCard[arg.data.first.exponent]] works. If we are here, variable of int occurs in both firstArg and reorderedArg, result of int will be nonzero, and we know we can recast back into firstArg Structure AllVarEval: PUBLIC AC.BinaryOp ~ { data: PolynomialRingData _ NARROW[firstArg.class.data]; baseCoeffRing: Object _ data.baseCoeffRing; removeMain: Points.Point; mainCood: AC.Object; pointData: Points.PointData _ NARROW[secondArg.data]; inTerms: LIST OF Term _ NARROW[firstArg.data]; coeff: Polynomial; IF NOT pointData.dimensionPlus1 = data.allVariables.lengthPlus1 THEN OperationError[$BadPointLength]; IF pointData.dimensionPlus1 - 1 = 1 THEN { at: AC.Object _ NARROW[secondArg.data, Points.PointData][1]; RETURN[MainVarEval[firstArg, at] ]; }; removeMain _ Points.RemoveMainCood[secondArg]; mainCood _ Points.MainCood[secondArg]; -- element of baseCoeffRing IF NOT baseCoeffRing.class.isElementOf[mainCood, baseCoeffRing] THEN TypeError[]; IF IsZero[firstArg] THEN RETURN[baseCoeffRing.class.zero[baseCoeffRing] ]; coeff _ NARROW[inTerms.first.coefficient]; result _ AllVarEval[coeff, removeMain]; -- element of baseCoeffRing WHILE inTerms.rest # NIL DO degreeDelta: CARDINAL _ DegreeDelta[inTerms]; newAddend: AC.Object _ baseCoeffRing.class.multiply[result, Power[mainCood, Ints.FromINT[degreeDelta] ] ]; inTerms _ inTerms.rest; coeff _ NARROW[inTerms.first.coefficient]; result _ baseCoeffRing.class.add[newAddend, AllVarEval[coeff, removeMain] ]; ENDLOOP; result _ baseCoeffRing.class.multiply[result, Power[mainCood, Ints.FromINT[inTerms.first.exponent] ] ]; RETURN[ result ]; }; Subst: PUBLIC AC.BinaryOp ~ { polyRing: Object _ firstArg.class; data: PolynomialRingData _ NARROW[polyRing.data]; inTerms: LIST OF Term _ NARROW[firstArg.data]; IF NOT polyRing.class.isElementOf[secondArg, polyRing] THEN TypeError[]; IF IsZero[firstArg] THEN RETURN[firstArg]; result _ Monomial[inTerms.first.coefficient, NEW[CARDINAL _ 0], polyRing]; -- lift coefficient WHILE inTerms.rest # NIL DO degreeDelta: CARDINAL _ DegreeDelta[inTerms]; trailCoeff: Polynomial; newAddend: Polynomial _ NARROW[polyRing.class.multiply[result, Power[secondArg, Ints.FromINT[degreeDelta] ] ] ]; inTerms _ inTerms.rest; trailCoeff _ Monomial[inTerms.first.coefficient, NEW[CARDINAL _ 0], polyRing]; -- lift result _ NARROW[ polyRing.class.add[newAddend, trailCoeff] ]; ENDLOOP; result _ NARROW[ polyRing.class.multiply[result, Power[secondArg, Ints.FromINT[inTerms.first.exponent] ] ] ]; RETURN[ result ]; }; Comparison Sign: PUBLIC AC.CompareToZeroOp ~ { data: PolynomialRingData _ NARROW[arg.class.data]; polyData: PolynomialData; IF NOT arg.class.class.ordered THEN TypeError[$UnorderedStructure]; IF IsZero[arg] THEN RETURN[equal]; -- needed since arg.data = NIL for zero poly polyData _ NARROW[arg.data]; RETURN[data.coeffRing.class.sign[polyData.first.coefficient] ]; }; Abs: PUBLIC AC.UnaryOp ~ { IF NOT arg.class.class.ordered THEN TypeError[$UnorderedStructure]; IF Sign[arg] = less THEN RETURN[Negate[arg]] ELSE RETURN[arg]; }; Compare: PUBLIC AC.BinaryCompareOp ~ { IF NOT firstArg.class.class.ordered THEN TypeError[$UnorderedStructure]; RETURN[Sign[ Subtract[firstArg, secondArg] ]]; }; Utility firstArg is polynomial, secondArg is a Variable that may or may not occur in firstArg's allVariables. result is firstArg with reordered variables so that secondArg is new main variable. Order of other variables is preserved Start Code polynomialsOverCommOrderedRingClass: PUBLIC AC.StructureClass ** Old ** NEW[AC.StructureClassRec _ [ characteristic: ClassCharacteristic, isElementOf: AC.defaultElementOfProc, integralDomain: TRUE, -- not necessarily accurate; need separate classrecs gcdDomain: FALSE, -- not necessarily accurate; need separate classrecs gcd: NIL, -- should have a poly gcd proc here when appropriate euclideanDomain: FALSE, ] ]; subclass[polynomialClass] subclass[polynomialsOverCommRingClass] subclass[polynomialsOverOrderedCommRingClass] subclass[polynomialClass]; this is e.g. for polynomials with matrix coefficients allVarEvalMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ AllVarEval], NIL, "allVarEval"]; substMethod: Method _ AC.MakeMethod[BinaryOp, TRUE, NEW[AC.BinaryOp _ Subst], NIL, "substitute"]; AC.AddMethodToClass[$allVarEval, allVarEvalMethod, polynomialsOverCommRingClass]; AC.AddMethodToClass[$subst, substMethod, polynomialsOverCommRingClass]; Κ,Ÿ˜Jšœ™J™3J˜šΟk ˜ Jšœ˜J˜J˜J˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜J™J˜ Jšœ˜Jšœ ˜ J˜ Jšœ ˜ —J˜head2šœœ˜Jšœœ˜£Jšœ˜J˜—Jšœœœœ œœ œœ˜ˆJ˜headšΟn™Icodešœœœ˜Mšœœœœ˜Mšœœœ˜Mšœœœ˜—™Jš œ œœ œœ˜0Jšœœœœ˜DJšœœœœ˜@Jš œ œœ œœ˜>Jš œœœ œœ˜C—šœ™šžœœœ#˜EMšœ'˜'Mšœœ ˜Mšœœ˜&Mšœ'˜'Mšœœœ˜3šœœ˜#Mšœ5œ˜SMšœœ˜'M˜—šœ˜Mšœ˜Mšœœ˜(M˜—šœ(œΟc(˜YJšœœ˜8Mšœ#˜#Mšœœ*˜˜_šœ ˜Jšœœ,œ˜RJšœ#˜#Jšœ˜—J˜—šžœ œ™-Jšœœ™2Jšœ7™=Jšœ™—šžœ œ˜3Jšœœœœ˜.Jšœœ4œ˜CJšœ˜——šœ™šžœ œ ˜Jšœ+™+J˜!Jšœ'œ˜AMšœœ2˜QJšœ;˜;Mšœ"œ8˜\Mšœœ5˜VJšœ œœ˜Jšœ)˜)Mšœ˜Jšœ œ˜J™J˜J™Jšœœ/œœ ˜JJ˜JšœH™HšœœŸ.˜RMšœ=˜=Jšœ!˜!J˜J™—Jšœ3œ ™DJšœœœ˜+™J™=Jš œœœ œœ œ4˜Jš œœœœœ˜)J˜Jšœ“™“Jšœ œœ/œ ˜VJšœœE˜NJ˜J˜—J™!šœ(œ˜0Jšœ)œ˜FJšœ?˜?J˜J™TJšœœV˜lJš œœœœœ˜)J˜Jšœ?™?Jšœ œœ0œ-˜tJš œœ œœœ˜!J˜Jšœ₯™₯Jšœ œœ/œ ˜VJšœœE˜NJ˜J˜—Jšœœx™“Jšœ œœ0œ)˜pšœ œ˜Jšœ œœ/œ ˜VJšœœE˜NJ˜JšœD™DJšœœ0œ ™eJšœœœ™BJ™—J˜J™ Jšœœ˜ M˜J˜—šž œ œ˜(JšœG™GJ˜!Jšœ'œ˜AJšœ;˜;Mšœ"œ8˜\Jšœ œœ˜Jšœœ$œœœœ œœ˜‘Mšœ˜Mšœœœ œ˜#J˜Jš œœ/œœœŸ˜WJ˜JšœH™Hšœ"œœŸ.˜wMšœ=˜=Jšœ!˜!Mšœœ ˜J˜—J˜Jšœ…™…šœœ%œ˜PJšœ4œ˜JJšœK˜KJšœ ˜ Jš œœœHœœœ˜dJšœœ%˜?Mšœ ˜ Mšœ#˜#Jšœ!˜!J˜J™—J™1šœœœ˜+J˜J™=Jšœœ˜Jš œ$œœœŸv˜±Jšœœœœ ˜7Jšœ&œœ4˜Jšœ˜J˜J˜—J™(šœ(œ˜0Jšœ)œ˜FJšœ?˜?J˜J™UJšœœV˜lJš œœœœœ˜+J˜Jšœ?™?Jšœ œœ0œ-˜tJšœ ˜J˜J˜—JšœœG™bJšœ œœ0œ)˜pJšœ ˜M˜J˜—šžœœœ ˜Jšœœ˜1Jšœœ!˜(Jšœœ˜Jšžœœ&˜/Jšœ'˜'Jšœ œœ˜Jšœ$œ˜)Jšœœ˜Jšœœ˜Jšœ œ˜Jšœ˜Jšœœ˜Jšœœ œ)œ˜NMšœœ0˜HMšœœ-˜FJšœ œœ"˜6Mšœ˜šž œœ œ˜&Jšœ˜šœ œ˜Jšœ œ-˜;Jšœ œ%œ ˜?J˜—šœŸ;˜BJšœ˜Jšœ˜J˜—Jšœœ˜Jšœœ˜Jšœ œ˜$šœ œ˜Jšœœ˜Jšœ8˜8Jšœ5˜5šœ ˜šœ#˜#Jšœœ#˜2Jšœ8˜8Jšœ˜——š˜Jšœ œœ#˜<—šœœ˜/Jšœ7˜7—Jšœœ˜Jšœ˜—šœœœ˜š œœœ%œœ˜IJšœ&œœ%œ˜o—J˜—Jšœ  œ%œ˜Ošœ œ˜&Jšœ/˜/—M˜—šœ œ˜Mšœ œ+˜:Mšœ œ*˜8J˜—Jšœœ œœ!˜BJšœ œŸ ˜ J˜ Jšœ˜šœœ˜Jšœ œŸ˜%šœ˜Jšœ,Ÿ˜A—š˜Jšœ3˜3—Jšœ˜Jšœ˜—Jšœ˜ J˜J˜—šžœ œ˜.Mšœ•™•Jšœœ˜2Jšœœ>˜ZMš œœFœœœ˜]Mšœœ.˜;Jšœ˜—šžœœœ ˜Jšœœ˜2Jšœœ ˜Jšœ œ˜Jšœœ6˜LJšœ$˜*J˜M˜—šžœœœ˜"Mš œœœœœ˜Mšœ˜M˜M˜—šžœ œ ˜Jšœœ˜1JšœœGœ˜TJ˜J˜—šž œ œ ™#Jšœ ™ J™J™—šžœ œ ˜Jšœ˜ Jšœ˜J˜—šž œœœ!œœœ œ˜`Jšœœ˜1JšœœQ˜YJ˜J˜—šž œœœœœœœ˜VJšœœ"˜9Jšœ˜J™—š ž œœœœ&œ˜eJšœ#œ˜?Jšœ+˜+Jšœœ œ/œ˜ZJšœ œœ!˜GMšœ œ˜0Jšœ œŸ3˜IJšœœŸ+˜QJšœœ Ÿ.˜MMšœŸ˜'Mšœœœœ˜.Jšœœ œœ˜'šœœ˜Jšœ œ+Ÿ˜Tšœ œ˜Jšœœœ?˜tJ˜ š œœœœ7˜LJšœœœS˜ˆJ˜ Jšœ˜—Jšœœ"˜:JšœE˜EJ˜—šœ˜Jšœ*˜*J˜ J˜—šœ œ ˜Jšœ˜Jšœ˜J˜—šœ œœ*œ ˜MMšœœ ˜0—Mšœ˜—JšœœœQ˜_M˜J˜—š ž œœœœœ˜MJšœ#œ˜9Jšœ œœ!˜GMšœ œ˜0Mšœ œœœ ˜(JšœœŸ2˜JJšœœ ˜"Jšœœ˜"Jšœœ˜ Jšœ œ˜Jšœ œœœ ˜(Jšœœ ˜šœ œ˜Mšœ&˜&šœ œ˜Jšœ"œ)˜Qšœœ˜Jšœœ)œ]˜’Jšœ+˜+Jšœ˜—J˜—šœ˜Mšœœ:œ˜SJšœœœœ˜Jšœœ/˜9J˜—Jšœ˜Jšœ˜—Jšœœ˜M˜——šœ ™ šžœœœ˜%Jšœ$œ˜;Jšœ,˜,Jšœœœœ˜%Jšœœ ˜Mšœœ0˜HJšœœ œ*œ˜PJš œœœ(œŸE˜ˆš œœ%œœŸ˜Zšœœœ˜Jšœ˜Jšœ˜Jšœ˜ J˜——šœ˜Mšœœ1˜DMšœ œœœ ˜'šœœœ˜Jšœ˜Jšœ˜Jšœ˜J˜—J˜—J˜——™ šžœœœ ˜)Jšœœ˜2Jšœ#˜#Mšœ˜Jš œ œœœ*œ˜ZJšœ œ ˜Mšœ˜#J˜J™—šžœœœ˜#Mšœ˜Jšœ œœ˜Jšœ œ ˜Jšœ˜ J˜J˜—šžœœœ ˜Mšœ˜Jšœ œœ˜ Jšœ œ ˜JšœœœS˜aJ˜J˜——šœ ™ šžœ œ˜Jšœœœ@œ˜VJšœ˜—šžœ œ˜Jšœœ˜2Mš œ œ.œœœ˜yJšœ˜—šžœœœ ˜Jšœœ˜7Jšœ#˜#Jšœœ œ*œ˜PJšœ@˜@JšœH˜HMšœ œœœ˜/Mšœ œœœ˜0Mšœ!œœœ˜4Mšœ˜Jšœ œ˜Jšœœœ ˜+Jšœœœ ˜+š œ œœ œ˜*Jšœ œ˜šœ˜#šœ˜Jšœ˜Jšœ˜J˜—šœ˜Jšœ˜Jšœ˜J˜—šœ˜Jšœœ œ%œ;˜yš œœœ$œ˜Ešœ œ ˜Jšœ"˜"Jšœ˜J˜——š˜Jšœ œ˜—Jšœ˜Jšœ˜J˜—Mšœ˜—šœ œ˜Mšœ œœ*œ ˜MMšœœ ˜0M˜—Mšœ˜—Mšœ œœœ˜<šœ œœ˜2Mšœ˜—JšœœœS˜aM˜J˜—šžœœœ ˜Jšœœ˜2Jšœ#˜#Jšœœ/˜HMšœ œœœ ˜)Mšœœœœ˜.Mšœ˜Jšœ œœ˜ šœ œ˜šœ œ ˜Jšœ!˜!Jšœ œ(œ˜XJšœ˜—šœ œœ*œ ˜MMšœœ ˜0—Jšœ˜Jšœ˜—JšœœœN˜\M˜J˜—šžœœœ ˜ Jšœ(˜.J˜J˜—šžœœœ ˜ Jšœ>™>Jšœœ˜7Jšœ#˜#Jšœ œ œ/œ˜^Jšœœ.˜HMšœ œœœ˜/Mšœ œœœ˜0Jšœ˜Mšœ)œœ˜6Jšœ˜Jšœœœ˜Jšœ˜Jšœœœœ ˜=šœ œ˜Mšœ+œ˜/Jšœ˜šœœ˜šœœ œ)œ˜CJšœ"˜"Jšœ˜Jšœ˜—šœœ ˜ JšœC˜CJšœ˜J˜—šœœœ8œ˜iMšœ,œ˜E—Jšœ'˜'Jšœ˜—Jšœ œœW˜jJšœ!˜!Jšœ˜Jšœ˜—M˜M˜—šžœœœ˜0JšœœŸ ˜@J˜J˜—šžœœœŸ1˜OMšœœ˜#M˜#Mšœœ)œ˜KMšœœ.˜Hšœ œ˜Mšœœ-˜FMšœ ˜ Mšœœœœ˜!Mšœ$œ ˜3Mšœœ(œ ˜@M˜—Mšœ œœ˜Mšœ˜šœœœ ˜Mšœ œ)œ˜MMšœ˜—M˜M˜—šž œœœ ˜%J™θJšœ œ‘™¦Jšœ<˜M™J™—šžœœœ™&Mšœœœ ™HJšœ(™.M™——™šžœœœ˜5JšœœŸ+˜UJ˜J˜—šžœœœ ˜'Jšœα™αJšœ#œ˜?Jšœ œ.˜=Jšœœœ%˜TJšœW˜WJšœ ˜&J˜——™ š œ%œœœœ™eJšœ$™$Mšœ œ™%MšœœŸ4™JMšœ œŸ4™FMšœœŸ4™>Mšœœ™M™M™—š œœ œœœ˜GM˜—šœœ œ<œ˜mMšœ™M˜—šœ%œ œPœ˜ˆMšœ&™&M˜—šœ&œ œXœ˜‘Mšœ-™-M˜—šœ!œ œ?œ˜sMšœS™SM˜—J˜Jš œ$œœœœ˜aJš œœœœœœ ˜bJš œœœœœœ ˜_Jš œ œœœœ˜YJš œœœœœ ˜IJš œœœœœ˜QJš œœœœœœ˜xJš œœœœœœ ˜_Jš œœœœœœ˜vJšœœœœœœœœ)˜“Jš œœœœœœ˜iJš œœœœœœ ˜VJš œœœœœœ ˜`Jš œœœœœœ˜pJšœœœœœ œœœ/˜¨Jšœœœœœœœœ)˜œJšœœœœœœœœ+˜–Jš œœœœœ œœ ˜]Jš œœœœœœ ˜\Jš œœœœœœ ˜YJšœœœœœœœœ&˜‰Jšœœœœœœœœ+˜”Jšœœœœœœœœ-˜œJšœœœœœœœœ*˜–Jš œœœœœœœ0˜„Jš œœœœœœœ:˜›Jš œ"œœœœœœA˜©Jš œœœœœœœC˜£Jšœ œœœœ žœœœ?˜§Jš œœœœœœ˜nJš œœœœœ ž œœ™kJš œœœœœ žœœ™aJšœ œœœœ žœœœœ2˜­Jšœœœœœ ž œœœœ,˜›Jšœœœœœ žœœœœ&˜‰Jšœœœœœ ž œœœœ,˜›Jšœœœœœœœœ)˜žJ˜Jš œ(œ,œœœ<œ˜ΏJ˜JšœT˜VJšœC˜EJšœJ˜LJšœ:˜˜@Jšœ6˜8Jšœ:˜˜@JšœF˜HJšœ:˜˜@Jšœ8˜:Jšœ6˜8Jšœ4˜6Jšœ4˜6Jšœ>˜@JšœB˜DJšœ<˜>JšœL˜NJ˜JšœO˜QJšœQ˜SJšœI˜KJšœC˜EJšœH˜JJšœX˜ZJšœK˜MJšœQ˜SJšœO™QJšœE™GJšœY˜[JšœM˜OJšœA˜CJ˜JšœP˜RJ˜Jšœa˜cJšœU˜WJ˜J˜Jšœg˜iJšœ[˜]J˜—Jšœ˜—…—”όαχ