<> <> <> <> DIRECTORY MathExpr, MathRules, MathDB, MathTypes, MathBox, Imager, Rope, Vector, MathConstructors; MathExprClassesArithmetic: CEDAR PROGRAM IMPORTS MathBox, MathRules, MathExpr, MathDB, MathConstructors ~ BEGIN <> EXPR: TYPE ~ MathExpr.EXPR; BOX: TYPE ~ MathBox.BOX; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector.VEC; CompoundBoxProc: TYPE ~ MathRules.CompoundBoxProc; CompositionProc: TYPE ~ MathRules.CompositionProc; Alignment2D: TYPE ~ MathRules.Alignment2D; Offset: TYPE ~ MathRules.Offset; Size: TYPE ~ MathRules.Size; Argument: TYPE ~ MathExpr.Argument; Symbol: TYPE ~ MathExpr.Symbol; CompoundClass: TYPE ~ MathExpr.CompoundClass; FormatClass: TYPE ~ MathTypes.FormatClass; Style: TYPE ~ MathTypes.Style; <> MakeArgument: PROC[name: ATOM, aliases: LIST OF ATOM, size: Size] RETURNS[Argument] ~ MathExpr.MakeArgument; MakeSymbol: PROC[name: ATOM, aliases: LIST OF ATOM, size: Size, value: EXPR] RETURNS[Symbol] ~ MathExpr.MakeSymbol; MakeCompoundClass: PROC[name: ATOM, formatClass: FormatClass, description: ROPE, args: LIST OF Argument, syms: LIST OF Symbol, boxRule: CompoundBoxProc, compBox: CompositionProc, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPE _ NIL] RETURNS[CompoundClass] ~ MathExpr.MakeCompoundClass; <> smallGap: REAL = 0.05; medGap: REAL = 0.10; bigGap: REAL = 0.25; <> FixedSizeBoxRule: CompoundBoxProc ~ { <> RETURN[boxes]; }; AbsBoxRule: CompoundBoxProc ~ { <> <<>> leftBox: BOX _ MathBox.GetBox[$leftAbs, boxes]; rightBox: BOX _ MathBox.GetBox[$rightAbs, boxes]; aBox: BOX _ MathBox.GetBox[$a, boxes]; <> scaleFactor: REAL _ MAX[0.25, 1.1 * aBox.Height[] / leftBox.Height[] ]; -- don't allow scaling to less than 1/4 size leftBox _ MathBox.Scale[leftBox, [1.2 * scaleFactor, scaleFactor]]; -- make wider than tall rightBox _ MathBox.Scale[rightBox, [1.2 * scaleFactor, scaleFactor]]; RETURN[LIST[aBox, leftBox, rightBox]]; }; FractionBoxRule: CompoundBoxProc ~ { <> <> fbarBox: BOX _ MathBox.GetBox[$fractionBar, boxes]; numBox: BOX _ MathBox.GetBox[$numerator, boxes]; denomBox: BOX _ MathBox.GetBox[$denominator, boxes]; topSpaceBox: BOX _ MathBox.GetBox[$topSpace, boxes]; bottomSpaceBox: BOX _ MathBox.GetBox[$bottomSpace, boxes]; <> scaleX: REAL _ 1.1 * MAX[numBox.Width[], denomBox.Width[] ] / fbarBox.Width[]; <> fbarBox _ MathBox.Scale[fbarBox, [scaleX, 1.0]]; RETURN[LIST[fbarBox, numBox, denomBox, topSpaceBox, bottomSpaceBox]]; }; <> PowCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; vertOffsetExponent, vertOffsetBase, horizOffsetBase: Offset; alignments: LIST OF Alignment2D _ NIL; baseBox: BOX _ MathBox.GetBox[$base, boxes]; exponentBox: BOX _ MathBox.GetBox[$exponent, boxes]; hintBox: BOX _ baseBox.SuperscriptHint[]; -- hint about where to place subscript w/i base IF hintBox # NIL THEN { <> horizOffsetBase _ [origin, hintBox.Offset[].x + hintBox.Extents[].rightExtent]; IF (hintBox.Height[] * baseBox.Height[]) > exponentBox.Height[] THEN { vertOffsetExponent _ [bottom, 0.2]; <> vertOffsetBase _ [origin, hintBox.Offset[].y + hintBox.Extents[].ascent]; } ELSE { vertOffsetExponent _ [bottom]; <<0.8 way up on hint box>> vertOffsetBase _ [origin, 0.8 * (hintBox.Offset[].y + hintBox.Extents[].ascent)]; }; } ELSE { <> horizOffsetBase _ [right]; IF baseBox.Height[] > exponentBox.Height[] THEN { vertOffsetExponent _ [bottom, 0.2]; vertOffsetBase _ [top]; } ELSE { vertOffsetExponent _ [bottom]; vertOffsetBase _ [top, -0.2]; }; }; alignments _ LIST[ [$exponent, [$base, [left], horizOffsetBase], [$base, vertOffsetExponent, vertOffsetBase]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$base, [origin]], [$base, [origin]]]; RETURN[tempBox, tempBoxes]; }; FractionCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$topSpace, [$fractionBar, [center], [center]], [$fractionBar, [bottom], [top]]], [$bottomSpace, [$fractionBar, [center], [center]], [$fractionBar, [top], [bottom]]], [$numerator, [$fractionBar, [center], [center]], [$topSpace, [bottom], [top]]], [$denominator, [$fractionBar, [center], [center]], [$bottomSpace, [top], [bottom]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$fractionBar, [origin]], [$fractionBar, [origin]]]; RETURN[tempBox, tempBoxes]; }; UnaryOpCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$aliasSpace, [$aliasUnaryOp, [left], [right]], [$aliasUnaryOp, [origin], [origin]]], [$aliasA, [$aliasSpace, [left], [right]], [$aliasSpace, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$aliasUnaryOp, [origin]], [$aliasUnaryOp, [origin]]]; RETURN[tempBox, tempBoxes]; }; BinaryOpCompRule: CompositionProc ~ { <> << symbols $aliasLeftSpace & $aliasRightSpace.>> <<>> tempBox: BOX; tempBoxes: LIST OF BOX; leftVertOffsetA, leftVertOffsetOp, rightVertOffsetB, rightVertOffsetOp: Offset; alignments: LIST OF Alignment2D; <> SELECT MathBox.GetBox[$aliasA, boxes].FormatClass[] FROM over => { leftVertOffsetA _ [origin]; leftVertOffsetOp _ [center]; }; matrix => { leftVertOffsetA _ [center]; leftVertOffsetOp _ [center]; }; ENDCASE => { leftVertOffsetA _ [origin]; leftVertOffsetOp _ [origin]; }; SELECT MathBox.GetBox[$aliasB, boxes].FormatClass[] FROM over => { rightVertOffsetB _ [origin]; rightVertOffsetOp _ [center]; }; matrix => { rightVertOffsetB _ [center]; rightVertOffsetOp _ [center]; }; ENDCASE => { rightVertOffsetB _ [origin]; rightVertOffsetOp _ [origin]; }; alignments _ LIST[ [$aliasLeftSpace, [$aliasBinOp, [right], [left]], [$aliasBinOp, [origin], [origin]]], [$aliasA, [$aliasLeftSpace, [right], [left]], [$aliasBinOp, leftVertOffsetA, leftVertOffsetOp]], [$aliasRightSpace, [$aliasBinOp, [left], [right]], [$aliasBinOp, [origin], [origin]]], [$aliasB, [$aliasRightSpace, [left], [right]], [$aliasBinOp, rightVertOffsetB, rightVertOffsetOp]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$aliasA, [origin]], [$aliasBinOp, [origin]]]; RETURN[tempBox, tempBoxes]; }; FactorialCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$space, [$a, [left], [right]], [$a, [origin], [origin]]], [$bang, [$space, [left], [right]], [$a, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$a, [origin]], [$a, [origin]]]; RETURN[tempBox, tempBoxes]; }; AbsCompRule: CompositionProc ~ { <> << $absBar and $absBar>> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$leftAbs, [$a, [right], [left]], [$a, [center], [center]]], [$rightAbs, [$a, [left], [right]], [$a, [center], [center]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$leftAbs, [origin]], [$self, [center, -0.25]]]; RETURN[tempBox, tempBoxes]; }; <> MakeUnaryOpClass: PUBLIC PROC[class, op, arg: ATOM, operation: EXPR, description: ROPE, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPE _ NIL] RETURNS[CompoundClass] ~ { <> << The alignment is "operation arg"; alignment is thru baselines. >> << Both op, arg are of fixed size "normal".>> <<>> argArg: Argument _ MakeArgument[arg, LIST[$aliasA, $aliasHot], normal]; spaceSym: Symbol _ MakeSymbol[$Space, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$medium]]; unaryOpSym: Symbol _ MakeSymbol[op, LIST[$aliasUnaryOp], normal, operation]; RETURN[MakeCompoundClass[class, unaryOp, description, LIST[argArg], LIST[unaryOpSym, spaceSym], FixedSizeBoxRule, UnaryOpCompRule, cvtAS, cvtReduce, cvtSMP, cvtOther]]; }; MakeBinOpClass: PUBLIC PROC[class, op, a, b: ATOM, operation: EXPR, description: ROPE, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPE _ NIL] RETURNS[CompoundClass] ~ { <> << The alignment is "a operation b"; alignment is thru baselines. >> << All of a, b, op are of fixed size "normal".>> aArg: Argument _ MakeArgument[a, LIST[$aliasA, $aliasHot], normal]; bArg: Argument _ MakeArgument[b, LIST[$aliasB], normal]; opSym: Symbol _ MakeSymbol[op, LIST[$aliasBinOp], normal, operation]; leftSpace: Symbol _ MakeSymbol[$leftThinSpace, LIST[$aliasLeftSpace], normal, MathConstructors.MakeSpace[$thin]]; rightSpace: Symbol _ MakeSymbol[$rightThinSpace, LIST[$aliasRightSpace], normal, MathConstructors.MakeSpace[$thin]]; RETURN[MakeCompoundClass[class, binaryOp, description, LIST[aArg, bArg], LIST[opSym, leftSpace, rightSpace], FixedSizeBoxRule, BinaryOpCompRule, cvtAS, cvtReduce, cvtSMP, cvtOther]]; }; <> wrongBoxType: PUBLIC ERROR = CODE; <> InstallArithmeticClassesA: PROC [] ~ { <> sumClass, fractionClass, differenceClass, powClass, productClass, negationClass, inverseClass: CompoundClass; baseArg, exponentArg, numeratorArg, denominatorArg: Argument; lineSym, numerSpSym, denomSpSym: Symbol; <> baseArg _ MakeArgument[$base, LIST[$aliasA, $aliasHot], normal]; exponentArg _ MakeArgument[$exponent, LIST[$aliasB], script]; <> numeratorArg _ MakeArgument[$numerator, LIST[$aliasA, $aliasHot], normal]; denominatorArg _ MakeArgument[$denominator, LIST[$aliasB], normal]; denomSpSym _ MakeSymbol[$bottomSpace, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]]; numerSpSym _ MakeSymbol[$topSpace, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]]; lineSym _ MakeSymbol[$fractionBar, LIST[$aliasLine], normal, MathConstructors.MakeLine[]]; <> <<>> <<-- functional notation for Reduce>> <> <> <> <> <> <> <> <<-- standard notation for Reduce>> inverseClass _ MakeUnaryOpClass[$invert, $inv, $a, MathConstructors.MakePlainRope["inv"], "inv a", "($a)**-1", "$a ** (-1)"]; negationClass _ MakeUnaryOpClass[$negation, $minus, $a, MathConstructors.MakePlainSym['-], "-a", "-$a", "- $a", "Minus[$a]"]; sumClass _ MakeBinOpClass[$sum, $plus, $addend, $augend, MathConstructors.MakePlainSym['+], "a + b", "$addend + $augend", "$addend + $augend", "Plus[$addend, $augend]"]; differenceClass _ MakeBinOpClass[$difference, $minus, $subtrahend, $minuend, MathConstructors.MakePlainSym['-], "a - b", "$subtrahend - $minuend", "$subtrahend - $minuend", "Minus[$subtrahend, $minuend]"]; productClass _ MakeBinOpClass[$product, $times, $multiplier, $multiplicand, MathConstructors.MakeSpace[$product], "a * b", "$multiplier * $multiplicand", "$multiplier * $multiplicand", "Mult[$multiplier, $multiplicand]"]; powClass _ MakeCompoundClass[$pow, other, "a^b", LIST[baseArg, exponentArg], NIL, FixedSizeBoxRule, PowCompRule, "$base ** $exponent", "$base ** $exponent", "Pow[$base, $exponent]"]; fractionClass _ MakeCompoundClass[$fraction, over, "a / b", LIST[numeratorArg, denominatorArg], LIST[lineSym, numerSpSym, denomSpSym], FractionBoxRule, FractionCompRule, "$numerator / $denominator", "$numerator / $denominator", "Div[$numerator, $denominator]"]; <> <<>> MathDB.InstallCompoundClass[sumClass]; MathDB.AddOperator[sumClass, $Arithmetic]; MathDB.InstallCompoundClass[negationClass]; MathDB.AddOperator[negationClass, $Arithmetic]; MathDB.InstallCompoundClass[differenceClass]; MathDB.AddOperator[differenceClass, $Arithmetic]; MathDB.InstallCompoundClass[productClass]; MathDB.AddOperator[productClass, $Arithmetic]; <> <> MathDB.InstallCompoundClass[powClass]; MathDB.AddOperator[powClass, $Arithmetic]; MathDB.InstallCompoundClass[fractionClass]; MathDB.AddOperator[fractionClass, $Arithmetic]; MathDB.InstallCompoundClass[inverseClass]; MathDB.AddOperator[inverseClass, $Arithmetic]; }; InstallArithmeticClassesAA: PROC [] ~ { <> absClass, factorialClass: CompoundClass; aAbsArg, factorialArg: Argument; leftAbsSym, rightAbsSym, factorialSym, factorialSpSym: Symbol; <> aAbsArg _ MakeArgument[$a, LIST[$aliasA, $aliasHot], normal]; leftAbsSym _ MakeSymbol[$leftAbs, NIL, normal, MathConstructors.MakePlainSym['\174]]; rightAbsSym _ MakeSymbol[$rightAbs, NIL, normal, MathConstructors.MakePlainSym['\174]]; <> factorialArg _ MakeArgument[$a, LIST[$aliasA, $aliasHot], normal]; factorialSym _ MakeSymbol[$bang, NIL, normal, MathConstructors.MakePlainSym['!]]; factorialSpSym _ MakeSymbol[$space, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]]; absClass _ MakeCompoundClass[$abs, paren, "| a |", LIST[aAbsArg], LIST[leftAbsSym, rightAbsSym], AbsBoxRule, AbsCompRule, "| $a |"]; factorialClass _ MakeCompoundClass[$factorial, other, "a!", LIST[factorialArg], LIST[factorialSym, factorialSpSym], FixedSizeBoxRule, FactorialCompRule, "$a!"]; MathDB.InstallCompoundClass[absClass]; MathDB.AddOperator[absClass, $Arithmetic]; MathDB.InstallCompoundClass[factorialClass]; MathDB.AddOperator[factorialClass, $Arithmetic]; }; <> InstallArithmeticClassesA[]; InstallArithmeticClassesAA[]; END.