From bbd5b00af07ba302d3e4d129c44a20d987366d9b Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 12 Sep 2011 22:57:23 +0400 Subject: [PATCH] new library dependency --- src/misc/lib/jscl.jar | Bin 0 -> 470044 bytes .../src/jscl/editorengine/EditorEngine.java | 58 ++ .../editorengine/EditorEngineFactory.java | 11 + .../jscl/editorengine/commands/elementary.bsh | 5 + .../src/jscl/editorengine/commands/expand.bsh | 5 + .../jscl/editorengine/commands/factorize.bsh | 5 + .../jscl/editorengine/commands/numeric.bsh | 5 + .../jscl/editorengine/commands/simplify.bsh | 5 + .../src/jscl/editorengine/commands/tojava.bsh | 5 + .../jscl/editorengine/commands/tomathml.bsh | 5 + src/misc/src/jscl/math/Antiderivative.java | 228 ++++++ src/misc/src/jscl/math/Arithmetic.java | 8 + src/misc/src/jscl/math/Debug.java | 38 + src/misc/src/jscl/math/DoubleVariable.java | 44 ++ src/misc/src/jscl/math/Expression.java | 709 ++++++++++++++++++ .../src/jscl/math/ExpressionVariable.java | 57 ++ src/misc/src/jscl/math/Factorization.java | 290 +++++++ src/misc/src/jscl/math/Field.java | 3 + src/misc/src/jscl/math/Generic.java | 138 ++++ src/misc/src/jscl/math/GenericVariable.java | 105 +++ src/misc/src/jscl/math/IntegerVariable.java | 57 ++ src/misc/src/jscl/math/JSCLBoolean.java | 16 + src/misc/src/jscl/math/JSCLInteger.java | 330 ++++++++ src/misc/src/jscl/math/JSCLVector.java | 476 ++++++++++++ src/misc/src/jscl/math/Literal.java | 368 +++++++++ src/misc/src/jscl/math/Matrix.java | 497 ++++++++++++ src/misc/src/jscl/math/MatrixVariable.java | 11 + src/misc/src/jscl/math/ModularInteger.java | 189 +++++ .../src/jscl/math/NotDivisibleException.java | 9 + .../src/jscl/math/NotExpressionException.java | 9 + .../src/jscl/math/NotIntegerException.java | 9 + .../src/jscl/math/NotIntegrableException.java | 9 + src/misc/src/jscl/math/NotPowerException.java | 9 + .../src/jscl/math/NotProductException.java | 9 + .../src/jscl/math/NotVariableException.java | 9 + src/misc/src/jscl/math/NumericWrapper.java | 344 +++++++++ src/misc/src/jscl/math/Power.java | 27 + src/misc/src/jscl/math/Rational.java | 281 +++++++ src/misc/src/jscl/math/Simplification.java | 226 ++++++ src/misc/src/jscl/math/TechnicalVariable.java | 96 +++ src/misc/src/jscl/math/Variable.java | 188 +++++ src/misc/src/jscl/math/VectorVariable.java | 11 + src/misc/src/jscl/math/function/Abs.java | 95 +++ .../src/jscl/math/function/Algebraic.java | 32 + .../jscl/math/function/ArcTrigonometric.java | 18 + .../src/jscl/math/function/Comparison.java | 97 +++ .../src/jscl/math/function/Conjugate.java | 132 ++++ src/misc/src/jscl/math/function/Constant.java | 229 ++++++ src/misc/src/jscl/math/function/Cubic.java | 96 +++ src/misc/src/jscl/math/function/Exp.java | 121 +++ src/misc/src/jscl/math/function/Frac.java | 162 ++++ src/misc/src/jscl/math/function/Function.java | 166 ++++ .../jscl/math/function/ImplicitFunction.java | 223 ++++++ src/misc/src/jscl/math/function/Inv.java | 27 + src/misc/src/jscl/math/function/Log.java | 75 ++ .../jscl/math/function/NotRootException.java | 9 + src/misc/src/jscl/math/function/Pow.java | 264 +++++++ src/misc/src/jscl/math/function/Root.java | 404 ++++++++++ src/misc/src/jscl/math/function/Sgn.java | 78 ++ src/misc/src/jscl/math/function/Sqrt.java | 123 +++ .../src/jscl/math/function/Trigonometric.java | 41 + .../jscl/math/function/hyperbolic/Acosh.java | 55 ++ .../jscl/math/function/hyperbolic/Acoth.java | 52 ++ .../jscl/math/function/hyperbolic/Asinh.java | 57 ++ .../jscl/math/function/hyperbolic/Atanh.java | 54 ++ .../jscl/math/function/hyperbolic/Cosh.java | 78 ++ .../jscl/math/function/hyperbolic/Coth.java | 76 ++ .../jscl/math/function/hyperbolic/Sinh.java | 78 ++ .../jscl/math/function/hyperbolic/Tanh.java | 82 ++ .../math/function/trigonometric/Acos.java | 58 ++ .../math/function/trigonometric/Acot.java | 53 ++ .../math/function/trigonometric/Asin.java | 58 ++ .../math/function/trigonometric/Atan.java | 55 ++ .../jscl/math/function/trigonometric/Cos.java | 82 ++ .../jscl/math/function/trigonometric/Cot.java | 76 ++ .../jscl/math/function/trigonometric/Sin.java | 82 ++ .../jscl/math/function/trigonometric/Tan.java | 87 +++ src/misc/src/jscl/math/numeric/Complex.java | 182 +++++ .../src/jscl/math/numeric/JSCLDouble.java | 174 +++++ src/misc/src/jscl/math/numeric/Numeric.java | 156 ++++ .../src/jscl/math/numeric/NumericMatrix.java | 277 +++++++ .../src/jscl/math/numeric/NumericVector.java | 160 ++++ .../src/jscl/math/operator/Coefficient.java | 24 + .../src/jscl/math/operator/Derivative.java | 112 +++ src/misc/src/jscl/math/operator/Division.java | 18 + .../src/jscl/math/operator/Factorial.java | 98 +++ src/misc/src/jscl/math/operator/Groebner.java | 138 ++++ .../math/operator/IndefiniteIntegral.java | 53 ++ src/misc/src/jscl/math/operator/Integral.java | 58 ++ src/misc/src/jscl/math/operator/Limit.java | 75 ++ src/misc/src/jscl/math/operator/Modulo.java | 25 + src/misc/src/jscl/math/operator/Operator.java | 140 ++++ src/misc/src/jscl/math/operator/Product.java | 65 ++ src/misc/src/jscl/math/operator/Solve.java | 61 ++ .../src/jscl/math/operator/Substitute.java | 41 + src/misc/src/jscl/math/operator/Sum.java | 65 ++ .../jscl/math/operator/VectorOperator.java | 40 + .../math/operator/matrix/Determinant.java | 61 ++ .../src/jscl/math/operator/matrix/Trace.java | 45 ++ .../jscl/math/operator/matrix/Transpose.java | 47 ++ .../jscl/math/operator/number/EulerPhi.java | 32 + .../jscl/math/operator/number/ModInverse.java | 26 + .../src/jscl/math/operator/number/ModPow.java | 27 + .../math/operator/number/PrimitiveRoots.java | 27 + .../math/operator/product/ComplexProduct.java | 31 + .../operator/product/GeometricProduct.java | 59 ++ .../math/operator/product/MatrixProduct.java | 38 + .../operator/product/QuaternionProduct.java | 31 + .../math/operator/product/TensorProduct.java | 34 + .../math/operator/product/VectorProduct.java | 34 + .../src/jscl/math/operator/vector/Curl.java | 34 + .../math/operator/vector/Dalembertian.java | 28 + .../src/jscl/math/operator/vector/Del.java | 46 ++ .../jscl/math/operator/vector/Divergence.java | 31 + .../src/jscl/math/operator/vector/Grad.java | 28 + .../jscl/math/operator/vector/Jacobian.java | 51 ++ .../jscl/math/operator/vector/Laplacian.java | 28 + .../jscl/math/polynomial/ArrayPolynomial.java | 328 ++++++++ .../polynomial/ArrayPolynomialBoolean.java | 111 +++ .../polynomial/ArrayPolynomialGeneric.java | 425 +++++++++++ .../polynomial/ArrayPolynomialInteger.java | 228 ++++++ .../polynomial/ArrayPolynomialModular.java | 207 +++++ .../polynomial/ArrayPolynomialRational.java | 52 ++ src/misc/src/jscl/math/polynomial/Basis.java | 126 ++++ .../jscl/math/polynomial/BooleanMonomial.java | 112 +++ .../polynomial/DefinedBooleanMonomial.java | 32 + .../jscl/math/polynomial/DegreeOrdering.java | 3 + .../src/jscl/math/polynomial/GeoBucket.java | 354 +++++++++ .../jscl/math/polynomial/ListPolynomial.java | 324 ++++++++ .../src/jscl/math/polynomial/Monomial.java | 406 ++++++++++ .../math/polynomial/NestedPolynomial.java | 225 ++++++ .../src/jscl/math/polynomial/Ordering.java | 11 + .../src/jscl/math/polynomial/Polynomial.java | 481 ++++++++++++ .../jscl/math/polynomial/SmallMonomial.java | 174 +++++ src/misc/src/jscl/math/polynomial/Term.java | 65 ++ .../jscl/math/polynomial/TreePolynomial.java | 303 ++++++++ .../math/polynomial/UnivariatePolynomial.java | 493 ++++++++++++ .../jscl/math/polynomial/groebner/Block.java | 60 ++ .../src/jscl/math/polynomial/groebner/F4.java | 35 + .../math/polynomial/groebner/F4Reduction.java | 98 +++ .../polynomial/groebner/Instrumented.java | 44 ++ .../math/polynomial/groebner/Natural.java | 17 + .../jscl/math/polynomial/groebner/Pair.java | 54 ++ .../math/polynomial/groebner/Projection.java | 73 ++ .../groebner/ReducedRowEchelonForm.java | 57 ++ .../math/polynomial/groebner/Standard.java | 227 ++++++ .../jscl/math/polynomial/groebner/Sugar.java | 19 + src/misc/src/jscl/mathml/MathML.java | 66 ++ .../src/jscl/text/BracketedExpression.java | 36 + .../src/jscl/text/CommaAndExpression.java | 28 + src/misc/src/jscl/text/CommaAndVector.java | 28 + .../src/jscl/text/CompoundIdentifier.java | 54 ++ src/misc/src/jscl/text/ConstantParser.java | 91 +++ src/misc/src/jscl/text/Digits.java | 25 + src/misc/src/jscl/text/DoubleParser.java | 164 ++++ .../src/jscl/text/DoubleVariableParser.java | 20 + src/misc/src/jscl/text/ExpressionParser.java | 355 +++++++++ src/misc/src/jscl/text/FunctionParser.java | 113 +++ src/misc/src/jscl/text/Identifier.java | 31 + .../src/jscl/text/ImplicitFunctionParser.java | 137 ++++ src/misc/src/jscl/text/IntegerParser.java | 29 + src/misc/src/jscl/text/JSCLIntegerParser.java | 22 + src/misc/src/jscl/text/MatrixParser.java | 49 ++ .../src/jscl/text/MatrixVariableParser.java | 20 + src/misc/src/jscl/text/OperatorParser.java | 107 +++ src/misc/src/jscl/text/ParameterList.java | 47 ++ src/misc/src/jscl/text/ParseException.java | 9 + src/misc/src/jscl/text/Parser.java | 14 + src/misc/src/jscl/text/PrimeCharacters.java | 25 + src/misc/src/jscl/text/RootParser.java | 40 + src/misc/src/jscl/text/Subscript.java | 35 + src/misc/src/jscl/text/VariableParser.java | 27 + src/misc/src/jscl/text/VectorParser.java | 49 ++ .../src/jscl/text/VectorVariableParser.java | 20 + src/misc/src/jscl/util/ArrayComparator.java | 23 + src/misc/src/jscl/util/ArrayUtils.java | 112 +++ 176 files changed, 17999 insertions(+) create mode 100644 src/misc/lib/jscl.jar create mode 100644 src/misc/src/jscl/editorengine/EditorEngine.java create mode 100644 src/misc/src/jscl/editorengine/EditorEngineFactory.java create mode 100644 src/misc/src/jscl/editorengine/commands/elementary.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/expand.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/factorize.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/numeric.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/simplify.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/tojava.bsh create mode 100644 src/misc/src/jscl/editorengine/commands/tomathml.bsh create mode 100644 src/misc/src/jscl/math/Antiderivative.java create mode 100644 src/misc/src/jscl/math/Arithmetic.java create mode 100644 src/misc/src/jscl/math/Debug.java create mode 100644 src/misc/src/jscl/math/DoubleVariable.java create mode 100644 src/misc/src/jscl/math/Expression.java create mode 100644 src/misc/src/jscl/math/ExpressionVariable.java create mode 100644 src/misc/src/jscl/math/Factorization.java create mode 100644 src/misc/src/jscl/math/Field.java create mode 100644 src/misc/src/jscl/math/Generic.java create mode 100644 src/misc/src/jscl/math/GenericVariable.java create mode 100644 src/misc/src/jscl/math/IntegerVariable.java create mode 100644 src/misc/src/jscl/math/JSCLBoolean.java create mode 100644 src/misc/src/jscl/math/JSCLInteger.java create mode 100644 src/misc/src/jscl/math/JSCLVector.java create mode 100644 src/misc/src/jscl/math/Literal.java create mode 100644 src/misc/src/jscl/math/Matrix.java create mode 100644 src/misc/src/jscl/math/MatrixVariable.java create mode 100644 src/misc/src/jscl/math/ModularInteger.java create mode 100644 src/misc/src/jscl/math/NotDivisibleException.java create mode 100644 src/misc/src/jscl/math/NotExpressionException.java create mode 100644 src/misc/src/jscl/math/NotIntegerException.java create mode 100644 src/misc/src/jscl/math/NotIntegrableException.java create mode 100644 src/misc/src/jscl/math/NotPowerException.java create mode 100644 src/misc/src/jscl/math/NotProductException.java create mode 100644 src/misc/src/jscl/math/NotVariableException.java create mode 100644 src/misc/src/jscl/math/NumericWrapper.java create mode 100644 src/misc/src/jscl/math/Power.java create mode 100644 src/misc/src/jscl/math/Rational.java create mode 100644 src/misc/src/jscl/math/Simplification.java create mode 100644 src/misc/src/jscl/math/TechnicalVariable.java create mode 100644 src/misc/src/jscl/math/Variable.java create mode 100644 src/misc/src/jscl/math/VectorVariable.java create mode 100644 src/misc/src/jscl/math/function/Abs.java create mode 100644 src/misc/src/jscl/math/function/Algebraic.java create mode 100644 src/misc/src/jscl/math/function/ArcTrigonometric.java create mode 100644 src/misc/src/jscl/math/function/Comparison.java create mode 100644 src/misc/src/jscl/math/function/Conjugate.java create mode 100644 src/misc/src/jscl/math/function/Constant.java create mode 100644 src/misc/src/jscl/math/function/Cubic.java create mode 100644 src/misc/src/jscl/math/function/Exp.java create mode 100644 src/misc/src/jscl/math/function/Frac.java create mode 100644 src/misc/src/jscl/math/function/Function.java create mode 100644 src/misc/src/jscl/math/function/ImplicitFunction.java create mode 100644 src/misc/src/jscl/math/function/Inv.java create mode 100644 src/misc/src/jscl/math/function/Log.java create mode 100644 src/misc/src/jscl/math/function/NotRootException.java create mode 100644 src/misc/src/jscl/math/function/Pow.java create mode 100644 src/misc/src/jscl/math/function/Root.java create mode 100644 src/misc/src/jscl/math/function/Sgn.java create mode 100644 src/misc/src/jscl/math/function/Sqrt.java create mode 100644 src/misc/src/jscl/math/function/Trigonometric.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Acosh.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Acoth.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Asinh.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Atanh.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Cosh.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Coth.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Sinh.java create mode 100644 src/misc/src/jscl/math/function/hyperbolic/Tanh.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Acos.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Acot.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Asin.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Atan.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Cos.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Cot.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Sin.java create mode 100644 src/misc/src/jscl/math/function/trigonometric/Tan.java create mode 100644 src/misc/src/jscl/math/numeric/Complex.java create mode 100644 src/misc/src/jscl/math/numeric/JSCLDouble.java create mode 100644 src/misc/src/jscl/math/numeric/Numeric.java create mode 100644 src/misc/src/jscl/math/numeric/NumericMatrix.java create mode 100644 src/misc/src/jscl/math/numeric/NumericVector.java create mode 100644 src/misc/src/jscl/math/operator/Coefficient.java create mode 100644 src/misc/src/jscl/math/operator/Derivative.java create mode 100644 src/misc/src/jscl/math/operator/Division.java create mode 100644 src/misc/src/jscl/math/operator/Factorial.java create mode 100644 src/misc/src/jscl/math/operator/Groebner.java create mode 100644 src/misc/src/jscl/math/operator/IndefiniteIntegral.java create mode 100644 src/misc/src/jscl/math/operator/Integral.java create mode 100644 src/misc/src/jscl/math/operator/Limit.java create mode 100644 src/misc/src/jscl/math/operator/Modulo.java create mode 100644 src/misc/src/jscl/math/operator/Operator.java create mode 100644 src/misc/src/jscl/math/operator/Product.java create mode 100644 src/misc/src/jscl/math/operator/Solve.java create mode 100644 src/misc/src/jscl/math/operator/Substitute.java create mode 100644 src/misc/src/jscl/math/operator/Sum.java create mode 100644 src/misc/src/jscl/math/operator/VectorOperator.java create mode 100644 src/misc/src/jscl/math/operator/matrix/Determinant.java create mode 100644 src/misc/src/jscl/math/operator/matrix/Trace.java create mode 100644 src/misc/src/jscl/math/operator/matrix/Transpose.java create mode 100644 src/misc/src/jscl/math/operator/number/EulerPhi.java create mode 100644 src/misc/src/jscl/math/operator/number/ModInverse.java create mode 100644 src/misc/src/jscl/math/operator/number/ModPow.java create mode 100644 src/misc/src/jscl/math/operator/number/PrimitiveRoots.java create mode 100644 src/misc/src/jscl/math/operator/product/ComplexProduct.java create mode 100644 src/misc/src/jscl/math/operator/product/GeometricProduct.java create mode 100644 src/misc/src/jscl/math/operator/product/MatrixProduct.java create mode 100644 src/misc/src/jscl/math/operator/product/QuaternionProduct.java create mode 100644 src/misc/src/jscl/math/operator/product/TensorProduct.java create mode 100644 src/misc/src/jscl/math/operator/product/VectorProduct.java create mode 100644 src/misc/src/jscl/math/operator/vector/Curl.java create mode 100644 src/misc/src/jscl/math/operator/vector/Dalembertian.java create mode 100644 src/misc/src/jscl/math/operator/vector/Del.java create mode 100644 src/misc/src/jscl/math/operator/vector/Divergence.java create mode 100644 src/misc/src/jscl/math/operator/vector/Grad.java create mode 100644 src/misc/src/jscl/math/operator/vector/Jacobian.java create mode 100644 src/misc/src/jscl/math/operator/vector/Laplacian.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomialBoolean.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomialGeneric.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomialInteger.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomialModular.java create mode 100644 src/misc/src/jscl/math/polynomial/ArrayPolynomialRational.java create mode 100644 src/misc/src/jscl/math/polynomial/Basis.java create mode 100644 src/misc/src/jscl/math/polynomial/BooleanMonomial.java create mode 100644 src/misc/src/jscl/math/polynomial/DefinedBooleanMonomial.java create mode 100644 src/misc/src/jscl/math/polynomial/DegreeOrdering.java create mode 100644 src/misc/src/jscl/math/polynomial/GeoBucket.java create mode 100644 src/misc/src/jscl/math/polynomial/ListPolynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/Monomial.java create mode 100644 src/misc/src/jscl/math/polynomial/NestedPolynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/Ordering.java create mode 100644 src/misc/src/jscl/math/polynomial/Polynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/SmallMonomial.java create mode 100644 src/misc/src/jscl/math/polynomial/Term.java create mode 100644 src/misc/src/jscl/math/polynomial/TreePolynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/UnivariatePolynomial.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Block.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/F4.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/F4Reduction.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Instrumented.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Natural.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Pair.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Projection.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Standard.java create mode 100644 src/misc/src/jscl/math/polynomial/groebner/Sugar.java create mode 100644 src/misc/src/jscl/mathml/MathML.java create mode 100644 src/misc/src/jscl/text/BracketedExpression.java create mode 100644 src/misc/src/jscl/text/CommaAndExpression.java create mode 100644 src/misc/src/jscl/text/CommaAndVector.java create mode 100644 src/misc/src/jscl/text/CompoundIdentifier.java create mode 100644 src/misc/src/jscl/text/ConstantParser.java create mode 100644 src/misc/src/jscl/text/Digits.java create mode 100644 src/misc/src/jscl/text/DoubleParser.java create mode 100644 src/misc/src/jscl/text/DoubleVariableParser.java create mode 100644 src/misc/src/jscl/text/ExpressionParser.java create mode 100644 src/misc/src/jscl/text/FunctionParser.java create mode 100644 src/misc/src/jscl/text/Identifier.java create mode 100644 src/misc/src/jscl/text/ImplicitFunctionParser.java create mode 100644 src/misc/src/jscl/text/IntegerParser.java create mode 100644 src/misc/src/jscl/text/JSCLIntegerParser.java create mode 100644 src/misc/src/jscl/text/MatrixParser.java create mode 100644 src/misc/src/jscl/text/MatrixVariableParser.java create mode 100644 src/misc/src/jscl/text/OperatorParser.java create mode 100644 src/misc/src/jscl/text/ParameterList.java create mode 100644 src/misc/src/jscl/text/ParseException.java create mode 100644 src/misc/src/jscl/text/Parser.java create mode 100644 src/misc/src/jscl/text/PrimeCharacters.java create mode 100644 src/misc/src/jscl/text/RootParser.java create mode 100644 src/misc/src/jscl/text/Subscript.java create mode 100644 src/misc/src/jscl/text/VariableParser.java create mode 100644 src/misc/src/jscl/text/VectorParser.java create mode 100644 src/misc/src/jscl/text/VectorVariableParser.java create mode 100644 src/misc/src/jscl/util/ArrayComparator.java create mode 100644 src/misc/src/jscl/util/ArrayUtils.java diff --git a/src/misc/lib/jscl.jar b/src/misc/lib/jscl.jar new file mode 100644 index 0000000000000000000000000000000000000000..7da29a66a0db522d276a6040a787ee47f41a054a GIT binary patch literal 470044 zcmeEv34B!5z5nlImOC@K1PBZ;Ss*Mzm~0R+Y62*-2tooih(@a=Bm+dVnFQRsSh}~i zwzd_uYSGtpu}V<`KCDX@ySMhWuiJaC`@Zk5Z>jvh-*eBsbMG*d5Vifh_xZoToV)$b zIlr_2&Tl*0HiyCq;os&PKisTuOc0l_w65R2rfyT)hKA=pE3(Z4y#SzVO9!XCLW%G< z6Hz?S)-`RLHmq;oUf;T*wX?rxcV>8`ZbxQlxM!fhxoUa+vMGr*{k}JA20Od@`T1$1xc z@NnI>&XK*%Ro7;Qx-!F?`UZRJ8tc!jUtWJ@=TOzPeZ6&^gFVA_%j-|CU$%nprX;2$ z+B*9(%~e+pcl9=8x_d?jhBEzodipaBQxffinXaDQJzbq6K)G&v&qyx-FKA!8CHIq8 zs>b@$PyW{5JuuW5FiFP6_7bkFfW;!OYOEf!?03apKO;A9rM^ zXU{}MCwj0CzuX9AfegF|sKTM1YbPHM81Bl9 zm!H?Vx{0v1p!YgddrxQYI9UbT+ZSce&_HHaf1rH1 zeZ}@?*Ee1+UUwbITsvODJ-B@%J^u7K&R%hBW&L90$X^Y9-dyVqU3MNbgVe9r6WNAN z*4TBv56%Qvzh2LF0U+N@!Gd;v=KlM(S|a={atj(5rv5bQyEp@X_PKw20-(!eBq3>O zv1DaJilikjOJ!9|R`cN;OU|`qO+sRFUP9)}+L)~4bv=U(2|%9DU?YP~3AsQv^KJ{1 zXtks*fn}y8CR=&k#wai09bo3mg)wQ5$@Z9B#HSrGxi}`5Ske)bOJj0bOkNt3%VTmy zOkNg~otAW3vP(&{r+*|fG^k|ymR-Yp8#d{up$y)&C<%AEDBo(Um>@JtM1?gsPYB0PNae%VrWQ^J?@ z^+Q7gLrThhi8eT$(5pA%*KJEib}LaxV2|vzrAMx`aRFy6LGGNOfBkYl@@e1%o)k{IQ*fJz&thsuS5c~S|*A5P4 zhDoc`1Lu92t-Gri0D1wSr{!jWj*z)_5UZ7v_-;Mgdah?b$e0y==sGmmFlx28XE$yw zGp*z0$UrMHYu$nrMg}fG2QxSXDG~o5Q&M_z#ZBD5w(hzT6DPXt9Di@wzISNgn$BIl znHF~6XfGy)k-fS%Z$eRq_w5?iJ)PZgQ{EmG&0M{&vllfN=&vTTrI!Zk%6Y2`?F=9# zGpqBb+BrA~QbtLwA6YZ%PLAQUFv?auGO%Ufn#|DJ&S6yltm;kqkxmR{275cZGHZG< zFwe@9#mVFHTbI4Yq> zC7gal!ljWhiC#P^Q??wJSVzrKi9h)fM4l=ssX#I!jrfJ}CWhbXvce>}97%@o<+PeH zNrbysRop4lN{eeM#>5_zDF-Ey#)p!c!@NvA48UMQ7(^za8k5j$A_HKJODl1yb#W1i zV|WB{5e`9F(j7c!VX-H;FrXS8G1Kb5=ns!nu7{mC+N}7RGSdmt`CNw6c4$i`H zZ2%sW2>yv23azd@A~T*iBv&J^1a2!EaqSLwH-(eoJLRI|G7}Y?ES)tbv(48zxE+&J zO)~6OP=kR&ZhTpWUnzh}%d?SYm!diu?eKw+8a?rrn$qIZ$}yR{rQ)E>bu*a<5TG%; zw90`UMJ+nG$D|oOz$x6>XhQzgO|w2K^E*PN3)(xvr3>3TBBhJkJEEnhwRc#hi`zS5 zrAyj7rbSDu+aH!0AJI{Kdo3==KfAg9X$(!_kL$m0DsUF{2LD`PR{orIxio=_oMK4{ zmttI}S~9KBQWoEn8FA)jjwg(Q>@La7*%)@d_0E#%wnW7`g=y?GUs{E6SCaCS7W)p$w%aorc`sclnn!O{!W{q1bUS_b?i0x|mJsWd;^jH7p*IV`hZT?8ikJD`owQ$PF8~911?#3G* z@qby?wBQ;b%-@pn5qBw`Q^wqlFlp4ih~wkFzG(Sp_X21BCg|xS10?cJ8FL4G(s(;G zU%o+kL-OhQy+D({398v8w|I_zUi*!O-jJ1{-5P zI9>ZQIg8PA3At2;5}15OEZG;w47@*qxf&1G@ZnlZuH!cGdImQzxG^E^aub7>CqNy& zg25{pyec6#%d2^Jz>?Qk@>*^RU&r9}36K|WVDLsu-jo1sH58LKC*&=13xl^N-pRXn5utZ8#_g6IOkmbQGI#KLCxg3U@}8L7&D(nz`(766 zy_Ou}^*#po$K)SaxcBj4G>*IX^AWE<5R(rw&WD)U1H8MRIewUT5AxkZmK-LUD8+d! z&&|ZJQ9crrBbGcIlSdM=Q65dmm>gxCW6a?(-u)v3?8HNIobP~CNN%#^aaQ0*8NA+- zC;0NogzR8-?ckfIut{-dGHh3BoK>HFroqP>xu_p4I@ALO?KY3c!Y%Reb=P0F2hpm0 z(XtR1_l)dq*ARro4r^cU2zJ*#*z+@Bxb$@Kv%9;V4H}(K(PI=mrkJ)mWd|b)WEY1^jBu03tOGN4<^K~IxE|)8? zrOhTAoNJi0cI%;w9s{1cPxl&{$GX89`me>Ro2fe|v5_6)J#dQ1)_C7pq((UO0* zf3u}e`fd3(-@QzB+VUNFnyBS)r(Cv&<#erT zTfQsbWAJ@&F>0$o0xz}Y2l7K(ek4D(ZkK>^t~r{K<^%=Q5ymuKE!5%PZk>nTRI=01)0(tMHgrH5!> z@%S-vryVd*vV~cf*|l#EiZKYD?MQEb0ag_fi}&<*4QY`a@ae<4)HB$Ns;kb2PySqE zdO^e(*X`rO*=u&pf&S#Y_xaNcb#{}b*q!n4iat-ySb&k{vgb}>b9sz3@FgAEupo=h z=@kRu&o=oB7Ih{kY|!^O^n+QK@?sb0G}*BlpiSnW zD>y6YMT6T1)(&KLLlE49@uXydf8^yy86$2OoYA4oZVcdc8IFyC;U0dXnvMd^o42TeDQ)6H#rp?_`Z{|xuYF+vEnnPie&V!YGT3Y)WtPxP z@SYJ6mtZJCjD-CdIjSL6!eB#&$PPUyGwVWNkCuQ(IrX6TA>0&6Mk)@;JVH#bOGW@P?GEqrfe84W-*aMD zG$xM8bZ|$rpZQ_YahcKKBu!Rm#cKcrrt6r@Ix4flz@2mWxTL^_EqfB!38XC!_bi1g zs4-L2A>eM|&F<3jV^VQUDuLzP)^u&Cu{I2h=C!4fLmh9c+L%jSq|wQvIgAe}@NDNd zNATUbi>6Z%vY^Lg!I&&er=mKMMPqW>qq6vzEHV64ijhqIJzx*A_AWmz)xdRWDJrlA zIMkNb;RZEcTUw8sF=+sLhC#lpjW_tV3`j8J<;{`EN2ReNRF?uT|MW3g0p4yZ>^-=g zY!GrL+v`oX{cg5rjGwJVj(8LEwQ7-Jlgao@^q}TQROg+FJR)bYqE?`-nLkiD8|-EM zo*iICyNd_tE`!H429K*;Jer>u9?Ns_aPlJ(E>ap3V&ozL3f4hF^`i%rh^SpI5-sB+ zp{pLlXiQeN)ji=b{Ue7c@IafaI;^|o>gGteDVmHX!-u3I6{$-`Q3I=!5K5e*yUc+o z`u7j&lB}@R%~9v(T;5x$NXjBiES-v_5MfPoJQWW$q7Te(PNd>t=dL&vk2E&h=~RL+ zRfGvQ;=6tiP)13`aD&d*T+FVUvKa+$Fetk@Sa56lvW--1JnH!RrkGtUl|UcU1=W~M zIWFgQFu!Ct+>L@9m9=BCF6}0lDjt*dKz@qObOY{OK>cD75OM1sbhxSeW$68^dkki$ z|DQij-5-~Y9i^L&$_3s40CLS*h=tl&#-VU7hRxK6a#8aXR3EBwM@O=l*j{)q z#uFrO$gQ}M6?gGbxnxW_bcLPPoH$@3+lLMmBfKY-aBC0SNHcu0VuVLzvH6@84Ui@F z>>s~4`!ASZ_zSAttQi6u1f+aVR}MQ2;+TXb#US}L=~wSxudy9eKE(5=~Z-bccE z#F39DVTldmE=wk7lgYc=sm$&#vyk3aHcE*KmpV-IVIWU=7p@U=jhd^4D{v$fu5rI8 zh4ppiYb)=GL&nG78~|mJTMNPY?t!81oZ4zhK&F^ZK%!F<$6YOhI!k8pTF-9{43;ri z&Y+RO=?qpdIDM2=SJyxjg>D<gl_%?li@a!q(S>>pgKCfyxZfok$KsH+d_FsG@ZFqY_G&SL}rN zTu(jMu1;50eo`Vuk4jWiJe7xJPl)6VZZ1h`m}6pLHPEyHZ!Ihg*3F!YIL#iDSW`UB zS7Q=yN+jdqolTs7F?}{BBgw=;i6@IkMkSIg-m2-M_a6vjMmXqF6R1OjXeSUQHE~gB zwZ??0ACip~n4+(J`Q37MQd3>d+uHJQGQzi&$Rm88*c#K&du2+cOJ}XtxqVsZ_Gsk; zNEjkXHlE3D8M4DTkwxW^`y^8KK=|=QYgu{iF-fehEDv|Hq{umZZEdK2ryCosZelkA zRmNUyVwZ)lUsV=<`RWQCHO8prNUdw`bW%o&3SKzObVK*K+xQTZfYLJMeLaRcnE6NVZ^vd#z z14T;59X;_|uhKCROq6rcUs>!G;Z@<)W#!%IET}1DQ&N!(?_H(y`h7 ^O^r-D>Au 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 K77}f@A1pWQ6uPr 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 && (" "+cmds[i].toLowerCase()).equals(str.substring(n))) return commands(str.substring(0,n),true)+"."+cmds[i]+"()"; + } + str=str.replaceAll("\n",""); + return found?"jscl.math.Expression.valueOf(\""+str+"\")":str; + } + + static final String cmds[]=new String[] {"expand","factorize","elementary","simplify","numeric","toMathML","toJava"}; +} diff --git a/src/misc/src/jscl/editorengine/EditorEngineFactory.java b/src/misc/src/jscl/editorengine/EditorEngineFactory.java new file mode 100644 index 00000000..61fc96d6 --- /dev/null +++ b/src/misc/src/jscl/editorengine/EditorEngineFactory.java @@ -0,0 +1,11 @@ +package jscl.editorengine; + +import jscl.editor.Engine; +import jscl.editor.EngineFactory; +import jscl.editor.EngineException; + +public class EditorEngineFactory extends EngineFactory { + public Engine getEngine() throws EngineException { + return new EditorEngine(); + } +} diff --git a/src/misc/src/jscl/editorengine/commands/elementary.bsh b/src/misc/src/jscl/editorengine/commands/elementary.bsh new file mode 100644 index 00000000..f3c6cab7 --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/elementary.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String elementary(String expr) { + return Expression.valueOf(expr).elementary().toString(); +} diff --git a/src/misc/src/jscl/editorengine/commands/expand.bsh b/src/misc/src/jscl/editorengine/commands/expand.bsh new file mode 100644 index 00000000..0b7af2d2 --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/expand.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String expand(String expr) { + return Expression.valueOf(expr).expand().toString(); +} diff --git a/src/misc/src/jscl/editorengine/commands/factorize.bsh b/src/misc/src/jscl/editorengine/commands/factorize.bsh new file mode 100644 index 00000000..b21abe8e --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/factorize.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String factorize(String expr) { + return Expression.valueOf(expr).factorize().toString(); +} diff --git a/src/misc/src/jscl/editorengine/commands/numeric.bsh b/src/misc/src/jscl/editorengine/commands/numeric.bsh new file mode 100644 index 00000000..d1d61910 --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/numeric.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String numeric(String expr) { + return Expression.valueOf(expr).numeric().toString(); +} diff --git a/src/misc/src/jscl/editorengine/commands/simplify.bsh b/src/misc/src/jscl/editorengine/commands/simplify.bsh new file mode 100644 index 00000000..c8a049fc --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/simplify.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String simplify(String expr) { + return Expression.valueOf(expr).simplify().toString(); +} diff --git a/src/misc/src/jscl/editorengine/commands/tojava.bsh b/src/misc/src/jscl/editorengine/commands/tojava.bsh new file mode 100644 index 00000000..40e794e9 --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/tojava.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String tojava(String expr) { + return Expression.valueOf(expr).toJava(); +} diff --git a/src/misc/src/jscl/editorengine/commands/tomathml.bsh b/src/misc/src/jscl/editorengine/commands/tomathml.bsh new file mode 100644 index 00000000..81afd4f3 --- /dev/null +++ b/src/misc/src/jscl/editorengine/commands/tomathml.bsh @@ -0,0 +1,5 @@ +import jscl.math.Expression; + +String tomathml(String expr) { + return Expression.valueOf(expr).toMathML(); +} diff --git a/src/misc/src/jscl/math/Antiderivative.java b/src/misc/src/jscl/math/Antiderivative.java new file mode 100644 index 00000000..0b4f1a8a --- /dev/null +++ b/src/misc/src/jscl/math/Antiderivative.java @@ -0,0 +1,228 @@ +package jscl.math; + +import jscl.math.function.Frac; +import jscl.math.function.Inv; +import jscl.math.function.Log; +import jscl.math.function.Pow; +import jscl.math.function.Root; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; + +public class Antiderivative { + UnivariatePolynomial factory; + PolynomialWithSyzygy syzygy; + Generic result; + + Antiderivative(Variable variable) { + factory=(UnivariatePolynomial)Polynomial.factory(variable); + syzygy=(PolynomialWithSyzygy)PolynomialWithSyzygy.factory(variable); + } + + public static Generic compute(Frac frac, Variable variable) { + Antiderivative s=new Antiderivative(variable); + s.compute(frac); + return s.getValue(); + } + + public static Generic compute(Root root, Variable variable) throws NotIntegrableException { + int d=root.degree(); + Generic a[]=root.parameters(); + boolean b=d>0; + b=b && a[0].negate().isIdentity(variable); + for(int i=1;i0?rs[i].normalize():rs[i]).genericValue()); + UnivariatePolynomial q[]=rs[0].squarefreeDecomposition(); + int m=q.length-1; + Generic s=JSCLInteger.valueOf(0); + for(int i=1;i<=m;i++) { + for(int j=0;j=0;i--) { + Generic c1=p.get(i+d2); + Generic c2=q.get(d2); + Generic c=c1.gcd(c2); + c1=c1.divide(c); + c2=c2.divide(c); + p=(PolynomialWithSyzygy)p.multiply(c2).subtract(q.multiply(monomial(Literal.valueOf(variable,i)),c1)).normalize(); + } + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + Polynomial p=this; + Polynomial q=polynomial; + while(q.signum()!=0) { + Polynomial r=p.remainderUpToCoefficient(q); + p=q; + q=r; + } + return p; + } + + public Generic gcd() { + Generic a=super.gcd(); + for(int i=0;i0?literal[--i1]:null; + Literal l2=i2>0?expression.literal[--i2]:null; + while(l1!=null || l2!=null) { + int c=l1==null?1:(l2==null?-1:-l1.compareTo(l2)); + if(c<0) { + JSCLInteger en=coef[i1]; + --i; + ex.literal[i]=l1; + ex.coef[i]=en; + l1=i1>0?literal[--i1]:null; + } else if(c>0) { + JSCLInteger en=expression.coef[i2]; + --i; + ex.literal[i]=l2; + ex.coef[i]=en; + l2=i2>0?expression.literal[--i2]:null; + } else { + JSCLInteger en=coef[i1].add(expression.coef[i2]); + if(en.signum()!=0) { + --i; + ex.literal[i]=l1; + ex.coef[i]=en; + } + l1=i1>0?literal[--i1]:null; + l2=i2>0?expression.literal[--i2]:null; + } + } + ex.resize(ex.size-i); + return ex; + } + + public Generic add(Generic generic) { + if(generic instanceof Expression) { + return add((Expression)generic); + } else if(generic instanceof JSCLInteger || generic instanceof Rational) { + return add(valueof(generic)); + } else { + return generic.valueof(this).add(generic); + } + } + + public Expression subtract(Expression expression) { + return multiplyAndAdd(Literal.valueOf(),JSCLInteger.valueOf(-1),expression); + } + + public Generic subtract(Generic generic) { + if(generic instanceof Expression) { + return subtract((Expression)generic); + } else if(generic instanceof JSCLInteger || generic instanceof Rational) { + return subtract(valueof(generic)); + } else { + return generic.valueof(this).subtract(generic); + } + } + + Expression multiplyAndAdd(Literal lit, JSCLInteger integer, Expression expression) { + if(integer.signum()==0) return this; + Expression ex=newinstance(size+expression.size); + int i=ex.size; + int i1=size; + int i2=expression.size; + Literal l1=i1>0?literal[--i1]:null; + Literal l2=i2>0?expression.literal[--i2].multiply(lit):null; + while(l1!=null || l2!=null) { + int c=l1==null?1:(l2==null?-1:-l1.compareTo(l2)); + if(c<0) { + JSCLInteger en=coef[i1]; + --i; + ex.literal[i]=l1; + ex.coef[i]=en; + l1=i1>0?literal[--i1]:null; + } else if(c>0) { + JSCLInteger en=expression.coef[i2].multiply(integer); + --i; + ex.literal[i]=l2; + ex.coef[i]=en; + l2=i2>0?expression.literal[--i2].multiply(lit):null; + } else { + JSCLInteger en=coef[i1].add(expression.coef[i2].multiply(integer)); + if(en.signum()!=0) { + --i; + ex.literal[i]=l1; + ex.coef[i]=en; + } + l1=i1>0?literal[--i1]:null; + l2=i2>0?expression.literal[--i2].multiply(lit):null; + } + } + ex.resize(ex.size-i); + return ex; + } + + public Expression multiply(Expression expression) { + Expression ex=newinstance(0); + for(int i=0;i=0;i--) en=en.gcd(coef[i]); + return en; + } + + public Literal literalScm() { + Literal l=Literal.valueOf(); + for(int i=0;i1) { + Generic s=JSCLInteger.valueOf(0); + for(int i=0;i0) return 1; + else { + c=coef[i1].compareTo(expression.coef[i2]); + if(c<0) return -1; + else if(c>0) return 1; + l1=i1==0?null:literal[--i1]; + l2=i2==0?null:expression.literal[--i2]; + } + } + return 0; + } + + public int compareTo(Generic generic) { + if(generic instanceof Expression) { + return compareTo((Expression)generic); + } else if(generic instanceof JSCLInteger || generic instanceof Rational) { + return compareTo(valueof(generic)); + } else { + return generic.valueof(this).compareTo(generic); + } + } + + public static Expression valueOf(Variable variable) { + return valueOf(Literal.valueOf(variable)); + } + + public static Expression valueOf(Literal literal) { + return valueOf(literal,JSCLInteger.valueOf(1)); + } + + public static Expression valueOf(JSCLInteger integer) { + return valueOf(Literal.valueOf(),integer); + } + + public static Expression valueOf(Literal literal, JSCLInteger integer) { + Expression ex=new Expression(); + ex.init(literal,integer); + return ex; + } + + void init(Literal lit, JSCLInteger integer) { + if(integer.signum()!=0) { + init(1); + literal[0]=lit; + coef[0]=integer; + } else init(0); + } + + public static Expression valueOf(Rational rational) { + Expression ex=new Expression(); + ex.init(rational); + return ex; + } + + public static Expression valueOf(String str) throws ParseException { + int pos[]=new int[1]; + Generic a; + try { + a=(Generic)ExpressionParser.parser.parse(str,pos); + } catch (ParseException e) { + throw e; + } + Parser.skipWhitespaces(str,pos); + if(pos[0]0 && i>0) buffer.append("+"); + if(l.degree()==0) buffer.append(en); + else { + if(en.abs().compareTo(JSCLInteger.valueOf(1))==0) { + if(en.signum()<0) buffer.append("-"); + } else buffer.append(en).append("*"); + buffer.append(l); + } + } + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer=new StringBuffer(); + if(signum()==0) buffer.append("JSCLDouble.valueOf(0)"); + for(int i=0;i0) { + if(en.signum()<0) { + buffer.append(".subtract("); + en=(JSCLInteger)en.negate(); + } else buffer.append(".add("); + } + if(l.degree()==0) buffer.append(en.toJava()); + else { + if(en.abs().compareTo(JSCLInteger.valueOf(1))==0) { + if(en.signum()>0) buffer.append(l.toJava()); + else if(en.signum()<0) buffer.append(l.toJava()).append(".negate()"); + } else buffer.append(en.toJava()).append(".multiply(").append(l.toJava()).append(")"); + } + if(i>0) buffer.append(")"); + } + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + MathML e1=element.element("mrow"); + if(signum()==0) { + MathML e2=element.element("mn"); + e2.appendChild(element.text("0")); + e1.appendChild(e2); + } + for(int i=0;i0 && i>0) { + MathML e2=element.element("mo"); + e2.appendChild(element.text("+")); + e1.appendChild(e2); + } + if(l.degree()==0) separateSign(e1,en); + else { + if(en.abs().compareTo(JSCLInteger.valueOf(1))==0) { + if(en.signum()<0) { + MathML e2=element.element("mo"); + e2.appendChild(element.text("-")); + e1.appendChild(e2); + } + } else separateSign(e1,en); + l.toMathML(e1,null); + } + } + element.appendChild(e1); + } + + public static void separateSign(MathML element, Generic generic) { + if(generic.signum()<0) { + MathML e1=element.element("mo"); + e1.appendChild(element.text("-")); + element.appendChild(e1); + generic.negate().toMathML(element,null); + } else generic.toMathML(element,null); + } + + protected Expression newinstance(int n) { + return new Expression(n); + } +} diff --git a/src/misc/src/jscl/math/ExpressionVariable.java b/src/misc/src/jscl/math/ExpressionVariable.java new file mode 100644 index 00000000..745a9a0c --- /dev/null +++ b/src/misc/src/jscl/math/ExpressionVariable.java @@ -0,0 +1,57 @@ +package jscl.math; + +import jscl.mathml.MathML; + +public class ExpressionVariable extends GenericVariable { + public ExpressionVariable(Generic generic) { + super(generic); + } + + public Generic substitute(Variable variable, Generic generic) { + if(isIdentity(variable)) return generic; + else return content.substitute(variable,generic); + } + + public Generic elementary() { + return content.elementary(); + } + + public Generic simplify() { + return content.simplify(); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append("(").append(content).append(")"); + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer=new StringBuffer(); + buffer.append("(").append(content.toJava()).append(")"); + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent=data instanceof Integer?((Integer)data).intValue():1; + if(exponent==1) bodyToMathML(element); + else { + MathML e1=element.element("msup"); + bodyToMathML(e1); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element) { + MathML e1=element.element("mfenced"); + content.toMathML(e1,null); + element.appendChild(e1); + } + + protected Variable newinstance() { + return new ExpressionVariable(null); + } +} diff --git a/src/misc/src/jscl/math/Factorization.java b/src/misc/src/jscl/math/Factorization.java new file mode 100644 index 00000000..5c72ea42 --- /dev/null +++ b/src/misc/src/jscl/math/Factorization.java @@ -0,0 +1,290 @@ +package jscl.math; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; +import jscl.util.ArrayComparator; +import jscl.util.ArrayUtils; + +public class Factorization { + Polynomial factory; + Generic result; + + Factorization(Polynomial factory) { + this.factory=factory; + } + + public static Generic compute(Generic generic) { + try { + return GenericVariable.content(factorize(generic.integerValue())); + } catch (NotIntegerException e) { + Factorization f=new Factorization(Polynomial.factory(generic.variables(),Monomial.iteratorOrdering,-1)); + f.computeValue(generic); + return f.getValue(); + } + } + + static Generic factorize(JSCLInteger integer) { + Generic n[]=integer.gcdAndNormalize(); + Generic s=n[1]; + Generic a=JSCLInteger.valueOf(1); + Generic p=JSCLInteger.valueOf(2); + while(s.compareTo(JSCLInteger.valueOf(1))>0) { + Generic q[]=s.divideAndRemainder(p); + if(q[0].compareTo(p)<0) { + p=s; + q=s.divideAndRemainder(p); + } + if(q[1].signum()==0) { + a=a.multiply(expression(p,true)); + s=q[0]; + } else p=p.add(JSCLInteger.valueOf(1)); + } + return a.multiply(n[0]); + } + + void computeValue(Generic generic) { + Debug.println("factorization"); + Polynomial n[]=factory.valueof(generic).gcdAndNormalize(); + Monomial m=n[1].monomialGcd(); + Polynomial s=n[1].divide(m); + Generic a=JSCLInteger.valueOf(1); + Divisor d[]=new Divisor[2]; + Monomial p[]=new Monomial[2]; + Monomial q[]=new Monomial[2]; + d[1]=new Divisor(s.head().monomial()); + loop: while(d[1].hasNext()) { + p[1]=(Monomial)d[1].next(); + q[1]=d[1].complementary(); + d[0]=new Divisor(s.tail().monomial()); + while(d[0].hasNext()) { + p[0]=(Monomial)d[0].next(); + q[0]=d[0].complementary(); + if(p[1].compareTo(p[0])<=0) continue loop; + Debug.println(toString(p)+" * "+toString(q)+" = "+s); + if(ArrayComparator.comparator.compare(q,p)<0) { + a=a.multiply(expression(s.genericValue())); + break loop; + } else { + Debug.increment(); + Polynomial r[]=remainder(s,polynomial(s,p),terminator(s)); + Debug.decrement(); + if(r[0].signum()==0) { + a=a.multiply(expression(r[1].genericValue())); + s=r[2]; + d[1].divide(); + d[0].divide(); + continue loop; + } + } + } + } + result=a.multiply(n[0].multiply(m).genericValue()); + } + + static Polynomial[] remainder(Polynomial s, Polynomial p, Generic t[]) { + Polynomial zero=s.valueof(JSCLInteger.valueOf(0)); + Generic a[]=Basis.augment(t,s.remainderUpToCoefficient(p).elements()); + Variable unk[]=Basis.augmentUnknown(new Variable[] {},p.elements()); + { + Variable u=unk[unk.length-1]; + System.arraycopy(unk,0,unk,1,unk.length-1); + unk[0]=u; + } + Generic be[][]=Linearization.compute(Basis.compute(a,unk,Monomial.lexicographic,0,Basis.DEGREE).elements(),unk); + for(int i=0;i1) { + flag=false; + Polynomial r[]=linearize(p,t); + for(int j=0;j0) return 1; + else { + GenericVariable v=(GenericVariable)variable; + return content.compareTo(v.content); + } + } + + public static GenericVariable valueOf(Generic generic) { + return valueOf(generic,false); + } + + public static GenericVariable valueOf(Generic generic, boolean integer) { + if(integer) return new IntegerVariable(generic); + else return new ExpressionVariable(generic); + } + + public String toString() { + return content.toString(); + } + + public String toJava() { + return content.toJava(); + } + + public void toMathML(MathML element, Object data) { + content.toMathML(element,data); + } +} diff --git a/src/misc/src/jscl/math/IntegerVariable.java b/src/misc/src/jscl/math/IntegerVariable.java new file mode 100644 index 00000000..d562d02a --- /dev/null +++ b/src/misc/src/jscl/math/IntegerVariable.java @@ -0,0 +1,57 @@ +package jscl.math; + +import jscl.mathml.MathML; + +class IntegerVariable extends GenericVariable { + IntegerVariable(Generic generic) { + super(generic); + } + + public Generic substitute(Variable variable, Generic generic) { + if(isIdentity(variable)) return generic; + else return content.substitute(variable,generic); + } + + public Generic elementary() { + return content.elementary(); + } + + public Generic simplify() { + return content.simplify(); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append("(").append(content).append(")"); + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer=new StringBuffer(); + buffer.append("(").append(content.toJava()).append(")"); + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent=data instanceof Integer?((Integer)data).intValue():1; + if(exponent==1) bodyToMathML(element); + else { + MathML e1=element.element("msup"); + bodyToMathML(e1); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element) { + MathML e1=element.element("mfenced"); + content.toMathML(e1,null); + element.appendChild(e1); + } + + protected Variable newinstance() { + return new IntegerVariable(null); + } +} diff --git a/src/misc/src/jscl/math/JSCLBoolean.java b/src/misc/src/jscl/math/JSCLBoolean.java new file mode 100644 index 00000000..79fc2adc --- /dev/null +++ b/src/misc/src/jscl/math/JSCLBoolean.java @@ -0,0 +1,16 @@ +package jscl.math; + +public class JSCLBoolean extends ModularInteger { + public static final JSCLBoolean factory=new JSCLBoolean(0); + + public JSCLBoolean(long content) { + super(content,2); + } + + protected ModularInteger newinstance(long content) { + return content%2==0?zero:one; + } + + private static final JSCLBoolean zero=factory; + private static final JSCLBoolean one=new JSCLBoolean(1); +} diff --git a/src/misc/src/jscl/math/JSCLInteger.java b/src/misc/src/jscl/math/JSCLInteger.java new file mode 100644 index 00000000..e65f4187 --- /dev/null +++ b/src/misc/src/jscl/math/JSCLInteger.java @@ -0,0 +1,330 @@ +package jscl.math; + +import java.math.BigInteger; +import jscl.mathml.MathML; + +public final class JSCLInteger extends Generic { + public static final JSCLInteger factory=new JSCLInteger(BigInteger.valueOf(0)); + final BigInteger content; + + public JSCLInteger(BigInteger content) { + this.content=content; + } + + public BigInteger content() { + return content; + } + + public JSCLInteger add(JSCLInteger integer) { + return new JSCLInteger(content.add(integer.content)); + } + + public Generic add(Generic generic) { + if(generic instanceof JSCLInteger) { + return add((JSCLInteger)generic); + } else { + return generic.valueof(this).add(generic); + } + } + + public JSCLInteger subtract(JSCLInteger integer) { + return new JSCLInteger(content.subtract(integer.content)); + } + + public Generic subtract(Generic generic) { + if(generic instanceof JSCLInteger) { + return subtract((JSCLInteger)generic); + } else { + return generic.valueof(this).subtract(generic); + } + } + + public JSCLInteger multiply(JSCLInteger integer) { + return new JSCLInteger(content.multiply(integer.content)); + } + + public Generic multiply(Generic generic) { + if(generic instanceof JSCLInteger) { + return multiply((JSCLInteger)generic); + } else { + return generic.multiply(this); + } + } + + public JSCLInteger divide(JSCLInteger integer) throws ArithmeticException { + JSCLInteger e[]=divideAndRemainder(integer); + if(e[1].signum()==0) return e[0]; + else throw new NotDivisibleException(); + } + + public Generic divide(Generic generic) throws ArithmeticException { + if(generic instanceof JSCLInteger) { + return divide((JSCLInteger)generic); + } else { + return generic.valueof(this).divide(generic); + } + } + + public JSCLInteger[] divideAndRemainder(JSCLInteger integer) throws ArithmeticException { + BigInteger b[]=content.divideAndRemainder(integer.content); + return new JSCLInteger[] {new JSCLInteger(b[0]),new JSCLInteger(b[1])}; + } + + public Generic[] divideAndRemainder(Generic generic) throws ArithmeticException { + if(generic instanceof JSCLInteger) { + return divideAndRemainder((JSCLInteger)generic); + } else { + return generic.valueof(this).divideAndRemainder(generic); + } + } + + public JSCLInteger remainder(JSCLInteger integer) throws ArithmeticException { + return new JSCLInteger(content.remainder(integer.content)); + } + + public Generic remainder(Generic generic) throws ArithmeticException { + if(generic instanceof JSCLInteger) { + return remainder((JSCLInteger)generic); + } else { + return generic.valueof(this).remainder(generic); + } + } + + public JSCLInteger gcd(JSCLInteger integer) { + return new JSCLInteger(content.gcd(integer.content)); + } + + public Generic gcd(Generic generic) { + if(generic instanceof JSCLInteger) { + return gcd((JSCLInteger)generic); + } else { + return generic.valueof(this).gcd(generic); + } + } + + public Generic gcd() { + return new JSCLInteger(BigInteger.valueOf(signum())); + } + + public Generic pow(int exponent) { + return new JSCLInteger(content.pow(exponent)); + } + + public Generic negate() { + return new JSCLInteger(content.negate()); + } + + public int signum() { + return content.signum(); + } + + public int degree() { + return 0; + } + + public JSCLInteger mod(JSCLInteger integer) { + return new JSCLInteger(content.mod(integer.content)); + } + + public JSCLInteger modPow(JSCLInteger exponent, JSCLInteger integer) { + return new JSCLInteger(content.modPow(exponent.content,integer.content)); + } + + public JSCLInteger modInverse(JSCLInteger integer) { + return new JSCLInteger(content.modInverse(integer.content)); + } + + public JSCLInteger phi() { + if(signum()==0) return this; + Generic a=factorize(); + Generic p[]=a.productValue(); + Generic s=JSCLInteger.valueOf(1); + for(int i=0;i0; + } + if(b) r[k++]=m; + m=m.add(JSCLInteger.valueOf(1)); + } + return k>0?r:new JSCLInteger[0]; + } + + public JSCLInteger sqrt() { + return nthrt(2); + } + + public JSCLInteger nthrt(int n) { +// return JSCLInteger.valueOf((int)Math.pow((double)intValue(),1./n)); + if(signum()==0) return JSCLInteger.valueOf(0); + else if(signum()<0) { + if(n%2==0) throw new ArithmeticException(); + else return (JSCLInteger)((JSCLInteger)negate()).nthrt(n).negate(); + } else { + Generic x0; + Generic x=this; + do { + x0=x; + x=divideAndRemainder(x.pow(n-1))[0].add(x.multiply(JSCLInteger.valueOf(n-1))).divideAndRemainder(JSCLInteger.valueOf(n))[0]; + } while(x.compareTo(x0)<0); + return x0.integerValue(); + } + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + return multiply(variable.expressionValue()); + } + + public Generic derivative(Variable variable) { + return JSCLInteger.valueOf(0); + } + + public Generic substitute(Variable variable, Generic generic) { + return this; + } + + public Generic expand() { + return this; + } + + public Generic factorize() { + return Factorization.compute(this); + } + + public Generic elementary() { + return this; + } + + public Generic simplify() { + return this; + } + + public Generic numeric() { + return new NumericWrapper(this); + } + + public Generic valueof(Generic generic) { + return new JSCLInteger(((JSCLInteger)generic).content); + } + + public Generic[] sumValue() { + if(content.signum()==0) return new Generic[0]; + else return new Generic[] {this}; + } + + public Generic[] productValue() throws NotProductException { + if(content.compareTo(BigInteger.valueOf(1))==0) return new Generic[0]; + else return new Generic[] {this}; + } + + public Power powerValue() throws NotPowerException { + if(content.signum()<0) throw new NotPowerException(); + else return new Power(this,1); + } + + public Expression expressionValue() throws NotExpressionException { + return Expression.valueOf(this); + } + + public JSCLInteger integerValue() throws NotIntegerException { + return this; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(Variable variable) { + return true; + } + + public boolean isConstant(Variable variable) { + return true; + } + + public int intValue() { + return content.intValue(); + } + + public int compareTo(JSCLInteger integer) { + return content.compareTo(integer.content); + } + + public int compareTo(Generic generic) { + if(generic instanceof JSCLInteger) { + return compareTo((JSCLInteger)generic); + } else { + return generic.valueof(this).compareTo(generic); + } + } + + private static final JSCLInteger ZERO=new JSCLInteger(BigInteger.valueOf(0)); + private static final JSCLInteger ONE=new JSCLInteger(BigInteger.valueOf(1)); + + public static JSCLInteger valueOf(long val) { + switch((int)val) { + case 0: + return ZERO; + case 1: + return ONE; + default: + return new JSCLInteger(BigInteger.valueOf(val)); + } + } + + public static JSCLInteger valueOf(String str) { + return new JSCLInteger(new BigInteger(str)); + } + + public String toString() { + return content.toString(); + } + + public String toJava() { + return "JSCLDouble.valueOf("+content+")"; + } + + public void toMathML(MathML element, Object data) { + int exponent=data instanceof Integer?((Integer)data).intValue():1; + if(exponent==1) bodyToMathML(element); + else { + MathML e1=element.element("msup"); + bodyToMathML(e1); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element) { + MathML e1=element.element("mn"); + e1.appendChild(element.text(String.valueOf(content))); + element.appendChild(e1); + } +} diff --git a/src/misc/src/jscl/math/JSCLVector.java b/src/misc/src/jscl/math/JSCLVector.java new file mode 100644 index 00000000..6a1622b6 --- /dev/null +++ b/src/misc/src/jscl/math/JSCLVector.java @@ -0,0 +1,476 @@ +package jscl.math; + +import jscl.math.function.Conjugate; +import jscl.math.function.Frac; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +public class JSCLVector extends Generic { + protected final Generic element[]; + protected final int n; + + public JSCLVector(Generic element[]) { + this.element=element; + n=element.length; + } + + public Generic[] elements() { + return element; + } + + public JSCLVector add(JSCLVector vector) { + JSCLVector v=(JSCLVector)newinstance(); + for(int i=0;i0) return 1; + } + return 0; + } + + public int degree() { + return 0; + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + JSCLVector v=(JSCLVector)newinstance(); + for(int i=0;i0) { + for(int j=i;j0 && (j>i || i>=p)) s=!s; + } + } + } + return s; + } + + static int combination(int l, int n) { + if(n<=2) return l; + int b[]=new int[1]; + int l1=decimation(l,n,b); + int c=combination(l1,n-1); + return (c<<1)+b[0]; + } + + static int location(int c, int n) { + if(n<=2) return c; + int c1=c>>1; + int b=c&1; + int l1=location(c1,n-1); + return dilatation(l1,n,new int[] {b}); + } + + static int decimation(int l, int n, int b[]) { + int p=grade(l,n-1,1); + int p1=(p+1)>>1; + b[0]=p&1; + return l-sum(p1,n-1); + } + + static int dilatation(int l, int n, int b[]) { + int p1=grade(l,n-1); + return l+sum(p1+b[0],n-1); + } + + static int grade(int l, int n) { + return grade(l,n,0); + } + + static int grade(int l, int n, int d) { + int s=0, p=0; + while(true) { + s+=binomial(n,p>>d); + if(s<=l) p++; + else break; + } + return p; + } + + static int sum(int p, int n) { + int q=0, s=0; + while(q1;n>>=1) i++; + return i; + } + + int[][] operator() { + return operator; + } +} diff --git a/src/misc/src/jscl/math/Literal.java b/src/misc/src/jscl/math/Literal.java new file mode 100644 index 00000000..d4c4c8d2 --- /dev/null +++ b/src/misc/src/jscl/math/Literal.java @@ -0,0 +1,368 @@ +package jscl.math; + +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import jscl.math.function.Frac; +import jscl.math.function.Pow; +import jscl.math.polynomial.Monomial; +import jscl.mathml.MathML; + +public class Literal implements Comparable { + Variable variable[]; + int power[]; + int degree; + int size; + + Literal() {} + + Literal(int size) { + init(size); + } + + public int size() { + return size; + } + + public Variable variable(int n) { + return variable[n]; + } + + public int power(int n) { + return power[n]; + } + + void init(int size) { + variable=new Variable[size]; + power=new int[size]; + this.size=size; + } + + void resize(int size) { + if(size0) { + int s=literal.power[i2]; + l.variable[i]=v2; + l.power[i]=s; + l.degree+=s; + i++; + i2++; + v2=i20) { + throw new NotDivisibleException(); + } else { + int s=power[i1]-literal.power[i2]; + if(s<0) throw new NotDivisibleException(); + else if(s==0); + else { + l.variable[i]=v1; + l.power[i]=s; + l.degree+=s; + i++; + } + i1++; + i2++; + v1=i10) { + i2++; + v2=i20) { + int s=literal.power[i2]; + l.variable[i]=v2; + l.power[i]=s; + l.degree+=s; + i++; + i2++; + v2=i20) return 1; + else { + int c1=power[i1]; + int c2=literal.power[i2]; + if(c1c2) return 1; + v1=i1==0?null:variable[--i1]; + v2=i2==0?null:literal.variable[--i2]; + } + } + return 0; + } + + public int compareTo(Object o) { + return compareTo((Literal)o); + } + + public static Literal valueOf() { + return new Literal(0); + } + + public static Literal valueOf(Variable variable) { + return valueOf(variable,1); + } + + public static Literal valueOf(Variable variable, int power) { + Literal l=new Literal(); + l.init(variable,power); + return l; + } + + void init(Variable var, int pow) { + if(pow!=0) { + init(1); + variable[0]=var; + power[0]=pow; + degree=pow; + } else init(0); + } + + public static Literal valueOf(Monomial monomial) { + Literal l=new Literal(); + l.init(monomial); + return l; + } + + void init(Monomial monomial) { + Map map=new TreeMap(); + Variable unk[]=monomial.unknown(); + for(int i=0;i0) map.put(unk[i],new Integer(c)); + } + init(map.size()); + Iterator it=map.entrySet().iterator(); + for(int i=0;it.hasNext();i++) { + Map.Entry e=(Map.Entry)it.next(); + Variable v=(Variable)e.getKey(); + int c=((Integer)e.getValue()).intValue(); + variable[i]=v; + power[i]=c; + degree+=c; + } + } + + Map content() { + Map map=new TreeMap(); + for(int i=0;i0) buffer.append("*"); + Variable v=variable[i]; + int c=power[i]; + if(c==1) buffer.append(v); + else { + if(v instanceof Frac || v instanceof Pow) { + buffer.append("(").append(v).append(")"); + } else buffer.append(v); + buffer.append("^").append(c); + } + } + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer=new StringBuffer(); + if(degree==0) buffer.append("JSCLDouble.valueOf(1)"); + for(int i=0;i0) buffer.append(".multiply("); + Variable v=variable[i]; + int c=power[i]; + buffer.append(v.toJava()); + if(c==1); + else buffer.append(".pow(").append(c).append(")"); + if(i>0) buffer.append(")"); + } + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + if(degree==0) { + MathML e1=element.element("mn"); + e1.appendChild(element.text("1")); + element.appendChild(e1); + } + for(int i=0;i0?element[0].length:0; + } + + public Generic[][] elements() { + return element; + } + + public Matrix add(Matrix matrix) { + Matrix m=(Matrix)newinstance(); + for(int i=0;i0) return 1; + } + } + return 0; + } + + public int degree() { + return 0; + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + Matrix m=(Matrix)newinstance(); + for(int i=0;i1) { + Generic a=JSCLInteger.valueOf(0); + for(int i=0;i0) return element[0][0]; + else return JSCLInteger.valueOf(0); + } + + public Generic conjugate() { + Matrix m=(Matrix)newinstance(); + for(int i=0;i0?vector[0].n:0][vector.length]); + for(int i=0;i0?1:0; + } + + public int degree() { + return 0; + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + throw new UnsupportedOperationException(); + } + + public Generic derivative(Variable variable) { + throw new UnsupportedOperationException(); + } + + public Generic substitute(Variable variable, Generic generic) { + throw new UnsupportedOperationException(); + } + + public Generic expand() { + throw new UnsupportedOperationException(); + } + + public Generic factorize() { + throw new UnsupportedOperationException(); + } + + public Generic elementary() { + throw new UnsupportedOperationException(); + } + + public Generic simplify() { + throw new UnsupportedOperationException(); + } + + public Generic numeric() { + throw new UnsupportedOperationException(); + } + + public Generic valueof(Generic generic) { + if(generic instanceof ModularInteger) { + return newinstance(((ModularInteger)generic).content); + } else { + return newinstance(((JSCLInteger)generic).content().mod(BigInteger.valueOf(modulo)).intValue()); + } + } + + public Generic[] sumValue() { + throw new UnsupportedOperationException(); + } + + public Generic[] productValue() throws NotProductException { + throw new UnsupportedOperationException(); + } + + public Power powerValue() throws NotPowerException { + throw new UnsupportedOperationException(); + } + + public Expression expressionValue() throws NotExpressionException { + return Expression.valueOf(integerValue()); + } + + public JSCLInteger integerValue() throws NotIntegerException { + return JSCLInteger.valueOf(content); + } + + public Variable variableValue() throws NotVariableException { + throw new UnsupportedOperationException(); + } + + public Variable[] variables() { + throw new UnsupportedOperationException(); + } + + public boolean isPolynomial(Variable variable) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(Variable variable) { + throw new UnsupportedOperationException(); + } + + public int compareTo(ModularInteger integer) { + return contentinteger.content?1:0; + } + + public int compareTo(Generic generic) { + if(generic instanceof ModularInteger) { + return compareTo((ModularInteger)generic); + } else if(generic instanceof JSCLInteger) { + return compareTo(valueof(generic)); + } else { + throw new UnsupportedOperationException(); + } + } + + public static ModularInteger factory(int modulo) { + return new ModularInteger(0,modulo); + } + + public String toString() { + return ""+content; + } + + public String toJava() { + throw new UnsupportedOperationException(); + } + + public void toMathML(MathML element, Object data) { + throw new UnsupportedOperationException(); + } + + protected ModularInteger newinstance(long content) { + return new ModularInteger(content,modulo); + } +} diff --git a/src/misc/src/jscl/math/NotDivisibleException.java b/src/misc/src/jscl/math/NotDivisibleException.java new file mode 100644 index 00000000..29ac1bac --- /dev/null +++ b/src/misc/src/jscl/math/NotDivisibleException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotDivisibleException extends ArithmeticException { + public NotDivisibleException() {} + + public NotDivisibleException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotExpressionException.java b/src/misc/src/jscl/math/NotExpressionException.java new file mode 100644 index 00000000..b1daf564 --- /dev/null +++ b/src/misc/src/jscl/math/NotExpressionException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotExpressionException extends ArithmeticException { + public NotExpressionException() {} + + public NotExpressionException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotIntegerException.java b/src/misc/src/jscl/math/NotIntegerException.java new file mode 100644 index 00000000..053c65d8 --- /dev/null +++ b/src/misc/src/jscl/math/NotIntegerException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotIntegerException extends ArithmeticException { + public NotIntegerException() {} + + public NotIntegerException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotIntegrableException.java b/src/misc/src/jscl/math/NotIntegrableException.java new file mode 100644 index 00000000..41017f32 --- /dev/null +++ b/src/misc/src/jscl/math/NotIntegrableException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotIntegrableException extends ArithmeticException { + public NotIntegrableException() {} + + public NotIntegrableException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotPowerException.java b/src/misc/src/jscl/math/NotPowerException.java new file mode 100644 index 00000000..eaa5ed69 --- /dev/null +++ b/src/misc/src/jscl/math/NotPowerException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotPowerException extends ArithmeticException { + public NotPowerException() {} + + public NotPowerException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotProductException.java b/src/misc/src/jscl/math/NotProductException.java new file mode 100644 index 00000000..c0a35ed1 --- /dev/null +++ b/src/misc/src/jscl/math/NotProductException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotProductException extends ArithmeticException { + public NotProductException() {} + + public NotProductException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NotVariableException.java b/src/misc/src/jscl/math/NotVariableException.java new file mode 100644 index 00000000..46580201 --- /dev/null +++ b/src/misc/src/jscl/math/NotVariableException.java @@ -0,0 +1,9 @@ +package jscl.math; + +public class NotVariableException extends ArithmeticException { + public NotVariableException() {} + + public NotVariableException(String s) { + super(s); + } +} diff --git a/src/misc/src/jscl/math/NumericWrapper.java b/src/misc/src/jscl/math/NumericWrapper.java new file mode 100644 index 00000000..b3d852c3 --- /dev/null +++ b/src/misc/src/jscl/math/NumericWrapper.java @@ -0,0 +1,344 @@ +package jscl.math; + +import jscl.math.function.Constant; +import jscl.math.numeric.JSCLDouble; +import jscl.math.numeric.Numeric; +import jscl.math.numeric.NumericMatrix; +import jscl.math.numeric.NumericVector; +import jscl.mathml.MathML; + +public final class NumericWrapper extends Generic { + final Numeric content; + + public NumericWrapper(JSCLInteger integer) { + content=JSCLDouble.valueOf(integer.content().doubleValue()); + } + + public NumericWrapper(Rational rational) { + content=JSCLDouble.valueOf(rational.numerator().doubleValue()/rational.denominator().doubleValue()); + } + + public NumericWrapper(JSCLVector vector) { + Numeric v[]=new Numeric[vector.n]; + for(int i=0;i0) return 1; + else return numerator.compareTo(rational.numerator); + } + + public int compareTo(Generic generic) { + if(generic instanceof Rational) { + return compareTo((Rational)generic); + } else if(generic instanceof JSCLInteger) { + return compareTo(valueof(generic)); + } else { + return generic.valueof(this).compareTo(generic); + } + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + try { + buffer.append(integerValue()); + } catch (NotIntegerException e) { + buffer.append(numerator); + buffer.append("/"); + buffer.append(denominator); + } + return buffer.toString(); + } + + public String toJava() { + return "JSCLDouble.valueOf("+numerator+"/"+denominator+")"; + } + + public void toMathML(MathML element, Object data) { + int exponent=data instanceof Integer?((Integer)data).intValue():1; + if(exponent==1) bodyToMathML(element); + else { + MathML e1=element.element("msup"); + bodyToMathML(e1); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element) { + try { + MathML e1=element.element("mn"); + e1.appendChild(element.text(String.valueOf(integerValue()))); + element.appendChild(e1); + } catch (NotIntegerException e) { + MathML e1=element.element("mfrac"); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(numerator))); + e1.appendChild(e2); + e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(denominator))); + e1.appendChild(e2); + element.appendChild(e1); + } + } +} diff --git a/src/misc/src/jscl/math/Simplification.java b/src/misc/src/jscl/math/Simplification.java new file mode 100644 index 00000000..d1f2eb9c --- /dev/null +++ b/src/misc/src/jscl/math/Simplification.java @@ -0,0 +1,226 @@ +package jscl.math; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import jscl.math.function.Cubic; +import jscl.math.function.Frac; +import jscl.math.function.NotRootException; +import jscl.math.function.Pow; +import jscl.math.function.Root; +import jscl.math.function.Sqrt; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; + +public class Simplification { + Map cache=new TreeMap(); + Generic result; + List constraint; + boolean linear; + + Simplification() {} + + public static Generic compute(Generic generic) { + Simplification s=new Simplification(); + s.computeValue(generic); + return s.getValue(); + } + + void computeValue(Generic generic) { + Debug.println("simplification"); + Debug.increment(); + Variable t=new TechnicalVariable("t"); + linear=false; + constraint=new ArrayList(); + process(new Constraint(t,t.expressionValue().subtract(generic),false)); + UnivariatePolynomial p=polynomial(t); + switch(p.degree()) { + case 0: + result=generic; + break; + case 1: + result=new Root(p,0).evalsimp(); + break; +// case 2: +// int n=branch(generic,p); +// if(n1); + } catch (NotRootException e) { + co=linearConstraint(v); + } + } else if(v instanceof Root) { + try { + Root r=(Root)v; + int d=r.degree(); + int n=r.subscript().integerValue().intValue(); + Generic g[]=r.parameters(); + if(linear) co=linearConstraint(v); + if(co==null) co=new Constraint(v,Root.sigma(g,d-n).multiply(JSCLInteger.valueOf(-1).pow(d-n)).multiply(g[d]).subtract(g[n]),d>1); + } catch (NotIntegerException e) { + co=linearConstraint(v); + } + } else co=linearConstraint(v); + if(co!=null) constraint.add(co); + } + } + + Constraint linearConstraint(Variable v) { + Generic s; + Object o=cache.get(v); + if(o!=null) s=(Generic)o; + else { + s=v.simplify(); + cache.put(v,s); + } + Generic a=v.expressionValue().subtract(s); + if(a.signum()!=0) return new Constraint(v,a,false); + else return null; + } + + Generic getValue() { + return result; + } +} + +class Constraint { + Variable unknown; + Generic generic; + boolean reduce; + + Constraint(Variable unknown, Generic generic, boolean reduce) { + this.unknown=unknown; + this.generic=generic; + this.reduce=reduce; + } + + Constraint(Variable unknown) { + this(unknown,null,false); + } + + public boolean equals(Object obj) { + return unknown.compareTo(((Constraint)obj).unknown)==0; + } +} diff --git a/src/misc/src/jscl/math/TechnicalVariable.java b/src/misc/src/jscl/math/TechnicalVariable.java new file mode 100644 index 00000000..06cfbfc1 --- /dev/null +++ b/src/misc/src/jscl/math/TechnicalVariable.java @@ -0,0 +1,96 @@ +package jscl.math; + +public class TechnicalVariable extends Variable { + public int subscript[]; + + public TechnicalVariable(String name) { + this(name,new int[0]); + } + + public TechnicalVariable(String name, int subscript[]) { + super(name); + this.subscript=subscript; + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + throw new NotIntegrableException(); + } + + public Generic derivative(Variable variable) { + if(isIdentity(variable)) return JSCLInteger.valueOf(1); + else return JSCLInteger.valueOf(0); + } + + public Generic substitute(Variable variable, Generic generic) { + if(isIdentity(variable)) return generic; + else return expressionValue(); + } + + public Generic expand() { + return expressionValue(); + } + + public Generic factorize() { + return expressionValue(); + } + + public Generic elementary() { + return expressionValue(); + } + + public Generic simplify() { + return expressionValue(); + } + + public Generic numeric() { + throw new ArithmeticException(); + } + + public boolean isConstant(Variable variable) { + return !isIdentity(variable); + } + + public int compareTo(Variable variable) { + if(this==variable) return 0; + int c=comparator.compare(this,variable); + if(c<0) return -1; + else if(c>0) return 1; + else { + TechnicalVariable v=(TechnicalVariable)variable; + c=name.compareTo(v.name); + if(c<0) return -1; + else if(c>0) return 1; + else return compareSubscript(subscript,v.subscript); + } + } + + public int compareSubscript(int c1[], int c2[]) { + if(c1.lengthc2.length) return 1; + for(int i=0;ic2[i]) return 1; + } + return 0; + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append(name); + if(subscript.length==1) buffer.append(subscript[0]); + else for(int i=0;i0; + case 3: + return a1.compareTo(a2)!=0; + case 4: + return a1.compareTo(a2)<=0; + case 5: + return a1.compareTo(a2)>=0; + case 6: + return a1.compareTo(a2)==0; + default: + return false; + } + } + + public String toJava() { + StringBuffer buffer=new StringBuffer(); + buffer.append(parameter[0].toJava()).append(easj[operator]).append(parameter[1].toJava()); + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + parameter[0].toMathML(element,null); + MathML e1=element.element("mo"); + e1.appendChild(element.text(easm[operator])); + element.appendChild(e1); + parameter[1].toMathML(element,null); + } + + protected Variable newinstance() { + return new Comparison(name,null,null); + } + + private static final String eass[]={"=","<=",">=","<>","<",">","~"}; + private static final String easj[]={"==","<=",">=","!=","<",">","=="}; + private static final String easm[]={"=","\u2264","\u2265","\u2260","<",">","\u2248"}; + private static final String easo[]={"eq","le","ge","ne","lt","gt","ap"}; +} diff --git a/src/misc/src/jscl/math/function/Conjugate.java b/src/misc/src/jscl/math/function/Conjugate.java new file mode 100644 index 00000000..40d52ece --- /dev/null +++ b/src/misc/src/jscl/math/function/Conjugate.java @@ -0,0 +1,132 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.JSCLVector; +import jscl.math.Matrix; +import jscl.math.NotIntegerException; +import jscl.math.NotIntegrableException; +import jscl.math.NotVariableException; +import jscl.math.NumericWrapper; +import jscl.math.Power; +import jscl.math.Variable; +import jscl.mathml.MathML; + +public class Conjugate extends Function { + public Conjugate(Generic generic) { + super("conjugate",new Generic[] {generic}); + } + + public Generic antiderivative(int n) throws NotIntegrableException { + return Constant.half.multiply(evaluate().pow(2)); + } + + public Generic derivative(int n) { + return JSCLInteger.valueOf(1); + } + + public Generic evaluate() { + try { + return parameter[0].integerValue(); + } catch (NotIntegerException e) {} + if(parameter[0] instanceof Matrix) { + return ((Matrix)parameter[0]).conjugate(); + } else if(parameter[0] instanceof JSCLVector) { + return ((JSCLVector)parameter[0]).conjugate(); + } + return expressionValue(); + } + + public Generic evalelem() { + try { + return parameter[0].integerValue(); + } catch (NotIntegerException e) {} + return expressionValue(); + } + + public Generic evalsimp() { + try { + return parameter[0].integerValue(); + } catch (NotIntegerException e) {} + if(parameter[0].signum()<0) { + return new Conjugate(parameter[0].negate()).evalsimp().negate(); + } else if(parameter[0].compareTo(Constant.i)==0) { + return Constant.i.negate(); + } + try { + Variable v=parameter[0].variableValue(); + if(v instanceof Conjugate) { + Generic g[]=((Conjugate)v).parameters(); + return g[0]; + } else if(v instanceof Exp) { + Generic g[]=((Exp)v).parameters(); + return new Exp(new Conjugate(g[0]).evalsimp()).evalsimp(); + } else if(v instanceof Log) { + Generic g[]=((Log)v).parameters(); + return new Log(new Conjugate(g[0]).evalsimp()).evalsimp(); + } + } catch (NotVariableException e) { + Generic a[]=parameter[0].sumValue(); + if(a.length>1) { + Generic s=JSCLInteger.valueOf(0); + for(int i=0;i0) return 1; + else { + Constant v=(Constant)variable; + c=name.compareTo(v.name); + if(c<0) return -1; + else if(c>0) return 1; + else { + c=ArrayComparator.comparator.compare(subscript,v.subscript); + if(c<0) return -1; + else if(c>0) return 1; + else { + if(primev.prime) return 1; + else return 0; + } + } + } + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append(name); + for(int i=0;i1) { + Generic s=JSCLInteger.valueOf(1); + for(int i=0;i0) return 1; + else { + Function v=(Function)variable; + c=name.compareTo(v.name); + if(c<0) return -1; + else if(c>0) return 1; + else return ArrayComparator.comparator.compare(parameter,v.parameter); + } + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append(name); + buffer.append("("); + for(int i=0;i0) c[i]=derivation[i]-1; + else throw new NotIntegrableException(); + } else c[i]=derivation[i]; + } + return new ImplicitFunction(name,parameter,c,subscript).evaluate(); + } + + public Generic derivative(int n) { + int c[]=new int[derivation.length]; + for(int i=0;i0) return 1; + else { + ImplicitFunction v=(ImplicitFunction)variable; + c=name.compareTo(v.name); + if(c<0) return -1; + else if(c>0) return 1; + else { + c=ArrayComparator.comparator.compare(subscript,v.subscript); + if(c<0) return -1; + else if(c>0) return 1; + else { + c=compareDerivation(derivation,v.derivation); + if(c<0) return -1; + else if(c>0) return 1; + else return ArrayComparator.comparator.compare(parameter,v.parameter); + } + } + } + } + + static int compareDerivation(int c1[], int c2[]) { + int n=c1.length; + for(int i=n-1;i>=0;i--) { + if(c1[i]c2[i]) return 1; + } + return 0; + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + int n=0; + for(int i=0;i0) { + Generic a[]=new Generic[d+1]; + a[0]=parameter[0].negate(); + for(int i=1;i0; + for(int i=0;i0; + for(int i=1;i0) return 1; + else { + Root v=(Root)variable; + c=ArrayComparator.comparator.compare(parameter,v.parameter); + if(c<0) return -1; + else if(c>0) return 1; + else return subscript.compareTo(v.subscript); + } + } + + public static Generic sigma(Generic parameter[], int n) { + Sigma s=new Sigma(parameter,n); + s.compute(); + return s.getValue(); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append(name); + buffer.append("[").append(subscript).append("]"); + buffer.append("("); + for(int i=0;i0) { + for(int i=p;i1) { +// Generic s=JSCLInteger.valueOf(0); +// for(int i=1;icomplex.imag) return 1; + else if(imag==complex.imag) { + if(realcomplex.real) return 1; + else if(real==complex.real) return 0; + else throw new ArithmeticException(); + } else throw new ArithmeticException(); + } + + public int compareTo(Numeric numeric) { + if(numeric instanceof Complex) { + return compareTo((Complex)numeric); + } else if(numeric instanceof JSCLDouble) { + return compareTo(valueof(numeric)); + } else { + return numeric.valueof(this).compareTo(numeric); + } + } + + public static Complex valueOf(double real, double imag) { + return new Complex(real,imag); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + if(imag==0.) { + buffer.append(real); + } else { + if(real==0.); + else { + buffer.append(real); + if(imag<=0.); + else buffer.append("+"); + } + if(imag==1.); + else if(imag==-1.) buffer.append("-"); + else { + buffer.append(imag); + buffer.append("*"); + } + buffer.append("sqrt(-1)"); + } + return buffer.toString(); + } +} diff --git a/src/misc/src/jscl/math/numeric/JSCLDouble.java b/src/misc/src/jscl/math/numeric/JSCLDouble.java new file mode 100644 index 00000000..cc10d65e --- /dev/null +++ b/src/misc/src/jscl/math/numeric/JSCLDouble.java @@ -0,0 +1,174 @@ +package jscl.math.numeric; + +public final class JSCLDouble extends Numeric { + double content; + + JSCLDouble(double val) { + content=val; + } + + public JSCLDouble add(JSCLDouble dble) { + return new JSCLDouble(content+dble.content); + } + + public Numeric add(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return add((JSCLDouble)numeric); + } else { + return numeric.valueof(this).add(numeric); + } + } + + public JSCLDouble subtract(JSCLDouble dble) { + return new JSCLDouble(content-dble.content); + } + + public Numeric subtract(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return subtract((JSCLDouble)numeric); + } else { + return numeric.valueof(this).subtract(numeric); + } + } + + public JSCLDouble multiply(JSCLDouble dble) { + return new JSCLDouble(content*dble.content); + } + + public Numeric multiply(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return multiply((JSCLDouble)numeric); + } else { + return numeric.multiply(this); + } + } + + public JSCLDouble divide(JSCLDouble dble) throws ArithmeticException { + return new JSCLDouble(content/dble.content); + } + + public Numeric divide(Numeric numeric) throws ArithmeticException { + if(numeric instanceof JSCLDouble) { + return divide((JSCLDouble)numeric); + } else { + return numeric.valueof(this).divide(numeric); + } + } + + public Numeric negate() { + return new JSCLDouble(-content); + } + + public int signum() { + return content==0.?0:(content<0.?-1:1); + } + + public Numeric log() { + return new JSCLDouble(Math.log(content)); + } + + public Numeric exp() { + return new JSCLDouble(Math.exp(content)); + } + + public Numeric inverse() { + return new JSCLDouble(1./content); + } + + public Numeric pow(JSCLDouble dble) { + if(signum()<0) { + return Complex.valueOf(content,0).pow(dble); + } else { + return new JSCLDouble(Math.pow(content,dble.content)); + } + } + + public Numeric pow(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return pow((JSCLDouble)numeric); + } else { + return numeric.valueof(this).pow(numeric); + } + } + + public Numeric sqrt() { + if(signum()<0) { + return Complex.valueOf(0,1).multiply(negate().sqrt()); + } else { + return new JSCLDouble(Math.sqrt(content)); + } + } + + public Numeric nthrt(int n) { + if(signum()<0) { + return n%2==0?sqrt().nthrt(n/2):negate().nthrt(n).negate(); + } else { + return super.nthrt(n); + } + } + + public Numeric conjugate() { + return this; + } + + public Numeric acos() { + return new JSCLDouble(Math.acos(content)); + } + + public Numeric asin() { + return new JSCLDouble(Math.asin(content)); + } + + public Numeric atan() { + return new JSCLDouble(Math.atan(content)); + } + + public Numeric cos() { + return new JSCLDouble(Math.cos(content)); + } + + public Numeric sin() { + return new JSCLDouble(Math.sin(content)); + } + + public Numeric tan() { + return new JSCLDouble(Math.tan(content)); + } + + public JSCLDouble valueof(JSCLDouble dble) { + return new JSCLDouble(dble.content); + } + + public Numeric valueof(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return valueof((JSCLDouble)numeric); + } else throw new ArithmeticException(); + } + + public double doubleValue() { + return content; + } + + public int compareTo(JSCLDouble dble) { + if(contentdble.content) return 1; + else if(content==dble.content) return 0; + else throw new ArithmeticException(); + } + + public int compareTo(Numeric numeric) { + if(numeric instanceof JSCLDouble) { + return compareTo((JSCLDouble)numeric); + } else { + return numeric.valueof(this).compareTo(numeric); + } + } + + public static JSCLDouble valueOf(double val) { + return new JSCLDouble(val); + } + + public String toString() { + return new Double(content).toString(); + } +} diff --git a/src/misc/src/jscl/math/numeric/Numeric.java b/src/misc/src/jscl/math/numeric/Numeric.java new file mode 100644 index 00000000..c2044ee0 --- /dev/null +++ b/src/misc/src/jscl/math/numeric/Numeric.java @@ -0,0 +1,156 @@ +package jscl.math.numeric; + +import jscl.math.Arithmetic; + +public abstract class Numeric implements Arithmetic, Comparable { + public abstract Numeric add(Numeric numeric); + + public Numeric subtract(Numeric numeric) { + return add(numeric.negate()); + } + + public abstract Numeric multiply(Numeric numeric); + public abstract Numeric divide(Numeric numeric) throws ArithmeticException; + + public Arithmetic add(Arithmetic arithmetic) { + return add((Numeric)arithmetic); + } + + public Arithmetic subtract(Arithmetic arithmetic) { + return subtract((Numeric)arithmetic); + } + + public Arithmetic multiply(Arithmetic arithmetic) { + return multiply((Numeric)arithmetic); + } + + public Arithmetic divide(Arithmetic arithmetic) throws ArithmeticException { + return divide((Numeric)arithmetic); + } + + public Numeric pow(int exponent) { + Numeric a=JSCLDouble.valueOf(1); + for(int i=0;i0?element[0].length:0; + } + + public Numeric[][] elements() { + return element; + } + + public NumericMatrix add(NumericMatrix matrix) { + NumericMatrix m=(NumericMatrix)newinstance(); + for(int i=0;i0) return 1; + } + } + return 0; + } + + public Numeric valueof(Numeric numeric) { + if(numeric instanceof NumericMatrix || numeric instanceof NumericVector) { + throw new ArithmeticException(); + } else { + NumericMatrix m=(NumericMatrix)identity(n,p).multiply(numeric); + return newinstance(m.element); + } + } + + public Numeric[] vectors() { + NumericVector v[]=new NumericVector[n]; + for(int i=0;i1) { + Numeric a=JSCLDouble.valueOf(0); + for(int i=0;i0) return element[0][0]; + else return JSCLDouble.valueOf(0); + } + + public Numeric log() { + throw new ArithmeticException(); + } + + public Numeric exp() { + throw new ArithmeticException(); + } + + public Numeric conjugate() { + NumericMatrix m=(NumericMatrix)newinstance(); + for(int i=0;i0) return 1; + } + return 0; + } + + public Numeric valueof(Numeric numeric) { + if(numeric instanceof NumericVector || numeric instanceof NumericMatrix) { + throw new ArithmeticException(); + } else { + NumericVector v=(NumericVector)unity(n).multiply(numeric); + return newinstance(v.element); + } + } + + public Numeric magnitude2() { + return scalarProduct(this); + } + + public Numeric scalarProduct(NumericVector vector) { + Numeric a=JSCLDouble.valueOf(0); + for(int i=0;i0) return 1; + else { + Factorial v=(Factorial)variable; + return ArrayComparator.comparator.compare(parameter,v.parameter); + } + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + try { + JSCLInteger en=parameter[0].integerValue(); + buffer.append(en); + } catch (NotIntegerException e) { + try { + Variable v=parameter[0].variableValue(); + if(v instanceof Frac || v instanceof Pow) { + buffer.append(GenericVariable.valueOf(parameter[0])); + } else buffer.append(v); + } catch (NotVariableException e2) { + buffer.append(GenericVariable.valueOf(parameter[0])); + } + } + buffer.append("!"); + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent=data instanceof Integer?((Integer)data).intValue():1; + if(exponent==1) bodyToMathML(element); + else { + MathML e1=element.element("msup"); + bodyToMathML(e1); + MathML e2=element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element) { + MathML e1=element.element("mrow"); + try { + JSCLInteger en=parameter[0].integerValue(); + en.toMathML(e1,null); + } catch (NotIntegerException e) { + try { + Variable v=parameter[0].variableValue(); + if(v instanceof Pow) { + GenericVariable.valueOf(parameter[0]).toMathML(e1,null); + } else v.toMathML(e1,null); + } catch (NotVariableException e2) { + GenericVariable.valueOf(parameter[0]).toMathML(e1,null); + } + } + MathML e2=element.element("mo"); + e2.appendChild(element.text("!")); + e1.appendChild(e2); + element.appendChild(e1); + } + + protected Variable newinstance() { + return new Factorial(null); + } +} diff --git a/src/misc/src/jscl/math/operator/Groebner.java b/src/misc/src/jscl/math/operator/Groebner.java new file mode 100644 index 00000000..52d9e427 --- /dev/null +++ b/src/misc/src/jscl/math/operator/Groebner.java @@ -0,0 +1,138 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.GenericVariable; +import jscl.math.JSCLInteger; +import jscl.math.JSCLVector; +import jscl.math.Variable; +import jscl.math.function.Constant; +import jscl.math.function.ImplicitFunction; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; +import jscl.mathml.MathML; + +public class Groebner extends Operator { + public Groebner(Generic generic, Generic variable, Generic ordering, Generic modulo) { + super("groebner",new Generic[] {generic,variable,ordering,modulo}); + } + + public Generic compute() { + Generic generic[]=((JSCLVector)parameter[0]).elements(); + Variable variable[]=variables(parameter[1]); + Ordering ord=ordering(parameter[2]); + int m=parameter[3].integerValue().intValue(); + return new PolynomialVector(Basis.compute(generic,variable,ord,m)); + } + + public Operator transmute() { + Generic p[]=new Generic[] {GenericVariable.content(parameter[0]),GenericVariable.content(parameter[1])}; + if(p[0] instanceof JSCLVector && p[1] instanceof JSCLVector) { + Generic generic[]=((JSCLVector)p[0]).elements(); + Variable variable[]=variables(p[1]); + Ordering ord=ordering(parameter[2]); + int m=parameter[3].integerValue().intValue(); + return new Groebner(new PolynomialVector(new Basis(generic,Polynomial.factory(variable,ord,m))),p[1],parameter[2],parameter[3]); + } + return this; + } + + static Ordering ordering(Generic generic) { + Variable v=generic.variableValue(); + if(v.compareTo(new Constant("lex"))==0) return Monomial.lexicographic; + else if(v.compareTo(new Constant("tdl"))==0) return Monomial.totalDegreeLexicographic; + else if(v.compareTo(new Constant("drl"))==0) return Monomial.degreeReverseLexicographic; + else if(v instanceof ImplicitFunction) { + Generic g[]=((ImplicitFunction)v).parameters(); + int k=g[0].integerValue().intValue(); + if(v.compareTo(new ImplicitFunction("elim",new Generic[] {JSCLInteger.valueOf(k)},new int[] {0},new Generic[] {}))==0) return Monomial.kthElimination(k); + } + throw new ArithmeticException(); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + int n=4; + if(parameter[3].signum()==0) { + n=3; + if(ordering(parameter[2])==Monomial.lexicographic) n=2; + } + buffer.append(name); + buffer.append("("); + for(int i=0;i0?generic:new Generic[] {JSCLInteger.valueOf(0)}); + this.basis=basis; + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + buffer.append("{"); + for(int i=0;i0) e5.appendChild(element.text("+")); + e4.appendChild(e5); + e3.appendChild(e4); + } + e2.appendChild(e3); + e1.appendChild(e2); + parameter[0].toMathML(e1,null); + element.appendChild(e1); + } + + protected Variable newinstance() { + return new Limit(null,null,null,null); + } +} diff --git a/src/misc/src/jscl/math/operator/Modulo.java b/src/misc/src/jscl/math/operator/Modulo.java new file mode 100644 index 00000000..2325f649 --- /dev/null +++ b/src/misc/src/jscl/math/operator/Modulo.java @@ -0,0 +1,25 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; + +public class Modulo extends Operator { + public Modulo(Generic expression1, Generic expression2) { + super("mod",new Generic[] {expression1,expression2}); + } + + public Generic compute() { + try { + JSCLInteger en=parameter[0].integerValue(); + JSCLInteger en2=parameter[1].integerValue(); + return en.mod(en2); + } catch (NotIntegerException e) {} + return parameter[0].remainder(parameter[1]); + } + + protected Variable newinstance() { + return new Modulo(null,null); + } +} diff --git a/src/misc/src/jscl/math/operator/Operator.java b/src/misc/src/jscl/math/operator/Operator.java new file mode 100644 index 00000000..b36d2e75 --- /dev/null +++ b/src/misc/src/jscl/math/operator/Operator.java @@ -0,0 +1,140 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.JSCLVector; +import jscl.math.NotIntegrableException; +import jscl.math.NotVariableException; +import jscl.math.Variable; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +public abstract class Operator extends Variable { + protected Generic parameter[]; + + public Operator(String name, Generic parameter[]) { + super(name); + this.parameter=parameter; + } + + public Generic[] parameters() { + return parameter; + } + + public abstract Generic compute(); + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + return null; + } + + public Generic derivative(Variable variable) { + if(isIdentity(variable)) return JSCLInteger.valueOf(1); + else return JSCLInteger.valueOf(0); + } + + public Generic substitute(Variable variable, Generic generic) { + Operator v=(Operator)newinstance(); + for(int i=0;i0) return 1; + else { + Operator v=(Operator)variable; + c=name.compareTo(v.name); + if(c<0) return -1; + else if(c>0) return 1; + else return ArrayComparator.comparator.compare(parameter,v.parameter); + } + } + + protected static Variable[] variables(Generic generic) throws NotVariableException { + Generic element[]=((JSCLVector)generic).elements(); + Variable variable[]=new Variable[element.length]; + for(int i=0;i0?a:new Generic[] {JSCLInteger.valueOf(0)}); + } catch (NotIntegerException e) {} + return expressionValue(); + } + + protected Variable newinstance() { + return new PrimitiveRoots(null); + } +} diff --git a/src/misc/src/jscl/math/operator/product/ComplexProduct.java b/src/misc/src/jscl/math/operator/product/ComplexProduct.java new file mode 100644 index 00000000..ed0a47ec --- /dev/null +++ b/src/misc/src/jscl/math/operator/product/ComplexProduct.java @@ -0,0 +1,31 @@ +package jscl.math.operator.product; + +import jscl.math.Generic; +import jscl.math.JSCLVector; +import jscl.math.Variable; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +public class ComplexProduct extends VectorOperator { + public ComplexProduct(Generic vector1, Generic vector2) { + super("complex",new Generic[] {vector1,vector2}); + } + + public Generic compute() { + if(parameter[0] instanceof JSCLVector && parameter[1] instanceof JSCLVector) { + JSCLVector v1=(JSCLVector)parameter[0]; + JSCLVector v2=(JSCLVector)parameter[1]; + return v1.complexProduct(v2); + } + return expressionValue(); + } + + protected void bodyToMathML(MathML element) { + parameter[0].toMathML(element,null); + parameter[1].toMathML(element,null); + } + + protected Variable newinstance() { + return new ComplexProduct(null,null); + } +} diff --git a/src/misc/src/jscl/math/operator/product/GeometricProduct.java b/src/misc/src/jscl/math/operator/product/GeometricProduct.java new file mode 100644 index 00000000..f5acaea6 --- /dev/null +++ b/src/misc/src/jscl/math/operator/product/GeometricProduct.java @@ -0,0 +1,59 @@ +package jscl.math.operator.product; + +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.JSCLVector; +import jscl.math.Variable; +import jscl.math.function.ImplicitFunction; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +public class GeometricProduct extends VectorOperator { + public GeometricProduct(Generic vector1, Generic vector2, Generic algebra) { + super("geometric",new Generic[] {vector1,vector2,algebra}); + } + + public Generic compute() { + int algebra[]=algebra(parameter[2]); + if(parameter[0] instanceof JSCLVector && parameter[1] instanceof JSCLVector) { + JSCLVector v1=(JSCLVector)parameter[0]; + JSCLVector v2=(JSCLVector)parameter[1]; + return v1.geometricProduct(v2,algebra); + } + return expressionValue(); + } + + public static int[] algebra(Generic generic) { + if(generic.signum()==0) return null; + Variable v=generic.variableValue(); + if(v instanceof ImplicitFunction) { + Generic g[]=((ImplicitFunction)v).parameters(); + int p=g[0].integerValue().intValue(); + int q=g[1].integerValue().intValue(); + if(v.compareTo(new ImplicitFunction("cl",new Generic[] {JSCLInteger.valueOf(p),JSCLInteger.valueOf(q)},new int[] {0,0},new Generic[] {}))==0) return new int[] {p,q}; + } + throw new ArithmeticException(); + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + int n=3; + if(parameter[2].signum()==0) n=2; + buffer.append(name); + buffer.append("("); + for(int i=0;i0:index0?content[--i1]:null; + Term t2=i2>0?q.content[--i2]:null; + while(t1!=null || t2!=null) { + int c=t1==null?1:(t2==null?-1:-ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) { + p.content[--i]=t1; + t1=i1>0?content[--i1]:null; + } else if(c>0) { + p.content[--i]=t2.negate(); + t2=i2>0?q.content[--i2]:null; + } else { + Term t=t1.subtract(t2); + if(t.signum()!=0) p.content[--i]=t; + t1=i1>0?content[--i1]:null; + t2=i2>0?q.content[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return subtract(polynomial); + ArrayPolynomial q=(ArrayPolynomial)polynomial; + ArrayPolynomial p=newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Term t1=i1>0?content[--i1]:null; + Term t2=i2>0?q.content[--i2].multiply(generic):null; + while(t1!=null || t2!=null) { + int c=t1==null?1:(t2==null?-1:-ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) { + p.content[--i]=t1; + t1=i1>0?content[--i1]:null; + } else if(c>0) { + p.content[--i]=t2.negate(); + t2=i2>0?q.content[--i2].multiply(generic):null; + } else { + Term t=t1.subtract(t2); + if(t.signum()!=0) p.content[--i]=t; + t1=i1>0?content[--i1]:null; + t2=i2>0?q.content[--i2].multiply(generic):null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(defined) throw new UnsupportedOperationException(); + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + ArrayPolynomial q=(ArrayPolynomial)polynomial; + ArrayPolynomial p=newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Term t1=i1>0?content[--i1]:null; + Term t2=i2>0?q.content[--i2].multiply(monomial,generic):null; + while(t1!=null || t2!=null) { + int c=t1==null?1:(t2==null?-1:-ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) { + p.content[--i]=t1; + t1=i1>0?content[--i1]:null; + } else if(c>0) { + p.content[--i]=t2.negate(); + t2=i2>0?q.content[--i2].multiply(monomial,generic):null; + } else { + Term t=t1.subtract(t2); + if(t.signum()!=0) p.content[--i]=t; + t1=i1>0?content[--i1]:null; + t2=i2>0?q.content[--i2].multiply(monomial,generic):null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar+monomial.degree()); + return p; + } + + public Polynomial multiply(Polynomial polynomial) { + Polynomial p=valueof(JSCLInteger.valueOf(0)); + for(int i=0;i=0;i--) a=a.gcd(content[i].coef()); + return a.signum()==signum()?a:a.negate(); + } + + public Monomial monomialGcd() { + Monomial m=monomial(tail()); + for(int i=0;i0?content[size-1]:null; + } + + public Term tail() { + return size>0?content[0]:null; + } + + void init(Polynomial polynomial) { + ArrayPolynomial q=(ArrayPolynomial)polynomial; + init(q.size); + System.arraycopy(q.content,0,content,0,size); + degree=q.degree; + sugar=q.sugar; + } + + void init(Expression expression) { + Map map=new TreeMap(ordering); + int n=expression.size(); + for(int i=0;i0?en.multiply(Expression.valueOf(l)):en); + Generic a1=(Generic)map.get(m); + Generic a=a1==null?a2:a1.add(a2); + if(a.signum()==0) map.remove(m); + else map.put(m,a); + } + init(map.size()); + int sugar=0; + Iterator it=map.entrySet().iterator(); + for(int i=0;i0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + p.monomial[--i]=m1; + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + p.monomial[--i]=m2; + m2=i2>0?q.monomial[--i2]:null; + } else { + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + return subtract(polynomial); + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + return multiplyAndSubtract(generic,polynomial.multiply(monomial)); + } + + public Polynomial multiply(Generic generic) { + if(generic.signum()==0) return valueof(JSCLInteger.valueOf(0)); + return this; + } + + public Polynomial multiply(Monomial monomial) { + if(defined) { + Map map=new TreeMap(ordering); + for(int i=0;i0:index0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + Generic a=getCoef(i1); + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + Generic a=q.getCoef(i2).negate(); + --i; + p.monomial[i]=m2; + p.setCoef(i,a); + m2=i2>0?q.monomial[--i2]:null; + } else { + Generic a=getCoef(i1).subtract(q.getCoef(i2)); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return subtract(polynomial); + ArrayPolynomialGeneric q=(ArrayPolynomialGeneric)polynomial; + ArrayPolynomialGeneric p=newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + Generic a=getCoef(i1); + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + Generic a=q.getCoef(i2).multiply(generic).negate(); + --i; + p.monomial[i]=m2; + p.setCoef(i,a); + m2=i2>0?q.monomial[--i2]:null; + } else { + Generic a=getCoef(i1).subtract(q.getCoef(i2).multiply(generic)); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(defined) throw new UnsupportedOperationException(); + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + ArrayPolynomialGeneric q=(ArrayPolynomialGeneric)polynomial; + ArrayPolynomialGeneric p=newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?this.monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2].multiply(monomial):null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + Generic a=getCoef(i1); + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + m1=i1>0?this.monomial[--i1]:null; + } else if(c>0) { + Generic a=q.getCoef(i2).multiply(generic).negate(); + --i; + p.monomial[i]=m2; + p.setCoef(i,a); + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } else { + Generic a=getCoef(i1).subtract(q.getCoef(i2).multiply(generic)); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.setCoef(i,a); + } + m1=i1>0?this.monomial[--i1]:null; + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar+monomial.degree()); + return p; + } + + public Polynomial multiply(Polynomial polynomial) { + Polynomial p=newinstance(0); + for(int i=0;i=0;i--) a=a.gcd(getCoef(i)); + return a.signum()==signum()?a:a.negate(); + } + + public Monomial monomialGcd() { + Monomial m=monomial(tail()); + for(int i=0;i0?term(size-1):null; + } + + public Term tail() { + return size>0?term(0):null; + } + + protected Generic getCoef(int n) { + return coef[n]; + } + + protected void setCoef(int n, Generic generic) { + coef[n]=generic; + } + + public Generic genericValue() { + Generic s=JSCLInteger.valueOf(0); + for(int i=0;i0?a.multiply(Expression.valueOf(m.literalValue())):a); + } + return s; + } + + public Generic[] elements() { + Generic a[]=new Generic[size]; + for(int i=0;i0) return 1; + else { + c=getCoef(i1).compareTo(q.getCoef(i2)); + if(c<0) return -1; + else if(c>0) return 1; + m1=i1==0?null:monomial[--i1]; + m2=i2==0?null:q.monomial[--i2]; + } + } + return 0; + } + + void init(Polynomial polynomial) { + ArrayPolynomialGeneric q=(ArrayPolynomialGeneric)polynomial; + init(q.size); + System.arraycopy(q.monomial,0,monomial,0,size); + for(int i=0;i0?en.multiply(Expression.valueOf(l)):en); + Generic a1=(Generic)map.get(m); + Generic a=a1==null?a2:a1.add(a2); + if(a.signum()==0) map.remove(m); + else map.put(m,a); + } + init(map.size()); + int sugar=0; + Iterator it=map.entrySet().iterator(); + for(int i=0;i0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + BigInteger a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + BigInteger a=q.coef[i2].negate(); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2]:null; + } else { + BigInteger a=coef[i1].subtract(q.coef[i2]); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + BigInteger g=generic.integerValue().content(); + if(g.compareTo(BigInteger.valueOf(1))==0) return subtract(polynomial); + ArrayPolynomialInteger q=(ArrayPolynomialInteger)polynomial; + ArrayPolynomialInteger p=(ArrayPolynomialInteger)newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + BigInteger a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + BigInteger a=q.coef[i2].multiply(g).negate(); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2]:null; + } else { + BigInteger a=coef[i1].subtract(q.coef[i2].multiply(g)); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(defined) throw new UnsupportedOperationException(); + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + BigInteger g=generic.integerValue().content(); + ArrayPolynomialInteger q=(ArrayPolynomialInteger)polynomial; + ArrayPolynomialInteger p=(ArrayPolynomialInteger)newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?this.monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2].multiply(monomial):null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + BigInteger a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?this.monomial[--i1]:null; + } else if(c>0) { + BigInteger a=q.coef[i2].multiply(g).negate(); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } else { + BigInteger a=coef[i1].subtract(q.coef[i2].multiply(g)); + if(a.signum()!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?this.monomial[--i1]:null; + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar+monomial.degree()); + return p; + } + + public Polynomial multiply(Generic generic) { + if(generic.signum()==0) return valueof(JSCLInteger.valueOf(0)); + BigInteger g=generic.integerValue().content(); + if(g.compareTo(BigInteger.valueOf(1))==0) return this; + ArrayPolynomialInteger p=(ArrayPolynomialInteger)newinstance(size); + for(int i=0;i=0;i--) if((a=a.gcd(coef[i])).compareTo(BigInteger.valueOf(1))==0) break; + return new JSCLInteger(a.signum()==signum()?a:a.negate()); + } + + protected Generic coefficient(Generic generic) { + return coefFactory.valueof(generic); + } + + protected Generic getCoef(int n) { + return new JSCLInteger(coef[n]); + } + + protected void setCoef(int n, Generic generic) { + coef[n]=generic.integerValue().content(); + } + + protected ArrayPolynomialGeneric newinstance(int n) { + return new ArrayPolynomialInteger(n,monomialFactory); + } +} diff --git a/src/misc/src/jscl/math/polynomial/ArrayPolynomialModular.java b/src/misc/src/jscl/math/polynomial/ArrayPolynomialModular.java new file mode 100644 index 00000000..e4ee5d62 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/ArrayPolynomialModular.java @@ -0,0 +1,207 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.ModularInteger; + +class ArrayPolynomialModular extends ArrayPolynomialGeneric { + final int modulo; + int coef[]; + + ArrayPolynomialModular(Monomial monomialFactory, Generic coefFactory) { + super(monomialFactory,coefFactory); + modulo=((ModularInteger)coefFactory).modulo(); + } + + ArrayPolynomialModular(int size, Monomial monomialFactory, Generic coefFactory) { + this(monomialFactory,coefFactory); + init(size); + } + + void init(int size) { + monomial=new Monomial[size]; + coef=new int[size]; + this.size=size; + } + + void resize(int size) { + int length=monomial.length; + if(size0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + int a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + int a=(int)(((long)modulo-(long)q.coef[i2])%modulo); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2]:null; + } else { + int a=(int)(((long)coef[i1]+(long)modulo-(long)q.coef[i2])%modulo); + if(a!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + int g=generic.integerValue().intValue(); + if(g==1) return subtract(polynomial); + ArrayPolynomialModular q=(ArrayPolynomialModular)polynomial; + ArrayPolynomialModular p=(ArrayPolynomialModular)newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2]:null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + int a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?monomial[--i1]:null; + } else if(c>0) { + int a=(int)(((long)modulo-((long)q.coef[i2]*(long)g)%modulo)%modulo); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2]:null; + } else { + int a=(int)(((long)coef[i1]+(long)modulo-((long)q.coef[i2]*(long)g)%modulo)%modulo); + if(a!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?monomial[--i1]:null; + m2=i2>0?q.monomial[--i2]:null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar); + return p; + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(defined) throw new UnsupportedOperationException(); + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + int g=generic.integerValue().intValue(); + ArrayPolynomialModular q=(ArrayPolynomialModular)polynomial; + ArrayPolynomialModular p=(ArrayPolynomialModular)newinstance(size+q.size); + int i=p.size; + int i1=size; + int i2=q.size; + Monomial m1=i1>0?this.monomial[--i1]:null; + Monomial m2=i2>0?q.monomial[--i2].multiply(monomial):null; + while(m1!=null || m2!=null) { + int c=m1==null?1:(m2==null?-1:-ordering.compare(m1,m2)); + if(c<0) { + int a=coef[i1]; + --i; + p.monomial[i]=m1; + p.coef[i]=a; + m1=i1>0?this.monomial[--i1]:null; + } else if(c>0) { + int a=(int)(((long)modulo-((long)q.coef[i2]*(long)g)%modulo)%modulo); + --i; + p.monomial[i]=m2; + p.coef[i]=a; + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } else { + int a=(int)(((long)coef[i1]+(long)modulo-((long)q.coef[i2]*(long)g)%modulo)%modulo); + if(a!=0) { + --i; + p.monomial[i]=m1; + p.coef[i]=a; + } + m1=i1>0?this.monomial[--i1]:null; + m2=i2>0?q.monomial[--i2].multiply(monomial):null; + } + } + p.resize(p.size-i); + p.degree=degree(p); + p.sugar=Math.max(sugar,q.sugar+monomial.degree()); + return p; + } + + public Polynomial multiply(Generic generic) { + if(generic.signum()==0) return valueof(JSCLInteger.valueOf(0)); + int g=generic.integerValue().intValue(); + if(g==1) return this; + ArrayPolynomialModular p=(ArrayPolynomialModular)newinstance(size); + for(int i=0;i0,(flags&DEFINING_EQS)>0); + } + + static Basis compute(Generic generic[], Variable unknown[], Ordering ordering, int modulo, int flags, boolean degree, boolean defining) { + if(degree) return compute(compute(generic,unknown,Monomial.degreeReverseLexicographic,modulo,flags,false,defining).elements(),unknown,ordering,modulo,flags,false,defining); + return Standard.compute(new Basis(defining?augment(defining(unknown,modulo),generic):generic,Polynomial.factory(unknown,ordering,modulo,flags)),flags); + } + + public Basis valueof(Generic generic[]) { + return new Basis(generic,factory); + } + + public Basis modulo(int modulo) { + return new Basis(element,Polynomial.factory(factory,modulo)); + } + + public static Generic[] defining(Variable unknown[], int modulo) { + Generic a[]=new Generic[unknown.length]; + for(int i=0;i0 && generic[0].compareTo(JSCLInteger.valueOf(1))==0); + } + + public static Generic[] augment(Generic element[], Generic generic[]) { + return (Generic[])ArrayUtils.concat(element,generic,new Generic[element.length+generic.length]); + } + + public static Variable[] augmentUnknown(Variable unknown[], Generic generic[]) { + Variable va[]=Expression.variables(generic); + List l=new ArrayList(); + for(int i=0;i>log2p)+1,unknown,ordering); + } + + BooleanMonomial(int length, Variable unknown[], Ordering ordering) { + super(length,unknown,ordering); + } + + public Monomial multiply(Monomial monomial) { + Monomial m=newinstance(); + for(int i=0;i>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=a+b; + if(c>nmask) throw new ArithmeticException(); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + if(a>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=a-b; + if(c<0) throw new NotDivisibleException(); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=Math.min(a,b); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=Math.max(a,b); + m.element[q]|=c<>log2p; + int r=(n&pmask)<>r)&nmask; + } + + void put(int n, int integer) { + if(reverse()) n=unknown.length-1-n; + int q=n>>log2p; + int r=(n&pmask)<>r)&nmask; + int c=a+integer; + if(c>nmask) throw new ArithmeticException(); + element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=a+b; + if(c>1) c=1; + m.element[q]|=c<0) { + t=u; + n=i; + } else if(ordering.compare(t.monomial(),u.monomial())==0) { + t=behead(t,n,i); + n=i; + } + } + if(t==null || t.coef().signum()!=0) { + term=t; + return; + } + } + } + + public boolean hasNext() { + return term!=null; + } + + public Object next() { + Term t=term; + seek(); + return t; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + Term behead(Term t, int n, int i) { + Monomial m=t.monomial(); + Polynomial p=factory.valueof(m).multiply(t.coef()); + content[n]=content[n].subtract(p); + content[i]=content[i].add(p); + return new Term(m,content[i].coefficient(m)); + } + + void canonicalize() { + Polynomial s=factory.valueof(JSCLInteger.valueOf(0)); + int sugar=0; + for(int i=0;i3;n>>=2) i++; + return i; + } + + Polynomial polynomial() { + if(canonicalized) return content[size-1]; + else throw new UnsupportedOperationException(); + } + + void set(Polynomial polynomial) { + content[size-1]=polynomial; + } + + public Polynomial subtract(Polynomial polynomial) { + if(mutable) { + Polynomial q=((GeoBucket)polynomial).polynomial(); + int n=log(q.size()); + if(n>=size) resize(n+1); + Polynomial p=content[n]; + Polynomial s=(p==null?factory.valueof(JSCLInteger.valueOf(0)):p).subtract(q); + content[n]=null; + while(n=size) resize(n+1); + p=content[n]; + if(p!=null) s=p.add(s); + content[n]=null; + } + content[n]=s; + canonicalized=false; + normalized=false; + return this; + } else return copy().subtract(polynomial); + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(mutable) { + Polynomial q=((GeoBucket)polynomial).polynomial(); + int n=log(q.size()); + if(n>=size) resize(n+1); + Polynomial p=content[n]; + Polynomial s=(p==null?factory.valueof(JSCLInteger.valueOf(0)):p).multiplyAndSubtract(generic,q); + content[n]=null; + while(n=size) resize(n+1); + p=content[n]; + if(p!=null) s=p.add(s); + content[n]=null; + } + content[n]=s; + canonicalized=false; + normalized=false; + return this; + } else return copy().multiplyAndSubtract(generic,polynomial); + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(mutable) { + Polynomial q=((GeoBucket)polynomial).polynomial(); + int n=log(q.size()); + if(n>=size) resize(n+1); + Polynomial p=content[n]; + Polynomial s=(p==null?factory.valueof(JSCLInteger.valueOf(0)):p).multiplyAndSubtract(monomial,generic,q); + content[n]=null; + while(n=size) resize(n+1); + p=content[n]; + if(p!=null) s=p.add(s); + content[n]=null; + } + content[n]=s; + canonicalized=false; + normalized=false; + return this; + } else return copy().multiplyAndSubtract(monomial,generic,polynomial); + } + + public Polynomial multiply(Generic generic) { + if(mutable) { + if(canonicalized) set(polynomial().multiply(generic)); + else for(int i=0;i0) { + if(t1!=null) it1.next(); + it1.add(t2.negate()); + } else { + Term t=t1.subtract(t2); + if(t.signum()==0) it1.remove(); + else it1.set(t); + } + t1=it1.hasPrevious()?(Term)it1.previous():null; + t2=it2.hasPrevious()?(Term)it2.previous():null; + } + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar); + normalized=false; + return this; + } else return copy().subtract(polynomial); + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return subtract(polynomial); + if(mutable) { + ListPolynomial q=(ListPolynomial)polynomial; + ListIterator it1=content.listIterator(content.size()); + ListIterator it2=q.content.listIterator(q.content.size()); + Term t1=it1.hasPrevious()?(Term)it1.previous():null; + Term t2=it2.hasPrevious()?((Term)it2.previous()).multiply(generic):null; + while(t2!=null) { + int c=t1==null?1:(t2==null?-1:-ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) { + t1=it1.hasPrevious()?(Term)it1.previous():null; + } else { + if(c>0) { + if(t1!=null) it1.next(); + it1.add(t2.negate()); + } else { + Term t=t1.subtract(t2); + if(t.signum()==0) it1.remove(); + else it1.set(t); + } + t1=it1.hasPrevious()?(Term)it1.previous():null; + t2=it2.hasPrevious()?((Term)it2.previous()).multiply(generic):null; + } + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar); + normalized=false; + return this; + } else return copy().multiplyAndSubtract(generic,polynomial); + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(defined) throw new UnsupportedOperationException(); + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + if(mutable) { + ListPolynomial q=(ListPolynomial)polynomial; + ListIterator it1=content.listIterator(content.size()); + ListIterator it2=q.content.listIterator(q.content.size()); + Term t1=it1.hasPrevious()?(Term)it1.previous():null; + Term t2=it2.hasPrevious()?((Term)it2.previous()).multiply(monomial,generic):null; + while(t2!=null) { + int c=t1==null?1:(t2==null?-1:-ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) { + t1=it1.hasPrevious()?(Term)it1.previous():null; + } else { + if(c>0) { + if(t1!=null) it1.next(); + it1.add(t2.negate()); + } else { + Term t=t1.subtract(t2); + if(t.signum()==0) it1.remove(); + else it1.set(t); + } + t1=it1.hasPrevious()?(Term)it1.previous():null; + t2=it2.hasPrevious()?((Term)it2.previous()).multiply(monomial,generic):null; + } + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar+monomial.degree()); + normalized=false; + return this; + } else return copy().multiplyAndSubtract(monomial,generic,polynomial); + } + + public Polynomial multiply(Generic generic) { + if(generic.signum()==0) return valueof(JSCLInteger.valueOf(0)); + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return this; + if(mutable) { + ListIterator it=content.listIterator(); + while(it.hasNext()) it.set(((Term)it.next()).multiply(generic)); + normalized=false; + return this; + } else return copy().multiply(generic); + } + + public Polynomial multiply(Monomial monomial) { + if(defined) throw new UnsupportedOperationException(); + if(monomial.degree()==0) return this; + if(mutable) { + ListIterator it=content.listIterator(); + while(it.hasNext()) it.set(((Term)it.next()).multiply(monomial)); + degree+=monomial.degree(); + sugar+=monomial.degree(); + return this; + } else return copy().multiply(monomial); + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return this; + if(mutable) { + ListIterator it=content.listIterator(); + while(it.hasNext()) it.set(((Term)it.next()).divide(generic)); + normalized=false; + return this; + } else return copy().divide(generic); + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + if(monomial.degree()==0) return this; + if(mutable) { + ListIterator it=content.listIterator(); + while(it.hasNext()) it.set(((Term)it.next()).divide(monomial)); + degree-=monomial.degree(); + sugar-=monomial.degree(); + return this; + } else return copy().divide(monomial); + } + + public Polynomial gcd(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public int degree() { + return degree; + } + + public Polynomial valueof(Polynomial polynomial) { + ListPolynomial p=newinstance(0); + p.init(polynomial); + return p; + } + + public Polynomial valueof(Generic generic) { + ListPolynomial p=newinstance(0); + p.init(generic); + return p; + } + + public Polynomial valueof(Monomial monomial) { + ListPolynomial p=newinstance(0); + p.init(monomial); + return p; + } + + public Polynomial freeze() { + mutable=false; + return this; + } + + public Term head() { + int size=content.size(); + return size>0?(Term)content.get(size-1):null; + } + + public Term tail() { + int size=content.size(); + return size>0?(Term)content.get(0):null; + } + + void init(Polynomial polynomial) { + ListPolynomial q=(ListPolynomial)polynomial; + content.addAll(q.content); + degree=q.degree; + sugar=q.sugar; + } + + void init(Expression expression) { + Map map=new TreeMap(ordering); + int n=expression.size(); + for(int i=0;i0?en.multiply(Expression.valueOf(l)):en); + Generic a1=(Generic)map.get(m); + Generic a=a1==null?a2:a1.add(a2); + if(a.signum()==0) map.remove(m); + else map.put(m,a); + } + int sugar=0; + Iterator it=map.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + Monomial m=(Monomial)e.getKey(); + Generic a=(Generic)e.getValue(); + content.add(new Term(m,a)); + sugar=Math.max(sugar,m.degree()); + } + degree=degree(this); + this.sugar=sugar; + } + + void init(Generic generic) { + if(generic instanceof Expression) { + init((Expression)generic); + } else { + Generic a=coefficient(generic); + if(a.signum()!=0) { + content.add(new Term(monomial(Literal.valueOf()),a)); + } + degree=0; + sugar=0; + } + } + + void init(Monomial monomial) { + content.add(new Term(monomial,coefficient(JSCLInteger.valueOf(1)))); + degree=monomial.degree(); + sugar=monomial.degree(); + } + + protected ListPolynomial newinstance(int n) { + return new ListPolynomial(monomialFactory,coefFactory); + } +} diff --git a/src/misc/src/jscl/math/polynomial/Monomial.java b/src/misc/src/jscl/math/polynomial/Monomial.java new file mode 100644 index 00000000..6658ab59 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/Monomial.java @@ -0,0 +1,406 @@ +package jscl.math.polynomial; + +import java.util.Iterator; +import jscl.math.Literal; +import jscl.math.NotDivisibleException; +import jscl.math.Variable; +import jscl.math.function.Frac; +import jscl.math.function.Pow; +import jscl.mathml.MathML; + +public class Monomial implements Comparable { + public static final Ordering lexicographic=Lexicographic.ordering; + public static final Ordering totalDegreeLexicographic=TotalDegreeLexicographic.ordering; + public static final Ordering degreeReverseLexicographic=DegreeReverseLexicographic.ordering; + public static final Ordering iteratorOrdering=totalDegreeLexicographic; + final Variable unknown[]; + final Ordering ordering; + final int element[]; + int degree; + + Monomial(Variable unknown[], Ordering ordering) { + this(unknown.length,unknown,ordering); + } + + Monomial(int length, Variable unknown[], Ordering ordering) { + this.unknown=unknown; + this.ordering=ordering; + element=new int[length]; + } + + public static Ordering kthElimination(int k) { + return new KthElimination(k,1); + } + + public Variable[] unknown() { + return unknown; + } + + public Ordering ordering() { + return ordering; + } + + public Monomial multiply(Monomial monomial) { + Monomial m=newinstance(); + for(int i=0;i0) { + if(b) buffer.append("*"); + else b=true; + Variable v=unknown[i]; + if(c==1) buffer.append(v); + else { + if(v instanceof Frac || v instanceof Pow) { + buffer.append("(").append(v).append(")"); + } else buffer.append(v); + buffer.append("^").append(c); + } + } + } + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + if(degree==0) { + MathML e1=element.element("mn"); + e1.appendChild(element.text("1")); + element.appendChild(e1); + } + for(int i=0;i0) { + unknown[i].toMathML(element,new Integer(c)); + } + } + } + + protected Monomial newinstance() { + return new Monomial(element.length,unknown,ordering); + } +} + +class MonomialIterator implements Iterator { + static final Ordering ordering=Monomial.iteratorOrdering; + Monomial monomial; + Monomial current; + boolean carry; + + MonomialIterator(Monomial beginning, Monomial monomial) { + this.monomial=monomial; + current=monomial.valueof(beginning); + if(ordering.compare(current,monomial)>0) carry=true; + } + + public boolean hasNext() { + return !carry; + } + + public Object next() { + Monomial m=monomial.valueof(current); + if(ordering.compare(current,monomial)<0) increment(); + else carry=true; + return m; + } + + void increment() { + int s=0; + int n=0; + while(n0) { + n--; + if(current.element[n]>monomial.element[n]) break; + } + int p=n; + while(n>0) { + n--; + current.element[p]+=current.element[n]; + current.element[n]=0; + } + if(pmonomial.element[p]) increment(); + } + + void increment() { + int s=0; + int n=0; + while(n=0;i--) { + if(c1[i]c2[i]) return 1; + } + return 0; + } +} + +class TotalDegreeLexicographic extends Lexicographic implements DegreeOrdering { + public static final Ordering ordering=new TotalDegreeLexicographic(); + + TotalDegreeLexicographic() {} + + public int compare(Monomial m1, Monomial m2) { + if(m1.degreem2.degree) return 1; + else return super.compare(m1,m2); + } +} + +class DegreeReverseLexicographic extends Ordering implements DegreeOrdering { + public static final Ordering ordering=new DegreeReverseLexicographic(); + + DegreeReverseLexicographic() {} + + public int compare(Monomial m1, Monomial m2) { + if(m1.degreem2.degree) return 1; + else { + int c1[]=m1.element; + int c2[]=m2.element; + int n=c1.length; + for(int i=0;ic2[i]) return -1; + else if(c1[i]=k;i--) { + if(c1[i]c2[i]) return 1; + } + return DegreeReverseLexicographic.ordering.compare(m1,m2); + } +} diff --git a/src/misc/src/jscl/math/polynomial/NestedPolynomial.java b/src/misc/src/jscl/math/polynomial/NestedPolynomial.java new file mode 100644 index 00000000..8ac7df8f --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/NestedPolynomial.java @@ -0,0 +1,225 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.NotExpressionException; +import jscl.math.NotIntegerException; +import jscl.math.NotIntegrableException; +import jscl.math.NotPowerException; +import jscl.math.NotProductException; +import jscl.math.NotVariableException; +import jscl.math.Power; +import jscl.math.Variable; +import jscl.mathml.MathML; + +class NestedPolynomial extends UnivariatePolynomial { + NestedPolynomial(Variable variable[]) { + this(variable[0],PolynomialWrapper.factory(variable)); + } + + NestedPolynomial(Variable variable, Generic coefFactory) { + super(variable,coefFactory); + } + + protected UnivariatePolynomial newinstance() { + return new NestedPolynomial(variable,coefFactory); + } +} + +final class PolynomialWrapper extends Generic { + final Polynomial content; + + PolynomialWrapper(Polynomial polynomial) { + content=polynomial; + } + + Polynomial content() { + return content; + } + + public PolynomialWrapper add(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.add(wrapper.content)); + } + + public Generic add(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return add((PolynomialWrapper)generic); + } else { + return add(valueof(generic)); + } + } + + public PolynomialWrapper subtract(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.subtract(wrapper.content)); + } + + public Generic subtract(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return subtract((PolynomialWrapper)generic); + } else { + return subtract(valueof(generic)); + } + } + + public PolynomialWrapper multiply(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.multiply(wrapper.content)); + } + + public Generic multiply(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return multiply((PolynomialWrapper)generic); + } else { + return multiply(valueof(generic)); + } + } + + public PolynomialWrapper divide(PolynomialWrapper wrapper) throws ArithmeticException { + return new PolynomialWrapper(content.divide(wrapper.content)); + } + + public Generic divide(Generic generic) throws ArithmeticException { + if(generic instanceof PolynomialWrapper) { + return divide((PolynomialWrapper)generic); + } else { + return divide(valueof(generic)); + } + } + + public PolynomialWrapper gcd(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.gcd(wrapper.content)); + } + + public Generic gcd(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return gcd((PolynomialWrapper)generic); + } else { + return gcd(valueof(generic)); + } + } + + public Generic gcd() { + return content.gcd(); + } + + public Generic negate() { + return new PolynomialWrapper(content.negate()); + } + + public int signum() { + return content.signum(); + } + + public int degree() { + return content.degree(); + } + + public Generic antiderivative(Variable variable) throws NotIntegrableException { + return null; + } + + public Generic derivative(Variable variable) { + return null; + } + + public Generic substitute(Variable variable, Generic generic) { + return null; + } + + public Generic expand() { + return null; + } + + public Generic factorize() { + return null; + } + + public Generic elementary() { + return null; + } + + public Generic simplify() { + return null; + } + + public Generic numeric() { + return null; + } + + public Generic valueof(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return new PolynomialWrapper(content.valueof(((PolynomialWrapper)generic).content)); + } else { + return new PolynomialWrapper(content.valueof(generic)); + } + } + + public Generic[] sumValue() { + return null; + } + + public Generic[] productValue() throws NotProductException { + return null; + } + + public Power powerValue() throws NotPowerException { + return null; + } + + public Expression expressionValue() throws NotExpressionException { + return content.genericValue().expressionValue(); + } + + public JSCLInteger integerValue() throws NotIntegerException { + throw new NotIntegerException(); + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(Variable variable) { + return false; + } + + public boolean isConstant(Variable variable) { + return false; + } + + public int compareTo(PolynomialWrapper wrapper) { + return content.compareTo(wrapper.content); + } + + public int compareTo(Generic generic) { + if(generic instanceof PolynomialWrapper) { + return compareTo((PolynomialWrapper)generic); + } else { + return compareTo(valueof(generic)); + } + } + + public static Generic factory(Variable variable[]) { + if(variable.length>1) { + Variable var[]=new Variable[variable.length-1]; + for(int i=0;i0?a.multiply(Expression.valueOf(m.literalValue())):a); + } + return s; + } + + public Generic[] elements() { + int size=size(); + Generic a[]=new Generic[size]; + Iterator it=iterator(); + for(int i=0;i0); + } + + static Polynomial factory(Monomial monomialFactory, int modulo, int data_struct, boolean buckets) { + if(buckets) return new GeoBucket(factory(monomialFactory,modulo,data_struct,false)); + else switch(data_struct) { + case Basis.ARRAY: + return new ArrayPolynomial(monomialFactory,generic(modulo)); + case Basis.TREE: + return new TreePolynomial(monomialFactory,generic(modulo)); + case Basis.LIST: + return new ListPolynomial(monomialFactory,generic(modulo)); + default: + switch(modulo) { + case -1: + return new ArrayPolynomialGeneric(monomialFactory,null); + case 0: + return new ArrayPolynomialInteger(monomialFactory); + case 1: + return new ArrayPolynomialRational(monomialFactory); + case 2: + return new ArrayPolynomialBoolean(monomialFactory); + default: + return new ArrayPolynomialModular(monomialFactory,ModularInteger.factory(modulo)); + } + } + } + + static Generic generic(int modulo) { + switch(modulo) { + case -1: + return null; + case 0: + return JSCLInteger.factory; + case 1: + return Rational.factory; + case 2: + return JSCLBoolean.factory; + default: + return ModularInteger.factory(modulo); + } + } + + static Polynomial factory(Polynomial polynomial, int modulo) { + Monomial m=polynomial.monomialFactory; + return factory(m.unknown(),m.ordering(),modulo); + } + + public int compareTo(Polynomial polynomial) { + Iterator it1=iterator(true); + Iterator it2=polynomial.iterator(true); + Term t1=it1.hasNext()?(Term)it1.next():null; + Term t2=it2.hasNext()?(Term)it2.next():null; + while(t1!=null || t2!=null) { + int c=t1==null?1:(t2==null?-1:ordering.compare(t1.monomial(),t2.monomial())); + if(c<0) return -1; + else if(c>0) return 1; + else { + c=t1.coef().compareTo(t2.coef()); + if(c<0) return -1; + else if(c>0) return 1; + t1=it1.hasNext()?(Term)it1.next():null; + t2=it2.hasNext()?(Term)it2.next():null; + } + } + return 0; + } + + public int compareTo(Object o) { + return compareTo((Polynomial)o); + } + + public boolean equals(Object obj) { + if(obj instanceof Polynomial) { + return compareTo((Polynomial)obj)==0; + } else return false; + } + + public String toString() { + StringBuffer buffer=new StringBuffer(); + if(signum()==0) buffer.append("0"); + int i=0; + for(Iterator it=iterator();it.hasNext();i++) { + Term t=(Term)it.next(); + Monomial m=t.monomial(); + Generic a=t.coef(); + if(a instanceof Expression) a=a.signum()>0?GenericVariable.valueOf(a).expressionValue():GenericVariable.valueOf(a.negate()).expressionValue().negate(); + if(a.signum()>0 && i>0) buffer.append("+"); + if(m.degree()==0) buffer.append(a); + else { + if(a.abs().compareTo(JSCLInteger.valueOf(1))==0) { + if(a.signum()<0) buffer.append("-"); + } else buffer.append(a).append("*"); + buffer.append(m); + } + } + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + MathML e1=element.element("mrow"); + if(signum()==0) { + MathML e2=element.element("mn"); + e2.appendChild(element.text("0")); + e1.appendChild(e2); + } + int i=0; + for(Iterator it=iterator();it.hasNext();i++) { + Term t=(Term)it.next(); + Monomial m=t.monomial(); + Generic a=t.coef(); + if(a instanceof Expression) a=a.signum()>0?GenericVariable.valueOf(a).expressionValue():GenericVariable.valueOf(a.negate()).expressionValue().negate(); + if(a.signum()>0 && i>0) { + MathML e2=element.element("mo"); + e2.appendChild(element.text("+")); + e1.appendChild(e2); + } + if(m.degree()==0) Expression.separateSign(e1,a); + else { + if(a.abs().compareTo(JSCLInteger.valueOf(1))==0) { + if(a.signum()<0) { + MathML e2=element.element("mo"); + e2.appendChild(element.text("-")); + e1.appendChild(e2); + } + } else Expression.separateSign(e1,a); + m.toMathML(e1,null); + } + } + element.appendChild(e1); + } +} diff --git a/src/misc/src/jscl/math/polynomial/SmallMonomial.java b/src/misc/src/jscl/math/polynomial/SmallMonomial.java new file mode 100644 index 00000000..00f1f329 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/SmallMonomial.java @@ -0,0 +1,174 @@ +package jscl.math.polynomial; + +import jscl.math.NotDivisibleException; +import jscl.math.Variable; + +class SmallMonomial extends Monomial { + static final Ordering lexicographic=SmallLexicographic.ordering; + static final Ordering totalDegreeLexicographic=SmallTotalDegreeLexicographic.ordering; + static final Ordering degreeReverseLexicographic=SmallDegreeReverseLexicographic.ordering; + static final int log2n=3; + static final int log2p=5-log2n; + static final int nmask=(1<<(1<>log2p)+1,unknown,ordering); + } + + SmallMonomial(int length, Variable unknown[], Ordering ordering) { + super(length,unknown,ordering); + } + + public Monomial multiply(Monomial monomial) { + Monomial m=newinstance(); + for(int i=0;i>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=a+b; + if(c>nmask) throw new ArithmeticException(); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + if(a>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=a-b; + if(c<0) throw new NotDivisibleException(); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=Math.min(a,b); + m.element[q]|=c<>log2p; + int r=(i&pmask)<>r)&nmask; + int b=(monomial.element[q]>>r)&nmask; + int c=Math.max(a,b); + m.element[q]|=c<>log2p; + int r=(n&pmask)<>r)&nmask; + } + + void put(int n, int integer) { + if(reverse()) n=unknown.length-1-n; + int q=n>>log2p; + int r=(n&pmask)<>r)&nmask; + int c=a+integer; + if(c>nmask) throw new ArithmeticException(); + element[q]|=c<=0;i--) { + long l1=c1[i]&0xffffffffl; + long l2=c2[i]&0xffffffffl; + if(l1l2) return 1; + } + return 0; + } +} + +class SmallTotalDegreeLexicographic extends SmallLexicographic implements DegreeOrdering { + public static final Ordering ordering=new SmallTotalDegreeLexicographic(); + + SmallTotalDegreeLexicographic() {} + + + public int compare(Monomial m1, Monomial m2) { + if(m1.degreem2.degree) return 1; + else return super.compare(m1,m2); + } +} + +class SmallDegreeReverseLexicographic extends Ordering implements DegreeOrdering { + public static final Ordering ordering=new SmallDegreeReverseLexicographic(); + + SmallDegreeReverseLexicographic() {} + + public int compare(Monomial m1, Monomial m2) { + if(m1.degreem2.degree) return 1; + else { + int c1[]=m1.element; + int c2[]=m2.element; + int n=c1.length; + for(int i=n-1;i>=0;i--) { + long l1=c1[i]&0xffffffffl; + long l2=c2[i]&0xffffffffl; + if(l1>l2) return -1; + else if(l10:iterator.hasNext(); + } + + public Object next() { + if(direction) { + Monomial m=(Monomial)map.lastKey(); + map=content.headMap(m); + return term(m); + } else { + return term((Map.Entry)iterator.next()); + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + Term term(Map.Entry entry) { + return new Term((Monomial)entry.getKey(),(Generic)entry.getValue()); + } + + Term term(Monomial monomial) { + return new Term(monomial,null) { + public Generic coef() { + return coef==null?coefficient(monomial):coef; + } + }; + } + + SortedMap subContent(Monomial monomial, boolean direction) { + if(monomial==null) return content; + return direction?content.headMap(monomial):content.tailMap(monomial); + } + + public Polynomial subtract(Polynomial polynomial) { + if(polynomial.signum()==0) return this; + if(mutable) { + TreePolynomial q=(TreePolynomial)polynomial; + Iterator it=q.content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + Monomial m=(Monomial)e.getKey(); + Generic a=(Generic)e.getValue(); + Generic s=coefficient(m).subtract(a); + if(s.signum()==0) content.remove(m); + else content.put(m,s); + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar); + normalized=false; + return this; + } else return copy().subtract(polynomial); + } + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return subtract(polynomial); + if(mutable) { + TreePolynomial q=(TreePolynomial)polynomial; + Iterator it=q.content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + Monomial m=(Monomial)e.getKey(); + Generic a=((Generic)e.getValue()).multiply(generic); + Generic s=coefficient(m).subtract(a); + if(s.signum()==0) content.remove(m); + else content.put(m,s); + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar); + normalized=false; + return this; + } else return copy().multiplyAndSubtract(generic,polynomial); + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + if(generic.signum()==0) return this; + if(monomial.degree()==0) return multiplyAndSubtract(generic,polynomial); + if(mutable) { + TreePolynomial q=(TreePolynomial)polynomial; + Iterator it=q.content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + Monomial m=((Monomial)e.getKey()).multiply(monomial); + Generic a=((Generic)e.getValue()).multiply(generic); + Generic s=coefficient(m).subtract(a); + if(s.signum()==0) content.remove(m); + else content.put(m,s); + } + degree=degree(this); + sugar=Math.max(sugar,q.sugar+monomial.degree()); + normalized=false; + return this; + } else return copy().multiplyAndSubtract(monomial,generic,polynomial); + } + + public Polynomial multiply(Generic generic) { + if(generic.signum()==0) return valueof(JSCLInteger.valueOf(0)); + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return this; + if(mutable) { + Iterator it=content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + e.setValue(((Generic)e.getValue()).multiply(generic)); + } + normalized=false; + return this; + } else return copy().multiply(generic); + } + + public Polynomial multiply(Monomial monomial) { + if(defined) { + TreePolynomial p=newinstance(); + Iterator it=content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + Monomial m=((Monomial)e.getKey()).multiply(monomial); + Generic a=(Generic)e.getValue(); + Generic s=p.coefficient(m).add(a); + if(s.signum()==0) p.content.remove(m); + else p.content.put(m,s); + } + p.degree=degree(p); + p.sugar=sugar+monomial.degree(); + return p; + } else { + if(monomial.degree()==0) return this; + TreePolynomial p=newinstance(); + Iterator it=content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + p.content.put(((Monomial)e.getKey()).multiply(monomial),(Generic)e.getValue()); + } + p.degree=degree+monomial.degree(); + p.sugar=sugar+monomial.degree(); + return p; + } + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + if(generic.compareTo(JSCLInteger.valueOf(1))==0) return this; + if(mutable) { + Iterator it=content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + e.setValue(((Generic)e.getValue()).divide(generic)); + } + normalized=false; + return this; + } else return copy().divide(generic); + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + if(monomial.degree()==0) return this; + TreePolynomial p=newinstance(); + Iterator it=content.entrySet().iterator(); + while(it.hasNext()) { + Map.Entry e=(Map.Entry)it.next(); + p.content.put(((Monomial)e.getKey()).divide(monomial),(Generic)e.getValue()); + } + p.degree=degree+monomial.degree(); + p.sugar=sugar+monomial.degree(); + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public int degree() { + return degree; + } + + public Polynomial valueof(Polynomial polynomial) { + TreePolynomial p=newinstance(); + p.init(polynomial); + return p; + } + + public Polynomial valueof(Generic generic) { + TreePolynomial p=newinstance(); + p.init(generic); + return p; + } + + public Polynomial valueof(Monomial monomial) { + TreePolynomial p=newinstance(); + p.init(monomial); + return p; + } + + public Polynomial freeze() { + mutable=false; + return this; + } + + public Term head() { + return content.size()>0?term((Monomial)content.lastKey()):null; + } + + public Term tail() { + return content.size()>0?term((Monomial)content.firstKey()):null; + } + + public Generic coefficient(Monomial monomial) { + Generic a=(Generic)content.get(monomial); + return a==null?coefficient(JSCLInteger.valueOf(0)):a; + } + + void init(Polynomial polynomial) { + TreePolynomial q=(TreePolynomial)polynomial; + content.putAll(q.content); + degree=q.degree; + sugar=q.sugar; + } + + void init(Expression expression) { + int sugar=0; + int n=expression.size(); + for(int i=0;i0?en.multiply(Expression.valueOf(l)):en); + Generic a1=coefficient(m); + Generic a=a1.add(a2); + if(a.signum()==0) content.remove(m); + else content.put(m,a); + sugar=Math.max(sugar,m.degree()); + } + degree=degree(this); + this.sugar=sugar; + } + + void init(Generic generic) { + if(generic instanceof Expression) { + init((Expression)generic); + } else { + Generic a=coefficient(generic); + if(a.signum()!=0) content.put(monomial(Literal.valueOf()),a); + degree=0; + sugar=0; + } + } + + void init(Monomial monomial) { + content.put(monomial,coefficient(JSCLInteger.valueOf(1))); + degree=monomial.degree(); + sugar=monomial.degree(); + } + + protected TreePolynomial newinstance() { + return new TreePolynomial(monomialFactory,coefFactory); + } +} diff --git a/src/misc/src/jscl/math/polynomial/UnivariatePolynomial.java b/src/misc/src/jscl/math/polynomial/UnivariatePolynomial.java new file mode 100644 index 00000000..ad500b85 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/UnivariatePolynomial.java @@ -0,0 +1,493 @@ +package jscl.math.polynomial; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JSCLInteger; +import jscl.math.Literal; +import jscl.math.NotDivisibleException; +import jscl.math.Variable; +import jscl.math.function.Inv; +import jscl.util.ArrayUtils; + +public class UnivariatePolynomial extends Polynomial { + protected final Variable variable; + Generic content[]=new Generic[8]; + int degree; + + protected UnivariatePolynomial(Variable variable) { + this(variable,null); + } + + UnivariatePolynomial(Variable variable, Generic coefFactory) { + super(Monomial.factory(new Variable[] {variable}),coefFactory); + this.variable=variable; + } + + public Variable variable() { + return variable; + } + + public int size() { + return degree+1; + } + + public Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction,current); + } + + class ContentIterator implements Iterator { + final boolean direction; + int index; + + ContentIterator(boolean direction, Monomial current) { + this.direction=direction; + if(direction) { + index=indexOf(current,true); + } else { + index=indexOf(current,false); + if(current!=null && get(index).signum()!=0) index++; + } + seek(); + } + + void seek() { + if(direction) while(index>0 && get(index).signum()==0) index--; + else while(index<=degree && get(index).signum()==0) index++; + } + + public boolean hasNext() { + return direction?index>0:index<=degree; + } + + public Object next() { + Term t=direction?term(--index):term(index++); + seek(); + return t; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + Term term(int n) { + return new Term(monomial(Literal.valueOf(variable,n)),get(n)); + } + + int indexOf(Monomial monomial, boolean direction) { + if(monomial==null) return direction?degree+1:0; + return monomial.degree(); + } + + public Polynomial add(Polynomial polynomial) { + UnivariatePolynomial p=newinstance(); + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + int d=Math.max(degree,q.degree); + for(int i=d;i>=0;i--) { + p.put(i,get(i).add(q.get(i))); + } + return p; + } + + public Polynomial subtract(Polynomial polynomial) { + UnivariatePolynomial p=newinstance(); + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + int d=Math.max(degree,q.degree); + for(int i=d;i>=0;i--) { + p.put(i,get(i).subtract(q.get(i))); + } + return p; + } + + public Polynomial multiply(Polynomial polynomial) { + UnivariatePolynomial p=newinstance(); + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + for(int i=degree;i>=0;i--) { + for(int j=q.degree;j>=0;j--) { + p.put(i+j,get(i).multiply(q.get(j))); + } + } + return p; + } + + public Polynomial multiply(Generic generic) { + UnivariatePolynomial p=newinstance(); + for(int i=degree;i>=0;i--) { + p.put(i,get(i).multiply(generic)); + } + return p; + } + + public Polynomial multiply(Monomial monomial, Generic generic) { + UnivariatePolynomial p=newinstance(); + int d=monomial.degree(); + for(int i=degree;i>=0;i--) { + p.put(i+d,get(i).multiply(generic)); + } + for(int i=d-1;i>=0;i--) { + p.put(i,JSCLInteger.valueOf(0)); + } + return p; + } + + public Polynomial multiply(Monomial monomial) { + return multiply(monomial,JSCLInteger.valueOf(1)); + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + UnivariatePolynomial p=newinstance(); + for(int i=degree;i>=0;i--) { + p.put(i,get(i).divide(generic)); + } + return p; + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + UnivariatePolynomial p=newinstance(); + int d=monomial.degree(); + for(int i=d-1;i>=0;i--) { + if(get(i).signum()==0); + else throw new NotDivisibleException(); + } + for(int i=degree;i>=d;i--) { + p.put(i-d,get(i)); + } + return p; + } + + public Polynomial[] divideAndRemainder(Polynomial polynomial) throws ArithmeticException { + UnivariatePolynomial p[]={newinstance(),this}; + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + if(p[1].signum()==0) return p; + for(int i=p[1].degree-q.degree;i>=0;i--) { + p[0].put(i,p[1].get(i+q.degree).divide(q.get(q.degree))); + UnivariatePolynomial r=newinstance(); + for(int j=i+q.degree-1;j>=0;j--) { + Generic a=p[1].get(j); + r.put(j,a.subtract(q.get(j-i).multiply(p[0].get(i)))); + } + p[1]=r; + } + return p; + } + + public Polynomial remainderUpToCoefficient(Polynomial polynomial) throws ArithmeticException { + UnivariatePolynomial p=this; + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + if(p.signum()==0) return p; + for(int i=p.degree-q.degree;i>=0;i--) { + UnivariatePolynomial r=newinstance(); + for(int j=i+q.degree-1;j>=0;j--) { + Generic a=p.get(j).multiply(q.get(q.degree)); + r.put(j,a.subtract(q.get(j-i).multiply(p.get(i+q.degree)))); + } + p=r; + } + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + UnivariatePolynomial p=this; + UnivariatePolynomial q=(UnivariatePolynomial)polynomial; + if(p.signum()==0) return q; + else if(q.signum()==0) return p; + if(p.degree0) { + UnivariatePolynomial r=(UnivariatePolynomial)p.remainderUpToCoefficient(q).divide(beta); + if(d>1) phi=q.get(q.degree).negate().pow(d).divide(phi.pow(d-1)); + else phi=q.get(q.degree).negate().pow(d).multiply(phi.pow(1-d)); + p=q; + q=r; + d=p.degree-q.degree; + beta=p.get(p.degree).negate().multiply(phi.pow(d)); + } + if(q.signum()==0) { + p=(UnivariatePolynomial)p.normalize(); + } else { + p=newinstance(); + p.put(0,JSCLInteger.valueOf(1)); + } + return p.multiply(gcd1.gcd(gcd2)); + } + + public Generic gcd() { + Generic a=coefficient(JSCLInteger.valueOf(0)); + for(int i=degree;i>=0;i--) a=a.gcd(get(i)); + return a.signum()==signum()?a:a.negate(); + } + + public Monomial monomialGcd() { + return monomial(tail()); + } + + public int degree() { + return degree; + } + + public UnivariatePolynomial valueof(Generic generic[]) { + UnivariatePolynomial p=newinstance(); + p.init(generic); + return p; + } + + public Polynomial valueof(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public Polynomial valueof(Generic generic) { + UnivariatePolynomial p=newinstance(); + p.init(generic); + return p; + } + + public Polynomial valueof(Monomial monomial) { + throw new UnsupportedOperationException(); + } + + public Polynomial freeze() { + return this; + } + + public Term head() { + return term(degree); + } + + public Generic coefficient(Monomial monomial) { + return term(monomial.degree()).coef(); + } + + public Polynomial reduce(Generic generic, Monomial monomial, Polynomial polynomial, boolean inPlace) { + throw new UnsupportedOperationException(); + } + + public Generic genericValue() { + Generic s=JSCLInteger.valueOf(0); + for(int i=degree;i>=0;i--) { + Generic a=get(i).expressionValue(); + s=s.add(i>0?a.multiply(Expression.valueOf(Literal.valueOf(variable,i))):a); + } + return s; + } + + public Generic[] elements() { + Generic a[]=new Generic[degree+1]; + for(int i=degree;i>=0;i--) a[i]=get(i); + return a; + } + + public UnivariatePolynomial derivative(Variable variable) { + return (UnivariatePolynomial)derivative().multiply(this.variable.derivative(variable)); + } + + public Generic substitute(Generic generic) { + Generic s=JSCLInteger.valueOf(0); + for(int i=degree;i>=0;i--) { + s=s.add(get(i).multiply(generic.pow(i))); + } + return s; + } + + public Generic solve() { + if(degree==1) { + return get(0).multiply(new Inv(get(1)).evaluate()).negate(); + } else return null; + } + + public Generic[] identification(UnivariatePolynomial polynomial) { + UnivariatePolynomial p=this; + UnivariatePolynomial q=polynomial; + if(p.degree=0;i--) a[r.degree-i]=r.get(i); + return a; + } + + public Generic resultant(UnivariatePolynomial polynomial) { + UnivariatePolynomial p=this; + UnivariatePolynomial q=polynomial; + if(p.degree0) { + UnivariatePolynomial r=(UnivariatePolynomial)p.remainderUpToCoefficient(q).divide(beta); + if(d>1) phi=q.get(q.degree).negate().pow(d).divide(phi.pow(d-1)); + else phi=q.get(q.degree).negate().pow(d).multiply(phi.pow(1-d)); + p=q; + q=r; + d=p.degree-q.degree; + beta=p.get(p.degree).negate().multiply(phi.pow(d)); + } + return q.get(0); + } + + public UnivariatePolynomial[] remainderSequence(UnivariatePolynomial polynomial) { + UnivariatePolynomial p=this; + UnivariatePolynomial q=polynomial; + if(p.degree0) { + UnivariatePolynomial r=(UnivariatePolynomial)p.remainderUpToCoefficient(q).divide(beta); + if(d>1) phi=q.get(q.degree).negate().pow(d).divide(phi.pow(d-1)); + else phi=q.get(q.degree).negate().pow(d).multiply(phi.pow(1-d)); + p=q; + q=r; + s[q.degree]=q; + d=p.degree-q.degree; + beta=p.get(p.degree).negate().multiply(phi.pow(d)); + } + return s; + } + + public UnivariatePolynomial squarefree() { + return (UnivariatePolynomial)divide(gcd(derivative())); + } + + public UnivariatePolynomial[] squarefreeDecomposition() { + return SquarefreeDecomposition.compute(this); + } + + public UnivariatePolynomial antiderivative() { + UnivariatePolynomial p=newinstance(); + for(int i=degree;i>=0;i--) { + p.put(i+1,get(i).multiply(new Inv(JSCLInteger.valueOf(i+1)).evaluate())); + } + return p; + } + + public UnivariatePolynomial derivative() { + UnivariatePolynomial p=newinstance(); + for(int i=degree-1;i>=0;i--) { + p.put(i,get(i+1).multiply(JSCLInteger.valueOf(i+1))); + } + return p; + } + + public int compareTo(Polynomial polynomial) { + UnivariatePolynomial p=(UnivariatePolynomial)polynomial; + int d=Math.max(degree,p.degree); + for(int i=d;i>=0;i--) { + Generic a1=get(i); + Generic a2=p.get(i); + int c=a1.compareTo(a2); + if(c<0) return -1; + else if(c>0) return 1; + } + return 0; + } + + void init(Generic generic[]) { + for(int i=0;i0) put(m.degree(),coefficient(en.multiply(Expression.valueOf(l)))); + else put(m.degree(),coefficient(en)); + } + } + + protected void init(Generic generic) { + if(generic instanceof Expression) { + init((Expression)generic); + } else put(0,coefficient(generic)); + } + + void put(int n, Generic generic) { + Generic a=generic.add(get(n)); + if(a.signum()==0) { + if(n<=degree) content[n]=null; + if(n==degree) { + while(n>0 && content[n]==null) n--; + degree=n; + } + } else { + if(n>=content.length) resize(n); + content[n]=a; + degree=Math.max(degree,n); + } + } + + void resize(int n) { + int length=content.length<<1; + while(n>=length) length<<=1; + Generic content[]=new Generic[length]; + System.arraycopy(this.content,0,content,0,this.content.length); + this.content=content; + } + + public Generic get(int n) { + Generic a=n<0 || n>degree?null:content[n]; + return a==null?JSCLInteger.valueOf(0):a; + } + + protected UnivariatePolynomial newinstance() { + return new UnivariatePolynomial(variable,coefFactory); + } +} + +class SquarefreeDecomposition { + final List list=new ArrayList(); + + static UnivariatePolynomial[] compute(UnivariatePolynomial polynomial) { + SquarefreeDecomposition sd=new SquarefreeDecomposition(); + Polynomial p[]=polynomial.gcdAndNormalize(); + sd.init((UnivariatePolynomial)p[0]); + sd.process((UnivariatePolynomial)p[1]); + return sd.getValue(); + } + + void init(UnivariatePolynomial polynomial) { + list.add(polynomial); + } + + void process(UnivariatePolynomial polynomial) { + UnivariatePolynomial r=(UnivariatePolynomial)polynomial.gcd(polynomial.derivative()); + UnivariatePolynomial s=(UnivariatePolynomial)polynomial.divide(r); + list.add(s.divide(s.gcd(r))); + if(r.degree()==0); + else process(r); + } + + UnivariatePolynomial[] getValue() { + return (UnivariatePolynomial[])ArrayUtils.toArray(list,new UnivariatePolynomial[list.size()]); + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/Block.java b/src/misc/src/jscl/math/polynomial/groebner/Block.java new file mode 100644 index 00000000..5be3b126 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/Block.java @@ -0,0 +1,60 @@ +package jscl.math.polynomial.groebner; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import jscl.math.Debug; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.DegreeOrdering; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; + +class Block extends Standard { + boolean degree; + + Block(Ordering ordering, int flags) { + super(flags); + degree=ordering instanceof DegreeOrdering; + } + + void compute() { + Debug.println("compute"); + int degree=0; + while(!pairs.isEmpty()) { + List list=new ArrayList(); + Iterator it=pairs.keySet().iterator(); + while(it.hasNext()) { + Pair pa=(Pair)it.next(); + int d=(flags&Basis.SUGAR)>0?pa.sugar:pa.scm.degree(); + if(degree==0) degree=d; + else if(d>degree || !this.degree) break; + list.add(pa); + } + process(list); + remove(list); + degree=0; + } + } + + void add(List list) { + super.add(ReducedRowEchelonForm.compute(list)); + } + + void process(List pairs) { + List list=new ArrayList(); + Iterator it=pairs.iterator(); + while(it.hasNext()) { + Pair pa=(Pair)it.next(); + if(criterion(pa)) continue; + Polynomial p=reduce(pa,polys); + if(p.signum()!=0) list.add(p); + npairs++; + } + add(list); + } + + void remove(List pairs) { + Iterator it=pairs.iterator(); + while(it.hasNext()) remove((Pair)it.next()); + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/F4.java b/src/misc/src/jscl/math/polynomial/groebner/F4.java new file mode 100644 index 00000000..b79d3a22 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/F4.java @@ -0,0 +1,35 @@ +package jscl.math.polynomial.groebner; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; + +class F4 extends Block { + List reduction=new ArrayList(); + + F4(Ordering ordering, int flags) { + super(ordering,flags); + } + + void add(List list) { + Iterator it=list.iterator(); + while(it.hasNext()) { + Polynomial p=(Polynomial)it.next(); + if(p.signum()!=0) add(p); + } + } + + void process(List pairs) { + List list=new ArrayList(); + Iterator it=pairs.iterator(); + while(it.hasNext()) { + Pair pa=(Pair)it.next(); + if(criterion(pa)) continue; + list.add(pa); + } + add(F4Reduction.compute(list,polys,reduction,flags)); + npairs+=list.size(); + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/F4Reduction.java b/src/misc/src/jscl/math/polynomial/groebner/F4Reduction.java new file mode 100644 index 00000000..6b6273b6 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/F4Reduction.java @@ -0,0 +1,98 @@ +package jscl.math.polynomial.groebner; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import jscl.math.Debug; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.Term; + +class F4Reduction { + final Collection ideal; + final List list; + final int flags; + final List polys=new ArrayList(); + final List content=new ArrayList(); + final Map considered=new TreeMap(); + final Map head=new TreeMap(); + final Map proj=new TreeMap(); + + F4Reduction(Collection ideal, List list, int flags) { + this.ideal=ideal; + this.list=list; + this.flags=flags; + } + + static List compute(List pairs, Collection ideal, List list, int flags) { + F4Reduction r=new F4Reduction(ideal,list,flags); + r.compute(pairs); + return r.content; + } + + void compute(List pairs) { + Iterator it=pairs.iterator(); + while(it.hasNext()) { + Pair pa=(Pair)it.next(); + considered.put(pa.scm,null); + add(pa); + } + process(); + if((flags&Basis.F4_SIMPLIFY)>0) list.add(this); + } + + void add(Pair pair) { + Debug.println(pair); + Projection pr[]=new Projection[] {new Projection(pair,0),new Projection(pair,1)}; + for(int i=0;i0) return 1; + else { + c=polynomial[1].index()-pair.polynomial[1].index(); + if(c<0) return -1; + else if(c>0) return 1; + else { + c=polynomial[0].index()-pair.polynomial[0].index(); + if(c<0) return -1; + else if(c>0) return 1; + else return 0; + } + } + } + + public int compareTo(Object o) { + return compareTo((Pair)o); + } + + public String toString() { + return "{"+polynomial[0].index()+", "+polynomial[1].index()+"}, "+sugar+", "+reduction; + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/Projection.java b/src/misc/src/jscl/math/polynomial/groebner/Projection.java new file mode 100644 index 00000000..6aa75c12 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/Projection.java @@ -0,0 +1,73 @@ +package jscl.math.polynomial.groebner; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; + +class Projection implements Comparable { + final Monomial monomial; + final Polynomial polynomial; + + Projection(Pair pair, int index) { + this(pair.scm.divide(pair.monomial[index]),pair.polynomial[index]); + } + + Projection(Monomial monomial, Polynomial polynomial) { + this.monomial=monomial; + this.polynomial=polynomial; + } + + Monomial scm() { + return polynomial.head().monomial().multiply(monomial); + } + + Polynomial mult() { + return polynomial.multiply(monomial); + } + + Projection simplify(List list) { + Monomial t=monomial; + if(t.degree()>0) { + Monomial m=polynomial.head().monomial(); + int n=list.size(); + for(int i=0;i0) return 1; + else { + c=polynomial.index()-proj.polynomial.index(); + if(c<0) return -1; + else if(c>0) return 1; + else return 0; + } + } + + public int compareTo(Object o) { + return compareTo((Projection)o); + } + + public String toString() { + return "{"+monomial+", "+polynomial.head().monomial()+"}"; + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java b/src/misc/src/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java new file mode 100644 index 00000000..2e0a2258 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java @@ -0,0 +1,57 @@ +package jscl.math.polynomial.groebner; + +import java.util.ArrayList; +import java.util.List; +import jscl.math.Generic; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; + +class ReducedRowEchelonForm { + List content=new ArrayList(); + + ReducedRowEchelonForm(List list) { + content.addAll(list); + } + + static List compute(List list) { + ReducedRowEchelonForm f=new ReducedRowEchelonForm(list); + f.compute(); + return f.content; + } + + void compute() { + int n=content.size(); + for(int i=0;i=0;i--) reduce(i,true); + } + + void reduce(int pivot, boolean direction) { + Polynomial p=polynomial(pivot); + content.set(pivot,p=p.normalize().freeze()); + if(p.signum()==0) return; + Monomial m=p.head().monomial(); + int b=direction?0:pivot+1; + int n=direction?pivot:content.size(); + for(int i=b;i0?", ":"").append(p); + } + buffer.append("}"); + return buffer.toString(); + } +} diff --git a/src/misc/src/jscl/math/polynomial/groebner/Standard.java b/src/misc/src/jscl/math/polynomial/groebner/Standard.java new file mode 100644 index 00000000..fe5c9e26 --- /dev/null +++ b/src/misc/src/jscl/math/polynomial/groebner/Standard.java @@ -0,0 +1,227 @@ +package jscl.math.polynomial.groebner; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import jscl.math.Debug; +import jscl.math.Generic; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; +import jscl.util.ArrayUtils; + +public class Standard { + final int flags; + final Comparator comparator; + final Map pairs; + final List polys=new ArrayList(); + final Map removed=new TreeMap(); + int npairs; + int npolys; + + Standard(int flags) { + this.flags=flags; + pairs=new TreeMap(comparator=(flags&Basis.SUGAR)>0?Sugar.comparator:Natural.comparator); + } + + public static Basis compute(Basis basis) { + return compute(basis,0); + } + + public static Basis compute(Basis basis, int flags) { + return compute(basis,flags,(flags&Basis.INSTRUMENTED)>0); + } + + static Basis compute(Basis basis, int flags, boolean instrumented) { + Standard a=instrumented?new Instrumented(flags):algorithm(basis.ordering(),flags); + a.computeValue(basis); + basis=basis.valueof(a.elements()); + if(instrumented) return compute(basis,flags,false); + return basis; + } + + static Standard algorithm(Ordering ordering, int flags) { + switch(flags&Basis.ALGORITHM) { + case Basis.F4: + return new F4(ordering,flags); + case Basis.BLOCK: + return new Block(ordering,flags); + default: + return new Standard(flags); + } + } + + void computeValue(Basis basis) { + Debug.println(basis); + populate(basis); + npolys=0; + compute(); + remove(); + reduce(); + Debug.println("signature = ("+npairs+", "+npolys+", "+polys.size()+")"); + } + + void populate(Basis basis) { + List list=new ArrayList(); + Generic a[]=basis.elements(); + for(int i=0;i0) makePairsGM(polynomial); + else makePairs(polynomial); + polys.add(polynomial); + npolys++; + } + + boolean criterion(Pair pair) { + return (flags&Basis.GM_SETTING)>0?false:b_criterion(pair); + } + + void makePairs(Polynomial polynomial) { + Iterator it=polys.iterator(); + while(it.hasNext()) { + Polynomial p=(Polynomial)it.next(); + Pair pa=new Pair(p,polynomial); + if(!pa.coprime) pairs.put(pa,null); + } + } + + boolean b_criterion(Pair pair) { + Iterator it=polys.iterator(); + while(it.hasNext()) { + Polynomial p=(Polynomial)it.next(); + if(pair.scm.multiple(p.head().monomial())) { + Pair pa1=new Pair(sort(pair.polynomial[0],p)); + Pair pa2=new Pair(sort(pair.polynomial[1],p)); + if(considered(pa1) && considered(pa2)) return true; + } + } + return false; + } + + boolean considered(Pair pair) { + return !pairs.containsKey(pair); + } + + Polynomial[] sort(Polynomial p1, Polynomial p2) { + return p1.index()0 && (flags&Basis.FUSSY)>0?Sugar.comparator:Natural.comparator); + it=polys.iterator(); + while(it.hasNext()) { + Polynomial p=(Polynomial)it.next(); + Pair pa=new Pair(p,polynomial); + pairs.put(pa,null); + map.put(pa,null); + } + list=ArrayUtils.list(map.keySet()); + n=list.size(); + for(int i=0;i0 && (flags&Basis.FUSSY)>0?Sugar.comparator.compare(p1,p2)>0:true); + } + + void remove() { + Iterator it=polys.iterator(); + while(it.hasNext()) if(removed.containsKey(it.next())) it.remove(); + } + + void reduce() { + Debug.println("reduce"); + Map map=new TreeMap(); + int size=polys.size(); + for(int i=0;ipa2.sugar) return 1; + else return pa1.compareTo(pa2); + } + + public int compare(Object o1, Object o2) { + return compare((Pair)o1,(Pair)o2); + } +} diff --git a/src/misc/src/jscl/mathml/MathML.java b/src/misc/src/jscl/mathml/MathML.java new file mode 100644 index 00000000..74e655f2 --- /dev/null +++ b/src/misc/src/jscl/mathml/MathML.java @@ -0,0 +1,66 @@ +package jscl.mathml; + +import java.io.ByteArrayOutputStream; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.DocumentTypeImpl; +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.TextImpl; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +public class MathML { + static Transformer xhtml; + Node node; + + MathML(Node node) { + this.node=node; + } + + public Document document() { + return node instanceof CoreDocumentImpl?(Document)node:node.getOwnerDocument(); + } + + public MathML(String qualifiedName, String publicID, String systemID) { + this(new CoreDocumentImpl()); + CoreDocumentImpl document=(CoreDocumentImpl)document(); + document.setXmlEncoding("utf-8"); + document.appendChild(new DocumentTypeImpl(document,qualifiedName,publicID,systemID)); + } + + public MathML element(String name) { + CoreDocumentImpl document=(CoreDocumentImpl)document(); + return new MathML(new ElementImpl(document,name)); + } + + public void setAttribute(String name, String value) { + ((Element)node).setAttribute(name, value); + } + + public MathML text(String data) { + CoreDocumentImpl document=(CoreDocumentImpl)document(); + return new MathML(new TextImpl(document,data)); + } + + public void appendChild(MathML math) { + node.appendChild(math.node); + } + + public String toString() { + ByteArrayOutputStream os=new ByteArrayOutputStream(); + try { + transformer().transform(new DOMSource(node), new StreamResult(os)); + } catch (TransformerException e) {} + String s=os.toString(); + return s.substring(s.indexOf(">")+1); + } + + static Transformer transformer() throws TransformerException { + return xhtml==null?xhtml=TransformerFactory.newInstance().newTransformer():xhtml; + } +} diff --git a/src/misc/src/jscl/text/BracketedExpression.java b/src/misc/src/jscl/text/BracketedExpression.java new file mode 100644 index 00000000..35b4821e --- /dev/null +++ b/src/misc/src/jscl/text/BracketedExpression.java @@ -0,0 +1,36 @@ +package jscl.text; + +import jscl.math.ExpressionVariable; +import jscl.math.Generic; + +public class BracketedExpression extends Parser { + public static final Parser parser=new BracketedExpression(); + + private BracketedExpression() {} + + public Object parse(String str, int pos[]) throws ParseException { + int pos0=pos[0]; + Generic a; + skipWhitespaces(str,pos); + if(pos[0]='A' && c<='Z') || (c>='a' && c<='z') || c=='_'; + } +} diff --git a/src/misc/src/jscl/text/ImplicitFunctionParser.java b/src/misc/src/jscl/text/ImplicitFunctionParser.java new file mode 100644 index 00000000..efdad98d --- /dev/null +++ b/src/misc/src/jscl/text/ImplicitFunctionParser.java @@ -0,0 +1,137 @@ +package jscl.text; + +import java.util.ArrayList; +import java.util.List; +import jscl.math.Generic; +import jscl.math.function.ImplicitFunction; +import jscl.util.ArrayUtils; + +public class ImplicitFunctionParser extends Parser { + public static final Parser parser=new ImplicitFunctionParser(); + + private ImplicitFunctionParser() {} + + public Object parse(String str, int pos[]) throws ParseException { + int pos0=pos[0]; + String name; + Generic a[]; + int b[]; + List l=new ArrayList(); + try { + name=(String)CompoundIdentifier.parser.parse(str,pos); + } catch (ParseException e) { + pos[0]=pos0; + throw e; + } + while(true) { + try { + Generic s=(Generic)Subscript.parser.parse(str,pos); + l.add(s); + } catch (ParseException e) { + break; + } + } + try { + b=(int [])Derivation.parser.parse(str,pos); + } catch (ParseException e) { + b=new int[0]; + } + try { + a=(Generic[])ParameterList.parser.parse(str,pos); + } catch (ParseException e) { + pos[0]=pos0; + throw e; + } + Generic s[]=(Generic[])ArrayUtils.toArray(l,new Generic[l.size()]); + int derivation[]=new int[a.length]; + for(int i=0;i2?a[2]:a[1],a.length>3?a[3]:JSCLInteger.valueOf(1)); + else if(name.compareTo("grad")==0) v=new Grad(a[0],a[1]); + else if(name.compareTo("diverg")==0) v=new Divergence(a[0],a[1]); + else if(name.compareTo("curl")==0) v=new Curl(a[0],a[1]); + else if(name.compareTo("jacobian")==0) v=new Jacobian(a[0],a[1]); + else if(name.compareTo("laplacian")==0) v=new Laplacian(a[0],a[1]); + else if(name.compareTo("dalembertian")==0) v=new Dalembertian(a[0],a[1]); + else if(name.compareTo("del")==0) v=new Del(a[0],a[1],a.length>2?a[2]:JSCLInteger.valueOf(0)); + else if(name.compareTo("vector")==0) v=new VectorProduct(a[0],a[1]); + else if(name.compareTo("complex")==0) v=new ComplexProduct(a[0],a[1]); + else if(name.compareTo("quaternion")==0) v=new QuaternionProduct(a[0],a[1]); + else if(name.compareTo("geometric")==0) v=new GeometricProduct(a[0],a[1],a.length>2?a[2]:JSCLInteger.valueOf(0)); + else if(name.compareTo("matrix")==0) v=new MatrixProduct(a[0],a[1]); + else if(name.compareTo("tensor")==0) v=new TensorProduct(a[0],a[1]); + else if(name.compareTo("tran")==0) v=new Transpose(a[0]); + else if(name.compareTo("trace")==0) v=new Trace(a[0]); + else if(name.compareTo("det")==0) v=new Determinant(a[0]); + else if(name.compareTo("coef")==0) v=new Coefficient(a[0],a[1]); + else if(name.compareTo("solve")==0) v=new Solve(a[0],a[1],a.length>2?a[2]:JSCLInteger.valueOf(0)); + else if(name.compareTo("subst")==0) v=new Substitute(a[0],a[1],a[2]).transmute(); + else if(name.compareTo("lim")==0) v=new Limit(a[0],a[1],a[2],a.length>3 && (a[2].compareTo(Constant.infinity)!=0 && a[2].compareTo(Constant.infinity.negate())!=0)?JSCLInteger.valueOf(a[3].signum()):JSCLInteger.valueOf(0)); + else if(name.compareTo("sum")==0) v=new Sum(a[0],a[1],a[2],a[3]); + else if(name.compareTo("prod")==0) v=new Product(a[0],a[1],a[2],a[3]); + else if(name.compareTo("integral")==0) v=a.length>2?(Operator)new Integral(a[0],a[1],a[2],a[3]):new IndefiniteIntegral(a[0],a[1]); + else if(name.compareTo("groebner")==0) v=new Groebner(a[0],a[1],a.length>2?a[2]:Expression.valueOf("lex"),a.length>3?a[3]:JSCLInteger.valueOf(0)).transmute(); + else if(name.compareTo("div")==0) v=new Division(a[0],a[1]); + else if(name.compareTo("mod")==0) v=new Modulo(a[0],a[1]); + else if(name.compareTo("modpow")==0) v=new ModPow(a[0],a[1],a[2]); + else if(name.compareTo("modinv")==0) v=new ModInverse(a[0],a[1]); + else if(name.compareTo("eulerphi")==0) v=new EulerPhi(a[0]); + else if(name.compareTo("primitiveroots")==0) v=new PrimitiveRoots(a[0]); + return v; + } + + static boolean valid(String name) { + for(int i=0;ico2.length) return 1; + for(int i=co1.length-1;i>=0;i--) { + if(co1[i].compareTo(co2[i])<0) return -1; + else if(co1[i].compareTo(co2[i])>0) return 1; + } + return 0; + } + + public int compare(Object o1, Object o2) { + return compare((Comparable[])o1,(Comparable[])o2); + } +} diff --git a/src/misc/src/jscl/util/ArrayUtils.java b/src/misc/src/jscl/util/ArrayUtils.java new file mode 100644 index 00000000..78cf21a5 --- /dev/null +++ b/src/misc/src/jscl/util/ArrayUtils.java @@ -0,0 +1,112 @@ +package jscl.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.RandomAccess; + +public class ArrayUtils { + private ArrayUtils() {} + + public static Object[] concat(Object o1[], Object o2[], Object res[]) { + System.arraycopy(o1,0,res,0,o1.length); + System.arraycopy(o2,0,res,o1.length,o2.length); + return res; + } + + public static Object[] toArray(List list, Object res[]) { +// return list.toArray(res); + int n=list.size(); + for(int i=0;i> 1; + Object midVal = list.get(mid); + int cmp = ((Comparable)midVal).compareTo(key); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found + } + + private static int iteratorBinarySearch(List list, Object key) { + int low = 0; + int high = list.size()-1; + ListIterator i = list.listIterator(); + + while (low <= high) { + int mid = (low + high) >> 1; + Object midVal = get(i, mid); + int cmp = ((Comparable)midVal).compareTo(key); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found + } + + private static Object get(ListIterator i, int index) { + Object obj = null; + int pos = i.nextIndex(); + if (pos <= index) { + do { + obj = i.next(); + } while (pos++ < index); + } else { + do { + obj = i.previous(); + } while (--pos > index); + } + return obj; + } +}