diff --git a/app/build.gradle b/app/build.gradle index 917e684b..b7f63e75 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,7 +74,7 @@ dependencies { compile 'org.solovyev.android:android-common-views:1.1.18@aar' compile 'org.solovyev.android:android-common-menus:1.1.18@aar' compile 'org.solovyev.android:android-common-preferences:1.1.18@aar' - compile('org.solovyev:jscl:1.0.12') { + compile(project(':jscl')) { exclude(module: 'xercesImpl') } compile 'org.solovyev.android:checkout:0.7.2@aar' @@ -92,9 +92,6 @@ dependencies { compile('com.google.guava:guava:11.0.2') { exclude(module: 'jsr305') } - compile('org.solovyev:jscl:1.0.11') { - exclude(module: 'xercesImpl') - } compile('org.simpleframework:simple-xml:2.6.1') { exclude(module: 'stax-api') exclude(module: 'xpp3') diff --git a/jscl/build.gradle b/jscl/build.gradle new file mode 100644 index 00000000..345f6457 --- /dev/null +++ b/jscl/build.gradle @@ -0,0 +1,37 @@ +/* + * Copyright 2016 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +apply plugin: 'java' + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'org.solovyev:common-core:1.0.7' + compile 'org.solovyev:common-msg:1.0.7' + compile 'com.google.code.findbugs:annotations:2.0.1' + compile 'xerces:xercesImpl:2.8.0' + + testCompile 'junit:junit:4.12' + testCompile 'net.sf.opencsv:opencsv:2.0' +} + +sourceCompatibility = JavaVersion.VERSION_1_7 +targetCompatibility = JavaVersion.VERSION_1_7 \ No newline at end of file diff --git a/jscl/src/main/java/jscl/AbstractJsclArithmeticException.java b/jscl/src/main/java/jscl/AbstractJsclArithmeticException.java new file mode 100644 index 00000000..429e853c --- /dev/null +++ b/jscl/src/main/java/jscl/AbstractJsclArithmeticException.java @@ -0,0 +1,67 @@ +package jscl; + +import jscl.text.msg.JsclMessage; +import org.solovyev.common.msg.Message; +import org.solovyev.common.msg.MessageLevel; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Locale; + +public abstract class AbstractJsclArithmeticException extends ArithmeticException implements Message { + + @Nonnull + private final Message message; + + public AbstractJsclArithmeticException(@Nonnull String messageCode, Object... parameters) { + this.message = new JsclMessage(messageCode, MessageType.error, parameters); + } + + public AbstractJsclArithmeticException(@Nonnull Message message) { + this.message = message; + } + + @Nonnull + public String getMessageCode() { + return this.message.getMessageCode(); + } + + @Nonnull + public List getParameters() { + return this.message.getParameters(); + } + + @Nonnull + public MessageLevel getMessageLevel() { + return this.message.getMessageLevel(); + } + + @Nonnull + public String getLocalizedMessage(@Nonnull Locale locale) { + return this.message.getLocalizedMessage(locale); + } + + @Nonnull + @Override + public String getLocalizedMessage() { + return this.getLocalizedMessage(Locale.getDefault()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AbstractJsclArithmeticException that = (AbstractJsclArithmeticException) o; + + if (!message.equals(that.message)) return false; + + return true; + } + + @Override + public int hashCode() { + return message.hashCode(); + } +} diff --git a/jscl/src/main/java/jscl/AngleUnit.java b/jscl/src/main/java/jscl/AngleUnit.java new file mode 100644 index 00000000..4085f7d2 --- /dev/null +++ b/jscl/src/main/java/jscl/AngleUnit.java @@ -0,0 +1,119 @@ +package jscl; + +import jscl.math.Generic; +import jscl.math.NumericWrapper; +import jscl.math.numeric.Numeric; +import jscl.math.numeric.Real; + +import javax.annotation.Nonnull; + +public enum AngleUnit { + + deg { + @Override + protected double getCoefficientTo(@Nonnull AngleUnit to) { + switch (to) { + case deg: + return 1d; + case rad: + return FROM_DEG_TO_RAD; + case grad: + return FROM_DEG_TO_GRAD; + case turns: + return FROM_DEG_TO_TURNS; + default: + throw new UnsupportedOperationException("Conversion from " + this + " to " + to + " is not supported!"); + } + } + }, + + rad { + @Override + protected double getCoefficientTo(@Nonnull AngleUnit to) { + switch (to) { + case deg: + return FROM_RAD_TO_DEG; + case rad: + return 1d; + case grad: + return FROM_RAD_TO_GRAD; + case turns: + return FROM_RAD_TO_TURNS; + default: + throw new UnsupportedOperationException("Conversion from " + this + " to " + to + " is not supported!"); + } + } + }, + + grad { + @Override + protected double getCoefficientTo(@Nonnull AngleUnit to) { + switch (to) { + case deg: + return FROM_GRAD_TO_DEG; + case rad: + return FROM_GRAD_TO_RAD; + case grad: + return 1d; + case turns: + return FROM_GRAD_TO_TURNS; + default: + throw new UnsupportedOperationException("Conversion from " + this + " to " + to + " is not supported!"); + } + } + }, + + turns { + @Override + protected double getCoefficientTo(@Nonnull AngleUnit to) { + switch (to) { + case deg: + return FROM_TURNS_TO_DEG; + case rad: + return FROM_TURNS_TO_RAD; + case grad: + return FROM_TURNS_TO_GRAD; + case turns: + return 1d; + default: + throw new UnsupportedOperationException("Conversion from " + this + " to " + to + " is not supported!"); + } + } + }; + + + private static final double FROM_RAD_TO_DEG = 180d / Math.PI; + private static final double FROM_RAD_TO_GRAD = 200d / Math.PI; + private static final double FROM_RAD_TO_TURNS = 0.5d / Math.PI; + + private static final double FROM_DEG_TO_RAD = Math.PI / 180d; + private static final double FROM_DEG_TO_TURNS = 0.5d / 180d; + private static final double FROM_DEG_TO_GRAD = 10d / 9d; + + private static final double FROM_GRAD_TO_RAD = Math.PI / 200d; + private static final double FROM_GRAD_TO_TURNS = 0.5d / 200d; + private static final double FROM_GRAD_TO_DEG = 9d / 10d; + + private static final double FROM_TURNS_TO_GRAD = 200d / 0.5d; + private static final double FROM_TURNS_TO_RAD = Math.PI / 0.5d; + private static final double FROM_TURNS_TO_DEG = 180d / 0.5d; + + + public final double transform(@Nonnull AngleUnit to, double value) { + return value * getCoefficientTo(to); + } + + protected abstract double getCoefficientTo(@Nonnull AngleUnit to); + + public final Numeric transform(@Nonnull AngleUnit to, @Nonnull Numeric value) { + return value.multiply(getRealCoefficientTo(to)); + } + + private Real getRealCoefficientTo(@Nonnull AngleUnit to) { + return Real.valueOf(getCoefficientTo(to)); + } + + public final Generic transform(@Nonnull AngleUnit to, @Nonnull Generic value) { + return value.multiply(new NumericWrapper(getRealCoefficientTo(to))); + } +} diff --git a/jscl/src/main/java/jscl/CustomFunctionCalculationException.java b/jscl/src/main/java/jscl/CustomFunctionCalculationException.java new file mode 100644 index 00000000..0360420a --- /dev/null +++ b/jscl/src/main/java/jscl/CustomFunctionCalculationException.java @@ -0,0 +1,14 @@ +package jscl; + +import jscl.math.function.CustomFunction; +import jscl.text.msg.Messages; +import org.solovyev.common.msg.Message; + +import javax.annotation.Nonnull; + +public class CustomFunctionCalculationException extends AbstractJsclArithmeticException { + + public CustomFunctionCalculationException(@Nonnull CustomFunction function, @Nonnull Message message) { + super(Messages.msg_19, function.getName(), message); + } +} diff --git a/jscl/src/main/java/jscl/FixedCapacityListMessageRegistry.java b/jscl/src/main/java/jscl/FixedCapacityListMessageRegistry.java new file mode 100644 index 00000000..823d3258 --- /dev/null +++ b/jscl/src/main/java/jscl/FixedCapacityListMessageRegistry.java @@ -0,0 +1,54 @@ +package jscl; + +import org.solovyev.common.msg.Message; +import org.solovyev.common.msg.MessageRegistry; + +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.ArrayList; +import java.util.List; + +@NotThreadSafe +public class FixedCapacityListMessageRegistry implements MessageRegistry { + + @Nonnull + private final List messages; + + private final int capacity; + + private volatile int size; + + public FixedCapacityListMessageRegistry(int capacity) { + this.size = 0; + this.capacity = capacity; + this.messages = new ArrayList(capacity); + } + + @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {"VO_VOLATILE_INCREMENT"}, justification = "NotThreadSafe - outer synchronization") + public void addMessage(@Nonnull Message message) { + if (!this.messages.contains(message)) { + if (this.size <= this.capacity) { + this.messages.add(message); + this.size++; + } else { + this.messages.remove(0); + this.messages.add(message); + } + } + } + + @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {"VO_VOLATILE_INCREMENT"}, justification = "NotThreadSafe - outer synchronization") + @Nonnull + public Message getMessage() { + if (hasMessage()) { + this.size--; + return messages.remove(0); + } else { + throw new IllegalStateException("No messages!"); + } + } + + public boolean hasMessage() { + return size > 0; + } +} diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java new file mode 100644 index 00000000..7473d16d --- /dev/null +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -0,0 +1,345 @@ +package jscl; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.NotIntegerException; +import jscl.math.function.*; +import jscl.math.operator.Operator; +import jscl.math.operator.Percent; +import jscl.math.operator.Rand; +import jscl.math.operator.matrix.OperatorsRegistry; +import jscl.text.ParseException; +import org.solovyev.common.JPredicate; +import org.solovyev.common.collections.Collections; +import org.solovyev.common.math.MathRegistry; +import org.solovyev.common.msg.MessageRegistry; +import org.solovyev.common.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class JsclMathEngine implements MathEngine { + + public static final AngleUnit DEFAULT_ANGLE_UNITS = AngleUnit.deg; + public static final NumeralBase DEFAULT_NUMERAL_BASE = NumeralBase.dec; + public static final String GROUPING_SEPARATOR_DEFAULT = " "; + public static final int MAX_FRACTION_DIGITS = 20; + @Nonnull + private static JsclMathEngine instance = new JsclMathEngine(); + + @Nonnull + private DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault()); + private boolean roundResult = false; + private boolean scienceNotation = false; + private int precision = 5; + private boolean useGroupingSeparator = false; + @Nonnull + private AngleUnit angleUnits = DEFAULT_ANGLE_UNITS; + @Nonnull + private NumeralBase numeralBase = DEFAULT_NUMERAL_BASE; + @Nonnull + private ConstantsRegistry constantsRegistry; + @Nonnull + private MessageRegistry messageRegistry = Messages.synchronizedMessageRegistry(new FixedCapacityListMessageRegistry(10)); + + { + decimalGroupSymbols.setDecimalSeparator('.'); + decimalGroupSymbols.setGroupingSeparator(GROUPING_SEPARATOR_DEFAULT.charAt(0)); + } + + private JsclMathEngine() { + this.constantsRegistry = new ConstantsRegistry(); + } + + @Nonnull + public static JsclMathEngine getInstance() { + return instance; + } + + private static int integerValue(final double value) throws NotIntegerException { + if (Math.floor(value) == value) { + return (int) value; + } else { + throw new NotIntegerException(); + } + } + + @Nonnull + public String evaluate(@Nonnull String expression) throws ParseException { + return evaluateGeneric(expression).toString(); + } + + @Nonnull + public String simplify(@Nonnull String expression) throws ParseException { + return simplifyGeneric(expression).toString(); + } + + @Nonnull + public String elementary(@Nonnull String expression) throws ParseException { + return elementaryGeneric(expression).toString(); + } + + @Nonnull + public Generic evaluateGeneric(@Nonnull String expression) throws ParseException { + if (expression.contains(Percent.NAME) || expression.contains(Rand.NAME)) { + return Expression.valueOf(expression).numeric(); + } else { + return Expression.valueOf(expression).expand().numeric(); + } + } + + @Nonnull + public Generic simplifyGeneric(@Nonnull String expression) throws ParseException { + if (expression.contains(Percent.NAME) || expression.contains(Rand.NAME)) { + return Expression.valueOf(expression); + } else { + return Expression.valueOf(expression).expand().simplify(); + } + } + + @Nonnull + public Generic elementaryGeneric(@Nonnull String expression) throws ParseException { + return Expression.valueOf(expression).elementary(); + } + + @Nonnull + public MathRegistry getFunctionsRegistry() { + return FunctionsRegistry.getInstance(); + } + + @Nonnull + public MathRegistry getOperatorsRegistry() { + return OperatorsRegistry.getInstance(); + } + + @Nonnull + public MathRegistry getPostfixFunctionsRegistry() { + return PostfixFunctionsRegistry.getInstance(); + } + + @Nonnull + public AngleUnit getAngleUnits() { + return angleUnits; + } + + public void setAngleUnits(@Nonnull AngleUnit angleUnits) { + this.angleUnits = angleUnits; + } + + @Nonnull + public NumeralBase getNumeralBase() { + return numeralBase; + } + + public void setNumeralBase(@Nonnull NumeralBase numeralBase) { + this.numeralBase = numeralBase; + } + + @Nonnull + public MathRegistry getConstantsRegistry() { + return constantsRegistry; + } + + @Nonnull + public String format(@Nonnull Double value) throws NumeralBaseException { + return format(value, numeralBase); + } + + @Nonnull + public String format(@Nonnull Double value, @Nonnull NumeralBase nb) throws NumeralBaseException { + if (value.isInfinite()) { + // return predefined constant for infinity + if (value >= 0) { + return Constants.INF.getName(); + } else { + return Constants.INF.expressionValue().negate().toString(); + } + } else { + if (value.isNaN()) { + // return "NaN" + return String.valueOf(value); + } else { + if (nb == NumeralBase.dec) { + // decimal numeral base => do specific formatting + + // detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS) + final Double localValue = value; + IConstant constant = Collections.find(this.getConstantsRegistry().getSystemEntities(), new JPredicate() { + public boolean apply(@Nullable IConstant constant) { + if (constant != null) { + if (localValue.equals(constant.getDoubleValue())) { + if (!constant.getName().equals(Constants.PI_INV.getName())) { + if (!constant.getName().equals(Constants.PI.getName()) || JsclMathEngine.getInstance().getAngleUnits() == AngleUnit.rad) { + return true; + } + } + } + } + + return false; + } + }); + + + if (constant == null) { + final IConstant piInv = this.getConstantsRegistry().get(Constants.PI_INV.getName()); + if (piInv != null && value.equals(piInv.getDoubleValue())) { + constant = piInv; + } + } + + if (constant == null) { + // prepare decimal format + final DecimalFormat df; + + if (roundResult) { + value = new BigDecimal(value).setScale(precision, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + if (value != 0d && value != -0d) { + if (Math.abs(value) < Math.pow(10, -5) || scienceNotation) { + df = new DecimalFormat("##0.#####E0"); + } else { + df = new DecimalFormat(); + } + } else { + df = new DecimalFormat(); + } + + df.setDecimalFormatSymbols(decimalGroupSymbols); + df.setGroupingUsed(useGroupingSeparator); + df.setGroupingSize(nb.getGroupingSize()); + + if (!scienceNotation) { + // using default round logic => try roundResult variable + if (!roundResult) { + // set maximum fraction digits high enough to show all fraction digits in case of no rounding + df.setMaximumFractionDigits(MAX_FRACTION_DIGITS); + } else { + df.setMaximumFractionDigits(precision); + } + } + + return df.format(value); + + } else { + return constant.getName(); + } + } else { + return convert(value, nb); + } + } + } + } + + @Nonnull + public String convert(@Nonnull Double value, @Nonnull NumeralBase to) { + String ungroupedValue; + try { + // check if double can be converted to integer + integerValue(value); + + ungroupedValue = to.toString(new BigDecimal(value).toBigInteger()); + } catch (NotIntegerException e) { + ungroupedValue = to.toString(value, roundResult ? precision : MAX_FRACTION_DIGITS); + } + + return addGroupingSeparators(to, ungroupedValue); + } + + @Nonnull + public MessageRegistry getMessageRegistry() { + return messageRegistry; + } + + public void setMessageRegistry(@Nonnull MessageRegistry messageRegistry) { + this.messageRegistry = messageRegistry; + } + + @Nonnull + public String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedDoubleValue) { + if (useGroupingSeparator) { + String groupingSeparator = nb == NumeralBase.dec ? String.valueOf(decimalGroupSymbols.getGroupingSeparator()) : " "; + + final int dotIndex = ungroupedDoubleValue.indexOf("."); + + String ungroupedValue; + if (dotIndex >= 0) { + ungroupedValue = ungroupedDoubleValue.substring(0, dotIndex); + } else { + ungroupedValue = ungroupedDoubleValue; + } + // inject group separator in the resulted string + // NOTE: space symbol is always used!!! + StringBuilder result = insertSeparators(nb, groupingSeparator, ungroupedValue, true); + + result = result.reverse(); + + if (dotIndex >= 0) { + result.append(insertSeparators(nb, groupingSeparator, ungroupedDoubleValue.substring(dotIndex), false)); + } + + return result.toString(); + } else { + return ungroupedDoubleValue; + } + } + + @Nonnull + private StringBuilder insertSeparators(@Nonnull NumeralBase nb, + @Nonnull String groupingSeparator, + @Nonnull String value, + boolean reversed) { + final StringBuilder result = new StringBuilder(value.length() + nb.getGroupingSize() * groupingSeparator.length()); + + if (reversed) { + for (int i = value.length() - 1; i >= 0; i--) { + result.append(value.charAt(i)); + if (i != 0 && (value.length() - i) % nb.getGroupingSize() == 0) { + result.append(groupingSeparator); + } + } + } else { + for (int i = 0; i < value.length(); i++) { + result.append(value.charAt(i)); + if (i != 0 && i != value.length() - 1 && i % nb.getGroupingSize() == 0) { + result.append(groupingSeparator); + } + } + } + + return result; + } + + public void setDecimalGroupSymbols(@Nonnull DecimalFormatSymbols decimalGroupSymbols) { + this.decimalGroupSymbols = decimalGroupSymbols; + } + + public void setRoundResult(boolean roundResult) { + this.roundResult = roundResult; + } + + public void setPrecision(int precision) { + this.precision = precision; + } + + public void setUseGroupingSeparator(boolean useGroupingSeparator) { + this.useGroupingSeparator = useGroupingSeparator; + } + + public void setScienceNotation(boolean scienceNotation) { + this.scienceNotation = scienceNotation; + } + + public char getGroupingSeparator() { + return this.decimalGroupSymbols.getGroupingSeparator(); + } + + public void setGroupingSeparator(char groupingSeparator) { + this.decimalGroupSymbols.setGroupingSeparator(groupingSeparator); + } +} diff --git a/jscl/src/main/java/jscl/MathContext.java b/jscl/src/main/java/jscl/MathContext.java new file mode 100644 index 00000000..fae52488 --- /dev/null +++ b/jscl/src/main/java/jscl/MathContext.java @@ -0,0 +1,59 @@ +package jscl; + +import jscl.math.function.Function; +import jscl.math.function.IConstant; +import jscl.math.operator.Operator; +import org.solovyev.common.math.MathRegistry; + +import javax.annotation.Nonnull; +import java.text.DecimalFormatSymbols; + +public interface MathContext { + + @Nonnull + MathRegistry getFunctionsRegistry(); + + @Nonnull + MathRegistry getOperatorsRegistry(); + + @Nonnull + MathRegistry getConstantsRegistry(); + + @Nonnull + MathRegistry getPostfixFunctionsRegistry(); + + @Nonnull + AngleUnit getAngleUnits(); + + void setAngleUnits(@Nonnull AngleUnit defaultAngleUnits); + + @Nonnull + NumeralBase getNumeralBase(); + + + // OUTPUT NUMBER FORMATTING + // todo serso: maybe gather all formatting data in one object? + + void setNumeralBase(@Nonnull NumeralBase numeralBase); + + void setDecimalGroupSymbols(@Nonnull DecimalFormatSymbols decimalGroupSymbols); + + void setRoundResult(boolean roundResult); + + void setPrecision(int precision); + + void setUseGroupingSeparator(boolean useGroupingSeparator); + + void setGroupingSeparator(char groupingSeparator); + + @Nonnull + String format(@Nonnull Double value) throws NumeralBaseException; + + @Nonnull + String format(@Nonnull Double value, @Nonnull NumeralBase nb) throws NumeralBaseException; + + @Nonnull + String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedIntValue); + + void setScienceNotation(boolean scienceNotation); +} diff --git a/jscl/src/main/java/jscl/MathEngine.java b/jscl/src/main/java/jscl/MathEngine.java new file mode 100644 index 00000000..a082c9a5 --- /dev/null +++ b/jscl/src/main/java/jscl/MathEngine.java @@ -0,0 +1,36 @@ +package jscl; + +import jscl.math.Generic; +import jscl.text.ParseException; +import org.solovyev.common.msg.MessageRegistry; + +import javax.annotation.Nonnull; + +public interface MathEngine extends MathContext { + + @Nonnull + String evaluate(@Nonnull String expression) throws ParseException; + + @Nonnull + String simplify(@Nonnull String expression) throws ParseException; + + @Nonnull + String elementary(@Nonnull String expression) throws ParseException; + + @Nonnull + Generic evaluateGeneric(@Nonnull String expression) throws ParseException; + + @Nonnull + Generic simplifyGeneric(@Nonnull String expression) throws ParseException; + + @Nonnull + Generic elementaryGeneric(@Nonnull String expression) throws ParseException; + + @Nonnull + String convert(@Nonnull Double value, @Nonnull NumeralBase to); + + @Nonnull + MessageRegistry getMessageRegistry(); + + void setMessageRegistry(@Nonnull MessageRegistry messageRegistry); +} diff --git a/jscl/src/main/java/jscl/NotSupportedException.java b/jscl/src/main/java/jscl/NotSupportedException.java new file mode 100644 index 00000000..44009f84 --- /dev/null +++ b/jscl/src/main/java/jscl/NotSupportedException.java @@ -0,0 +1,10 @@ +package jscl; + +import javax.annotation.Nonnull; + +public class NotSupportedException extends AbstractJsclArithmeticException { + + public NotSupportedException(@Nonnull String messageCode, Object... parameters) { + super(messageCode, parameters); + } +} diff --git a/jscl/src/main/java/jscl/NumeralBase.java b/jscl/src/main/java/jscl/NumeralBase.java new file mode 100644 index 00000000..747a94de --- /dev/null +++ b/jscl/src/main/java/jscl/NumeralBase.java @@ -0,0 +1,170 @@ +package jscl; + +import jscl.math.JsclInteger; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + +public enum NumeralBase { + + dec(10, 3) { + + private final List characters = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + @Nonnull + @Override + public Double toDouble(@Nonnull String doubleString) { + return Double.valueOf(doubleString); + } + + @Nonnull + public String toString(@Nonnull Double value) { + return value.toString(); + } + + @Nonnull + @Override + public String getJsclPrefix() { + return "0d:"; + } + + @Nonnull + @Override + public List getAcceptableCharacters() { + return characters; + } + }, + + hex(16, 2) { + + private final List characters = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + + @Nonnull + @Override + public String getJsclPrefix() { + return "0x:"; + } + + @Nonnull + @Override + public List getAcceptableCharacters() { + return characters; + } + }, + + oct(8, 4) { + + private final List characters = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7'); + + @Nonnull + @Override + public String getJsclPrefix() { + return "0o:"; + } + + @Nonnull + @Override + public List getAcceptableCharacters() { + return characters; + } + }, + + bin(2, 4) { + + private final List characters = Arrays.asList('0', '1'); + + @Nonnull + @Override + public String getJsclPrefix() { + return "0b:"; + } + + @Nonnull + @Override + public List getAcceptableCharacters() { + return characters; + } + }; + + protected final int radix; + protected final int groupingSize; + + NumeralBase(int radix, int groupingSize) { + this.radix = radix; + this.groupingSize = groupingSize; + } + + @Nullable + public static NumeralBase getByPrefix(@Nonnull String prefix) { + for (NumeralBase nb : NumeralBase.values()) { + if (prefix.equals(nb.getJsclPrefix())) { + return nb; + } + } + + return null; + } + + @Nonnull + protected static String toString(@Nonnull Double value, int radix, int fractionDigits) { + final BigDecimal mult = BigDecimal.valueOf(radix).pow(fractionDigits); + final BigDecimal bd = BigDecimal.valueOf(value).multiply(mult); + + final BigInteger bi = bd.toBigInteger(); + final StringBuilder result = new StringBuilder(bi.toString(radix)); + + while (result.length() < fractionDigits + 1) { // +1 for leading zero + result.insert(0, "0"); + } + result.insert(result.length() - fractionDigits, "."); + + return result.toString().toUpperCase(); + } + + @Nonnull + public Double toDouble(@Nonnull String doubleString) throws NumberFormatException { + return Double.longBitsToDouble(Long.valueOf(doubleString, radix)); + } + + @Nonnull + public Integer toInteger(@Nonnull String integerString) throws NumberFormatException { + return Integer.valueOf(integerString, radix); + } + + @Nonnull + public JsclInteger toJsclInteger(@Nonnull String integerString) throws NumberFormatException { + return new JsclInteger(toBigInteger(integerString)); + } + + @Nonnull + public BigInteger toBigInteger(@Nonnull String value) throws NumberFormatException { + return new BigInteger(value, radix); + } + + public String toString(@Nonnull BigInteger value) { + return value.toString(radix).toUpperCase(); + } + + public String toString(@Nonnull Integer value) { + return Integer.toString(value, radix).toUpperCase(); + } + + @Nonnull + public abstract String getJsclPrefix(); + + @Nonnull + public abstract List getAcceptableCharacters(); + + public int getGroupingSize() { + return groupingSize; + } + + @Nonnull + public String toString(@Nonnull Double value, int fractionDigits) { + return toString(value, radix, fractionDigits); + } +} diff --git a/jscl/src/main/java/jscl/NumeralBaseException.java b/jscl/src/main/java/jscl/NumeralBaseException.java new file mode 100644 index 00000000..7b51652a --- /dev/null +++ b/jscl/src/main/java/jscl/NumeralBaseException.java @@ -0,0 +1,12 @@ +package jscl; + +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +public class NumeralBaseException extends AbstractJsclArithmeticException { + + public NumeralBaseException(@Nonnull Double value) { + super(Messages.msg_17, value); + } +} diff --git a/jscl/src/main/java/jscl/math/AntiDerivative.java b/jscl/src/main/java/jscl/math/AntiDerivative.java new file mode 100644 index 00000000..faac87e4 --- /dev/null +++ b/jscl/src/main/java/jscl/math/AntiDerivative.java @@ -0,0 +1,232 @@ +package jscl.math; + +import jscl.math.function.*; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; + +import javax.annotation.Nonnull; + +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(Fraction fraction, Variable variable) { + AntiDerivative s = new AntiDerivative(variable); + s.compute(fraction); + return s.getValue(); + } + + public static Generic compute(Root root, Variable variable) throws NotIntegrableException { + int d = root.degree(); + Generic a[] = root.getParameters(); + boolean b = d > 0; + b = b && a[0].negate().isIdentity(variable); + for (int i = 1; i < d; i++) b = b && a[i].signum() == 0; + b = b && a[d].compareTo(JsclInteger.valueOf(1)) == 0; + if (b) { + return new Pow( + a[0].negate(), + new Inverse(JsclInteger.valueOf(d)).selfExpand() + ).antiDerivative(0); + } else { + throw new NotIntegrableException(); + } + } + + void compute(Fraction fraction) { + Debug.println("antiDerivative"); + Debug.increment(); + Generic g[] = fraction.getParameters(); + Generic r[] = reduce(g[0], g[1]); + r = divideAndRemainder(r[0], r[1]); + Generic s = new Inverse(r[2]).selfExpand(); + Generic p = r[0].multiply(s); + Generic a = r[1].multiply(s); + result = p.antiDerivative(factory.variable()).add(hermite(a, g[1])); + Debug.decrement(); + } + + Generic[] reduce(Generic n, Generic d) { + Debug.println("reduce(" + n + ", " + d + ")"); + Polynomial pn = factory.valueOf(n); + Polynomial pd = factory.valueOf(d); + Polynomial gcd = pn.gcd(pd); + return new Generic[]{ + pn.divide(gcd).genericValue(), + pd.divide(gcd).genericValue() + }; + } + + Generic[] divideAndRemainder(Generic n, Generic d) { + Debug.println("divideAndRemainder(" + n + ", " + d + ")"); + Polynomial pn = syzygy.valueof(n, 0); + Polynomial pd = syzygy.valueof(d, 1); + PolynomialWithSyzygy pr = (PolynomialWithSyzygy) pn.remainderUpToCoefficient(pd); + return new Generic[]{ + pr.syzygy[1].genericValue().negate(), + pr.genericValue(), + pr.syzygy[0].genericValue() + }; + } + + Generic[] bezout(Generic a, Generic b) { + Debug.println("bezout(" + a + ", " + b + ")"); + Polynomial pa = syzygy.valueof(a, 0); + Polynomial pb = syzygy.valueof(b, 1); + PolynomialWithSyzygy gcd = (PolynomialWithSyzygy) pa.gcd(pb); + return new Generic[]{ + gcd.syzygy[0].genericValue(), + gcd.syzygy[1].genericValue(), + gcd.genericValue() + }; + } + + Generic hermite(Generic a, Generic d) { + Debug.println("hermite(" + a + ", " + d + ")"); + UnivariatePolynomial sd[] = ((UnivariatePolynomial) factory.valueOf(d)).squarefreeDecomposition(); + int m = sd.length - 1; + if (m < 2) return trager(a, d); + else { + Generic u = sd[0].genericValue(); + for (int i = 1; i < m; i++) { + u = u.multiply(sd[i].genericValue().pow(i)); + } + Generic v = sd[m].genericValue(); + Generic vprime = sd[m].derivative().genericValue(); + Generic uvprime = u.multiply(vprime); + Generic r[] = bezout(uvprime, v); + Generic b = r[0].multiply(a); + Generic c = r[1].multiply(a); + Generic s = r[2]; + r = divideAndRemainder(b, v); + b = r[1]; + c = c.multiply(r[2]).add(r[0].multiply(uvprime)); + s = new Inverse(s.multiply(r[2]).multiply(JsclInteger.valueOf(1 - m))).selfExpand(); + b = b.multiply(s); + c = c.multiply(s); + Generic bprime = ((UnivariatePolynomial) factory.valueOf(b)).derivative().genericValue(); + return new Fraction(b, v.pow(m - 1)).selfExpand().add(hermite(JsclInteger.valueOf(1 - m).multiply(c).subtract(u.multiply(bprime)), u.multiply(v.pow(m - 1)))); + } + } + + Generic trager(Generic a, Generic d) { + Debug.println("trager(" + a + ", " + d + ")"); + Variable t = new TechnicalVariable("t"); + UnivariatePolynomial pd = (UnivariatePolynomial) factory.valueOf(d); + UnivariatePolynomial pa = (UnivariatePolynomial) factory.valueOf(a).subtract(pd.derivative().multiply(t.expressionValue())); + UnivariatePolynomial rs[] = pd.remainderSequence(pa); + Polynomial fact = UnivariatePolynomial.factory(t); + for (int i = 0; i < rs.length; i++) + if (rs[i] != null) + rs[i] = (UnivariatePolynomial) fact.valueOf((i > 0 ? 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 < q[i].degree(); j++) { + Generic a2 = new Root(q[i], j).selfExpand(); + s = s.add(a2.multiply(new Ln(i == pd.degree() ? d : rs[i].substitute(a2)).selfExpand())); + } + } + return s; + } + + Generic getValue() { + return result; + } +} + +class PolynomialWithSyzygy extends UnivariatePolynomial { + Polynomial syzygy[] = new Polynomial[2]; + + PolynomialWithSyzygy(Variable variable) { + super(variable); + } + + public static Polynomial factory(Variable variable) { + return new PolynomialWithSyzygy(variable); + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + PolynomialWithSyzygy p2 = (PolynomialWithSyzygy) that; + PolynomialWithSyzygy p = (PolynomialWithSyzygy) super.subtract(p2); + for (int i = 0; i < syzygy.length; i++) p.syzygy[i] = syzygy[i].subtract(p2.syzygy[i]); + return p; + } + + public Polynomial multiply(Generic generic) { + PolynomialWithSyzygy p = (PolynomialWithSyzygy) super.multiply(generic); + for (int i = 0; i < syzygy.length; i++) p.syzygy[i] = syzygy[i].multiply(generic); + return p; + } + + public Polynomial multiply(Monomial monomial, Generic generic) { + PolynomialWithSyzygy p = (PolynomialWithSyzygy) super.multiply(monomial, generic); + for (int i = 0; i < syzygy.length; i++) p.syzygy[i] = syzygy[i].multiply(monomial).multiply(generic); + return p; + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + PolynomialWithSyzygy p = (PolynomialWithSyzygy) super.divide(generic); + for (int i = 0; i < syzygy.length; i++) p.syzygy[i] = syzygy[i].divide(generic); + return p; + } + + public Polynomial remainderUpToCoefficient(Polynomial polynomial) throws ArithmeticException { + PolynomialWithSyzygy p = this; + PolynomialWithSyzygy q = (PolynomialWithSyzygy) polynomial; + if (p.signum() == 0) return p; + int d = p.degree(); + int d2 = q.degree(); + for (int i = d - d2; i >= 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; i < syzygy.length; i++) a = a.gcd(syzygy[i].gcd()); + return a.signum() == signum() ? a : a.negate(); + } + + public PolynomialWithSyzygy valueof(Generic generic, int n) { + PolynomialWithSyzygy p = (PolynomialWithSyzygy) newinstance(); + p.init(generic, n); + return p; + } + + void init(Generic generic, int n) { + init(generic); + for (int i = 0; i < syzygy.length; i++) + syzygy[i] = Polynomial.factory(variable).valueOf(JsclInteger.valueOf(i == n ? 1 : 0)); + } + + protected UnivariatePolynomial newinstance() { + return new PolynomialWithSyzygy(variable); + } +} diff --git a/jscl/src/main/java/jscl/math/Arithmetic.java b/jscl/src/main/java/jscl/math/Arithmetic.java new file mode 100644 index 00000000..218b73cb --- /dev/null +++ b/jscl/src/main/java/jscl/math/Arithmetic.java @@ -0,0 +1,19 @@ +package jscl.math; + +import javax.annotation.Nonnull; + +public interface Arithmetic> { + + @Nonnull + T add(@Nonnull T that); + + @Nonnull + T subtract(@Nonnull T that); + + @Nonnull + T multiply(@Nonnull T that); + + @Nonnull + T divide(@Nonnull T that) throws NotDivisibleException; + +} diff --git a/jscl/src/main/java/jscl/math/Clifford.java b/jscl/src/main/java/jscl/math/Clifford.java new file mode 100644 index 00000000..5e035896 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Clifford.java @@ -0,0 +1,110 @@ +package jscl.math; + +/** + * User: serso + * Date: 12/26/11 + * Time: 9:45 AM + */ +class Clifford { + int p, n; + int operator[][]; + + Clifford(int algebra[]) { + this(algebra[0], algebra[1]); + } + + Clifford(int p, int q) { + this.p = p; + n = p + q; + int m = 1 << n; + operator = new int[m][m]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < m; j++) { + int a = combination(i, n); + int b = combination(j, n); + int c = a ^ b; + int l = location(c, n); + boolean s = sign(a, b); + int k = l + 1; + operator[i][j] = s ? -k : k; + } + } + } + + 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 (q < p) s += binomial(n, q++); + return s; + } + + static int binomial(int n, int p) { + int a = 1, b = 1; + for (int i = n - p + 1; i <= n; i++) a *= i; + for (int i = 2; i <= p; i++) b *= i; + return a / b; + } + + static int log2e(int n) { + int i; + for (i = 0; n > 1; n >>= 1) i++; + return i; + } + + boolean sign(int a, int b) { + boolean s = false; + for (int i = 0; i < n; i++) { + if ((b & (1 << i)) > 0) { + for (int j = i; j < n; j++) { + if ((a & (1 << j)) > 0 && (j > i || i >= p)) s = !s; + } + } + } + return s; + } + + int[][] operator() { + return operator; + } +} diff --git a/jscl/src/main/java/jscl/math/Debug.java b/jscl/src/main/java/jscl/math/Debug.java new file mode 100644 index 00000000..91b07e25 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Debug.java @@ -0,0 +1,41 @@ +package jscl.math; + +import java.io.PrintStream; + +public class Debug { + + private static PrintStream out; + private static int indentation; + + private Debug() { + } + + public static void println(Object x) { + if (out != null) { + for (int i = 0; i < indentation; i++) { + out.print(" "); + } + out.println(x); + } + } + + public static PrintStream getOutputStream() { + return out; + } + + public static void setOutputStream(PrintStream out) { + Debug.out = out; + } + + public static void increment() { + indentation++; + } + + public static void decrement() { + indentation--; + } + + public static void reset() { + indentation = 0; + } +} diff --git a/jscl/src/main/java/jscl/math/DoubleVariable.java b/jscl/src/main/java/jscl/math/DoubleVariable.java new file mode 100644 index 00000000..eba4ecb6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/DoubleVariable.java @@ -0,0 +1,49 @@ +package jscl.math; + +import javax.annotation.Nonnull; + +public class DoubleVariable extends GenericVariable { + + public DoubleVariable(Generic generic) { + super(generic); + } + + public JsclInteger symbolic() { + return content.integerValue(); + } + + public Generic antiDerivative(Variable variable) throws NotIntegrableException { + return expressionValue().multiply(variable.expressionValue()); + } + + @Nonnull + public Generic derivative(Variable variable) { + 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(); + } + + @Nonnull + public Variable newInstance() { + return new DoubleVariable(null); + } +} diff --git a/jscl/src/main/java/jscl/math/Expression.java b/jscl/src/main/java/jscl/math/Expression.java new file mode 100644 index 00000000..6a8be1d0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Expression.java @@ -0,0 +1,887 @@ +package jscl.math; + +import jscl.JsclMathEngine; +import jscl.math.function.Constant; +import jscl.math.function.Fraction; +import jscl.math.function.Inverse; +import jscl.math.numeric.Real; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; +import jscl.mathml.MathML; +import jscl.text.*; +import jscl.text.msg.Messages; +import jscl.util.ArrayUtils; +import org.solovyev.common.Converter; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; + +public class Expression extends Generic { + + protected static final Converter FACTORIZE_CONVERTER = new Converter() { + @Nonnull + public Generic convert(@Nonnull Variable variable) { + return variable.factorize(); + } + }; + protected static final Converter ELEMENTARY_CONVERTER = new Converter() { + @Nonnull + public Generic convert(@Nonnull Variable variable) { + return variable.elementary(); + } + }; + protected static final Converter EXPAND_CONVERTER = new Converter() { + @Nonnull + public Generic convert(@Nonnull Variable variable) { + return variable.expand(); + } + }; + protected static final Converter NUMERIC_CONVERTER = new Converter() { + @Nonnull + public Generic convert(@Nonnull Variable variable) { + return variable.numeric(); + } + }; + int size; + private Literal literals[]; + private JsclInteger coefficients[]; + + Expression() { + } + + Expression(int size) { + init(size); + } + + public static Variable[] variables(Generic elements[]) { + final List result = new ArrayList(); + + for (Generic element : elements) { + for (Variable variable : element.variables()) { + if (!result.contains(variable)) { + result.add(variable); + } + } + } + + return ArrayUtils.toArray(result, new Variable[result.size()]); + } + + @Nonnull + public static Expression valueOf(@Nonnull Variable variable) { + return valueOf(Literal.valueOf(variable)); + } + + @Nonnull + public static Expression valueOf(@Nonnull Literal literal) { + return valueOf(literal, JsclInteger.valueOf(1)); + } + + @Nonnull + public static Expression valueOf(@Nonnull JsclInteger integer) { + return valueOf(Literal.newInstance(), integer); + } + + @Nonnull + public static Expression valueOf(@Nonnull Literal literal, @Nonnull JsclInteger integer) { + final Expression result = new Expression(); + result.init(literal, integer); + return result; + } + + public static Expression valueOf(Rational rational) { + Expression ex = new Expression(); + ex.init(rational); + return ex; + } + + public static Expression valueOf(@Nonnull Constant constant) { + final Expression expression = new Expression(1); + Literal literal = new Literal(); + literal.init(constant, 1); + expression.init(literal, JsclInteger.ONE); + return expression; + } + + public static Expression valueOf(@Nonnull Double value) { + final Expression expression = new Expression(1); + Literal literal = new Literal(); + literal.init(new DoubleVariable(new NumericWrapper(Real.valueOf(value))), 1); + expression.init(literal, JsclInteger.ONE); + return expression; + } + + public static Expression valueOf(@Nonnull String expression) throws ParseException { + final MutableInt position = new MutableInt(0); + + final Parser.Parameters p = Parser.Parameters.newInstance(expression, position, JsclMathEngine.getInstance()); + + final Generic generic = ExpressionParser.parser.parse(p, null); + + ParserUtils.skipWhitespaces(p); + + int index = position.intValue(); + if (index < expression.length()) { + throw new ParseException(Messages.msg_1, index, expression, index + 1); + } + + return new Expression().init(generic); + } + + public static Expression init(@Nonnull NumericWrapper numericWrapper) { + final Expression expression = new Expression(1); + Literal literal = new Literal(); + literal.init(new ExpressionVariable(numericWrapper), 1); + expression.init(literal, JsclInteger.ONE); + return expression; + } + + 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); + } + } + + public int size() { + return size; + } + + public Literal literal(int n) { + return literals[n]; + } + + public JsclInteger coef(int n) { + return coefficients[n]; + } + + void init(int size) { + literals = new Literal[size]; + coefficients = new JsclInteger[size]; + this.size = size; + } + + void resize(int size) { + int length = literals.length; + if (size < length) { + Literal literal[] = new Literal[size]; + JsclInteger coef[] = new JsclInteger[size]; + System.arraycopy(this.literals, length - size, literal, 0, size); + System.arraycopy(this.coefficients, length - size, coef, 0, size); + this.literals = literal; + this.coefficients = coef; + this.size = size; + } + } + + public Expression add(@Nonnull Expression that) { + final Expression result = newInstance(size + that.size); + int i = result.size; + + int thisI = this.size; + int thatI = that.size; + + Literal thisLiteral = thisI > 0 ? this.literals[--thisI] : null; + Literal thatLiteral = thatI > 0 ? that.literals[--thatI] : null; + + while (thisLiteral != null || thatLiteral != null) { + int c; + + if (thisLiteral == null) { + c = 1; + } else if (thatLiteral == null) { + c = -1; + } else { + c = -thisLiteral.compareTo(thatLiteral); + } + + if (c < 0) { + final JsclInteger thisCoefficient = this.coefficients[thisI]; + --i; + result.literals[i] = thisLiteral; + result.coefficients[i] = thisCoefficient; + thisLiteral = thisI > 0 ? literals[--thisI] : null; + } else if (c > 0) { + JsclInteger en = that.coefficients[thatI]; + --i; + result.literals[i] = thatLiteral; + result.coefficients[i] = en; + thatLiteral = thatI > 0 ? that.literals[--thatI] : null; + } else { + JsclInteger sum = coefficients[thisI].add(that.coefficients[thatI]); + if (sum.signum() != 0) { + --i; + result.literals[i] = thisLiteral; + result.coefficients[i] = sum; + } + + thisLiteral = thisI > 0 ? literals[--thisI] : null; + thatLiteral = thatI > 0 ? that.literals[--thatI] : null; + } + } + + result.resize(result.size - i); + + return result; + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof Expression) { + return add((Expression) that); + } else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) { + return add(valueOf(that)); + } else { + return that.valueOf(this).add(that); + } + } + + public Expression subtract(Expression expression) { + return multiplyAndAdd(Literal.newInstance(), JsclInteger.valueOf(-1), expression); + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof Expression) { + return subtract((Expression) that); + } else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) { + return subtract(valueOf(that)); + } else { + return that.valueOf(this).subtract(that); + } + } + + Expression multiplyAndAdd(@Nonnull Literal literal, @Nonnull JsclInteger coefficient, @Nonnull Expression that) { + if (coefficient.signum() == 0) return this; + + final Expression result = newInstance(size + that.size); + int i = result.size; + + int thisI = this.size; + int thatI = that.size; + + Literal thisLiteral = thisI > 0 ? literals[--thisI] : null; + Literal thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null; + + while (thisLiteral != null || thatLiteral != null) { + int c = thisLiteral == null ? 1 : (thatLiteral == null ? -1 : -thisLiteral.compareTo(thatLiteral)); + + if (c < 0) { + JsclInteger en = coefficients[thisI]; + --i; + result.literals[i] = thisLiteral; + result.coefficients[i] = en; + thisLiteral = thisI > 0 ? literals[--thisI] : null; + } else if (c > 0) { + JsclInteger en = that.coefficients[thatI].multiply(coefficient); + --i; + result.literals[i] = thatLiteral; + result.coefficients[i] = en; + thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null; + } else { + JsclInteger en = coefficients[thisI].add(that.coefficients[thatI].multiply(coefficient)); + if (en.signum() != 0) { + --i; + result.literals[i] = thisLiteral; + result.coefficients[i] = en; + } + thisLiteral = thisI > 0 ? literals[--thisI] : null; + thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null; + } + } + + result.resize(result.size - i); + + return result; + } + + public Expression multiply(Expression expression) { + Expression result = newInstance(0); + + for (int i = 0; i < size; i++) { + result = result.multiplyAndAdd(literals[i], coefficients[i], expression); + } + + return result; + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof Expression) { + return multiply((Expression) that); + } else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) { + return multiply(valueOf(that)); + } else { + return that.multiply(this); + } + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + Generic a[] = divideAndRemainder(that); + if (a[1].signum() == 0) return a[0]; + else throw new NotDivisibleException(); + } + + public Generic[] divideAndRemainder(Generic generic) throws ArithmeticException { + if (generic instanceof Expression) { + Expression ex = (Expression) generic; + Literal l1 = literalScm(); + Literal l2 = ex.literalScm(); + Literal l = l1.gcd(l2); + Variable va[] = l.variables(); + if (va.length == 0) { + if (signum() == 0 && ex.signum() != 0) return new Generic[]{this, JsclInteger.valueOf(0)}; + else try { + return divideAndRemainder(ex.integerValue()); + } catch (NotIntegerException e) { + return new Generic[]{JsclInteger.valueOf(0), this}; + } + } else { + Polynomial fact = Polynomial.factory(va[0]); + Polynomial p[] = fact.valueOf(this).divideAndRemainder(fact.valueOf(ex)); + return new Generic[]{p[0].genericValue(), p[1].genericValue()}; + } + } else if (generic instanceof JsclInteger) { + try { + Expression ex = newInstance(size); + for (int i = 0; i < size; i++) { + ex.literals[i] = literals[i]; + ex.coefficients[i] = coefficients[i].divide((JsclInteger) generic); + } + return new Generic[]{ex, JsclInteger.valueOf(0)}; + } catch (NotDivisibleException e) { + return new Generic[]{JsclInteger.valueOf(0), this}; + } + } else if (generic instanceof Rational || generic instanceof NumericWrapper) { + return divideAndRemainder(valueOf(generic)); + } else { + return generic.valueOf(this).divideAndRemainder(generic); + } + } + + public Generic gcd(@Nonnull Generic generic) { + if (generic instanceof Expression) { + final Expression that = (Expression) generic; + + final Literal thisL = this.literalScm(); + final Literal thatL = that.literalScm(); + + final Literal gcdL = thisL.gcd(thatL); + + final Variable vars[] = gcdL.variables(); + if (vars.length == 0) { + if (signum() == 0) { + return that; + } else { + return this.gcd(that.gcd()); + } + } else { + Polynomial p = Polynomial.factory(vars[0]); + return p.valueOf(this).gcd(p.valueOf(that)).genericValue(); + } + } else if (generic instanceof JsclInteger) { + if (generic.signum() == 0) { + return this; + } else { + return this.gcd().gcd(generic); + } + } else if (generic instanceof Rational || generic instanceof NumericWrapper) { + return gcd(valueOf(generic)); + } else { + return generic.valueOf(this).gcd(generic); + } + } + + @Nonnull + public Generic gcd() { + JsclInteger result = JsclInteger.valueOf(0); + + for (int i = size - 1; i >= 0; i--) { + result = result.gcd(coefficients[i]); + } + + return result; + } + + @Nonnull + public Literal literalScm() { + Literal result = Literal.newInstance(); + for (int i = 0; i < size; i++) { + result = result.scm(literals[i]); + } + return result; + } + + public Generic negate() { + return multiply(JsclInteger.valueOf(-1)); + } + + public int signum() { + return size == 0 ? 0 : coefficients[0].signum(); + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + if (isPolynomial(variable)) { + return ((UnivariatePolynomial) Polynomial.factory(variable).valueOf(this)).antiderivative().genericValue(); + } else { + try { + Variable v = variableValue(); + try { + return v.antiDerivative(variable); + } catch (NotIntegrableException e) { + if (v instanceof Fraction) { + Generic g[] = ((Fraction) v).getParameters(); + if (g[1].isConstant(variable)) { + return new Inverse(g[1]).selfExpand().multiply(g[0].antiDerivative(variable)); + } + } + } + } catch (NotVariableException e) { + Generic sumElements[] = sumValue(); + if (sumElements.length > 1) { + + Generic result = JsclInteger.valueOf(0); + for (Generic sumElement : sumElements) { + result = result.add(sumElement.antiDerivative(variable)); + } + return result; + + } else { + final Generic products[] = sumElements[0].productValue(); + Generic constantProduct = JsclInteger.valueOf(1); + Generic notConstantProduct = JsclInteger.valueOf(1); + for (Generic product : products) { + if (product.isConstant(variable)) { + constantProduct = constantProduct.multiply(product); + } else { + notConstantProduct = notConstantProduct.multiply(product); + } + } + if (constantProduct.compareTo(JsclInteger.valueOf(1)) != 0) { + return constantProduct.multiply(notConstantProduct.antiDerivative(variable)); + } + } + } + } + throw new NotIntegrableException(this); + } + + public Generic derivative(@Nonnull Variable variable) { + Generic s = JsclInteger.valueOf(0); + Literal l = literalScm(); + int n = l.size(); + for (int i = 0; i < n; i++) { + Variable v = l.getVariable(i); + Generic a = ((UnivariatePolynomial) Polynomial.factory(v).valueOf(this)).derivative(variable).genericValue(); + s = s.add(a); + } + return s; + } + + public Generic substitute(@Nonnull final Variable variable, final Generic generic) { + final Map content = literalScm().content(new Converter() { + @Nonnull + public Generic convert(@Nonnull Variable v) { + return v.substitute(variable, generic); + } + }); + + return substitute(content); + } + + @Nonnull + private Generic substitute(@Nonnull Map content) { + // sum = sumElement_0 + sumElement_1 + ... + sumElement_size + Generic sum = JsclInteger.ZERO; + + for (int i = 0; i < size; i++) { + final Literal literal = literals[i]; + + // sumElement = variable_1 ^ power_1 * variable_2 ^ power_2 * ... * variable_size ^ power_size + Generic sumElement = coefficients[i]; + + for (int j = 0; j < literal.size(); j++) { + final Variable variable = literal.getVariable(j); + + Generic b = content.get(variable).pow(literal.getPower(j)); + + if (Matrix.isMatrixProduct(sumElement, b)) { + throw new ArithmeticException("Should not be matrix!"); + } + + sumElement = sumElement.multiply(b); + } + + sum = sum.add(sumElement); + } + + return sum; + } + + public Generic expand() { + return substitute(literalScm().content(EXPAND_CONVERTER)); + } + + public Generic factorize() { + return Factorization.compute(substitute(literalScm().content(FACTORIZE_CONVERTER))); + } + + public Generic elementary() { + return substitute(literalScm().content(ELEMENTARY_CONVERTER)); + } + + public Generic simplify() { + return Simplification.compute(this); + } + + public Generic numeric() { + try { + return integerValue().numeric(); + } catch (NotIntegerException ex) { + final Literal literal = literalScm(); + + final Map content = literal.content(NUMERIC_CONVERTER); + + return substitute(content); + } + } + + @Nonnull + public Generic valueOf(@Nonnull Generic generic) { + final Expression result = newInstance(0); + + result.init(generic); + + return result; + } + + @Nonnull + public Generic[] sumValue() { + final Generic result[] = new Generic[size]; + + for (int i = 0; i < result.length; i++) { + result[i] = valueOf(literals[i], coefficients[i]); + } + + return result; + } + + @Nonnull + public Generic[] productValue() throws NotProductException { + if (size == 0) { + return new Generic[]{JsclInteger.valueOf(0)}; + } else if (size == 1) { + final Literal l = literals[0]; + final JsclInteger k = coefficients[0]; + + Generic productElements[] = l.productValue(); + if (k.compareTo(JsclInteger.valueOf(1)) == 0) { + return productElements; + } else { + final Generic result[] = new Generic[productElements.length + 1]; + System.arraycopy(productElements, 0, result, 1, productElements.length); + result[0] = k; + return result; + } + } else { + throw new NotProductException(); + } + } + + public Power powerValue() throws NotPowerException { + if (size == 0) return new Power(JsclInteger.valueOf(0), 1); + else if (size == 1) { + Literal l = literals[0]; + JsclInteger en = coefficients[0]; + if (en.compareTo(JsclInteger.valueOf(1)) == 0) return l.powerValue(); + else if (l.degree() == 0) return en.powerValue(); + else throw new NotPowerException(); + } else throw new NotPowerException(); + } + + public Expression expressionValue() throws NotExpressionException { + return this; + } + + @Override + public boolean isInteger() { + try { + integerValue(); + return true; + } catch (NotIntegerException e) { + return false; + } + } + + public JsclInteger integerValue() throws NotIntegerException { + if (size == 0) { + return JsclInteger.valueOf(0); + } else if (size == 1) { + + final Literal l = literals[0]; + final JsclInteger c = coefficients[0]; + + if (l.degree() == 0) { + return c; + } else { + throw new NotIntegerException(); + } + } else { + throw new NotIntegerException(); + } + } + + public Variable variableValue() throws NotVariableException { + if (size == 0) { + throw new NotVariableException(); + } else if (size == 1) { + final Literal l = literals[0]; + final JsclInteger c = coefficients[0]; + if (c.compareTo(JsclInteger.valueOf(1)) == 0) { + return l.variableValue(); + } else { + throw new NotVariableException(); + } + } else { + throw new NotVariableException(); + } + } + + public Variable[] variables() { + return literalScm().variables(); + } + + public boolean isPolynomial(@Nonnull Variable variable) { + boolean result = true; + + final Literal l = literalScm(); + for (int i = 0; i < l.size(); i++) { + + final Variable v = l.getVariable(i); + if (!v.isConstant(variable) && !v.isIdentity(variable)) { + result = false; + break; + } + } + + return result; + } + + public boolean isConstant(@Nonnull Variable variable) { + + Literal l = literalScm(); + for (int i = 0; i < l.size(); i++) { + if (!l.getVariable(i).isConstant(variable)) { + return false; + } + } + + return true; + } + + public JsclVector grad(Variable variable[]) { + Generic v[] = new Generic[variable.length]; + for (int i = 0; i < variable.length; i++) v[i] = derivative(variable[i]); + return new JsclVector(v); + } + + public Generic laplacian(Variable variable[]) { + return grad(variable).divergence(variable); + } + + public Generic dalembertian(Variable variable[]) { + Generic a = derivative(variable[0]).derivative(variable[0]); + for (int i = 1; i < 4; i++) a = a.subtract(derivative(variable[i]).derivative(variable[i])); + return a; + } + + public int compareTo(Expression expression) { + int i1 = size; + int i2 = expression.size; + Literal l1 = i1 == 0 ? null : literals[--i1]; + Literal l2 = i2 == 0 ? null : expression.literals[--i2]; + while (l1 != null || l2 != null) { + int c = l1 == null ? -1 : (l2 == null ? 1 : l1.compareTo(l2)); + if (c < 0) return -1; + else if (c > 0) return 1; + else { + c = coefficients[i1].compareTo(expression.coefficients[i2]); + if (c < 0) return -1; + else if (c > 0) return 1; + l1 = i1 == 0 ? null : literals[--i1]; + l2 = i2 == 0 ? null : expression.literals[--i2]; + } + } + return 0; + } + + public int compareTo(@Nonnull Generic generic) { + if (generic instanceof Expression) { + return compareTo((Expression) generic); + } else if (generic instanceof JsclInteger || generic instanceof Rational || generic instanceof NumericWrapper) { + return compareTo(valueOf(generic)); + } else { + return generic.valueOf(this).compareTo(generic); + } + } + + void init(Literal lit, JsclInteger integer) { + if (integer.signum() != 0) { + init(1); + literals[0] = lit; + coefficients[0] = integer; + } else init(0); + } + + void init(Expression expression) { + init(expression.size); + System.arraycopy(expression.literals, 0, literals, 0, size); + System.arraycopy(expression.coefficients, 0, coefficients, 0, size); + } + + void init(JsclInteger integer) { + init(Literal.newInstance(), integer); + } + + void init(Rational rational) { + try { + init(Literal.newInstance(), rational.integerValue()); + } catch (NotIntegerException e) { + init(Literal.valueOf(rational.variableValue()), JsclInteger.valueOf(1)); + } + } + + Expression init(@Nonnull Generic generic) { + if (generic instanceof Expression) { + init((Expression) generic); + } else if (generic instanceof JsclInteger) { + init((JsclInteger) generic); + } else if (generic instanceof NumericWrapper) { + init((NumericWrapper) generic); + } else if (generic instanceof Rational) { + init((Rational) generic); + } else throw new ArithmeticException("Could not initialize expression with " + generic.getClass()); + + return this; + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + if (signum() == 0) { + result.append("0"); + } + + // result = coef[0] * literal[0] + coef[1] * literal[1] + ... + + for (int i = 0; i < size; i++) { + final Literal literal = literals[i]; + final JsclInteger coefficient = coefficients[i]; + + if (coefficient.signum() > 0 && i > 0) { + result.append("+"); + } + + if (literal.degree() == 0) { + result.append(coefficient); + } else { + if (coefficient.abs().compareTo(JsclInteger.valueOf(1)) == 0) { + if (coefficient.signum() < 0) { + result.append("-"); + } + } else { + result.append(coefficient).append("*"); + } + result.append(literal); + } + } + + return result.toString(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + if (signum() == 0) { + result.append("JsclDouble.valueOf(0)"); + } + + for (int i = 0; i < size; i++) { + Literal l = literals[i]; + JsclInteger en = coefficients[i]; + if (i > 0) { + if (en.signum() < 0) { + result.append(".subtract("); + en = (JsclInteger) en.negate(); + } else result.append(".add("); + } + if (l.degree() == 0) result.append(en.toJava()); + else { + if (en.abs().compareTo(JsclInteger.valueOf(1)) == 0) { + if (en.signum() > 0) result.append(l.toJava()); + else if (en.signum() < 0) result.append(l.toJava()).append(".negate()"); + } else result.append(en.toJava()).append(".multiply(").append(l.toJava()).append(")"); + } + if (i > 0) result.append(")"); + } + + return result.toString(); + } + + public void toMathML(MathML element, @Nullable 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; i < size; i++) { + Literal l = literals[i]; + JsclInteger en = coefficients[i]; + if (en.signum() > 0 && 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); + } + + @Nonnull + @Override + public Set getConstants() { + final Set result = new HashSet(); + + for (Literal literal : literals) { + for (Variable variable : literal.variables()) { + result.addAll(variable.getConstants()); + } + } + + return result; + } + + @Nonnull + private Expression newInstance(int n) { + return new Expression(n); + } +} diff --git a/jscl/src/main/java/jscl/math/ExpressionVariable.java b/jscl/src/main/java/jscl/math/ExpressionVariable.java new file mode 100644 index 00000000..8a5c2f14 --- /dev/null +++ b/jscl/src/main/java/jscl/math/ExpressionVariable.java @@ -0,0 +1,60 @@ +package jscl.math; + +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +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); + } + + @Nonnull + public Variable newInstance() { + return new ExpressionVariable(null); + } +} diff --git a/jscl/src/main/java/jscl/math/Factorization.java b/jscl/src/main/java/jscl/math/Factorization.java new file mode 100644 index 00000000..9f40b465 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Factorization.java @@ -0,0 +1,298 @@ +package jscl.math; + +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; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class Factorization { + private static final String ter = "t"; + 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]); + } + + 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; i < be.length; i++) { + Polynomial r = substitute(p, be[i], unk); + try { + return new Polynomial[]{zero, r, s.divide(r)}; + } catch (NotDivisibleException e) { + } + } + return new Polynomial[]{s, zero, zero}; + } + + static Polynomial substitute(Polynomial p, Generic a[], Variable unk[]) { + Generic s[] = new Generic[]{p.genericValue()}; + return p.valueOf(Basis.compute(Basis.augment(a, s), Basis.augmentUnknown(unk, s)).elements()[0]); + } + + static Polynomial polynomial(Polynomial s, Monomial monomial[]) { + Polynomial p = s.valueOf(JsclInteger.valueOf(0)); + Iterator it = monomial[1].iterator(monomial[0]); + for (int i = 0; it.hasNext(); i++) { + Monomial m = (Monomial) it.next(); + Variable t = it.hasNext() ? new TechnicalVariable(ter, new int[]{i}) : new TechnicalVariable(ter); + p = p.add(p.valueOf(m).multiply(t.expressionValue())); + } + return p; + } + + static Generic[] terminator(Polynomial polynomial) { + Generic t[] = new Generic[2]; + t[1] = terminator(polynomial.head().coef().abs(), new TechnicalVariable(ter), false); + t[0] = terminator(polynomial.tail().coef(), new TechnicalVariable(ter, new int[]{0}), true); + return t; + } + + static Generic terminator(Generic generic, Variable var, boolean tail) { + Generic x = var.expressionValue(); + Generic a = JsclInteger.valueOf(1); + Iterator it = IntegerDivisor.create(generic.integerValue()); + while (it.hasNext()) { + Generic s = (Generic) it.next(); + a = a.multiply(x.subtract(s)); + if (!tail) a = a.multiply(x.add(s)); + } + return a; + } + + static Generic expression(Generic generic) { + return expression(generic, false); + } + + static Generic expression(Generic generic, boolean integer) { + if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return generic; + else return GenericVariable.valueOf(generic, integer).expressionValue(); + } + + static String toString(Monomial monomial[]) { + return "{" + monomial[0] + ", " + monomial[1] + "}"; + } + + 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()); + } + + Generic getValue() { + return GenericVariable.content(result, true); + } +} + +class Linearization { + Variable unknown[]; + List result = new ArrayList(); + + Linearization(Variable unknown[]) { + this.unknown = unknown; + } + + static Generic[][] compute(Generic generic[], Variable unknown[]) { + Linearization l = new Linearization(unknown); + Debug.println("linearization"); + Debug.increment(); + l.process(generic); + Debug.decrement(); + return l.getValue(); + } + + static Polynomial[] linearize(Polynomial polynomial, Variable variable) { + List l = new ArrayList(); + Generic x = variable.expressionValue(); + Polynomial s = polynomial; + try { + Polynomial r = s.valueOf(x); + s = s.divide(r); + l.add(r); + while (true) s = s.divide(r); + } catch (NotDivisibleException e) { + } + IntegerDivisor d[] = new IntegerDivisor[2]; + Generic p[] = new Generic[2]; + Generic q[] = new Generic[2]; + d[1] = IntegerDivisor.create(JsclInteger.valueOf(1)); + loop: + while (d[1].hasNext()) { + p[1] = (Generic) d[1].next(); + q[1] = d[1].integer(d[1].complementary()); + d[0] = IntegerDivisor.create(s.tail().coef().integerValue()); + while (d[0].hasNext()) { + p[0] = (Generic) d[0].next(); + q[0] = d[0].integer(d[0].complementary()); + if (ArrayComparator.comparator.compare(q, p) < 0) break loop; + for (int i = 0; i < 2; i++) { + Polynomial r = s.valueOf(i == 0 ? p[1].multiply(x).subtract(p[0]) : p[1].multiply(x).add(p[0])); + for (boolean flag = true; true; flag = false) { + try { + s = s.divide(r); + } catch (NotDivisibleException e) { + break; + } + d[1].divide(); + d[0].divide(); + if (flag) l.add(r); + } + } + } + } + return (Polynomial[]) ArrayUtils.toArray(l, new Polynomial[l.size()]); + } + + void process(Generic generic[]) { + boolean flag = true; + for (int i = 0; i < generic.length; i++) { + Generic s = generic[i]; + Variable va[] = s.variables(); + if (va.length == 1) { + Variable t = va[0]; + Polynomial p = Polynomial.factory(t).valueOf(s); + if (p.degree() > 1) { + flag = false; + Polynomial r[] = linearize(p, t); + for (int j = 0; j < r.length; j++) { + process(Basis.compute(Basis.augment(new Generic[]{r[j].genericValue()}, generic), unknown).elements()); + } + } + } else flag = false; + } + if (flag) result.add(generic); + } + + Generic[][] getValue() { + return (Generic[][]) ArrayUtils.toArray(result, new Generic[result.size()][]); + } +} + +class Divisor implements Iterator { + Monomial monomial; + Monomial current; + Iterator iterator; + + Divisor(Monomial monomial) { + this.monomial = monomial; + iterator = monomial.divisor(); + } + + Monomial complementary() { + return monomial.divide(current); + } + + void divide() { + monomial = complementary(); + iterator = monomial.divisor(current); + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public Object next() { + return current = (Monomial) iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} + +class IntegerDivisor extends Divisor { + IntegerDivisor(Generic generic, Variable unknown[], Ordering ordering) { + super(Polynomial.factory(unknown, ordering).valueOf(generic).head().monomial()); + } + + static IntegerDivisor create(JsclInteger integer) { + Generic a = Factorization.factorize(integer); + return new IntegerDivisor(a, a.variables(), Monomial.iteratorOrdering); + } + + public Object next() { + return integer((Monomial) super.next()); + } + + Generic integer(Monomial monomial) { + return Expression.valueOf(Literal.valueOf(monomial)).expand(); + } +} diff --git a/jscl/src/main/java/jscl/math/Field.java b/jscl/src/main/java/jscl/math/Field.java new file mode 100644 index 00000000..1fec155f --- /dev/null +++ b/jscl/src/main/java/jscl/math/Field.java @@ -0,0 +1,4 @@ +package jscl.math; + +public interface Field { +} diff --git a/jscl/src/main/java/jscl/math/Generic.java b/jscl/src/main/java/jscl/math/Generic.java new file mode 100644 index 00000000..c6b5a005 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Generic.java @@ -0,0 +1,189 @@ +package jscl.math; + +import jscl.math.function.Constant; +import jscl.mathml.MathML; +import jscl.text.ParserUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +public abstract class Generic implements Arithmetic, Comparable { + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + return add(that.negate()); + } + + public boolean multiple(Generic generic) throws ArithmeticException { + return remainder(generic).signum() == 0; + } + +/* public Arithmetic add(@Nonnull Arithmetic arithmetic) { + return add((Generic)arithmetic); + } + + public Arithmetic subtract(@Nonnull Arithmetic arithmetic) { + return subtract((Generic)arithmetic); + } + + public Arithmetic multiply(@Nonnull Arithmetic arithmetic) { + return multiply((Generic)arithmetic); + } + + public Generic divide(@Nonnull Arithmetic arithmetic) throws ArithmeticException { + return divide((Generic)arithmetic); + }*/ + + public Generic[] divideAndRemainder(Generic generic) { + try { + return new Generic[]{divide(generic), JsclInteger.valueOf(0)}; + } catch (NotDivisibleException e) { + return new Generic[]{JsclInteger.valueOf(0), this}; + } + } + + public Generic remainder(Generic generic) throws ArithmeticException { + return divideAndRemainder(generic)[1]; + } + + public Generic inverse() { + return JsclInteger.valueOf(1).divide(this); + } + + public abstract Generic gcd(@Nonnull Generic generic); + + public Generic scm(Generic generic) { + return divide(gcd(generic)).multiply(generic); + } + + @Nonnull + protected abstract Generic gcd(); + + public Generic[] gcdAndNormalize() { + Generic gcd = gcd(); + + if (gcd.signum() == 0) { + return new Generic[]{gcd, this}; + } + + if (gcd.signum() != signum()) { + gcd = gcd.negate(); + } + + return new Generic[]{gcd, divide(gcd)}; + } + + @SuppressWarnings({"UnusedDeclaration"}) + public Generic normalize() { + return gcdAndNormalize()[1]; + } + + public Generic pow(int exponent) { + assert exponent >= 0; + + Generic result = JsclInteger.valueOf(1); + + for (int i = 0; i < exponent; i++) { + + ParserUtils.checkInterruption(); + + result = result.multiply(this); + } + + return result; + } + + public Generic abs() { + return signum() < 0 ? negate() : this; + } + + public abstract Generic negate(); + + public abstract int signum(); + + public abstract int degree(); + + // public abstract Generic mod(Generic generic); +// public abstract Generic modPow(Generic exponent, Generic generic); +// public abstract Generic modInverse(Generic generic); +// public abstract boolean isProbablePrime(int certainty); + public abstract Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException; + + public abstract Generic derivative(@Nonnull Variable variable); + + public abstract Generic substitute(@Nonnull Variable variable, Generic generic); + + public abstract Generic expand(); + + public abstract Generic factorize(); + + public abstract Generic elementary(); + + public abstract Generic simplify(); + + public abstract Generic numeric(); + + public abstract Generic valueOf(Generic generic); + + public abstract Generic[] sumValue(); + + public abstract Generic[] productValue() throws NotProductException; + + public abstract Power powerValue() throws NotPowerException; + + public abstract Expression expressionValue() throws NotExpressionException; + + public abstract boolean isInteger(); + + public abstract JsclInteger integerValue() throws NotIntegerException; + + public abstract Variable variableValue() throws NotVariableException; + + public abstract Variable[] variables(); + + public abstract boolean isPolynomial(@Nonnull Variable variable); + + public abstract boolean isConstant(@Nonnull Variable variable); + + public boolean isIdentity(@Nonnull Variable variable) { + try { + return variableValue().isIdentity(variable); + } catch (NotVariableException e) { + return false; + } + } + + public abstract int compareTo(Generic generic); + + public int compareTo(Object o) { + return compareTo((Generic) o); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof Generic) { + final Generic that = ((Generic) o); + return compareTo(that) == 0; + } + + return false; + } + + public abstract String toJava(); + + public String toMathML() { + MathML document = new MathML("math", "-//W3C//DTD MathML 2.0//EN", "http://www.w3.org/TR/MathML2/dtd/mathml2.dtd"); + MathML e = document.element("math"); + toMathML(e, null); + return e.toString(); + } + + public abstract void toMathML(MathML element, @Nullable Object data); + + @Nonnull + public abstract Set getConstants(); +} diff --git a/jscl/src/main/java/jscl/math/GenericVariable.java b/jscl/src/main/java/jscl/math/GenericVariable.java new file mode 100644 index 00000000..9dbc5754 --- /dev/null +++ b/jscl/src/main/java/jscl/math/GenericVariable.java @@ -0,0 +1,118 @@ +package jscl.math; + +import jscl.math.function.Constant; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +public abstract class GenericVariable extends Variable { + Generic content; + + GenericVariable(Generic generic) { + super(""); + content = generic; + } + + public static Generic content(Generic generic) { + return content(generic, false); + } + + public static Generic content(Generic generic, boolean expression) { + try { + Variable v = generic.variableValue(); + if (expression) { + if (v instanceof ExpressionVariable) generic = ((ExpressionVariable) v).content; + } else { + if (v instanceof GenericVariable) generic = ((GenericVariable) v).content; + } + } catch (NotVariableException e) { + } + return generic; + } + + 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 Generic antiDerivative(Variable variable) throws NotIntegrableException { + return content.antiDerivative(variable); + } + + @Nonnull + public Generic derivative(Variable variable) { + return content.derivative(variable); + } + + public Generic substitute(Variable variable, Generic generic) { + GenericVariable v = (GenericVariable) newInstance(); + v.content = content.substitute(variable, generic); + if (v.isIdentity(variable)) return generic; + else return v.expressionValue(); + } + + public Generic expand() { + return content.expand(); + } + + public Generic factorize() { + GenericVariable v = (GenericVariable) newInstance(); + v.content = content.factorize(); + return v.expressionValue(); + } + + public Generic elementary() { + GenericVariable v = (GenericVariable) newInstance(); + v.content = content.elementary(); + return v.expressionValue(); + } + + public Generic simplify() { + GenericVariable v = (GenericVariable) newInstance(); + v.content = content.simplify(); + return v.expressionValue(); + } + + public Generic numeric() { + return content.numeric(); + } + + public boolean isConstant(Variable variable) { + return content.isConstant(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 { + GenericVariable v = (GenericVariable) variable; + return content.compareTo(v.content); + } + } + + public String toString() { + return content.toString(); + } + + public String toJava() { + return content.toJava(); + } + + public void toMathML(MathML element, @Nullable Object data) { + content.toMathML(element, data); + } + + @Nonnull + @Override + public Set getConstants() { + return content.getConstants(); + } +} diff --git a/jscl/src/main/java/jscl/math/IntegerVariable.java b/jscl/src/main/java/jscl/math/IntegerVariable.java new file mode 100644 index 00000000..00164789 --- /dev/null +++ b/jscl/src/main/java/jscl/math/IntegerVariable.java @@ -0,0 +1,60 @@ +package jscl.math; + +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +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); + } + + @Nonnull + public Variable newInstance() { + return new IntegerVariable(null); + } +} diff --git a/jscl/src/main/java/jscl/math/JsclBoolean.java b/jscl/src/main/java/jscl/math/JsclBoolean.java new file mode 100644 index 00000000..e41d5dc4 --- /dev/null +++ b/jscl/src/main/java/jscl/math/JsclBoolean.java @@ -0,0 +1,15 @@ +package jscl.math; + +public class JsclBoolean extends ModularInteger { + public static final JsclBoolean factory = new JsclBoolean(0); + private static final JsclBoolean zero = factory; + private static final JsclBoolean one = new JsclBoolean(1); + + public JsclBoolean(long content) { + super(content, 2); + } + + protected ModularInteger newinstance(long content) { + return content % 2 == 0 ? zero : one; + } +} diff --git a/jscl/src/main/java/jscl/math/JsclInteger.java b/jscl/src/main/java/jscl/math/JsclInteger.java new file mode 100644 index 00000000..1ddf8e58 --- /dev/null +++ b/jscl/src/main/java/jscl/math/JsclInteger.java @@ -0,0 +1,367 @@ +package jscl.math; + +import jscl.JsclMathEngine; +import jscl.math.function.Constant; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.Collections; +import java.util.Set; + +public final class JsclInteger extends Generic { + + public static final JsclInteger factory = new JsclInteger(BigInteger.valueOf(0)); + public static final JsclInteger ZERO = new JsclInteger(BigInteger.valueOf(0)); + public static final JsclInteger ONE = new JsclInteger(BigInteger.valueOf(1)); + private final BigInteger content; + + public JsclInteger(BigInteger content) { + this.content = content; + } + + 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 BigInteger content() { + return content; + } + + public JsclInteger add(JsclInteger integer) { + return new JsclInteger(content.add(integer.content)); + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof JsclInteger) { + return add((JsclInteger) that); + } else { + return that.valueOf(this).add(that); + } + } + + public JsclInteger subtract(JsclInteger integer) { + return new JsclInteger(content.subtract(integer.content)); + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof JsclInteger) { + return subtract((JsclInteger) that); + } else { + return that.valueOf(this).subtract(that); + } + } + + public JsclInteger multiply(JsclInteger integer) { + return new JsclInteger(content.multiply(integer.content)); + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof JsclInteger) { + return multiply((JsclInteger) that); + } else { + return that.multiply(this); + } + } + + public JsclInteger divide(@Nonnull JsclInteger that) { + JsclInteger e[] = divideAndRemainder(that); + if (e[1].signum() == 0) { + return e[0]; + } else { + throw new NotDivisibleException(); + } + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof JsclInteger) { + return divide((JsclInteger) that); + } else { + return that.valueOf(this).divide(that); + } + } + + @Nonnull + private JsclInteger[] divideAndRemainder(@Nonnull JsclInteger that) { + try { + final BigInteger result[] = content.divideAndRemainder(that.content); + return new JsclInteger[]{new JsclInteger(result[0]), new JsclInteger(result[1])}; + } catch (ArithmeticException e) { + throw new NotDivisibleException(); + } + } + + public Generic[] divideAndRemainder(@Nonnull Generic that) { + if (that instanceof JsclInteger) { + return divideAndRemainder((JsclInteger) that); + } else { + return that.valueOf(this).divideAndRemainder(that); + } + } + + 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); + } + } + + @Nonnull + public JsclInteger gcd(@Nonnull JsclInteger integer) { + return new JsclInteger(content.gcd(integer.content)); + } + + public Generic gcd(@Nonnull Generic generic) { + if (generic instanceof JsclInteger) { + return gcd((JsclInteger) generic); + } else { + return generic.valueOf(this).gcd(generic); + } + } + + @Nonnull + 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; i < p.length; i++) { + Power o = p[i].powerValue(); + Generic q = o.value(true); + int c = o.exponent(); + s = s.multiply(q.subtract(JsclInteger.valueOf(1)).multiply(q.pow(c - 1))); + } + return s.integerValue(); + } + + public JsclInteger[] primitiveRoots() { + JsclInteger phi = phi(); + Generic a = phi.factorize(); + Generic p[] = a.productValue(); + JsclInteger d[] = new JsclInteger[p.length]; + for (int i = 0; i < p.length; i++) { + d[i] = phi.divide(p[i].powerValue().value(true).integerValue()); + } + int k = 0; + JsclInteger n = this; + JsclInteger m = JsclInteger.valueOf(1); + JsclInteger r[] = new JsclInteger[phi.phi().intValue()]; + while (m.compareTo(n) < 0) { + boolean b = m.gcd(n).compareTo(JsclInteger.valueOf(1)) == 0; + for (int i = 0; i < d.length; i++) { + b = b && m.modPow(d[i], n).compareTo(JsclInteger.valueOf(1)) > 0; + } + 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("Could not calculate root of negative argument: " + this + " of odd order: " + n); + } 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(@Nonnull Variable variable) throws NotIntegrableException { + return multiply(variable.expressionValue()); + } + + public Generic derivative(@Nonnull Variable variable) { + return JsclInteger.valueOf(0); + } + + public Generic substitute(@Nonnull 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; + } + + @Override + public boolean isInteger() { + return true; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return true; + } + + public boolean isConstant(@Nonnull 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); + } + } + + public String toString() { + // todo serso: actually better way is to provide custom format() method for integers and not to convert integer to double + return JsclMathEngine.getInstance().format(this.content.doubleValue()); + } + + public String toJava() { + return "JsclDouble.valueOf(" + content + ")"; + } + + public void toMathML(MathML element, @Nullable Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Set getConstants() { + return Collections.emptySet(); + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mn"); + e1.appendChild(element.text(String.valueOf(content))); + element.appendChild(e1); + } +} diff --git a/jscl/src/main/java/jscl/math/JsclVector.java b/jscl/src/main/java/jscl/math/JsclVector.java new file mode 100644 index 00000000..ee179a19 --- /dev/null +++ b/jscl/src/main/java/jscl/math/JsclVector.java @@ -0,0 +1,466 @@ +package jscl.math; + +import jscl.math.function.Conjugate; +import jscl.math.function.Constant; +import jscl.math.function.Fraction; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; + +public class JsclVector extends Generic { + + @Nonnull + protected final Generic elements[]; + + protected final int rows; + + public JsclVector(@Nonnull Generic elements[]) { + this.elements = elements; + this.rows = elements.length; + } + + @Nonnull + public static JsclVector unity(int dimension) { + final JsclVector result = new JsclVector(new Generic[dimension]); + + for (int i = 0; i < result.rows; i++) { + if (i == 0) { + result.elements[i] = JsclInteger.valueOf(1); + } else { + result.elements[i] = JsclInteger.valueOf(0); + } + } + + return result; + } + + @Nonnull + public Generic[] elements() { + return elements; + } + + public JsclVector add(@Nonnull JsclVector vector) { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].add(vector.elements[i]); + } + + return result; + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof JsclVector) { + return add((JsclVector) that); + } else { + return add(valueOf(that)); + } + } + + public JsclVector subtract(@Nonnull JsclVector vector) { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].subtract(vector.elements[i]); + } + + return result; + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof JsclVector) { + return subtract((JsclVector) that); + } else { + return subtract(valueOf(that)); + } + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof JsclVector) { + return scalarProduct((JsclVector) that); + } else if (that instanceof Matrix) { + return ((Matrix) that).transpose().multiply(this); + } else { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].multiply(that); + } + + return result; + } + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof JsclVector) { + throw new ArithmeticException("Unable to divide vector by vector!"); + } else if (that instanceof Matrix) { + return multiply(that.inverse()); + } else { + final JsclVector result = (JsclVector) newInstance(); + for (int i = 0; i < rows; i++) { + try { + result.elements[i] = elements[i].divide(that); + } catch (NotDivisibleException e) { + result.elements[i] = new Fraction(elements[i], that).selfExpand(); + } + } + return result; + } + } + + public Generic gcd(@Nonnull Generic generic) { + return null; + } + + @Nonnull + public Generic gcd() { + return null; + } + + public Generic negate() { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].negate(); + } + + return result; + } + + public int signum() { + for (int i = 0; i < rows; i++) { + int c = elements[i].signum(); + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } + } + return 0; + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].antiDerivative(variable); + } + + return result; + } + + public Generic derivative(@Nonnull Variable variable) { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].derivative(variable); + } + + return result; + } + + public Generic substitute(@Nonnull Variable variable, Generic generic) { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].substitute(variable, generic); + } + + return result; + } + + public Generic expand() { + JsclVector v = (JsclVector) newInstance(); + for (int i = 0; i < rows; i++) v.elements[i] = elements[i].expand(); + return v; + } + + public Generic factorize() { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].factorize(); + } + + return result; + } + + public Generic elementary() { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].elementary(); + } + + return result; + } + + public Generic simplify() { + final JsclVector result = (JsclVector) newInstance(); + + for (int i = 0; i < rows; i++) { + result.elements[i] = elements[i].simplify(); + } + + return result; + } + + public Generic numeric() { + return new NumericWrapper(this); + } + + public Generic valueOf(@Nonnull Generic generic) { + if (generic instanceof JsclVector || generic instanceof Matrix) { + throw new ArithmeticException("Unable to create vector: vector of vectors or vector of matrices are forbidden!"); + } else { + JsclVector v = (JsclVector) unity(rows).multiply(generic); + return newInstance(v.elements); + } + } + + public Generic[] sumValue() { + return new Generic[]{this}; + } + + public Generic[] productValue() throws NotProductException { + return new Generic[]{this}; + } + + public Power powerValue() throws NotPowerException { + return new Power(this, 1); + } + + public Expression expressionValue() throws NotExpressionException { + throw new NotExpressionException(); + } + + public JsclInteger integerValue() throws NotIntegerException { + throw new NotIntegerException(); + } + + @Override + public boolean isInteger() { + return false; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return null; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return false; + } + + public boolean isConstant(@Nonnull Variable variable) { + return false; + } + + public Generic magnitude2() { + return scalarProduct(this); + } + + public Generic scalarProduct(@Nonnull JsclVector vector) { + Generic result = JsclInteger.valueOf(0); + + for (int i = 0; i < rows; i++) { + result = result.add(elements[i].multiply(vector.elements[i])); + } + + return result; + } + + public JsclVector vectorProduct(@Nonnull JsclVector vector) { + final JsclVector result = (JsclVector) newInstance(); + Generic m[][] = { + {JsclInteger.valueOf(0), elements[2].negate(), elements[1]}, + {elements[2], JsclInteger.valueOf(0), elements[0].negate()}, + {elements[1].negate(), elements[0], JsclInteger.valueOf(0)} + }; + + JsclVector v2 = (JsclVector) new Matrix(m).multiply(vector); + + for (int i = 0; i < rows; i++) { + result.elements[i] = i < v2.rows ? v2.elements[i] : JsclInteger.valueOf(0); + } + + return result; + } + + public JsclVector complexProduct(JsclVector vector) { + return product(new Clifford(0, 1).operator(), vector); + } + + public JsclVector quaternionProduct(JsclVector vector) { + return product(new Clifford(0, 2).operator(), vector); + } + + public JsclVector geometricProduct(JsclVector vector, int algebra[]) { + return product(new Clifford(algebra == null ? new int[]{Clifford.log2e(rows), 0} : algebra).operator(), vector); + } + + JsclVector product(int product[][], JsclVector vector) { + JsclVector v = (JsclVector) newInstance(); + for (int i = 0; i < rows; i++) v.elements[i] = JsclInteger.valueOf(0); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + Generic a = elements[i].multiply(vector.elements[j]); + int k = Math.abs(product[i][j]) - 1; + v.elements[k] = v.elements[k].add(product[i][j] < 0 ? a.negate() : a); + } + } + return v; + } + + public Generic divergence(Variable variable[]) { + Generic a = JsclInteger.valueOf(0); + for (int i = 0; i < rows; i++) a = a.add(elements[i].derivative(variable[i])); + return a; + } + + public JsclVector curl(Variable variable[]) { + JsclVector v = (JsclVector) newInstance(); + v.elements[0] = elements[2].derivative(variable[1]).subtract(elements[1].derivative(variable[2])); + v.elements[1] = elements[0].derivative(variable[2]).subtract(elements[2].derivative(variable[0])); + v.elements[2] = elements[1].derivative(variable[0]).subtract(elements[0].derivative(variable[1])); + for (int i = 3; i < rows; i++) v.elements[i] = elements[i]; + return v; + } + + public Matrix jacobian(Variable variable[]) { + Matrix m = new Matrix(new Generic[rows][variable.length]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < variable.length; j++) { + m.elements[i][j] = elements[i].derivative(variable[j]); + } + } + return m; + } + + public Generic del(Variable variable[], int algebra[]) { + return differential(new Clifford(algebra == null ? new int[]{Clifford.log2e(rows), 0} : algebra).operator(), variable); + } + + JsclVector differential(int product[][], Variable variable[]) { + JsclVector v = (JsclVector) newInstance(); + for (int i = 0; i < rows; i++) v.elements[i] = JsclInteger.valueOf(0); + int l = Clifford.log2e(rows); + for (int i = 1; i <= l; i++) { + for (int j = 0; j < rows; j++) { + Generic a = elements[j].derivative(variable[i - 1]); + int k = Math.abs(product[i][j]) - 1; + v.elements[k] = v.elements[k].add(product[i][j] < 0 ? a.negate() : a); + } + } + return v; + } + + public Generic conjugate() { + JsclVector v = (JsclVector) newInstance(); + for (int i = 0; i < rows; i++) { + v.elements[i] = new Conjugate(elements[i]).selfExpand(); + } + return v; + } + + public int compareTo(JsclVector vector) { + return ArrayComparator.comparator.compare(elements, vector.elements); + } + + public int compareTo(Generic generic) { + if (generic instanceof JsclVector) { + return compareTo((JsclVector) generic); + } else { + return compareTo(valueOf(generic)); + } + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + result.append("["); + + for (int i = 0; i < rows; i++) { + result.append(elements[i]).append(i < rows - 1 ? ", " : ""); + } + + result.append("]"); + + return result.toString(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + result.append("new Vector(new Numeric[] {"); + for (int i = 0; i < rows; i++) { + result.append(elements[i].toJava()).append(i < rows - 1 ? ", " : ""); + } + result.append("})"); + return result.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Set getConstants() { + final Set result = new HashSet(elements.length); + + for (Generic element : elements) { + result.addAll(element.getConstants()); + } + + return result; + } + + protected void bodyToMathML(MathML e0) { + MathML e1 = e0.element("mfenced"); + MathML e2 = e0.element("mtable"); + for (int i = 0; i < rows; i++) { + MathML e3 = e0.element("mtr"); + MathML e4 = e0.element("mtd"); + elements[i].toMathML(e4, null); + e3.appendChild(e4); + e2.appendChild(e3); + } + e1.appendChild(e2); + e0.appendChild(e1); + } + + @Nonnull + protected Generic newInstance() { + return newInstance(new Generic[rows]); + } + + @Nonnull + protected Generic newInstance(@Nonnull Generic element[]) { + return new JsclVector(element); + } +} + diff --git a/jscl/src/main/java/jscl/math/Literal.java b/jscl/src/main/java/jscl/math/Literal.java new file mode 100644 index 00000000..5e9e68a1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Literal.java @@ -0,0 +1,455 @@ +package jscl.math; + +import jscl.math.function.Fraction; +import jscl.math.function.Pow; +import jscl.math.polynomial.Monomial; +import jscl.mathml.MathML; +import org.solovyev.common.Converter; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +public class Literal implements Comparable { + + private Variable variables[]; + private int powers[]; + private int degree; + private int size; + + Literal() { + } + + Literal(int size) { + init(size); + } + + public static Literal newInstance() { + 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; + } + + public static Literal valueOf(Monomial monomial) { + Literal l = new Literal(); + l.init(monomial); + return l; + } + + public int size() { + return size; + } + + @Nonnull + public Variable getVariable(int i) { + return variables[i]; + } + + public int getPower(int i) { + return powers[i]; + } + + void init(int size) { + variables = new Variable[size]; + powers = new int[size]; + this.size = size; + } + + void resize(int size) { + if (size < variables.length) { + Variable variable[] = new Variable[size]; + int power[] = new int[size]; + System.arraycopy(this.variables, 0, variable, 0, size); + System.arraycopy(this.powers, 0, power, 0, size); + this.variables = variable; + this.powers = power; + this.size = size; + } + } + + public Literal multiply(@Nonnull Literal that) { + final Literal result = newInstance(size + that.size); + int i = 0; + + int thisI = 0; + int thatI = 0; + + Variable thisVariable = thisI < this.size ? this.variables[thisI] : null; + Variable thatVariable = thatI < that.size ? that.variables[thatI] : null; + + while (thisVariable != null || thatVariable != null) { + int c = thisVariable == null ? 1 : (thatVariable == null ? -1 : thisVariable.compareTo(thatVariable)); + + if (c < 0) { + int s = powers[thisI]; + result.variables[i] = thisVariable; + result.powers[i] = s; + result.degree += s; + i++; + thisI++; + thisVariable = thisI < size ? variables[thisI] : null; + } else if (c > 0) { + int s = that.powers[thatI]; + result.variables[i] = thatVariable; + result.powers[i] = s; + result.degree += s; + i++; + thatI++; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } else { + int s = powers[thisI] + that.powers[thatI]; + + result.variables[i] = thisVariable; + result.powers[i] = s; + result.degree += s; + + i++; + thisI++; + thatI++; + + thisVariable = thisI < this.size ? this.variables[thisI] : null; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } + } + + result.resize(i); + + return result; + } + + public Literal divide(Literal literal) throws ArithmeticException { + Literal l = newInstance(size + literal.size); + int i = 0; + int i1 = 0; + int i2 = 0; + Variable v1 = i1 < size ? variables[i1] : null; + Variable v2 = i2 < literal.size ? literal.variables[i2] : null; + while (v1 != null || v2 != null) { + int c = v1 == null ? 1 : (v2 == null ? -1 : v1.compareTo(v2)); + if (c < 0) { + int s = powers[i1]; + l.variables[i] = v1; + l.powers[i] = s; + l.degree += s; + i++; + i1++; + v1 = i1 < size ? variables[i1] : null; + } else if (c > 0) { + throw new NotDivisibleException(); + } else { + int s = powers[i1] - literal.powers[i2]; + if (s < 0) throw new NotDivisibleException(); + else if (s == 0) ; + else { + l.variables[i] = v1; + l.powers[i] = s; + l.degree += s; + i++; + } + i1++; + i2++; + v1 = i1 < size ? variables[i1] : null; + v2 = i2 < literal.size ? literal.variables[i2] : null; + } + } + l.resize(i); + return l; + } + + @Nonnull + public Literal gcd(@Nonnull Literal that) { + Literal result = newInstance(Math.min(this.size, that.size)); + int i = 0; + + int thisI = 0; + int thatI = 0; + + Variable thisVariable = thisI < this.size ? this.variables[thisI] : null; + Variable thatVariable = thatI < that.size ? that.variables[thatI] : null; + + while (thisVariable != null || thatVariable != null) { + int c; + + if (thisVariable == null) { + c = 1; + } else if (thatVariable == null) { + c = -1; + } else { + c = thisVariable.compareTo(thatVariable); + } + + if (c < 0) { + thisI++; + thisVariable = thisI < this.size ? this.variables[thisI] : null; + } else if (c > 0) { + thatI++; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } else { + int minPower = Math.min(this.powers[thisI], that.powers[thatI]); + + result.variables[i] = thisVariable; + result.powers[i] = minPower; + result.degree += minPower; + + i++; + thisI++; + thatI++; + + thisVariable = thisI < this.size ? this.variables[thisI] : null; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } + } + + result.resize(i); + + return result; + } + + public Literal scm(@Nonnull Literal that) { + final Literal result = newInstance(this.size + that.size); + int i = 0; + + int thisI = 0; + int thatI = 0; + + Variable thisVariable = thisI < this.size ? this.variables[thisI] : null; + Variable thatVariable = thatI < that.size ? that.variables[thatI] : null; + + while (thisVariable != null || thatVariable != null) { + int c; + if (thisVariable == null) { + c = 1; + } else if (thatVariable == null) { + c = -1; + } else { + c = thisVariable.compareTo(thatVariable); + } + + if (c < 0) { + int thisPower = this.powers[thisI]; + + result.variables[i] = thisVariable; + result.powers[i] = thisPower; + result.degree += thisPower; + + i++; + thisI++; + thisVariable = thisI < size ? variables[thisI] : null; + } else if (c > 0) { + int thatPower = that.powers[thatI]; + + result.variables[i] = thatVariable; + result.powers[i] = thatPower; + result.degree += thatPower; + + i++; + thatI++; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } else { + int maxPower = Math.max(this.powers[thisI], that.powers[thatI]); + + result.variables[i] = thisVariable; + result.powers[i] = maxPower; + result.degree += maxPower; + + i++; + thisI++; + thatI++; + + thisVariable = thisI < this.size ? this.variables[thisI] : null; + thatVariable = thatI < that.size ? that.variables[thatI] : null; + } + } + + result.resize(i); + + return result; + } + + public Generic[] productValue() throws NotProductException { + Generic a[] = new Generic[size]; + for (int i = 0; i < a.length; i++) a[i] = variables[i].expressionValue().pow(powers[i]); + return a; + } + + public Power powerValue() throws NotPowerException { + if (size == 0) return new Power(JsclInteger.valueOf(1), 1); + else if (size == 1) { + Variable v = variables[0]; + int c = powers[0]; + return new Power(v.expressionValue(), c); + } else throw new NotPowerException(); + } + + public Variable variableValue() throws NotVariableException { + if (size == 0) throw new NotVariableException(); + else if (size == 1) { + Variable v = variables[0]; + int c = powers[0]; + if (c == 1) return v; + else throw new NotVariableException(); + } else throw new NotVariableException(); + } + + public Variable[] variables() { + Variable va[] = new Variable[size]; + System.arraycopy(variables, 0, va, 0, size); + return va; + } + + public int degree() { + return degree; + } + + public int compareTo(@Nonnull Literal that) { + int thisI = this.size; + int thatI = that.size; + + Variable thisVariable = thisI == 0 ? null : this.variables[--thisI]; + Variable thatVariable = thatI == 0 ? null : that.variables[--thatI]; + + while (thisVariable != null || thatVariable != null) { + int c; + if (thisVariable == null) { + c = -1; + } else if (thatVariable == null) { + c = 1; + } else { + c = thisVariable.compareTo(thatVariable); + } + + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } else { + + int thisPower = this.powers[thisI]; + int thatPower = that.powers[thatI]; + if (thisPower < thatPower) { + return -1; + } else if (thisPower > thatPower) { + return 1; + } + + thisVariable = thisI == 0 ? null : this.variables[--thisI]; + thatVariable = thatI == 0 ? null : that.variables[--thatI]; + } + } + return 0; + } + + public int compareTo(Object o) { + return compareTo((Literal) o); + } + + void init(Variable var, int pow) { + if (pow != 0) { + init(1); + variables[0] = var; + powers[0] = pow; + degree = pow; + } else init(0); + } + + void init(Monomial monomial) { + Map map = new TreeMap(); + Variable unk[] = monomial.unknown(); + for (int i = 0; i < unk.length; i++) { + int c = monomial.element(i); + if (c > 0) map.put(unk[i], 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(); + variables[i] = v; + powers[i] = c; + degree += c; + } + } + + Map content(@Nonnull Converter c) { + final Map result = new TreeMap(); + + for (int i = 0; i < size; i++) { + result.put(variables[i], c.convert(variables[i])); + } + + return result; + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + if (degree == 0) { + result.append("1"); + } + + // result = var[0] ^ power[0] * var[1] ^ power[1]* ... + for (int i = 0; i < size; i++) { + if (i > 0) { + result.append("*"); + } + + final Variable var = variables[i]; + int power = powers[i]; + if (power == 1) { + result.append(var); + } else { + if (var instanceof Fraction || var instanceof Pow) { + result.append("(").append(var).append(")"); + } else { + result.append(var); + } + result.append("^").append(power); + } + } + return result.toString(); + } + + public String toJava() { + StringBuilder buffer = new StringBuilder(); + if (degree == 0) buffer.append("JsclDouble.valueOf(1)"); + for (int i = 0; i < size; i++) { + if (i > 0) buffer.append(".multiply("); + Variable v = variables[i]; + int c = powers[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, @Nullable Object data) { + if (degree == 0) { + MathML e1 = element.element("mn"); + e1.appendChild(element.text("1")); + element.appendChild(e1); + } + for (int i = 0; i < size; i++) { + Variable v = variables[i]; + int c = powers[i]; + v.toMathML(element, c); + } + } + + @Nonnull + private Literal newInstance(int n) { + return new Literal(n); + } +} diff --git a/jscl/src/main/java/jscl/math/Matrix.java b/jscl/src/main/java/jscl/math/Matrix.java new file mode 100644 index 00000000..609f5974 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Matrix.java @@ -0,0 +1,544 @@ +package jscl.math; + +import jscl.math.function.Conjugate; +import jscl.math.function.Constant; +import jscl.math.function.Fraction; +import jscl.math.function.trigonometric.Cos; +import jscl.math.function.trigonometric.Sin; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; + +public class Matrix extends Generic { + + protected final Generic elements[][]; + protected final int rows, cols; + + public Matrix(Generic elements[][]) { + this.elements = elements; + rows = elements.length; + cols = elements.length > 0 ? elements[0].length : 0; + } + + public static boolean isMatrixProduct(@Nonnull Generic a, @Nonnull Generic b) { + return (a instanceof Matrix && b instanceof Matrix) || + (a instanceof Matrix && b instanceof JsclVector) || + (a instanceof JsclVector && b instanceof Matrix); + } + + public static Matrix identity(int dimension) { + return identity(dimension, dimension); + } + + public static Matrix identity(int n, int p) { + Matrix m = new Matrix(new Generic[n][p]); + for (int i = 0; i < n; i++) { + for (int j = 0; j < p; j++) { + if (i == j) { + m.elements[i][j] = JsclInteger.valueOf(1); + } else { + m.elements[i][j] = JsclInteger.valueOf(0); + } + } + } + return m; + } + + public static Matrix frame(JsclVector vector[]) { + Matrix m = new Matrix(new Generic[vector.length > 0 ? vector[0].rows : 0][vector.length]); + for (int i = 0; i < m.rows; i++) { + for (int j = 0; j < m.cols; j++) { + m.elements[i][j] = vector[j].elements[i]; + } + } + return m; + } + + public static Matrix rotation(int dimension, int plane, Generic angle) { + return rotation(dimension, plane, 2, angle); + } + + public static Matrix rotation(int dimension, int axis1, int axis2, Generic angle) { + Matrix m = new Matrix(new Generic[dimension][dimension]); + for (int i = 0; i < m.rows; i++) { + for (int j = 0; j < m.cols; j++) { + if (i == axis1 && j == axis1) { + m.elements[i][j] = new Cos(angle).selfExpand(); + } else if (i == axis1 && j == axis2) { + m.elements[i][j] = new Sin(angle).selfExpand().negate(); + } else if (i == axis2 && j == axis1) { + m.elements[i][j] = new Sin(angle).selfExpand(); + } else if (i == axis2 && j == axis2) { + m.elements[i][j] = new Cos(angle).selfExpand(); + } else if (i == j) { + m.elements[i][j] = JsclInteger.valueOf(1); + } else { + m.elements[i][j] = JsclInteger.valueOf(0); + } + } + } + return m; + } + + @Nonnull + protected static Generic newInstance(Generic element[][]) { + return new Matrix(element); + } + + public Generic[][] elements() { + return elements; + } + + public Matrix add(Matrix matrix) { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].add(matrix.elements[i][j]); + } + } + return m; + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof Matrix) { + return add((Matrix) that); + } else { + return add(valueOf(that)); + } + } + + public Matrix subtract(Matrix matrix) { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].subtract(matrix.elements[i][j]); + } + } + return m; + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof Matrix) { + return subtract((Matrix) that); + } else { + return subtract(valueOf(that)); + } + } + + public Matrix multiply(Matrix matrix) { + if (cols != matrix.rows) { + throw new ArithmeticException("Unable to multiply matrix by matrix: number of columns of left matrix doesn't match number of rows of right matrix!"); + } + Matrix m = (Matrix) newInstance(new Generic[rows][matrix.cols]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < matrix.cols; j++) { + m.elements[i][j] = JsclInteger.valueOf(0); + for (int k = 0; k < cols; k++) { + m.elements[i][j] = m.elements[i][j].add(elements[i][k].multiply(matrix.elements[k][j])); + } + } + } + return m; + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof Matrix) { + return multiply((Matrix) that); + } else if (that instanceof JsclVector) { + JsclVector v = (JsclVector) ((JsclVector) that).newInstance(new Generic[rows]); + JsclVector v2 = (JsclVector) that; + if (cols != v2.rows) { + throw new ArithmeticException("Unable to multiply matrix by vector: number of matrix columns doesn't match number of vector rows!"); + } + for (int i = 0; i < rows; i++) { + v.elements[i] = JsclInteger.valueOf(0); + for (int k = 0; k < cols; k++) { + v.elements[i] = v.elements[i].add(elements[i][k].multiply(v2.elements[k])); + } + } + return v; + } else { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].multiply(that); + } + } + return m; + } + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof Matrix) { + return multiply(that.inverse()); + } else if (that instanceof JsclVector) { + throw new ArithmeticException("Unable to divide matrix by vector: matrix could not be divided by vector!"); + } else { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + try { + m.elements[i][j] = elements[i][j].divide(that); + } catch (NotDivisibleException e) { + m.elements[i][j] = new Fraction(elements[i][j], that).selfExpand(); + } + } + } + return m; + } + } + + public Generic gcd(@Nonnull Generic generic) { + return null; + } + + @Nonnull + public Generic gcd() { + return null; + } + + public Generic negate() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].negate(); + } + } + return m; + } + + public int signum() { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + int c = elements[i][j].signum(); + if (c < 0) return -1; + else if (c > 0) return 1; + } + } + return 0; + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].antiDerivative(variable); + } + } + return m; + } + + public Generic derivative(@Nonnull Variable variable) { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].derivative(variable); + } + } + return m; + } + + public Generic substitute(@Nonnull Variable variable, Generic generic) { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].substitute(variable, generic); + } + } + return m; + } + + public Generic expand() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].expand(); + } + } + return m; + } + + public Generic factorize() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].factorize(); + } + } + return m; + } + + public Generic elementary() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].elementary(); + } + } + return m; + } + + public Generic simplify() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = elements[i][j].simplify(); + } + } + return m; + } + + public Generic numeric() { + return new NumericWrapper(this); + } + + public Generic valueOf(Generic generic) { + if (generic instanceof Matrix || generic instanceof JsclVector) { + throw new ArithmeticException("Unable to create matrix: matrix of vectors and matrix of matrices are forbidden"); + } else { + Matrix m = (Matrix) identity(rows, cols).multiply(generic); + return newInstance(m.elements); + } + } + + public Generic[] sumValue() { + return new Generic[]{this}; + } + + public Generic[] productValue() throws NotProductException { + return new Generic[]{this}; + } + + public Power powerValue() throws NotPowerException { + return new Power(this, 1); + } + + public Expression expressionValue() throws NotExpressionException { + throw new NotExpressionException(); + } + + public JsclInteger integerValue() throws NotIntegerException { + throw new NotIntegerException(); + } + + @Override + public boolean isInteger() { + return false; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return null; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return false; + } + + public boolean isConstant(@Nonnull Variable variable) { + return false; + } + + public Generic[] vectors() { + JsclVector v[] = new JsclVector[rows]; + for (int i = 0; i < rows; i++) { + v[i] = new JsclVector(new Generic[cols]); + for (int j = 0; j < cols; j++) { + v[i].elements[j] = elements[i][j]; + } + } + return v; + } + + public Generic tensorProduct(Matrix matrix) { + Matrix m = (Matrix) newInstance(new Generic[rows * matrix.rows][cols * matrix.cols]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + for (int k = 0; k < matrix.rows; k++) { + for (int l = 0; l < matrix.cols; l++) { + m.elements[i * matrix.rows + k][j * matrix.cols + l] = elements[i][j].multiply(matrix.elements[k][l]); + } + } + } + } + return m; + } + + public Matrix transpose() { + Matrix m = (Matrix) newInstance(new Generic[cols][rows]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[j][i] = elements[i][j]; + } + } + return m; + } + + public Generic trace() { + Generic s = JsclInteger.valueOf(0); + for (int i = 0; i < rows; i++) { + s = s.add(elements[i][i]); + } + return s; + } + + public Generic inverse() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + m.elements[i][j] = inverseElement(i, j); + } + } + return m.transpose().divide(determinant()); + } + + Generic inverseElement(int k, int l) { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + m.elements[i][j] = i == k ? JsclInteger.valueOf(j == l ? 1 : 0) : elements[i][j]; + } + } + return m.determinant(); + } + + public Generic determinant() { + if (rows > 1) { + Generic a = JsclInteger.valueOf(0); + for (int i = 0; i < rows; i++) { + if (elements[i][0].signum() == 0) ; + else { + Matrix m = (Matrix) newInstance(new Generic[rows - 1][rows - 1]); + for (int j = 0; j < rows - 1; j++) { + for (int k = 0; k < rows - 1; k++) m.elements[j][k] = elements[j < i ? j : j + 1][k + 1]; + } + if (i % 2 == 0) a = a.add(elements[i][0].multiply(m.determinant())); + else a = a.subtract(elements[i][0].multiply(m.determinant())); + } + } + return a; + } else if (rows > 0) return elements[0][0]; + else return JsclInteger.valueOf(0); + } + + public Generic conjugate() { + Matrix m = (Matrix) newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.elements[i][j] = new Conjugate(elements[i][j]).selfExpand(); + } + } + return m; + } + + public int compareTo(Matrix matrix) { + return ArrayComparator.comparator.compare(vectors(), matrix.vectors()); + } + + public int compareTo(Generic generic) { + if (generic instanceof Matrix) { + return compareTo((Matrix) generic); + } else { + return compareTo(valueOf(generic)); + } + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + result.append("["); + for (int i = 0; i < rows; i++) { + result.append("["); + + for (int j = 0; j < cols; j++) { + result.append(elements[i][j]).append(j < cols - 1 ? ", " : ""); + } + + result.append("]").append(i < rows - 1 ? ",\n" : ""); + } + + result.append("]"); + + return result.toString(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + + result.append("new Matrix(new Numeric[][] {"); + + for (int i = 0; i < rows; i++) { + result.append("{"); + for (int j = 0; j < cols; j++) { + result.append(elements[i][j].toJava()).append(j < cols - 1 ? ", " : ""); + } + result.append("}").append(i < rows - 1 ? ", " : ""); + } + + result.append("})"); + + return result.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Set getConstants() { + final Set result = new HashSet(); + + for (Generic[] element : elements) { + for (Generic generic : element) { + result.addAll(generic.getConstants()); + } + } + + return result; + } + + protected void bodyToMathML(MathML e0) { + MathML e1 = e0.element("mfenced"); + MathML e2 = e0.element("mtable"); + for (int i = 0; i < rows; i++) { + MathML e3 = e0.element("mtr"); + for (int j = 0; j < cols; j++) { + MathML e4 = e0.element("mtd"); + elements[i][j].toMathML(e4, null); + e3.appendChild(e4); + } + e2.appendChild(e3); + } + e1.appendChild(e2); + e0.appendChild(e1); + } + + @Nonnull + protected Generic newInstance() { + return newInstance(new Generic[rows][cols]); + } +} diff --git a/jscl/src/main/java/jscl/math/MatrixVariable.java b/jscl/src/main/java/jscl/math/MatrixVariable.java new file mode 100644 index 00000000..c7471f50 --- /dev/null +++ b/jscl/src/main/java/jscl/math/MatrixVariable.java @@ -0,0 +1,14 @@ +package jscl.math; + +import javax.annotation.Nonnull; + +public class MatrixVariable extends GenericVariable { + public MatrixVariable(Generic generic) { + super(generic); + } + + @Nonnull + public Variable newInstance() { + return new MatrixVariable(null); + } +} diff --git a/jscl/src/main/java/jscl/math/ModularInteger.java b/jscl/src/main/java/jscl/math/ModularInteger.java new file mode 100644 index 00000000..29cdd666 --- /dev/null +++ b/jscl/src/main/java/jscl/math/ModularInteger.java @@ -0,0 +1,210 @@ +package jscl.math; + +import jscl.math.function.Constant; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.math.BigInteger; +import java.util.Collections; +import java.util.Set; + +public class ModularInteger extends Generic implements Field { + public static final ModularInteger booleanFactory = new ModularInteger(0, 2); + final int modulo; + final int content; + + public ModularInteger(long content, int modulo) { + this.modulo = modulo; + this.content = (int) (content % modulo); + } + + public static ModularInteger factory(int modulo) { + return new ModularInteger(0, modulo); + } + + public int content() { + return content; + } + + public int modulo() { + return modulo; + } + + public ModularInteger add(ModularInteger integer) { + return newinstance((long) content + integer.content); + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + return add((ModularInteger) that); + } + + public ModularInteger subtract(ModularInteger integer) { + return newinstance((long) content + (modulo - integer.content)); + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + return subtract((ModularInteger) that); + } + + public ModularInteger multiply(ModularInteger integer) { + return newinstance((long) content * integer.content); + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + return multiply((ModularInteger) that); + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + return multiply(that.inverse()); + } + + public Generic inverse() { + return newinstance(BigInteger.valueOf(content).modInverse(BigInteger.valueOf(modulo)).intValue()); + } + + public Generic gcd(@Nonnull Generic generic) { + throw new UnsupportedOperationException(); + } + + @Nonnull + public Generic gcd() { + throw new UnsupportedOperationException(); + } + + public Generic pow(int exponent) { + throw new UnsupportedOperationException(); + } + + public Generic negate() { + return newinstance(modulo - content); + } + + public int signum() { + return content > 0 ? 1 : 0; + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + throw new UnsupportedOperationException(); + } + + public Generic derivative(@Nonnull Variable variable) { + throw new UnsupportedOperationException(); + } + + public Generic substitute(@Nonnull 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); + } + + @Override + public boolean isInteger() { + return true; + } + + public Variable variableValue() throws NotVariableException { + throw new UnsupportedOperationException(); + } + + public Variable[] variables() { + throw new UnsupportedOperationException(); + } + + public boolean isPolynomial(@Nonnull Variable variable) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(@Nonnull Variable variable) { + throw new UnsupportedOperationException(); + } + + public int compareTo(ModularInteger integer) { + return content < integer.content ? -1 : content > integer.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 String toString() { + return "" + content; + } + + public String toJava() { + throw new UnsupportedOperationException(); + } + + public void toMathML(MathML element, Object data) { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public Set getConstants() { + return Collections.emptySet(); + } + + protected ModularInteger newinstance(long content) { + return new ModularInteger(content, modulo); + } +} diff --git a/jscl/src/main/java/jscl/math/NotDivisibleException.java b/jscl/src/main/java/jscl/math/NotDivisibleException.java new file mode 100644 index 00000000..2646a57e --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotDivisibleException.java @@ -0,0 +1,11 @@ +package jscl.math; + +public class NotDivisibleException extends ArithmeticException { + + public NotDivisibleException() { + } + + public NotDivisibleException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NotExpressionException.java b/jscl/src/main/java/jscl/math/NotExpressionException.java new file mode 100644 index 00000000..e9bb8ef9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotExpressionException.java @@ -0,0 +1,10 @@ +package jscl.math; + +public class NotExpressionException extends ArithmeticException { + public NotExpressionException() { + } + + public NotExpressionException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NotIntegerException.java b/jscl/src/main/java/jscl/math/NotIntegerException.java new file mode 100644 index 00000000..d6d96afd --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotIntegerException.java @@ -0,0 +1,11 @@ +package jscl.math; + +public class NotIntegerException extends ArithmeticException { + public NotIntegerException() { + this("Not integer!"); + } + + public NotIntegerException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NotIntegrableException.java b/jscl/src/main/java/jscl/math/NotIntegrableException.java new file mode 100644 index 00000000..a2962d0b --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotIntegrableException.java @@ -0,0 +1,25 @@ +package jscl.math; + +import jscl.AbstractJsclArithmeticException; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +public class NotIntegrableException extends AbstractJsclArithmeticException { + + public NotIntegrableException(@Nonnull String messageCode, Object... parameters) { + super(messageCode, parameters); + } + + public NotIntegrableException(@Nonnull Expression e) { + this(Messages.msg_21, e.toString()); + } + + public NotIntegrableException(@Nonnull Variable v) { + this(Messages.msg_21, v.getName()); + } + + public NotIntegrableException() { + this(Messages.msg_22); + } +} diff --git a/jscl/src/main/java/jscl/math/NotPowerException.java b/jscl/src/main/java/jscl/math/NotPowerException.java new file mode 100644 index 00000000..92af75c6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotPowerException.java @@ -0,0 +1,10 @@ +package jscl.math; + +public class NotPowerException extends ArithmeticException { + public NotPowerException() { + } + + public NotPowerException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NotProductException.java b/jscl/src/main/java/jscl/math/NotProductException.java new file mode 100644 index 00000000..130aed79 --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotProductException.java @@ -0,0 +1,10 @@ +package jscl.math; + +public class NotProductException extends ArithmeticException { + public NotProductException() { + } + + public NotProductException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NotVariableException.java b/jscl/src/main/java/jscl/math/NotVariableException.java new file mode 100644 index 00000000..38c8f21a --- /dev/null +++ b/jscl/src/main/java/jscl/math/NotVariableException.java @@ -0,0 +1,10 @@ +package jscl.math; + +public class NotVariableException extends ArithmeticException { + public NotVariableException() { + } + + public NotVariableException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/NumericWrapper.java b/jscl/src/main/java/jscl/math/NumericWrapper.java new file mode 100644 index 00000000..1c0ea0d4 --- /dev/null +++ b/jscl/src/main/java/jscl/math/NumericWrapper.java @@ -0,0 +1,445 @@ +package jscl.math; + +import jscl.JsclMathEngine; +import jscl.math.function.Constant; +import jscl.math.function.Constants; +import jscl.math.function.IConstant; +import jscl.math.numeric.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Set; + +public final class NumericWrapper extends Generic implements INumeric { + + @Nonnull + private final Numeric content; + + public NumericWrapper(@Nonnull JsclInteger integer) { + content = Real.valueOf(integer.content().doubleValue()); + } + + public NumericWrapper(@Nonnull Rational rational) { + content = Real.valueOf(rational.numerator().doubleValue() / rational.denominator().doubleValue()); + } + + public NumericWrapper(@Nonnull JsclVector vector) { + final Numeric elements[] = new Numeric[vector.rows]; + + for (int i = 0; i < vector.rows; i++) { + elements[i] = ((NumericWrapper) vector.elements[i].numeric()).content(); + } + + content = new Vector(elements); + } + + public NumericWrapper(@Nonnull Matrix matrix) { + final Numeric elements[][] = new Numeric[matrix.rows][matrix.cols]; + + for (int i = 0; i < matrix.rows; i++) { + for (int j = 0; j < matrix.cols; j++) { + elements[i][j] = ((NumericWrapper) matrix.elements[i][j].numeric()).content(); + } + } + + content = new jscl.math.numeric.Matrix(elements); + } + + public NumericWrapper(@Nonnull Constant constant) { + final IConstant constantFromRegistry = JsclMathEngine.getInstance().getConstantsRegistry().get(constant.getName()); + + if (constantFromRegistry != null) { + if (constantFromRegistry.getName().equals(Constants.I.getName())) { + content = Complex.I; + } else { + if (constantFromRegistry.getValue() != null) { + final Double value = constantFromRegistry.getDoubleValue(); + if (value == null) { + throw new ArithmeticException("Constant " + constant.getName() + " has invalid definition: " + constantFromRegistry.getValue()); + } else { + content = Real.valueOf(value); + } + } else { + throw new ArithmeticException("Could not create numeric wrapper: constant in registry doesn't have specified value: " + constant.getName()); + } + } + } else { + throw new ArithmeticException("Could not create numeric wrapper: constant is not registered in constants registry: " + constant.getName()); + } + } + + public NumericWrapper(@Nonnull Numeric numeric) { + content = numeric; + } + + public static Generic root(int subscript, Generic parameter[]) { + Numeric param[] = new Numeric[parameter.length]; + for (int i = 0; i < param.length; i++) param[i] = ((NumericWrapper) parameter[i]).content; + return new NumericWrapper(Numeric.root(subscript, param)); + } + + public Numeric content() { + return content; + } + + public NumericWrapper add(NumericWrapper wrapper) { + return new NumericWrapper(content.add(wrapper.content)); + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof Expression) { + return that.add(this); + } else if (that instanceof NumericWrapper) { + return add((NumericWrapper) that); + } else { + return add(valueOf(that)); + } + } + + public NumericWrapper subtract(NumericWrapper wrapper) { + return new NumericWrapper(content.subtract(wrapper.content)); + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof Expression) { + return that.add(this); + } else if (that instanceof NumericWrapper) { + return subtract((NumericWrapper) that); + } else { + return subtract(valueOf(that)); + } + } + + public NumericWrapper multiply(NumericWrapper wrapper) { + return new NumericWrapper(content.multiply(wrapper.content)); + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof Expression) { + return that.add(this); + } else if (that instanceof NumericWrapper) { + return multiply((NumericWrapper) that); + } else { + return multiply(valueOf(that)); + } + } + + public NumericWrapper divide(NumericWrapper wrapper) throws ArithmeticException { + return new NumericWrapper(content.divide(wrapper.content)); + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof Expression) { + return that.add(this); + } else if (that instanceof NumericWrapper) { + return divide((NumericWrapper) that); + } else { + return divide(valueOf(that)); + } + } + + public Generic gcd(@Nonnull Generic generic) { + return null; + } + + @Nonnull + public Generic gcd() { + return null; + } + + @Nonnull + public NumericWrapper abs() { + return new NumericWrapper(content.abs()); + } + + @Nonnull + public NumericWrapper negate() { + return new NumericWrapper(content.negate()); + } + + public int signum() { + return content.signum(); + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + return null; + } + + public Generic derivative(@Nonnull Variable variable) { + return null; + } + + public Generic substitute(@Nonnull 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 this; + } + + public NumericWrapper valueOf(NumericWrapper wrapper) { + return new NumericWrapper(content.valueOf(wrapper.content)); + } + + public Generic valueOf(@Nonnull Generic generic) { + if (generic instanceof NumericWrapper) { + return valueOf((NumericWrapper) generic); + } else if (generic instanceof JsclInteger) { + return new NumericWrapper((JsclInteger) generic); + } else { + throw new ArithmeticException("Could not create numeric wrapper for class: " + generic.getClass()); + } + } + + public Generic[] sumValue() { + return null; + } + + public Generic[] productValue() throws NotProductException { + return null; + } + + public Power powerValue() throws NotPowerException { + return null; + } + + public Expression expressionValue() throws NotExpressionException { + throw new NotExpressionException(); + } + + public JsclInteger integerValue() throws NotIntegerException { + if (content instanceof Real) { + double doubleValue = ((Real) content).doubleValue(); + if (Math.floor(doubleValue) == doubleValue) { + return JsclInteger.valueOf((int) doubleValue); + } else { + throw new NotIntegerException(); + } + } else { + throw new NotIntegerException(); + } + } + + @Override + public boolean isInteger() { + if (content instanceof Real) { + double value = ((Real) content).doubleValue(); + return Math.floor(value) == value; + } + return false; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return true; + } + + public boolean isConstant(@Nonnull Variable variable) { + return true; + } + + @Nonnull + public NumericWrapper sgn() { + return new NumericWrapper(content.sgn()); + } + + @Nonnull + public NumericWrapper ln() { + return new NumericWrapper(content.ln()); + } + + @Nonnull + public NumericWrapper lg() { + return new NumericWrapper(content.lg()); + } + + @Nonnull + public NumericWrapper exp() { + return new NumericWrapper(content.exp()); + } + + @Nonnull + public NumericWrapper inverse() { + return new NumericWrapper(content.inverse()); + } + + @Nonnull + public NumericWrapper pow(int exponent) { + return new NumericWrapper(content.pow(exponent)); + } + + public Generic pow(Generic generic) { + return new NumericWrapper(content.pow(((NumericWrapper) generic).content)); + } + + @Nonnull + public NumericWrapper sqrt() { + return new NumericWrapper(content.sqrt()); + } + + @Nonnull + public NumericWrapper nThRoot(int n) { + return new NumericWrapper(content.nThRoot(n)); + } + + public Generic conjugate() { + return new NumericWrapper(content.conjugate()); + } + + @Nonnull + public NumericWrapper acos() { + return new NumericWrapper(content.acos()); + } + + @Nonnull + public NumericWrapper asin() { + return new NumericWrapper(content.asin()); + } + + @Nonnull + public NumericWrapper atan() { + return new NumericWrapper(content.atan()); + } + + @Nonnull + public NumericWrapper acot() { + return new NumericWrapper(content.acot()); + } + + @Nonnull + public NumericWrapper cos() { + return new NumericWrapper(content.cos()); + } + + @Nonnull + public NumericWrapper sin() { + return new NumericWrapper(content.sin()); + } + + @Nonnull + public NumericWrapper tan() { + return new NumericWrapper(content.tan()); + } + + @Nonnull + public NumericWrapper cot() { + return new NumericWrapper(content.cot()); + } + + @Nonnull + public NumericWrapper acosh() { + return new NumericWrapper(content.acosh()); + } + + @Nonnull + public NumericWrapper asinh() { + return new NumericWrapper(content.asinh()); + } + + @Nonnull + public NumericWrapper atanh() { + return new NumericWrapper(content.atanh()); + } + + @Nonnull + public NumericWrapper acoth() { + return new NumericWrapper(content.acoth()); + } + + @Nonnull + public NumericWrapper cosh() { + return new NumericWrapper(content.cosh()); + } + + @Nonnull + public NumericWrapper sinh() { + return new NumericWrapper(content.sinh()); + } + + @Nonnull + public NumericWrapper tanh() { + return new NumericWrapper(content.tanh()); + } + + @Nonnull + public NumericWrapper coth() { + return new NumericWrapper(content.coth()); + } + + public int compareTo(NumericWrapper wrapper) { + return content.compareTo(wrapper.content); + } + + public int compareTo(Generic generic) { + if (generic instanceof NumericWrapper) { + return compareTo((NumericWrapper) generic); + } else { + return compareTo(valueOf(generic)); + } + } + + public String toString() { + return content.toString(); + } + + public String toJava() { + return "JsclDouble.valueOf(" + new Double(((Real) content).doubleValue()) + ")"; + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Set getConstants() { + return Collections.emptySet(); + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mn"); + e1.appendChild(element.text(String.valueOf(new Double(((Real) content).doubleValue())))); + element.appendChild(e1); + } +} diff --git a/jscl/src/main/java/jscl/math/Power.java b/jscl/src/main/java/jscl/math/Power.java new file mode 100644 index 00000000..af59ccd5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Power.java @@ -0,0 +1,27 @@ +package jscl.math; + +public class Power { + final Generic value; + final int exponent; + + public Power(Generic value, int exponent) { + this.value = value; + this.exponent = exponent; + } + + public Generic value() { + return value(false); + } + + public Generic value(boolean content) { + return content ? GenericVariable.content(value) : value; + } + + public int exponent() { + return exponent; + } + + public String toString() { + return "(" + value + ", " + exponent + ")"; + } +} diff --git a/jscl/src/main/java/jscl/math/Rational.java b/jscl/src/main/java/jscl/math/Rational.java new file mode 100644 index 00000000..f13f8547 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Rational.java @@ -0,0 +1,311 @@ +package jscl.math; + +import jscl.math.function.Constant; +import jscl.math.function.Fraction; +import jscl.math.function.Inverse; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.math.BigInteger; +import java.util.Collections; +import java.util.Set; + +public final class Rational extends Generic implements Field { + + public static final Rational factory = new Rational(BigInteger.valueOf(0), BigInteger.valueOf(1)); + + final BigInteger numerator; + final BigInteger denominator; + + public Rational(BigInteger numerator, BigInteger denominator) { + this.numerator = numerator; + this.denominator = denominator; + } + + static BigInteger scm(BigInteger b1, BigInteger b2) { + return b1.multiply(b2).divide(b1.gcd(b2)); + } + + public BigInteger numerator() { + return numerator; + } + + public BigInteger denominator() { + return denominator; + } + + public Rational add(Rational rational) { + BigInteger gcd = denominator.gcd(rational.denominator); + BigInteger c = denominator.divide(gcd); + BigInteger c2 = rational.denominator.divide(gcd); + return new Rational(numerator.multiply(c2).add(rational.numerator.multiply(c)), denominator.multiply(c2)).reduce(); + } + + Rational reduce() { + BigInteger gcd = numerator.gcd(denominator); + if (gcd.signum() != denominator.signum()) gcd = gcd.negate(); + return gcd.signum() == 0 ? this : new Rational(numerator.divide(gcd), denominator.divide(gcd)); + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof Rational) { + return add((Rational) that); + } else if (that instanceof JsclInteger) { + return add(valueOf(that)); + } else { + return that.valueOf(this).add(that); + } + } + + public Rational multiply(Rational rational) { + BigInteger gcd = numerator.gcd(rational.denominator); + BigInteger gcd2 = denominator.gcd(rational.numerator); + return new Rational(numerator.divide(gcd).multiply(rational.numerator.divide(gcd2)), denominator.divide(gcd2).multiply(rational.denominator.divide(gcd))); + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof Rational) { + return multiply((Rational) that); + } else if (that instanceof JsclInteger) { + return multiply(valueOf(that)); + } else { + return that.multiply(this); + } + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof Rational) { + return multiply(that.inverse()); + } else if (that instanceof JsclInteger) { + return divide(valueOf(that)); + } else { + return that.valueOf(this).divide(that); + } + } + + public Generic inverse() { + if (signum() < 0) return new Rational(denominator.negate(), numerator.negate()); + else return new Rational(denominator, numerator); + } + + public Rational gcd(Rational rational) { + return new Rational(numerator.gcd(rational.numerator), scm(denominator, rational.denominator)); + } + + public Generic gcd(@Nonnull Generic generic) { + if (generic instanceof Rational) { + return gcd((Rational) generic); + } else if (generic instanceof JsclInteger) { + return gcd(valueOf(generic)); + } else { + return generic.valueOf(this).gcd(generic); + } + } + + @Nonnull + public Generic gcd() { + return null; + } + + public Generic pow(int exponent) { + return null; + } + + public Generic negate() { + return new Rational(numerator.negate(), denominator); + } + + public int signum() { + return numerator.signum(); + } + + public int degree() { + return 0; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + return multiply(variable.expressionValue()); + } + + public Generic derivative(@Nonnull Variable variable) { + return JsclInteger.valueOf(0); + } + + public Generic substitute(@Nonnull Variable variable, Generic generic) { + return this; + } + + public Generic expand() { + return this; + } + + public Generic factorize() { + return expressionValue().factorize(); + } + + public Generic elementary() { + return this; + } + + public Generic simplify() { + return reduce(); + } + + public Generic numeric() { + return new NumericWrapper(this); + } + + public Generic valueOf(Generic generic) { + if (generic instanceof Rational) { + Rational r = (Rational) generic; + return new Rational(r.numerator, r.denominator); + } else if (generic instanceof Expression) { + boolean sign = generic.signum() < 0; + Generic g[] = ((Fraction) (sign ? generic.negate() : generic).variableValue()).getParameters(); + JsclInteger numerator = (JsclInteger) (sign ? g[0].negate() : g[0]); + JsclInteger denominator = (JsclInteger) g[1]; + return new Rational(numerator.content(), denominator.content()); + } else { + JsclInteger en = (JsclInteger) generic; + return new Rational(en.content(), BigInteger.valueOf(1)); + } + } + + public Generic[] sumValue() { + try { + if (integerValue().signum() == 0) return new Generic[0]; + else return new Generic[]{this}; + } catch (NotIntegerException e) { + return new Generic[]{this}; + } + } + + public Generic[] productValue() throws NotProductException { + try { + if (integerValue().compareTo(JsclInteger.valueOf(1)) == 0) return new Generic[0]; + else return new Generic[]{this}; + } catch (NotIntegerException e) { + return new Generic[]{this}; + } + } + + public Power powerValue() throws NotPowerException { + return new Power(this, 1); + } + + public Expression expressionValue() throws NotExpressionException { + return Expression.valueOf(this); + } + + public JsclInteger integerValue() throws NotIntegerException { + if (denominator.compareTo(BigInteger.ONE) == 0) { + return new JsclInteger(numerator); + } else { + throw new NotIntegerException(); + } + } + + @Override + public boolean isInteger() { + try { + integerValue(); + return true; + } catch (NotIntegerException e) { + return false; + } + } + + public Variable variableValue() throws NotVariableException { + try { + integerValue(); + throw new NotVariableException(); + } catch (NotIntegerException e) { + if (numerator.compareTo(BigInteger.valueOf(1)) == 0) return new Inverse(new JsclInteger(denominator)); + else return new Fraction(new JsclInteger(numerator), new JsclInteger(denominator)); + } + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return true; + } + + public boolean isConstant(@Nonnull Variable variable) { + return true; + } + + public int compareTo(Rational rational) { + int c = denominator.compareTo(rational.denominator); + if (c < 0) return -1; + else if (c > 0) 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() { + final StringBuilder result = new StringBuilder(); + try { + result.append(integerValue()); + } catch (NotIntegerException e) { + result.append(numerator); + result.append("/"); + result.append(denominator); + } + return result.toString(); + } + + public String toJava() { + return "JsclDouble.valueOf(" + numerator + "/" + denominator + ")"; + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Set getConstants() { + return Collections.emptySet(); + } + + 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/jscl/src/main/java/jscl/math/Simplification.java b/jscl/src/main/java/jscl/math/Simplification.java new file mode 100644 index 00000000..094f8dd6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Simplification.java @@ -0,0 +1,266 @@ +package jscl.math; + +import jscl.math.function.*; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public final class Simplification { + + private final Map cache = new TreeMap(); + private final List constraints = new ArrayList(); + Generic result; + boolean linear; + + private Simplification() { + } + + public static Generic compute(@Nonnull Generic generic) { + final Simplification s = new Simplification(); + s.computeValue(generic); + return s.getValue(); + } + + void computeValue(Generic generic) { + Debug.println("simplification"); + Debug.increment(); + + final Variable t = new TechnicalVariable("t"); + linear = false; + 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).selfSimplify(); + break; +// case 2: +// int n=branch(generic,p); +// if(n 1); + } + + } catch (NotRootException e) { + result = linearConstraint(v); + } + } else if (v instanceof Root) { + try { + Root r = (Root) v; + int d = r.degree(); + int n = r.subscript().integerValue().intValue(); + + if (linear) { + result = linearConstraint(v); + } + + if (result == null) { + final Generic parameters[] = r.getParameters(); + result = new Constraint(v, Root.sigma(parameters, d - n).multiply(JsclInteger.valueOf(-1).pow(d - n)).multiply(parameters[d]).subtract(parameters[n]), d > 1); + } + } catch (NotIntegerException e) { + result = linearConstraint(v); + } + } else { + result = linearConstraint(v); + } + + if (result != null) { + constraints.add(result); + } + } + } + + @Nullable + private Constraint linearConstraint(@Nonnull Variable v) { + Generic s = cache.get(v); + if (s == null) { + 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/jscl/src/main/java/jscl/math/TechnicalVariable.java b/jscl/src/main/java/jscl/math/TechnicalVariable.java new file mode 100644 index 00000000..71ed8305 --- /dev/null +++ b/jscl/src/main/java/jscl/math/TechnicalVariable.java @@ -0,0 +1,111 @@ +package jscl.math; + +import jscl.math.function.Constant; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Set; + +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(this); + } + + @Nonnull + 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("Could not evaluate numeric value for technical variable!"); + } + + 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.length < c2.length) return -1; + else if (c1.length > c2.length) return 1; + for (int i = 0; i < c1.length; i++) { + if (c1[i] < c2[i]) return -1; + else if (c1[i] > c2[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; i < subscript.length; i++) buffer.append("[").append(subscript[i]).append("]"); + return buffer.toString(); + } + + public String toJava() { + return null; + } + + public String toMathML(Object data) { + return null; + } + + @Nonnull + public Variable newInstance() { + return new TechnicalVariable(name); + } + + @Nonnull + @Override + public Set getConstants() { + // todo serso: check + return Collections.emptySet(); + } +} diff --git a/jscl/src/main/java/jscl/math/TimeDependent.java b/jscl/src/main/java/jscl/math/TimeDependent.java new file mode 100644 index 00000000..8a123e47 --- /dev/null +++ b/jscl/src/main/java/jscl/math/TimeDependent.java @@ -0,0 +1,9 @@ +package jscl.math; + +/** + * User: serso + * Date: 12/26/11 + * Time: 10:23 AM + */ +public interface TimeDependent { +} diff --git a/jscl/src/main/java/jscl/math/Variable.java b/jscl/src/main/java/jscl/math/Variable.java new file mode 100644 index 00000000..5475f537 --- /dev/null +++ b/jscl/src/main/java/jscl/math/Variable.java @@ -0,0 +1,271 @@ +package jscl.math; + +import jscl.math.function.*; +import jscl.math.operator.Factorial; +import jscl.math.operator.Operator; +import jscl.mathml.MathML; +import jscl.text.ParseException; +import org.solovyev.common.Converter; +import org.solovyev.common.math.MathEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public abstract class Variable implements Comparable, MathEntity { + + @Nonnull + public static final Comparator comparator = VariableComparator.comparator; + protected static final Converter FACTORIZE_CONVERTER = new Converter() { + @Nonnull + @Override + public Generic convert(@Nonnull Generic generic) { + return generic.factorize(); + } + }; + protected static final Converter ELEMENTARY_CONVERTER = new Converter() { + @Nonnull + @Override + public Generic convert(@Nonnull Generic generic) { + return generic.elementary(); + } + }; + protected static final Converter EXPAND_CONVERTER = new Converter() { + @Nonnull + @Override + public Generic convert(@Nonnull Generic generic) { + return generic.expand(); + } + }; + protected static final Converter NUMERIC_CONVERTER = new Converter() { + @Nonnull + @Override + public Generic convert(@Nonnull Generic generic) { + return generic.numeric(); + } + }; + static final Map special = new HashMap(); + + static { + special.put("Alpha", "\u0391"); + special.put("Beta", "\u0392"); + special.put("Gamma", "\u0393"); + special.put("Delta", "\u0394"); + special.put("Epsilon", "\u0395"); + special.put("Zeta", "\u0396"); + special.put("Eta", "\u0397"); + special.put("Theta", "\u0398"); + special.put("Iota", "\u0399"); + special.put("Kappa", "\u039A"); + special.put("Lambda", "\u039B"); + special.put("Mu", "\u039C"); + special.put("Nu", "\u039D"); + special.put("Xi", "\u039E"); + special.put("Pi", "\u03A0"); + special.put("Rho", "\u03A1"); + special.put("Sigma", "\u03A3"); + special.put("Tau", "\u03A4"); + special.put("Upsilon", "\u03A5"); + special.put("Phi", "\u03A6"); + special.put("Chi", "\u03A7"); + special.put("Psi", "\u03A8"); + special.put("Omega", "\u03A9"); + special.put("alpha", "\u03B1"); + special.put("beta", "\u03B2"); + special.put("gamma", "\u03B3"); + special.put("delta", "\u03B4"); + special.put("epsilon", "\u03B5"); + special.put("zeta", "\u03B6"); + special.put("eta", "\u03B7"); + special.put("theta", "\u03B8"); + special.put("iota", "\u03B9"); + special.put("kappa", "\u03BA"); + special.put("lambda", "\u03BB"); + special.put("mu", "\u03BC"); + special.put("nu", "\u03BD"); + special.put("xi", "\u03BE"); + special.put("pi", "\u03C0"); + special.put("rho", "\u03C1"); + special.put("sigma", "\u03C3"); + special.put("tau", "\u03C4"); + special.put("upsilon", "\u03C5"); + special.put("phi", "\u03C6"); + special.put("chi", "\u03C7"); + special.put("psi", "\u03C8"); + special.put("omega", "\u03C9"); + special.put("infin", "\u221E"); + special.put("nabla", "\u2207"); + special.put("aleph", "\u2135"); + special.put("hbar", "\u210F"); + special.put("hamilt", "\u210B"); + special.put("lagran", "\u2112"); + special.put("square", "\u25A1"); + } + + @Nonnull + protected String name; + private Integer id; + private boolean system = true; + + public Variable(@Nonnull String name) { + this.name = name; + } + + public static Variable valueOf(String str) throws ParseException, NotVariableException { + return Expression.valueOf(str).variableValue(); + } + + public static Variable[] valueOf(String str[]) throws ParseException, NotVariableException { + int n = str.length; + Variable var[] = new Variable[n]; + for (int i = 0; i < n; i++) var[i] = valueOf(str[i]); + return var; + } + + @Nonnull + @Override + public Integer getId() { + return id; + } + + public void setId(@Nonnull Integer id) { + this.id = id; + } + + @Override + public boolean isIdDefined() { + return id != null; + } + + @Nonnull + public final String getName() { + return name; + } + + public boolean isSystem() { + return system; + } + + public void setSystem(boolean system) { + this.system = system; + } + + public void copy(@Nonnull MathEntity that) { + if (that instanceof Variable) { + this.name = ((Variable) that).name; + this.id = ((Variable) that).id; + this.system = ((Variable) that).system; + } + } + + public abstract Generic antiDerivative(Variable variable) throws NotIntegrableException; + + @Nonnull + public abstract Generic derivative(Variable variable); + + public abstract Generic substitute(Variable variable, Generic generic); + + public abstract Generic expand(); + + public abstract Generic factorize(); + + public abstract Generic elementary(); + + public abstract Generic simplify(); + + public abstract Generic numeric(); + + @Nonnull + public Expression expressionValue() { + return Expression.valueOf(this); + } + + public abstract boolean isConstant(Variable variable); + + public boolean isIdentity(@Nonnull Variable variable) { + return this.compareTo(variable) == 0; + } + + public abstract int compareTo(Variable variable); + + public int compareTo(Object o) { + return compareTo((Variable) o); + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + return obj instanceof Variable && compareTo((Variable) obj) == 0; + } + + public String toString() { + return name; + } + + public String toJava() { + return name; + } + + public void toMathML(MathML element, @Nullable Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) nameToMathML(element); + else { + MathML e1 = element.element("msup"); + nameToMathML(e1); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + protected void nameToMathML(MathML element) { + MathML e1 = element.element("mi"); + e1.appendChild(element.text(special.containsKey(name) ? special.get(name) : name)); + element.appendChild(e1); + } + + @Nonnull + public abstract Variable newInstance(); + + @Nonnull + public abstract Set getConstants(); +} + +class VariableComparator implements Comparator { + + public static final Comparator comparator = new VariableComparator(); + + private VariableComparator() { + } + + static int value(Variable v) { + int n; + if (v instanceof TechnicalVariable) n = 0; + else if (v instanceof IntegerVariable) n = 1; + else if (v instanceof DoubleVariable) n = 2; + else if (v instanceof Fraction && ((Fraction) v).integer()) n = 3; + else if (v instanceof Sqrt && ((Sqrt) v).imaginary()) n = 4; + else if (v instanceof Constant) n = 5; + else if (v instanceof Root) n = 6; + else if (v instanceof Algebraic) n = 7; + else if (v instanceof ImplicitFunction) n = 8; + else if (v instanceof Function) n = 9; + else if (v instanceof Factorial) n = 10; + else if (v instanceof Operator) n = 11; + else if (v instanceof ExpressionVariable) n = 12; + else if (v instanceof VectorVariable) n = 13; + else if (v instanceof MatrixVariable) n = 14; + else throw new ArithmeticException("Forget to add compare object of type: " + v.getClass()); + return n; + } + + public int compare(Variable o1, Variable o2) { + return value(o1) - value(o2); + } +} diff --git a/jscl/src/main/java/jscl/math/VectorVariable.java b/jscl/src/main/java/jscl/math/VectorVariable.java new file mode 100644 index 00000000..2daf3101 --- /dev/null +++ b/jscl/src/main/java/jscl/math/VectorVariable.java @@ -0,0 +1,14 @@ +package jscl.math; + +import javax.annotation.Nonnull; + +public class VectorVariable extends GenericVariable { + public VectorVariable(Generic generic) { + super(generic); + } + + @Nonnull + public Variable newInstance() { + return new VectorVariable(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Abs.java b/jscl/src/main/java/jscl/math/function/Abs.java new file mode 100644 index 00000000..5a5701f1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Abs.java @@ -0,0 +1,98 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Abs extends Function { + + public Abs(Generic generic) { + super("abs", new Generic[]{generic}); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + return Constants.Generic.HALF.multiply(parameters[0]).multiply(new Abs(parameters[0]).selfExpand()); + } + + public Generic derivative(int n) { + return new Sgn(parameters[0]).selfExpand(); + } + + public Generic selfExpand() { + if (parameters[0].signum() < 0) { + return new Abs(parameters[0].negate()).selfExpand(); + } + try { + return parameters[0].integerValue().abs(); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfElementary() { + return new Sqrt( + parameters[0].pow(2) + ).selfElementary(); + } + + public Generic selfSimplify() { + if (parameters[0].signum() < 0) { + return new Abs(parameters[0].negate()).selfSimplify(); + } + try { + return parameters[0].integerValue().abs(); + } catch (NotIntegerException e) { + } + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Abs) { + Function f = (Function) v; + return f.selfSimplify(); + } else if (v instanceof Sgn) { + return JsclInteger.valueOf(1); + } + } catch (NotVariableException e) { + } + return expressionValue(); + } + + public Generic selfNumeric() { + return parameters[0].abs(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + + result.append(parameters[0].toJava()); + result.append(".abs()"); + + return result.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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"); + e1.setAttribute("open", "|"); + e1.setAttribute("close", "|"); + parameters[0].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Abs(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/AbstractDms.java b/jscl/src/main/java/jscl/math/function/AbstractDms.java new file mode 100644 index 00000000..219707f1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/AbstractDms.java @@ -0,0 +1,103 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 11/12/11 + * Time: 3:48 PM + */ +public abstract class AbstractDms extends Algebraic { + + protected AbstractDms(@Nonnull String name, Generic degrees, Generic minutes, Generic seconds) { + super(name, new Generic[]{degrees, minutes, seconds}); + } + + @Nonnull + private static Generic[] createParameters(@Nullable Generic degrees, + @Nullable Generic minutes, + @Nullable Generic seconds) { + final Generic[] result = new Generic[3]; + + setDefaultValue(result, degrees, 0); + setDefaultValue(result, minutes, 1); + setDefaultValue(result, seconds, 2); + + return result; + } + + private static void setDefaultValue(@Nonnull Generic[] parameters, + @Nullable Generic parameter, + int position) { + if (parameter == null) { + parameters[position] = JsclInteger.valueOf(0); + } else { + parameters[position] = parameter; + } + } + + @Override + public int getMaxParameters() { + return 3; + } + + @Override + public void setParameters(@Nullable Generic[] parameters) { + super.setParameters(createParameters(getParameter(parameters, 0), getParameter(parameters, 1), getParameter(parameters, 2))); + } + + @Override + public Root rootValue() throws NotRootException { + throw new UnsupportedOperationException("Root for " + name + "() is not supported!"); + } + + @Override + void bodyToMathML(MathML element, boolean fenced) { + final MathML child = element.element(name); + parameters[0].toMathML(child, null); + // todo serso: add other parameters + element.appendChild(child); + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfElementary() { + return selfExpand(); + } + + @Override + public Generic selfSimplify() { + return selfExpand(); + } + + @Override + public Generic selfNumeric() { + Generic degrees = parameters[0]; + + if (parameters.length > 1 && parameters[1] != null) { + Generic minutes = parameters[1]; + degrees = degrees.add(minutes.divide(JsclInteger.valueOf(60))); + } + + if (parameters.length > 2 && parameters[2] != null) { + Generic seconds = parameters[2]; + degrees = degrees.add(seconds.divide(JsclInteger.valueOf(60 * 60))); + } + + return degrees; + } + + @Override + public Generic derivative(int n) { + throw new UnsupportedOperationException("Derivative for " + name + "() is not supported!"); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Algebraic.java b/jscl/src/main/java/jscl/math/function/Algebraic.java new file mode 100644 index 00000000..f6312a71 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Algebraic.java @@ -0,0 +1,33 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.NotIntegrableException; +import jscl.mathml.MathML; + +public abstract class Algebraic extends Function { + + public Algebraic(String name, Generic parameters[]) { + super(name, parameters); + } + + public abstract Root rootValue() throws NotRootException; + + public Generic antiDerivative(int n) throws NotIntegrableException { + return null; + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) bodyToMathML(element, false); + else { + MathML e1 = element.element("msup"); + bodyToMathML(e1, true); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + abstract void bodyToMathML(MathML element, boolean fenced); +} diff --git a/jscl/src/main/java/jscl/math/function/ArcTrigonometric.java b/jscl/src/main/java/jscl/math/function/ArcTrigonometric.java new file mode 100644 index 00000000..cbc40c31 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/ArcTrigonometric.java @@ -0,0 +1,19 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.NotIntegrableException; + +public abstract class ArcTrigonometric extends Function { + + public ArcTrigonometric(String name, Generic parameter[]) { + super(name, parameter); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + throw new NotIntegrableException(this); + } + + public Generic selfSimplify() { + return selfExpand(); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Comparison.java b/jscl/src/main/java/jscl/math/function/Comparison.java new file mode 100644 index 00000000..e34fb03d --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Comparison.java @@ -0,0 +1,106 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; + +public class Comparison extends Function { + + public static final List names = Arrays.asList("eq", "le", "ge", "ne", "lt", "gt", "ap"); + private static final String eass[] = {"=", "<=", ">=", "<>", "<", ">", "~"}; + private static final String easj[] = {"==", "<=", ">=", "!=", "<", ">", "=="}; + private static final String easm[] = {"=", "\u2264", "\u2265", "\u2260", "<", ">", "\u2248"}; + int operator; + + public Comparison(String name, Generic expression1, Generic expression2) { + super(name, new Generic[]{expression1, expression2}); + operator = names.indexOf(name); + if (operator < 0) { + throw new ArithmeticException(name + " comparison function doesn't exist!"); + } + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + throw new NotIntegrableException(this); + } + + public Generic derivative(int n) { + return JsclInteger.valueOf(0); + } + + public Generic selfExpand() { + try { + return compare(parameters[0].integerValue(), parameters[1].integerValue()); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfElementary() { + return expressionValue(); + } + + public Generic selfSimplify() { + return expressionValue(); + } + + public Generic selfNumeric() { + return compare((NumericWrapper) parameters[0], (NumericWrapper) parameters[1]); + } + + JsclInteger compare(JsclInteger a1, JsclInteger a2) { + return JsclInteger.valueOf(compare((Generic) a1, a2) ? 1 : 0); + } + + NumericWrapper compare(NumericWrapper a1, NumericWrapper a2) { + return new NumericWrapper(JsclInteger.valueOf(compare(a1, (Generic) a2) ? 1 : 0)); + } + + boolean compare(Generic a1, Generic a2) { + switch (operator) { + case 0: + return a1.compareTo(a2) == 0; + case 1: + return a1.compareTo(a2) <= 0; + case 2: + return a1.compareTo(a2) >= 0; + 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() { + final StringBuilder result = new StringBuilder(); + result.append(parameters[0].toJava()).append(easj[operator]).append(parameters[1].toJava()); + return result.toString(); + } + + public void toMathML(MathML element, Object data) { + parameters[0].toMathML(element, null); + MathML e1 = element.element("mo"); + e1.appendChild(element.text(easm[operator])); + element.appendChild(e1); + parameters[1].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Comparison(name, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Conjugate.java b/jscl/src/main/java/jscl/math/function/Conjugate.java new file mode 100644 index 00000000..3be810d1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Conjugate.java @@ -0,0 +1,136 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +import static jscl.math.function.Constants.Generic.I; + +public class Conjugate extends Function { + public Conjugate(Generic generic) { + super("conjugate", new Generic[]{generic}); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + return Constants.Generic.HALF.multiply(selfExpand().pow(2)); + } + + public Generic derivative(int n) { + return JsclInteger.valueOf(1); + } + + public Generic selfExpand() { + try { + return parameters[0].integerValue(); + } catch (NotIntegerException e) { + } + if (parameters[0] instanceof Matrix) { + return ((Matrix) parameters[0]).conjugate(); + } else if (parameters[0] instanceof JsclVector) { + return ((JsclVector) parameters[0]).conjugate(); + } + return expressionValue(); + } + + public Generic selfElementary() { + try { + return parameters[0].integerValue(); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfSimplify() { + try { + return parameters[0].integerValue(); + } catch (NotIntegerException e) { + } + + if (parameters[0].signum() < 0) { + return new Conjugate(parameters[0].negate()).selfSimplify().negate(); + } else if (parameters[0].compareTo(I) == 0) { + return I.negate(); + } + + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Conjugate) { + Generic g[] = ((Conjugate) v).getParameters(); + return g[0]; + } else if (v instanceof Exp) { + Generic g[] = ((Exp) v).getParameters(); + return new Exp(new Conjugate(g[0]).selfSimplify()).selfSimplify(); + } else if (v instanceof Ln) { + Generic g[] = ((Ln) v).getParameters(); + return new Ln(new Conjugate(g[0]).selfSimplify()).selfSimplify(); + } else if (v instanceof Lg) { + Generic g[] = ((Lg) v).getParameters(); + return new Lg(new Conjugate(g[0]).selfSimplify()).selfSimplify(); + } + } catch (NotVariableException e) { + Generic a[] = parameters[0].sumValue(); + if (a.length > 1) { + Generic s = JsclInteger.valueOf(0); + for (int i = 0; i < a.length; i++) { + s = s.add(new Conjugate(a[i]).selfSimplify()); + } + return s; + } else { + Generic p[] = a[0].productValue(); + Generic s = JsclInteger.valueOf(1); + for (int i = 0; i < p.length; i++) { + Power o = p[i].powerValue(); + s = s.multiply(new Conjugate(o.value()).selfSimplify().pow(o.exponent())); + } + return s; + } + } + Generic n[] = Fraction.separateCoefficient(parameters[0]); + if (n[0].compareTo(JsclInteger.valueOf(1)) == 0 && n[1].compareTo(JsclInteger.valueOf(1)) == 0) ; + else return new Conjugate(n[2]).selfSimplify().multiply( + new Fraction(n[0], n[1]).selfSimplify() + ); + return expressionValue(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).conjugate(); + } + + public String toJava() { + StringBuffer buffer = new StringBuffer(); + buffer.append(parameters[0].toJava()); + buffer.append(".conjugate()"); + 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"); + MathML e2 = element.element("mfenced"); + bodyToMathML(e2); + e1.appendChild(e2); + 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("mover"); + parameters[0].toMathML(e1, null); + MathML e2 = element.element("mo"); + e2.appendChild(element.text("_")); + e1.appendChild(e2); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Conjugate(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Constant.java b/jscl/src/main/java/jscl/math/function/Constant.java new file mode 100644 index 00000000..f291b12e --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Constant.java @@ -0,0 +1,269 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import jscl.math.*; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; +import org.solovyev.common.HashCodeBuilder; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; + +public class Constant extends Variable { + + public static final int PRIME_CHARS = 3; + private int prime; + private Generic subscripts[]; + + public Constant(String name) { + this(name, 0, new Generic[0]); + } + + public Constant(String name, int prime, Generic subscripts[]) { + super(name); + this.prime = prime; + this.subscripts = subscripts; + } + + static String primeChars(int n) { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < n; i++) buffer.append("'"); + return buffer.toString(); + } + + static String underscores(int n) { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < n; i++) buffer.append("_"); + return buffer.toString(); + } + + static void primeCharsToMathML(MathML element, int n) { + MathML e1 = element.element("mo"); + for (int i = 0; i < n; i++) e1.appendChild(element.text("\u2032")); + element.appendChild(e1); + } + + public int prime() { + return prime; + } + + public Generic[] subscript() { + return subscripts; + } + + public Generic antiDerivative(Variable variable) throws NotIntegrableException { + return null; + } + + @Nonnull + public Generic derivative(Variable variable) { + if (isIdentity(variable)) { + return JsclInteger.valueOf(1); + } else { + return JsclInteger.valueOf(0); + } + } + + public Generic substitute(Variable variable, Generic generic) { + Constant v = (Constant) newInstance(); + for (int i = 0; i < subscripts.length; i++) { + v.subscripts[i] = subscripts[i].substitute(variable, generic); + } + + if (v.isIdentity(variable)) { + return generic; + } else { + return v.expressionValue(); + } + } + + public Generic expand() { + Constant v = (Constant) newInstance(); + for (int i = 0; i < subscripts.length; i++) { + v.subscripts[i] = subscripts[i].expand(); + } + return v.expressionValue(); + } + + public Generic factorize() { + Constant v = (Constant) newInstance(); + for (int i = 0; i < subscripts.length; i++) { + v.subscripts[i] = subscripts[i].factorize(); + } + return v.expressionValue(); + } + + public Generic elementary() { + Constant v = (Constant) newInstance(); + for (int i = 0; i < subscripts.length; i++) { + v.subscripts[i] = subscripts[i].elementary(); + } + return v.expressionValue(); + } + + public Generic simplify() { + Constant v = (Constant) newInstance(); + for (int i = 0; i < subscripts.length; i++) { + v.subscripts[i] = subscripts[i].simplify(); + } + return v.expressionValue(); + } + + public Generic numeric() { + return new NumericWrapper(this); + } + + 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) { + final Constant that = (Constant) variable; + c = name.compareTo(that.name); + if (c == 0) { + c = ArrayComparator.comparator.compare(this.subscripts, that.subscripts); + if (c == 0) { + if (prime < that.prime) { + return -1; + } else if (prime > that.prime) { + return 1; + } else return 0; + } else { + return c; + } + } else { + return c; + } + } else { + return c; + } + } + + @Override + public int hashCode() { + final HashCodeBuilder result = HashCodeBuilder.newInstance(); + + result.append(Constant.class); + result.append(name); + result.append(subscripts); + result.append(prime); + + return result.toHashCode(); + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + result.append(name); + + for (Generic subscript : subscripts) { + result.append("[").append(subscript).append("]"); + } + + if (prime != 0) { + if (prime <= PRIME_CHARS) result.append(primeChars(prime)); + else result.append("{").append(prime).append("}"); + } + + return result.toString(); + } + + public String toJava() { + final IConstant constantFromRegistry = JsclMathEngine.getInstance().getConstantsRegistry().get(getName()); + + if (constantFromRegistry != null) { + return constantFromRegistry.toJava(); + } + + final StringBuilder result = new StringBuilder(); + result.append(name); + + if (prime != 0) { + if (prime <= PRIME_CHARS) result.append(underscores(prime)); + else result.append("_").append(prime); + } + + for (Generic subscript : subscripts) { + result.append("[").append(subscript.integerValue().intValue()).append("]"); + } + return result.toString(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + public void bodyToMathML(MathML element) { + if (subscripts.length == 0) { + if (prime == 0) { + nameToMathML(element); + } else { + MathML e1 = element.element("msup"); + nameToMathML(e1); + primeToMathML(e1); + element.appendChild(e1); + } + } else { + if (prime == 0) { + MathML e1 = element.element("msub"); + nameToMathML(e1); + MathML e2 = element.element("mrow"); + for (int i = 0; i < subscripts.length; i++) { + subscripts[i].toMathML(e2, null); + } + e1.appendChild(e2); + element.appendChild(e1); + } else { + MathML e1 = element.element("msubsup"); + nameToMathML(e1); + MathML e2 = element.element("mrow"); + for (int i = 0; i < subscripts.length; i++) { + subscripts[i].toMathML(e2, null); + } + e1.appendChild(e2); + primeToMathML(e1); + element.appendChild(e1); + } + } + } + + void primeToMathML(MathML element) { + if (prime <= PRIME_CHARS) { + primeCharsToMathML(element, prime); + } else { + MathML e1 = element.element("mfenced"); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(prime))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + @Nonnull + public Variable newInstance() { + return new Constant(name, prime, new Generic[subscripts.length]); + } + + @Nonnull + @Override + public Set getConstants() { + final Set result = new HashSet(); + result.add(this); + return result; + } +} diff --git a/jscl/src/main/java/jscl/math/function/Constants.java b/jscl/src/main/java/jscl/math/function/Constants.java new file mode 100644 index 00000000..6e9e23c0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Constants.java @@ -0,0 +1,45 @@ +package jscl.math.function; + +import jscl.math.JsclInteger; + +/** + * User: serso + * Date: 1/7/12 + * Time: 3:40 PM + */ +public final class Constants { + + public static final Constant PI = new Constant("Π"); + public static final Constant PI_INV = new Constant("π"); + public static final Constant I = new Constant("i"); + public static final Constant INF = new Constant("∞"); + public static final Constant INF_2 = new Constant("Infinity"); + + // not intended for instantiation + private Constants() { + throw new AssertionError(); + } + + public static class Generic { + + public static final jscl.math.Generic E = new Exp(JsclInteger.ONE).expressionValue(); + public static final jscl.math.Generic PI = Constants.PI.expressionValue(); + public static final jscl.math.Generic PI_INV = Constants.PI_INV.expressionValue(); + public static final jscl.math.Generic INF = Constants.INF.expressionValue(); + public static final jscl.math.Generic I = new Sqrt(JsclInteger.valueOf(-1)).expressionValue(); + // i * PI + public static final jscl.math.Generic I_BY_PI = I.multiply(PI_INV); + + // fraction = 1/2 + public static final jscl.math.Generic HALF = new Inverse(JsclInteger.valueOf(2)).expressionValue(); + // fraction = 1/3 + public static final jscl.math.Generic THIRD = new Inverse(JsclInteger.valueOf(3)).expressionValue(); + + // -1/2 * (1 - i * sqrt (3) ) + public static final jscl.math.Generic J = HALF.negate().multiply(JsclInteger.ONE.subtract(I.multiply(new Sqrt(JsclInteger.valueOf(3)).expressionValue()))); + + // -1/2 * (1 + i * sqrt (3) ) + public static final jscl.math.Generic J_BAR = HALF.negate().multiply(JsclInteger.ONE.add(I.multiply(new Sqrt(JsclInteger.valueOf(3)).expressionValue()))); + + } +} diff --git a/jscl/src/main/java/jscl/math/function/ConstantsRegistry.java b/jscl/src/main/java/jscl/math/function/ConstantsRegistry.java new file mode 100644 index 00000000..1b29dd75 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/ConstantsRegistry.java @@ -0,0 +1,33 @@ +package jscl.math.function; + +import org.solovyev.common.math.AbstractMathRegistry; + +/** + * User: serso + * Date: 11/7/11 + * Time: 11:59 AM + */ +public class ConstantsRegistry extends AbstractMathRegistry { + + public static final String E = "e"; + public static final String C = "c"; + public static final Double C_VALUE = 299792458d; + public static final String G = "G"; + public static final Double G_VALUE = 6.6738480E-11; + public static final String H_REDUCED = "h"; + public static final Double H_REDUCED_VALUE = 6.6260695729E-34 / (2 * Math.PI); + public final static String NAN = "NaN"; + + public ConstantsRegistry() { + this.add(new PiConstant()); + this.add(new ExtendedConstant(Constants.PI_INV, Math.PI, null)); + this.add(new ExtendedConstant(Constants.INF, Double.POSITIVE_INFINITY, "JsclDouble.valueOf(Double.POSITIVE_INFINITY)")); + this.add(new ExtendedConstant(Constants.INF_2, Double.POSITIVE_INFINITY, "JsclDouble.valueOf(Double.POSITIVE_INFINITY)")); + this.add(new ExtendedConstant(Constants.I, "√(-1)", null)); + this.add(new ExtendedConstant(new Constant(E), Math.E, null)); + this.add(new ExtendedConstant(new Constant(C), C_VALUE, null)); + this.add(new ExtendedConstant(new Constant(G), G_VALUE, null)); + this.add(new ExtendedConstant(new Constant(H_REDUCED), H_REDUCED_VALUE, null)); + this.add(new ExtendedConstant(new Constant(NAN), Double.NaN, null)); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Cubic.java b/jscl/src/main/java/jscl/math/function/Cubic.java new file mode 100644 index 00000000..b1d7c8ef --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Cubic.java @@ -0,0 +1,95 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Cubic extends Algebraic { + public Cubic(Generic generic) { + super("cubic", new Generic[]{generic}); + } + + public Root rootValue() { + return new Root( + new Generic[]{ + parameters[0].negate(), + JsclInteger.valueOf(0), + JsclInteger.valueOf(0), + JsclInteger.valueOf(1) + }, + 0 + ); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + Root r = rootValue(); + Generic g[] = r.getParameters(); + if (g[0].isPolynomial(variable)) { + return AntiDerivative.compute(r, variable); + } else throw new NotIntegrableException(this); + } + + public Generic derivative(int n) { + return Constants.Generic.THIRD.multiply( + new Inverse( + selfExpand().pow(2) + ).selfExpand() + ); + } + + public Generic selfExpand() { + try { + JsclInteger en = parameters[0].integerValue(); + if (en.signum() < 0) ; + else { + Generic rt = en.nthrt(3); + if (rt.pow(3).compareTo(en) == 0) return rt; + } + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + try { + JsclInteger en = parameters[0].integerValue(); + if (en.signum() < 0) return new Cubic(en.negate()).selfSimplify().negate(); + else { + Generic rt = en.nthrt(3); + if (rt.pow(3).compareTo(en) == 0) return rt; + } + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).nThRoot(3); + } + + public String toJava() { + StringBuffer buffer = new StringBuffer(); + buffer.append(parameters[0].toJava()); + buffer.append(".pow("); + buffer.append(Constants.Generic.THIRD.toJava()); + buffer.append(")"); + return buffer.toString(); + } + + void bodyToMathML(MathML element, boolean fenced) { + MathML e1 = element.element("mroot"); + parameters[0].toMathML(e1, null); + JsclInteger.valueOf(3).toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Cubic(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/CustomFunction.java b/jscl/src/main/java/jscl/math/function/CustomFunction.java new file mode 100644 index 00000000..fbda2ad6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/CustomFunction.java @@ -0,0 +1,333 @@ +package jscl.math.function; + +import jscl.CustomFunctionCalculationException; +import jscl.JsclMathEngine; +import jscl.math.*; +import jscl.text.ParseException; +import org.solovyev.common.JBuilder; +import org.solovyev.common.math.MathEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class CustomFunction extends Function implements IFunction { + + private static final String LOCAL_VAR_POSTFIX = "_lv_09_03_1988_"; + + private final static AtomicInteger counter = new AtomicInteger(0); + + @Nonnull + private final Integer localVarId; + @Nonnull + private Expression content; + @Nullable + private String description; + @Nonnull + private List parameterNames = Collections.emptyList(); + + private CustomFunction(@Nonnull String name, + @Nonnull List parameterNames, + @Nonnull Expression content, + @Nullable String description) { + super(name, new Generic[parameterNames.size()]); + this.parameterNames = parameterNames; + this.content = content; + this.description = description; + this.localVarId = counter.incrementAndGet(); + } + + private CustomFunction(@Nonnull String name, + @Nonnull List parameterNames, + @Nonnull String content, + @Nullable String description) { + super(name, new Generic[parameterNames.size()]); + this.parameterNames = parameterNames; + try { + this.content = Expression.valueOf(content); + } catch (ParseException e) { + throw new CustomFunctionCalculationException(this, e); + } + this.description = description; + this.localVarId = counter.incrementAndGet(); + } + + @Override + public int getMinParameters() { + return parameterNames == null ? 0 : parameterNames.size(); + } + + @Override + public int getMaxParameters() { + return parameterNames == null ? Integer.MAX_VALUE: parameterNames.size(); + } + + @Override + public Generic substitute(@Nonnull Variable variable, @Nonnull Generic generic) { + return super.substitute(variable, generic); + } + + @Override + public Generic numeric() { + return selfExpand().numeric(); + } + + @Override + public Generic expand() { + return selfExpand().expand(); + } + + @Override + public Generic elementary() { + return selfExpand().elementary(); + } + + @Override + public Generic factorize() { + return selfExpand().factorize(); + } + + @Override + public Generic selfExpand() { + Generic localContent = content; + + try { + for (String parameterName : parameterNames) { + localContent = localContent.substitute(new Constant(parameterName), Expression.valueOf(new Constant(getParameterNameForConstant(parameterName)))); + } + + for (int i = 0; i < parameterNames.size(); i++) { + localContent = localContent.substitute(new Constant(getParameterNameForConstant(parameterNames.get(i))), parameters[i]); + } + + } finally { + for (String parameterName : parameterNames) { + localContent = localContent.substitute(new Constant(getParameterNameForConstant(parameterName)), Expression.valueOf(new Constant(parameterName))); + } + } + + return localContent; + } + + @Nonnull + private String getParameterNameForConstant(@Nonnull String parameterName) { + return parameterName + LOCAL_VAR_POSTFIX + "_" + this.localVarId; + } + + @Override + public void copy(@Nonnull MathEntity mathEntity) { + super.copy(mathEntity); + if (mathEntity instanceof CustomFunction) { + final CustomFunction that = (CustomFunction) mathEntity; + this.content = that.content; + this.parameterNames = new ArrayList(that.parameterNames); + this.description = that.description; + } + } + + @Override + public Generic selfElementary() { + throw new ArithmeticException(); + } + + @Override + public Generic selfSimplify() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + throw new ArithmeticException(); + } + + @Override + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + if (getParameterForAntiDerivation(variable) < 0) { + throw new NotIntegrableException(this); + } else { + return this.content.antiDerivative(variable); + } + } + + @Override + public Generic antiDerivative(int n) throws NotIntegrableException { + throw new NotIntegrableException(this); + } + + @Nonnull + @Override + public Generic derivative(@Nonnull Variable variable) { + Generic result = JsclInteger.valueOf(0); + + for (int i = 0; i < parameters.length; i++) { + // chain rule: f(x) = g(h(x)) => f'(x) = g'(h(x)) * h'(x) + // hd = h'(x) + // gd = g'(x) + final Generic hd = parameters[i].derivative(variable); + final Generic gd = this.content.derivative(variable); + + result = result.add(hd.multiply(gd)); + } + + return result; + } + + @Override + public Generic derivative(int n) { + throw new ArithmeticException(); + } + + @Nonnull + public String getContent() { + return this.content.toString(); + } + + @Nullable + public String getDescription() { + return this.description; + } + + @Nonnull + public List getParameterNames() { + return Collections.unmodifiableList(parameterNames); + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + if (i < this.parameterNames.size()) { + return parameterNames.get(i); + } else { + return super.formatUndefinedParameter(i); + } + } + + @Nonnull + @Override + public CustomFunction newInstance() { + return new CustomFunction(name, parameterNames, content, description); + } + + public static class Builder implements JBuilder { + + private final boolean system; + + @Nonnull + private String content; + + @Nullable + private String description; + + @Nonnull + private List parameterNames; + + @Nonnull + private String name; + + @Nullable + private Integer id; + + public Builder(@Nonnull String name, + @Nonnull List parameterNames, + @Nonnull String content) { + this.system = false; + this.content = content; + this.parameterNames = parameterNames; + this.name = name; + } + + public Builder(@Nonnull IFunction function) { + this.system = function.isSystem(); + this.content = function.getContent(); + this.description = function.getDescription(); + this.parameterNames = new ArrayList(function.getParameterNames()); + this.name = function.getName(); + if (function.isIdDefined()) { + this.id = function.getId(); + } + } + + public Builder() { + this.system = false; + } + + public Builder(boolean system, + @Nonnull String name, + @Nonnull List parameterNames, + @Nonnull String content) { + this.system = system; + this.content = content; + this.parameterNames = parameterNames; + this.name = name; + } + + @Nonnull + private static String prepareContent(@Nonnull String content) { + final StringBuilder result = new StringBuilder(content.length()); + + final char groupingSeparator = JsclMathEngine.getInstance().getGroupingSeparator(); + + for (int i = 0; i < content.length(); i++) { + final char ch = content.charAt(i); + switch (ch) { + case ' ': + case '\'': + case '\n': + case '\r': + // do nothing + break; + default: + // remove grouping separator + if (ch != groupingSeparator) { + result.append(ch); + } + } + } + + return result.toString(); + } + + @Nonnull + public Builder setDescription(@Nullable String description) { + this.description = description; + return this; + } + + @Nonnull + public Builder setId(@Nonnull Integer id) { + this.id = id; + return this; + } + + @Nonnull + public Builder setContent(@Nonnull String content) { + this.content = content; + return this; + } + + @Nonnull + public Builder setParameterNames(@Nonnull List parameterNames) { + this.parameterNames = parameterNames; + return this; + } + + @Nonnull + public Builder setName(@Nonnull String name) { + this.name = name; + return this; + } + + @Nonnull + public CustomFunction create() { + final CustomFunction customFunction = new CustomFunction(name, parameterNames, prepareContent(content), description); + customFunction.setSystem(system); + if (id != null) { + customFunction.setId(id); + } + return customFunction; + } + } +} diff --git a/jscl/src/main/java/jscl/math/function/Deg.java b/jscl/src/main/java/jscl/math/function/Deg.java new file mode 100644 index 00000000..d3e9e119 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Deg.java @@ -0,0 +1,63 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.math.Generic; +import jscl.math.Variable; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 11/12/11 + * Time: 4:16 PM + */ +public class Deg extends Algebraic { + + public Deg(Generic generic) { + super("deg", new Generic[]{generic}); + } + + @Override + public Root rootValue() throws NotRootException { + throw new UnsupportedOperationException("Root for deg() is not supported!"); + } + + @Override + void bodyToMathML(MathML element, boolean fenced) { + final MathML child = element.element("deg"); + parameters[0].toMathML(child, null); + element.appendChild(child); + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfElementary() { + return selfExpand(); + } + + @Override + public Generic selfSimplify() { + return selfExpand(); + } + + @Override + public Generic selfNumeric() { + return AngleUnit.rad.transform(AngleUnit.deg, parameters[0]); + } + + @Override + public Generic derivative(int n) { + throw new UnsupportedOperationException("Derivative for deg() is not supported!"); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Deg(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Dms.java b/jscl/src/main/java/jscl/math/function/Dms.java new file mode 100644 index 00000000..0247d03f --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Dms.java @@ -0,0 +1,40 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 11/14/11 + * Time: 1:44 PM + */ +public class Dms extends AbstractDms { + + public Dms(Generic degrees, Generic minutes, Generic seconds) { + super("dms", degrees, minutes, seconds); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Dms(null, null, null); + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + switch (i) { + case 0: + return "d"; + case 1: + return "m"; + case 2: + return "s"; + default: + return super.formatUndefinedParameter(i); + + } + } +} diff --git a/jscl/src/main/java/jscl/math/function/Exp.java b/jscl/src/main/java/jscl/math/function/Exp.java new file mode 100644 index 00000000..30c1ea51 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Exp.java @@ -0,0 +1,123 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.math.polynomial.Polynomial; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Exp extends Function { + + public Exp(Generic generic) { + super("exp", new Generic[]{generic}); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + Generic s = parameters[0]; + if (s.isPolynomial(variable)) { + Polynomial p = Polynomial.factory(variable).valueOf(s); + if (p.degree() == 1) { + Generic a[] = p.elements(); + return new Inverse(a[1]).selfExpand().multiply(antiDerivative(0)); + } else throw new NotIntegrableException(this); + } else throw new NotIntegrableException(this); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + return selfExpand(); + } + + public Generic derivative(int n) { + return selfExpand(); + } + + public Generic selfExpand() { + if (parameters[0].signum() < 0) { + return new Inverse(new Exp(parameters[0].negate()).selfExpand()).selfExpand(); + } else if (parameters[0].signum() == 0) { + return JsclInteger.valueOf(1); + } + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + + if (parameters[0].signum() < 0) { + return new Inverse(new Exp(parameters[0].negate()).selfSimplify()).selfSimplify(); + } else if (parameters[0].signum() == 0) { + return JsclInteger.valueOf(1); + } else if (parameters[0].compareTo(Constants.Generic.I_BY_PI) == 0) { + return JsclInteger.valueOf(-1); + } + + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Lg) { + Generic g[] = ((Lg) v).getParameters(); + return g[0]; + } + } catch (NotVariableException e) { + Generic sumElements[] = parameters[0].sumValue(); + if (sumElements.length > 1) { + Generic result = JsclInteger.valueOf(1); + for (Generic sumElement : sumElements) { + result = result.multiply(new Exp(sumElement).selfSimplify()); + } + return result; + } + } + + Generic n[] = Fraction.separateCoefficient(parameters[0]); + if (n[0].compareTo(JsclInteger.valueOf(1)) == 0 && n[1].compareTo(JsclInteger.valueOf(1)) == 0) ; + else return new Pow( + new Exp(n[2]).selfSimplify(), + new Fraction(n[0], n[1]).selfSimplify() + ).selfSimplify(); + return expressionValue(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).exp(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? ((Integer) data).intValue() : 1; + if (exponent == 1) bodyToMathML(element, false); + else { + MathML e1 = element.element("msup"); + bodyToMathML(e1, true); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + void bodyToMathML(MathML element, boolean fenced) { + if (fenced) { + MathML e1 = element.element("mfenced"); + bodyToMathML(e1); + element.appendChild(e1); + } else { + bodyToMathML(element); + } + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("msup"); + MathML e2 = element.element("mi"); + e2.appendChild(element.text(/*"\u2147"*/"e")); + e1.appendChild(e2); + parameters[0].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Exp(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/ExtendedConstant.java b/jscl/src/main/java/jscl/math/function/ExtendedConstant.java new file mode 100644 index 00000000..433ef06d --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/ExtendedConstant.java @@ -0,0 +1,226 @@ +package jscl.math.function; + +import org.solovyev.common.JBuilder; +import org.solovyev.common.math.MathEntity; +import org.solovyev.common.text.Strings; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 11/7/11 + * Time: 12:06 PM + */ +public class ExtendedConstant implements Comparable, IConstant { + + @Nonnull + private Constant constant; + + @Nullable + private String value; + + @Nullable + private String javaString; + + @Nullable + private String description; + + ExtendedConstant() { + } + + ExtendedConstant(@Nonnull Constant constant, + @Nullable String value, + @Nullable String javaString) { + this.constant = constant; + this.value = value; + this.javaString = javaString; + } + + ExtendedConstant(@Nonnull Constant constant, + @Nullable Double value, + @Nullable String javaString) { + this.constant = constant; + this.value = value == null ? null : String.valueOf(value); + this.javaString = javaString; + } + + @Nonnull + public static String toString(@Nonnull IConstant constant) { + final Double doubleValue = constant.getDoubleValue(); + if (doubleValue == null) { + final String stringValue = constant.getValue(); + if (!Strings.isEmpty(stringValue)) { + return constant.getName() + " = " + stringValue; + } else { + return constant.getName(); + } + } else { + return constant.getName() + " = " + doubleValue; + } + } + + @Nonnull + @Override + public String getName() { + return this.constant.getName(); + } + + @Override + public boolean isSystem() { + return this.constant.isSystem(); + } + + @Nonnull + @Override + public Integer getId() { + return constant.getId(); + } + + @Override + public void setId(@Nonnull Integer id) { + constant.setId(id); + } + + @Override + public boolean isIdDefined() { + return constant.isIdDefined(); + } + + @Override + public void copy(@Nonnull MathEntity that) { + this.constant.copy(that); + + if (that instanceof IConstant) { + this.description = ((IConstant) that).getDescription(); + this.value = ((IConstant) that).getValue(); + } + + if (that instanceof ExtendedConstant) { + this.javaString = ((ExtendedConstant) that).javaString; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ExtendedConstant)) return false; + + ExtendedConstant that = (ExtendedConstant) o; + + if (!constant.equals(that.constant)) return false; + + return true; + } + + @Override + public int hashCode() { + return constant.hashCode(); + } + + @Override + @Nonnull + public Constant getConstant() { + return constant; + } + + @Override + @Nullable + public String getDescription() { + return description; + } + + @Override + public boolean isDefined() { + return value != null; + } + + @Override + @Nullable + public String getValue() { + return value; + } + + @Override + public Double getDoubleValue() { + Double result = null; + + if (value != null) { + try { + result = Double.valueOf(value); + } catch (NumberFormatException e) { + // do nothing - string is not a double + } + } + + return result; + } + + @Override + @Nonnull + public String toJava() { + if (javaString != null) { + return javaString; + } else if (value != null) { + return String.valueOf(value); + } else { + return constant.getName(); + } + } + + @Override + public String toString() { + return toString(this); + } + + @Override + public int compareTo(ExtendedConstant o) { + return this.constant.compareTo(o.getConstant()); + } + + public static final class Builder implements JBuilder { + @Nonnull + private Constant constant; + + @Nullable + private String value; + + @Nullable + private String javaString; + + @Nullable + private String description; + + public Builder(@Nonnull Constant constant, @Nullable Double value) { + this(constant, value == null ? null : String.valueOf(value)); + } + + public Builder(@Nonnull Constant constant, @Nullable String value) { + this.constant = constant; + this.value = value; + } + + public Builder setJavaString(@Nullable String javaString) { + this.javaString = javaString; + return this; + } + + public Builder setDescription(@Nullable String description) { + this.description = description; + return this; + } + + @Nonnull + @Override + public ExtendedConstant create() { + final ExtendedConstant result = new ExtendedConstant(); + + result.constant = constant; + result.value = value; + result.javaString = javaString; + result.description = description; + + return result; + } + } +} diff --git a/jscl/src/main/java/jscl/math/function/Fraction.java b/jscl/src/main/java/jscl/math/function/Fraction.java new file mode 100644 index 00000000..6388d146 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Fraction.java @@ -0,0 +1,186 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Fraction extends Algebraic { + + // fraction: n/d + // where n = numerator, + // d = denominator + public Fraction(Generic numerator, Generic denominator) { + super("frac", new Generic[]{numerator, denominator}); + } + + /** + * @param generic any generic value + * @return array of 3 elements where + * a[0] = + */ + static Generic[] separateCoefficient(@Nonnull Generic generic) { + + if (generic.signum() < 0) { + Generic n[] = separateCoefficient(generic.negate()); + return new Generic[]{n[0], n[1], n[2].negate()}; + } + + try { + final Variable v = generic.variableValue(); + if (v instanceof Fraction) { + final Generic parameters[] = ((Fraction) v).getParameters(); + + // v = n / d + + // numerator + final Generic n = parameters[0].expressionValue(); + + // denumerator + final Generic d = parameters[1].expressionValue(); + + // na = [gcd(n), n/(gcd(n))] + Generic na[] = n.gcdAndNormalize(); + // nd = [gcd(d), d/(gcd(d))] + Generic nd[] = d.gcdAndNormalize(); + return new Generic[]{na[0], nd[0], new Fraction(na[1], nd[1]).selfExpand()}; + } + } catch (NotVariableException e) { + try { + Generic a = generic.expressionValue(); + Generic n[] = a.gcdAndNormalize(); + return new Generic[]{n[0], JsclInteger.valueOf(1), n[1]}; + } catch (NotExpressionException e2) { + } + } + + return new Generic[]{JsclInteger.valueOf(1), JsclInteger.valueOf(1), generic}; + } + + @Override + public int getMinParameters() { + return 2; + } + + public Root rootValue() { + return new Root(new Generic[]{parameters[0].negate(), parameters[1]}, 0); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + if (parameters[0].isPolynomial(variable) && parameters[1].isPolynomial(variable)) { + return AntiDerivative.compute(this, variable); + } else throw new NotIntegrableException(this); + } + + public Generic derivative(int n) { + if (n == 0) { + return new Inverse(parameters[1]).selfExpand(); + } else { + return parameters[0].multiply(new Inverse(parameters[1]).selfExpand().pow(2).negate()); + } + } + + public boolean integer() { + try { + if (parameters[0] != null && parameters[1] != null) { + parameters[0].integerValue().intValue(); + parameters[1].integerValue().intValue(); + return true; + } + } catch (NotIntegerException e) { + } + return false; + } + + public Generic selfExpand() { + if (parameters[0].compareTo(JsclInteger.valueOf(1)) == 0) { + return new Inverse(parameters[1]).selfExpand(); + } + try { + return parameters[0].divide(parameters[1]); + } catch (NotDivisibleException e) { + } catch (ArithmeticException e) { + } + + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + if (parameters[0].signum() < 0) { + return new Fraction(parameters[0].negate(), parameters[1]).selfSimplify().negate(); + } + if (parameters[1].signum() < 0) { + return new Fraction(parameters[0].negate(), parameters[1].negate()).selfSimplify(); + } + return selfExpand(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).divide((NumericWrapper) parameters[1]); + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + try { + parameters[0].powerValue(); + result.append(parameters[0]); + } catch (NotPowerException e) { + result.append(GenericVariable.valueOf(parameters[0])); + } + + result.append("/"); + + try { + final Variable v = parameters[1].variableValue(); + if (v instanceof Fraction) { + result.append(GenericVariable.valueOf(parameters[1])); + } else { + result.append(v); + } + } catch (NotVariableException e) { + try { + parameters[1].abs().powerValue(); + result.append(parameters[1]); + } catch (NotPowerException e2) { + result.append(GenericVariable.valueOf(parameters[1])); + } + } + return result.toString(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + result.append(parameters[0].toJava()); + result.append(".divide("); + result.append(parameters[1].toJava()); + result.append(")"); + return result.toString(); + } + + void bodyToMathML(MathML element, boolean fenced) { + if (fenced) { + MathML e1 = element.element("mfenced"); + bodyToMathML(e1); + element.appendChild(e1); + } else { + bodyToMathML(element); + } + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mfrac"); + parameters[0].toMathML(e1, null); + parameters[1].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Fraction(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Function.java b/jscl/src/main/java/jscl/math/function/Function.java new file mode 100644 index 00000000..3592be2e --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Function.java @@ -0,0 +1,101 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegrableException; +import jscl.math.Variable; +import jscl.math.operator.AbstractFunction; +import jscl.text.ParserUtils; +import org.solovyev.common.math.MathEntity; + +import javax.annotation.Nonnull; + +public abstract class Function extends AbstractFunction { + + protected Function(String name, Generic parameters[]) { + super(name, parameters); + } + + public int getMinParameters() { + return 1; + } + + @Override + public void copy(@Nonnull MathEntity that) { + super.copy(that); + if (that instanceof Function) { + if (((Function) that).parameters != null) { + this.parameters = ParserUtils.copyOf(((Function) that).parameters); + } else { + this.parameters = null; + } + } + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + final int parameter = getParameterForAntiDerivation(variable); + + if (parameter < 0) { + throw new NotIntegrableException(this); + } else { + return antiDerivative(parameter); + } + } + + protected int getParameterForAntiDerivation(@Nonnull Variable variable) { + int result = -1; + + for (int i = 0; i < parameters.length; i++) { + if (result == -1 && parameters[i].isIdentity(variable)) { + // found! + result = i; + } else if (!parameters[i].isConstant(variable)) { + result = -1; + break; + } + } + + return result; + } + + public abstract Generic antiDerivative(int n) throws NotIntegrableException; + + @Nonnull + public Generic derivative(@Nonnull Variable variable) { + if (isIdentity(variable)) { + return JsclInteger.valueOf(1); + } else { + Generic result = JsclInteger.valueOf(0); + + for (int i = 0; i < parameters.length; i++) { + // chain rule: f(x) = g(h(x)) => f'(x) = g'(h(x)) * h'(x) + // hd = h'(x) + // gd = g'(x) + final Generic hd = parameters[i].derivative(variable); + final Generic gd = this.derivative(i); + + result = result.add(hd.multiply(gd)); + } + + return result; + } + } + + public abstract Generic derivative(int n); + + + public boolean isConstant(Variable variable) { + boolean result = !isIdentity(variable); + + if (result) { + for (Generic parameter : parameters) { + if (!parameter.isConstant(variable)) { + result = false; + break; + } + } + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/math/function/FunctionsRegistry.java b/jscl/src/main/java/jscl/math/function/FunctionsRegistry.java new file mode 100644 index 00000000..0d721b32 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/FunctionsRegistry.java @@ -0,0 +1,81 @@ +package jscl.math.function; + +import jscl.math.Variable; +import jscl.math.function.hyperbolic.*; +import jscl.math.function.trigonometric.*; +import org.solovyev.common.math.AbstractMathRegistry; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/29/11 + * Time: 12:54 PM + */ +public class FunctionsRegistry extends AbstractMathRegistry { + + private final static FunctionsRegistry instance = new FunctionsRegistry(); + + static { + instance.add(new Deg(null)); + instance.add(new Rad(null, null, null)); + instance.add(new Dms(null, null, null)); + + instance.add(new Sin(null)); + instance.add(new Cos(null)); + instance.add(new Tan(null)); + instance.add(new Cot(null)); + + instance.add(new Asin(null)); + instance.add(new Acos(null)); + instance.add(new Atan(null)); + instance.add(new Acot(null)); + + instance.add(new Ln(null)); + instance.add(new Lg(null)); + instance.add(new Exp(null)); + instance.add(new Sqrt(null)); + instance.add(new Cubic(null)); + + instance.add(new Sinh(null)); + instance.add(new Cosh(null)); + instance.add(new Tanh(null)); + instance.add(new Coth(null)); + + instance.add(new Asinh(null)); + instance.add(new Acosh(null)); + instance.add(new Atanh(null)); + instance.add(new Acoth(null)); + + instance.add(new Abs(null)); + instance.add(new Sgn(null)); + + instance.add(new Conjugate(null)); + + for (String name : Comparison.names) { + instance.add(new Comparison(name, null, null)); + } + } + + + @Nonnull + public static FunctionsRegistry getInstance() { + return instance; + } + + @Nonnull + public static T copy(@Nonnull T variable) { + final T result = (T) variable.newInstance(); + if (variable.isIdDefined()) { + result.setId(variable.getId()); + } + result.setSystem(variable.isSystem()); + return result; + } + + @Override + public Function get(@Nonnull String name) { + final Function function = super.get(name); + return function == null ? null : copy(function); + } +} diff --git a/jscl/src/main/java/jscl/math/function/IConstant.java b/jscl/src/main/java/jscl/math/function/IConstant.java new file mode 100644 index 00000000..5256cb64 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/IConstant.java @@ -0,0 +1,31 @@ +package jscl.math.function; + +import org.solovyev.common.math.MathEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 11/10/11 + * Time: 6:01 PM + */ +public interface IConstant extends MathEntity { + + @Nonnull + Constant getConstant(); + + @Nullable + String getDescription(); + + boolean isDefined(); + + @Nullable + String getValue(); + + @Nullable + Double getDoubleValue(); + + @Nonnull + String toJava(); +} diff --git a/jscl/src/main/java/jscl/math/function/IFunction.java b/jscl/src/main/java/jscl/math/function/IFunction.java new file mode 100644 index 00000000..b07e6f84 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/IFunction.java @@ -0,0 +1,21 @@ +package jscl.math.function; + +import org.solovyev.common.math.MathEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public interface IFunction extends MathEntity { + + @Nonnull + String getContent(); + + @Nullable + String getDescription(); + + String toJava(); + + @Nonnull + List getParameterNames(); +} diff --git a/jscl/src/main/java/jscl/math/function/ImplicitFunction.java b/jscl/src/main/java/jscl/math/function/ImplicitFunction.java new file mode 100644 index 00000000..8c049011 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/ImplicitFunction.java @@ -0,0 +1,273 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.NotIntegrableException; +import jscl.math.Variable; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; + +public class ImplicitFunction extends Function { + + private int derivations[]; + + private Generic subscripts[]; + + public ImplicitFunction(String name, Generic parameter[], int derivations[], Generic subscripts[]) { + super(name, parameter); + this.derivations = derivations; + this.subscripts = subscripts; + } + + 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; + else if (c1[i] > c2[i]) return 1; + } + return 0; + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + int c[] = new int[derivations.length]; + for (int i = 0; i < c.length; i++) { + if (i == n) { + if (derivations[i] > 0) c[i] = derivations[i] - 1; + else throw new NotIntegrableException(this); + } else c[i] = derivations[i]; + } + return new ImplicitFunction(name, parameters, c, subscripts).selfExpand(); + } + + public Generic derivative(int n) { + int c[] = new int[derivations.length]; + for (int i = 0; i < c.length; i++) { + if (i == n) c[i] = derivations[i] + 1; + else c[i] = derivations[i]; + } + return new ImplicitFunction(name, parameters, c, subscripts).selfExpand(); + } + + public Generic selfExpand() { + return expressionValue(); + } + + public Generic selfElementary() { + return expressionValue(); + } + + public Generic selfSimplify() { + return expressionValue(); + } + + /*@Override + public Generic numeric() { + return evaluateNumerically(); + }*/ + + public Generic selfNumeric() { + throw new ArithmeticException(); + /*Function function = FunctionsRegistry.getInstance().get(this.name); + + Generic result; + if ( function == null ) { + throw new ArithmeticException(); + } else { + function.setParameters(this.parameters); + + result = function; + for (int derivation : derivations) { + for ( int i = 0; i < derivation; i++ ) { + result = result.derivative(derivation); + } + } + + result = result.numeric(); + } + + return result;*/ + } + + public int compareTo(Variable that) { + if (this == that) return 0; + int c = comparator.compare(this, that); + if (c < 0) return -1; + else if (c > 0) return 1; + else { + ImplicitFunction v = (ImplicitFunction) that; + c = name.compareTo(v.name); + if (c < 0) return -1; + else if (c > 0) return 1; + else { + c = ArrayComparator.comparator.compare(subscripts, v.subscripts); + if (c < 0) return -1; + else if (c > 0) return 1; + else { + c = compareDerivation(derivations, v.derivations); + if (c < 0) return -1; + else if (c > 0) return 1; + else return ArrayComparator.comparator.compare(parameters, v.parameters); + } + } + } + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + int n = 0; + for (int derivation : derivations) { + n += derivation; + } + + result.append(name); + + for (Generic aSubscript : subscripts) { + result.append("[").append(aSubscript).append("]"); + } + + if (n == 0) { + // do nothing + } else if (parameters.length == 1 && n <= Constant.PRIME_CHARS) { + result.append(Constant.primeChars(n)); + } else { + result.append(derivationToString()); + } + + result.append("("); + + for (int i = 0; i < parameters.length; i++) { + result.append(parameters[i]).append(i < parameters.length - 1 ? ", " : ""); + } + + result.append(")"); + + return result.toString(); + } + + String derivationToString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("{"); + for (int i = 0; i < derivations.length; i++) { + buffer.append(derivations[i]).append(i < derivations.length - 1 ? ", " : ""); + } + buffer.append("}"); + return buffer.toString(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + + int n = 0; + for (int derivation : derivations) { + n += derivation; + } + + result.append(name); + if (n == 0) { + // do nothing + } else if (parameters.length == 1 && n <= Constant.PRIME_CHARS) { + result.append(Constant.underscores(n)); + } else { + result.append(derivationToJava()); + } + + result.append("("); + for (int i = 0; i < parameters.length; i++) { + result.append(parameters[i].toJava()).append(i < parameters.length - 1 ? ", " : ""); + } + result.append(")"); + + for (Generic subscript : subscripts) { + result.append("[").append(subscript.integerValue().intValue()).append("]"); + } + + return result.toString(); + } + + String derivationToJava() { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < derivations.length; i++) { + buffer.append("_").append(derivations[i]); + } + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + MathML e1; + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) bodyToMathML(element); + else { + e1 = element.element("msup"); + bodyToMathML(e1); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + e1 = element.element("mfenced"); + for (Generic parameter : parameters) { + parameter.toMathML(e1, null); + } + element.appendChild(e1); + } + + void bodyToMathML(MathML element) { + int n = 0; + for (int derivation : derivations) { + n += derivation; + } + + if (subscripts.length == 0) { + if (n == 0) { + nameToMathML(element); + } else { + MathML e1 = element.element("msup"); + nameToMathML(e1); + derivationToMathML(e1, n); + element.appendChild(e1); + } + } else { + if (n == 0) { + MathML e1 = element.element("msub"); + nameToMathML(e1); + MathML e2 = element.element("mrow"); + for (Generic subscript : subscripts) { + subscript.toMathML(e2, null); + } + e1.appendChild(e2); + element.appendChild(e1); + } else { + MathML e1 = element.element("msubsup"); + nameToMathML(e1); + MathML e2 = element.element("mrow"); + for (Generic subscript : subscripts) { + subscript.toMathML(e2, null); + } + e1.appendChild(e2); + derivationToMathML(e1, n); + element.appendChild(e1); + } + } + } + + void derivationToMathML(MathML element, int n) { + if (parameters.length == 1 && n <= Constant.PRIME_CHARS) { + Constant.primeCharsToMathML(element, n); + } else { + MathML e1 = element.element("mfenced"); + for (int derivation : derivations) { + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(derivation))); + e1.appendChild(e2); + } + element.appendChild(e1); + } + } + + @Nonnull + public Variable newInstance() { + return new ImplicitFunction(name, new Generic[parameters.length], derivations, subscripts); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Inverse.java b/jscl/src/main/java/jscl/math/function/Inverse.java new file mode 100644 index 00000000..963dd286 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Inverse.java @@ -0,0 +1,43 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotDivisibleException; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +public class Inverse extends Fraction { + + // inverse function: 1/g + public Inverse(Generic generic) { + super(JsclInteger.valueOf(1), generic); + } + + public Generic selfExpand() { + try { + Generic parameter = parameter(); + /*try { + if (JsclInteger.ZERO.equals(parameter.integerValue())) { + throw new ArithmeticException("Division by 0!"); + } + } catch (NotIntegerException e) { + // ok + }*/ + + return JsclInteger.ONE.divide(parameter); + } catch (NotDivisibleException e) { + } + + return expressionValue(); + } + + public Generic parameter() { + return parameters[1]; + } + + @Nonnull + public Variable newInstance() { + return new Inverse(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Lg.java b/jscl/src/main/java/jscl/math/function/Lg.java new file mode 100644 index 00000000..a015f626 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Lg.java @@ -0,0 +1,86 @@ +package jscl.math.function; + +import jscl.math.*; + +import javax.annotation.Nonnull; + +import static jscl.math.JsclInteger.ONE; +import static jscl.math.JsclInteger.ZERO; + +public class Lg extends Function { + + public Lg(Generic generic) { + super("lg", new Generic[]{generic}); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + // tmp = ln(x) - 1 + final Generic tmp = new Ln(parameters[0]).expressionValue().subtract(ONE); + + // ln10 = ln (10) + final Generic ln10 = new Ln(JsclInteger.valueOf(10L)).expressionValue(); + return new Fraction(parameters[0].multiply(tmp), ln10).expressionValue(); + } + + public Generic derivative(int n) { + return new Inverse(parameters[0].multiply(new Ln(JsclInteger.valueOf(10L)).expressionValue())).expressionValue(); + } + + public Generic selfExpand() { + if (parameters[0].compareTo(JsclInteger.valueOf(1)) == 0) { + return JsclInteger.valueOf(0); + } + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + + Generic coefficents[] = Fraction.separateCoefficient(parameters[0]); + final Generic a = coefficents[0]; + final Generic b = coefficents[1]; + final Generic c = coefficents[2]; + + final boolean aOne = a.compareTo(ONE) == 0; + final boolean bOne = b.compareTo(ONE) == 0; + final boolean cOne = c.compareTo(ONE) == 0; + + if (aOne && bOne && cOne) { + return ZERO; + } else { + if (aOne && bOne) { + return expressionValue(); + } else if (bOne && cOne) { + return expressionValue(); + } else { + // lg ( a * c / b ) = lg ( c ) + lg( a ) - lg (b) + final Generic lga = lg(a, aOne); + final Generic lgb = lg(b, bOne); + final Generic lgc = lg(c, cOne); + return lgc.add(lga).subtract(lgb); + } + } + } + + private Generic lg(Generic a, boolean aOne) { + Generic lga; + if (aOne) { + lga = ZERO; + } else { + lga = new Lg(a).selfSimplify(); + } + return lga; + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).lg(); + } + + @Nonnull + public Variable newInstance() { + return new Lg(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Ln.java b/jscl/src/main/java/jscl/math/function/Ln.java new file mode 100644 index 00000000..00e6454e --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Ln.java @@ -0,0 +1,75 @@ +package jscl.math.function; + +import jscl.math.*; + +import javax.annotation.Nonnull; + +public class Ln extends Function { + + public Ln(Generic generic) { + super("ln", new Generic[]{generic}); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + return parameters[0].multiply(new Ln(parameters[0]).selfExpand().subtract(JsclInteger.ONE)); + } + + public Generic derivative(int n) { + return new Inverse(parameters[0]).selfExpand(); + } + + public Generic selfExpand() { + if (parameters[0].compareTo(JsclInteger.valueOf(1)) == 0) { + return JsclInteger.valueOf(0); + } + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + try { + JsclInteger en = parameters[0].integerValue(); + if (en.signum() < 0) { + return Constants.Generic.I_BY_PI.add(new Ln(en.negate()).selfSimplify()); + } else { + Generic a = en.factorize(); + Generic p[] = a.productValue(); + Generic s = JsclInteger.valueOf(0); + for (int i = 0; i < p.length; i++) { + Power o = p[i].powerValue(); + s = s.add(JsclInteger.valueOf(o.exponent()).multiply(new Ln(o.value(true)).expressionValue())); + } + return s; + } + } catch (NotIntegerException e) { + } + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Sqrt) { + Generic g[] = ((Sqrt) v).getParameters(); + return Constants.Generic.HALF.multiply(new Ln(g[0]).selfSimplify()); + } + } catch (NotVariableException e) { + } + Generic n[] = Fraction.separateCoefficient(parameters[0]); + if (n[0].compareTo(JsclInteger.valueOf(1)) == 0 && n[1].compareTo(JsclInteger.valueOf(1)) == 0) ; + else return new Ln(n[2]).selfSimplify().add( + new Ln(n[0]).selfSimplify() + ).subtract( + new Ln(n[1]).selfSimplify() + ); + return expressionValue(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).ln(); + } + + @Nonnull + public Variable newInstance() { + return new Ln(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/NotRootException.java b/jscl/src/main/java/jscl/math/function/NotRootException.java new file mode 100644 index 00000000..e1cbf489 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/NotRootException.java @@ -0,0 +1,10 @@ +package jscl.math.function; + +public class NotRootException extends ArithmeticException { + public NotRootException() { + } + + public NotRootException(String s) { + super(s); + } +} diff --git a/jscl/src/main/java/jscl/math/function/PiConstant.java b/jscl/src/main/java/jscl/math/function/PiConstant.java new file mode 100644 index 00000000..aceba566 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/PiConstant.java @@ -0,0 +1,29 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; + +/** + * User: serso + * Date: 11/29/11 + * Time: 11:28 AM + */ +public class PiConstant extends ExtendedConstant { + + public PiConstant() { + super(Constants.PI, Math.PI, "JsclDouble.valueOf(Math.PI)"); + } + + @Override + public Double getDoubleValue() { + Double result = null; + + try { + result = AngleUnit.rad.transform(JsclMathEngine.getInstance().getAngleUnits(), Double.valueOf(getValue())); + } catch (NumberFormatException e) { + // do nothing - string is not a double + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/math/function/PostfixFunctionsRegistry.java b/jscl/src/main/java/jscl/math/function/PostfixFunctionsRegistry.java new file mode 100644 index 00000000..7439e7f5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/PostfixFunctionsRegistry.java @@ -0,0 +1,43 @@ +package jscl.math.function; + +import jscl.math.Generic; +import jscl.math.operator.*; +import org.solovyev.common.math.AbstractMathRegistry; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/31/11 + * Time: 10:56 PM + */ +public class PostfixFunctionsRegistry extends AbstractMathRegistry { + + private final static PostfixFunctionsRegistry instance = new PostfixFunctionsRegistry(); + + static { + instance.add(new DoubleFactorial(null)); + instance.add(new Factorial(null)); + instance.add(new Degree(null)); + instance.add(new Percent(null, null)); + } + + @Nonnull + public static PostfixFunctionsRegistry getInstance() { + return instance; + } + + @Nullable + public Operator get(@Nonnull String name, @Nonnull Generic[] parameters) { + final Operator operator = super.get(name); + return operator == null ? null : operator.newInstance(parameters); + } + + @Override + public Operator get(@Nonnull String name) { + final Operator operator = super.get(name); + return operator == null ? null : FunctionsRegistry.copy(operator); + } + +} diff --git a/jscl/src/main/java/jscl/math/function/Pow.java b/jscl/src/main/java/jscl/math/function/Pow.java new file mode 100644 index 00000000..197f097d --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Pow.java @@ -0,0 +1,289 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +import static jscl.math.JsclInteger.ONE; +import static jscl.math.JsclInteger.ZERO; + +public class Pow extends Algebraic { + + private static final int MAX_ARRAY_SIZE = 10000; + + public Pow(Generic generic, Generic exponent) { + super("pow", new Generic[]{generic, exponent}); + } + + static Generic root_minus_1(int d) { + switch (d) { + case 1: + return JsclInteger.valueOf(-1); + case 2: + return Constants.Generic.I; + case 3: + return Constants.Generic.J_BAR.negate(); + case 4: + return new Sqrt(Constants.Generic.HALF).expressionValue().multiply(JsclInteger.valueOf(1).add(Constants.Generic.I)); + case 6: + return Constants.Generic.HALF.multiply(new Sqrt(JsclInteger.valueOf(3)).expressionValue().add(Constants.Generic.I)); + default: + return null; + } + } + + @Override + public int getMinParameters() { + return 2; + } + + public Root rootValue() throws NotRootException { + try { + Variable v = parameters[1].variableValue(); + if (v instanceof Inverse) { + Generic g = ((Inverse) v).parameter(); + try { + int d = g.integerValue().intValue(); + if (d > 0 && d < MAX_ARRAY_SIZE) { + Generic a[] = new Generic[d + 1]; + a[0] = parameters[0].negate(); + for (int i = 1; i < d; i++) { + a[i] = ZERO; + } + a[d] = ONE; + return new Root(a, 0); + } + } catch (NotIntegerException e) { + } + } + } catch (NotVariableException e) { + } + throw new NotRootException(); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + try { + Root r = rootValue(); + Generic g[] = r.getParameters(); + if (g[0].isPolynomial(variable)) { + return AntiDerivative.compute(r, variable); + } else throw new NotIntegrableException(this); + } catch (NotRootException e) { + } + return super.antiDerivative(variable); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + if (n == 0) { + return new Pow(parameters[0], parameters[1].add(JsclInteger.valueOf(1))).selfExpand().multiply(new Inverse(parameters[1].add(JsclInteger.valueOf(1))).selfExpand()); + } else { + return new Pow(parameters[0], parameters[1]).selfExpand().multiply(new Inverse(new Ln(parameters[0]).selfExpand()).selfExpand()); + } + } + + public Generic derivative(int n) { + if (n == 0) { + return new Pow(parameters[0], parameters[1].subtract(JsclInteger.valueOf(1))).selfExpand().multiply(parameters[1]); + } else { + return new Pow(parameters[0], parameters[1]).selfExpand().multiply(new Ln(parameters[0]).selfExpand()); + } + } + + public Generic selfExpand() { + if (parameters[0].compareTo(JsclInteger.valueOf(1)) == 0) { + return JsclInteger.valueOf(1); + } + if (parameters[1].signum() < 0) { + return new Pow(new Inverse(parameters[0]).selfExpand(), parameters[1].negate()).selfExpand(); + } + try { + int c = parameters[1].integerValue().intValue(); + return parameters[0].pow(c); + } catch (NotIntegerException e) { + } + try { + Root r = rootValue(); + int d = r.degree(); + Generic g[] = r.getParameters(); + Generic a = g[0].negate(); + try { + JsclInteger en = a.integerValue(); + if (en.signum() < 0) ; + else { + Generic rt = en.nthrt(d); + if (rt.pow(d).compareTo(en) == 0) return rt; + } + } catch (NotIntegerException e) { + } + } catch (NotRootException e) { + } + return expressionValue(); + } + + public Generic selfElementary() { + return new Exp( + new Ln( + parameters[0] + ).selfElementary().multiply( + parameters[1] + ) + ).selfElementary(); + } + + public Generic selfSimplify() { + // a ^ b + + // a = 1 => for any b: 1 ^ b = 1 + if (parameters[0].compareTo(ONE) == 0) { + return JsclInteger.valueOf(1); + } + + // b < 0 => a ^ b = (1 / a) ^ (-b) + if (parameters[1].signum() < 0) { + return new Pow(new Inverse(parameters[0]).selfSimplify(), parameters[1].negate()).selfSimplify(); + } + + try { + // if b is integer => just calculate the result + int intPower = parameters[1].integerValue().intValue(); + return parameters[0].pow(intPower); + } catch (NotIntegerException e) { + } + + try { + Root r = rootValue(); + int d = r.degree(); + Generic g[] = r.getParameters(); + Generic a = g[0].negate(); + try { + JsclInteger en = a.integerValue(); + if (en.signum() < 0) ; + else { + Generic rt = en.nthrt(d); + if (rt.pow(d).compareTo(en) == 0) return rt; + } + } catch (NotIntegerException e) { + } + switch (d) { + case 2: + return new Sqrt(a).selfSimplify(); + case 3: + case 4: + case 6: + if (a.compareTo(JsclInteger.valueOf(-1)) == 0) return root_minus_1(d); + } + } catch (NotRootException e) { + Generic n[] = Fraction.separateCoefficient(parameters[1]); + if (n[0].compareTo(ONE) == 0 && n[1].compareTo(ONE) == 0) { + // do nothing + } else { + return new Pow( + new Pow( + new Pow( + parameters[0], + n[2] + ).selfSimplify(), + new Inverse( + n[1] + ).selfSimplify() + ).selfSimplify(), + n[0] + ).selfSimplify(); + } + } + return expressionValue(); + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).pow((NumericWrapper) parameters[1]); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + try { + JsclInteger en = parameters[0].integerValue(); + if (en.signum() < 0) buffer.append(GenericVariable.valueOf(en, true)); + else buffer.append(en); + } catch (NotIntegerException e) { + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Fraction || v instanceof Pow) { + buffer.append(GenericVariable.valueOf(parameters[0])); + } else buffer.append(v); + } catch (NotVariableException e2) { + try { + Power o = parameters[0].powerValue(); + if (o.exponent() == 1) buffer.append(o.value(true)); + else buffer.append(GenericVariable.valueOf(parameters[0])); + } catch (NotPowerException e3) { + buffer.append(GenericVariable.valueOf(parameters[0])); + } + } + } + buffer.append("^"); + try { + JsclInteger en = parameters[1].integerValue(); + buffer.append(en); + } catch (NotIntegerException e) { + try { + Variable v = parameters[1].variableValue(); + if (v instanceof Fraction) { + buffer.append(GenericVariable.valueOf(parameters[1])); + } else buffer.append(v); + } catch (NotVariableException e2) { + try { + parameters[1].powerValue(); + buffer.append(parameters[1]); + } catch (NotPowerException e3) { + buffer.append(GenericVariable.valueOf(parameters[1])); + } + } + } + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer = new StringBuffer(); + buffer.append(parameters[0].toJava()); + buffer.append(".pow("); + buffer.append(parameters[1].toJava()); + buffer.append(")"); + return buffer.toString(); + } + + void bodyToMathML(MathML element, boolean fenced) { + if (fenced) { + MathML e1 = element.element("mfenced"); + bodyToMathML(e1); + element.appendChild(e1); + } else { + bodyToMathML(element); + } + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("msup"); + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Fraction || v instanceof Pow || v instanceof Exp) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } else parameters[0].toMathML(e1, null); + } catch (NotVariableException e2) { + try { + Power o = parameters[0].powerValue(); + if (o.exponent() == 1) o.value(true).toMathML(e1, null); + else GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } catch (NotPowerException e3) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } + } + parameters[1].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Pow(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Rad.java b/jscl/src/main/java/jscl/math/function/Rad.java new file mode 100644 index 00000000..e7884a5a --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Rad.java @@ -0,0 +1,30 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 11/14/11 + * Time: 1:40 PM + */ +public class Rad extends AbstractDms { + + public Rad(Generic degrees, Generic minutes, Generic seconds) { + super("rad", degrees, minutes, seconds); + } + + @Override + public Generic selfNumeric() { + return AngleUnit.deg.transform(AngleUnit.rad, super.selfNumeric()); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Rad(null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Root.java b/jscl/src/main/java/jscl/math/function/Root.java new file mode 100644 index 00000000..5678bfaa --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Root.java @@ -0,0 +1,419 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; + +public class Root extends Algebraic { + + protected Generic subscript; + + public Root(Generic parameters[], Generic subscript) { + super("root", parameters); + this.subscript = subscript; + } + + public Root(Generic parameters[], int s) { + this(parameters, JsclInteger.valueOf(s)); + } + + public Root(@Nonnull UnivariatePolynomial polynomial, int s) { + this(polynomial.normalize().elements(), s); + } + + static Generic nth(Generic parameter[]) { + int degree = parameter.length - 1; + Generic a = new Fraction(parameter[0], parameter[degree]).selfSimplify(); + return new Pow( + a.negate(), + new Inverse(JsclInteger.valueOf(degree)).selfSimplify() + ).selfSimplify(); + } + + static Generic linear(Generic parameter[]) { + Generic a = new Fraction(parameter[0], parameter[1]).selfSimplify(); + return a.negate(); + } + + static Generic quadratic(Generic parameter[], int subscript) { + Generic a = new Fraction(parameter[1], parameter[2]).selfSimplify(); + Generic b = new Fraction(parameter[0], parameter[2]).selfSimplify(); + Generic y = new Sqrt( + a.pow(2).subtract(JsclInteger.valueOf(4).multiply(b)) + ).selfSimplify(); + switch (subscript) { + case 0: + return new Fraction( + a.subtract(y), + JsclInteger.valueOf(2) + ).selfSimplify().negate(); + default: + return new Fraction( + a.add(y), + JsclInteger.valueOf(2) + ).selfSimplify().negate(); + } + } + + static Generic cubic(Generic parameter[], int subscript) { + Generic a = new Fraction(parameter[2], parameter[3]).selfSimplify(); + Generic b = new Fraction(parameter[1], parameter[3]).selfSimplify(); + Generic c = new Fraction(parameter[0], parameter[3]).selfSimplify(); + Generic y[] = new Generic[2]; + for (int i = 0; i < y.length; i++) { + y[i] = new Cubic( + new Root( + new Generic[]{ + a.pow(6).subtract(JsclInteger.valueOf(9).multiply(a.pow(4)).multiply(b)).add(JsclInteger.valueOf(27).multiply(a.pow(2)).multiply(b.pow(2))).subtract(JsclInteger.valueOf(27).multiply(b.pow(3))), + JsclInteger.valueOf(2).multiply(a.pow(3)).subtract(JsclInteger.valueOf(9).multiply(a).multiply(b)).add(JsclInteger.valueOf(27).multiply(c)), + JsclInteger.valueOf(1) + }, + i + ).selfSimplify() + ).selfSimplify(); + } + switch (subscript) { + case 0: + return new Fraction( + a.subtract(y[0]).subtract(y[1]), + JsclInteger.valueOf(3) + ).selfSimplify().negate(); + case 1: + return new Fraction( + a.subtract(Constants.Generic.J.multiply(y[0])).subtract(Constants.Generic.J_BAR.multiply(y[1])), + JsclInteger.valueOf(3) + ).selfSimplify().negate(); + default: + return new Fraction( + a.subtract(Constants.Generic.J_BAR.multiply(y[0])).subtract(Constants.Generic.J.multiply(y[1])), + JsclInteger.valueOf(3) + ).selfSimplify().negate(); + } + } + + static Generic quartic(Generic parameter[], int subscript) { + Generic a = new Fraction(parameter[3], parameter[4]).selfSimplify(); + Generic b = new Fraction(parameter[2], parameter[4]).selfSimplify(); + Generic c = new Fraction(parameter[1], parameter[4]).selfSimplify(); + Generic d = new Fraction(parameter[0], parameter[4]).selfSimplify(); + Generic y[] = new Generic[3]; + for (int i = 0; i < y.length; i++) { + y[i] = new Sqrt( + new Root( + new Generic[]{ + a.pow(6).subtract(JsclInteger.valueOf(8).multiply(a.pow(4)).multiply(b)).add(JsclInteger.valueOf(16).multiply(a.pow(2)).multiply(b.pow(2))).add(JsclInteger.valueOf(16).multiply(a.pow(3)).multiply(c)).subtract(JsclInteger.valueOf(64).multiply(a).multiply(b).multiply(c)).add(JsclInteger.valueOf(64).multiply(c.pow(2))), + JsclInteger.valueOf(-3).multiply(a.pow(4)).add(JsclInteger.valueOf(16).multiply(a.pow(2)).multiply(b)).subtract(JsclInteger.valueOf(16).multiply(b.pow(2))).subtract(JsclInteger.valueOf(16).multiply(a).multiply(c)).add(JsclInteger.valueOf(64).multiply(d)), + JsclInteger.valueOf(3).multiply(a.pow(2)).subtract(JsclInteger.valueOf(8).multiply(b)), + JsclInteger.valueOf(-1) + }, + i + ).selfSimplify() + ).selfSimplify(); + } + switch (subscript) { + case 0: + return new Fraction( + a.add(y[0]).subtract(y[1]).subtract(y[2]), + JsclInteger.valueOf(4) + ).selfSimplify().negate(); + case 1: + return new Fraction( + a.subtract(y[0]).subtract(y[1]).add(y[2]), + JsclInteger.valueOf(4) + ).selfSimplify().negate(); + case 2: + return new Fraction( + a.add(y[0]).add(y[1]).add(y[2]), + JsclInteger.valueOf(4) + ).selfSimplify().negate(); + default: + return new Fraction( + a.subtract(y[0]).add(y[1]).subtract(y[2]), + JsclInteger.valueOf(4) + ).selfSimplify().negate(); + } + } + + public static Generic sigma(Generic parameter[], int n) { + Sigma s = new Sigma(parameter, n); + s.compute(); + return s.getValue(); + } + + @Override + public int getMaxParameters() { + return Integer.MAX_VALUE; + } + + public Generic subscript() { + return subscript; + } + + public Root rootValue() { + return this; + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + boolean polynomial = true; + for (Generic parameter : parameters) { + polynomial = parameter.isPolynomial(variable); + if (!polynomial) { + break; + } + } + + if (polynomial) { + return AntiDerivative.compute(this, variable); + } else { + throw new NotIntegrableException(this); + } + } + + @Nonnull + public Generic derivative(@Nonnull Variable variable) { + if (compareTo(variable) == 0) { + return JsclInteger.valueOf(1); + } else { + Variable t = new TechnicalVariable("t"); + Generic a[] = new Generic[parameters.length]; + for (int i = 0; i < parameters.length; i++) a[i] = parameters[i].derivative(variable); + UnivariatePolynomial fact = (UnivariatePolynomial) Polynomial.factory(this); + UnivariatePolynomial p = fact.valueof(parameters); + UnivariatePolynomial q = (UnivariatePolynomial) p.derivative().multiply(t.expressionValue()).add(fact.valueof(a)); + UnivariatePolynomial r = (UnivariatePolynomial) Polynomial.factory(t).valueOf(p.resultant(q)); + return new Root(r.elements(), subscript).selfExpand(); + } + } + + public Generic derivative(int n) { + return null; + } + + public Generic substitute(@Nonnull Variable variable, @Nonnull Generic generic) { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].substitute(variable, generic); + } + v.subscript = subscript.substitute(variable, generic); + if (v.isIdentity(variable)) return generic; + else return v.selfExpand(); + } + + public Generic expand() { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].expand(); + } + v.subscript = subscript.expand(); + return v.selfExpand(); + } + + public Generic factorize() { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].factorize(); + } + v.subscript = subscript; + return v.expressionValue(); + } + + public Generic elementary() { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].elementary(); + } + v.subscript = subscript.elementary(); + return v.selfElementary(); + } + + public Generic simplify() { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].simplify(); + } + v.subscript = subscript.simplify(); + return v.selfSimplify(); + } + + public Generic numeric() { + Root v = (Root) newInstance(); + for (int i = 0; i < parameters.length; i++) { + v.parameters[i] = parameters[i].numeric(); + } + v.subscript = subscript; + return v.selfNumeric(); + } + + public Generic selfExpand() { + if (isZero()) return JsclInteger.valueOf(0); + try { + int s = subscript.integerValue().intValue(); + switch (degree()) { + case 1: + return new Fraction(parameters[0], parameters[1]).selfExpand().negate(); + } + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + if (isZero()) return JsclInteger.valueOf(0); + try { + int s = subscript.integerValue().intValue(); + switch (degree()) { + case 1: + return linear(parameters); + case 2: + return quadratic(parameters, s); + case 3: + return cubic(parameters, s); + case 4: + return quartic(parameters, s); + default: + if (isNth() && s == 0) return nth(parameters); + } + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + boolean isZero() { + boolean b = degree() > 0; + for (int i = 0; i < degree(); i++) b = b && parameters[i].signum() == 0; + b = b && parameters[degree()].signum() != 0; + return b; + } + + boolean isNth() { + boolean b = degree() > 0; + for (int i = 1; i < degree(); i++) b = b && parameters[i].signum() == 0; + b = b && parameters[degree()].signum() != 0; + return b; + } + + public int degree() { + return parameters.length - 1; + } + + public Generic selfNumeric() { + return NumericWrapper.root(subscript.integerValue().intValue(), parameters); + } + + public int compareTo(Variable that) { + if (this == that) return 0; + int c = comparator.compare(this, that); + if (c < 0) return -1; + else if (c > 0) return 1; + else { + Root v = (Root) that; + c = ArrayComparator.comparator.compare(parameters, v.parameters); + if (c < 0) return -1; + else if (c > 0) return 1; + else return subscript.compareTo(v.subscript); + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(name); + buffer.append("[").append(subscript).append("]"); + buffer.append("("); + for (int i = 0; i < parameters.length; i++) { + buffer.append(parameters[i]).append(i < parameters.length - 1 ? ", " : ""); + } + buffer.append(")"); + return buffer.toString(); + } + + public String toJava() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Numeric.").append(name).append("("); + buffer.append(subscript.integerValue().intValue()); + buffer.append(", new Numeric[] {"); + for (int i = 0; i < parameters.length; i++) { + buffer.append(parameters[i].toJava()).append(i < parameters.length - 1 ? ", " : ""); + } + buffer.append("})"); + return buffer.toString(); + } + + public void toMathML(MathML element, Object data) { + MathML e1; + int exponent = data instanceof Integer ? ((Integer) data).intValue() : 1; + if (exponent == 1) { + e1 = element.element("msub"); + nameToMathML(e1); + subscript.toMathML(e1, null); + element.appendChild(e1); + } else { + e1 = element.element("msubsup"); + nameToMathML(e1); + subscript.toMathML(e1, null); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + e1 = element.element("mfenced"); + for (int i = 0; i < parameters.length; i++) { + parameters[i].toMathML(e1, null); + } + element.appendChild(e1); + } + + void bodyToMathML(MathML element, boolean fenced) { + } + + @Nonnull + public Variable newInstance() { + return new Root(new Generic[parameters.length], null); + } +} + +class Sigma { + Generic root[]; + Generic generic; + boolean place[]; + int n; + + Sigma(Generic parameter[], int n) { + root = new Generic[parameter.length - 1]; + for (int i = 0; i < root.length; i++) root[i] = new Root(parameter, i).expressionValue(); + place = new boolean[root.length]; + this.n = n; + } + + void compute() { + generic = JsclInteger.valueOf(0); + compute(0, n); + } + + void compute(int p, int nn) { + if (nn > 0) { + for (int i = p; i < root.length; i++) { + place[i] = true; + compute(i + 1, nn - 1); + place[i] = false; + } + } else { + Generic s = JsclInteger.valueOf(1); + for (int i = 0; i < root.length; i++) { + if (place[i]) s = s.multiply(root[i]); + } + generic = generic.add(s); + } + } + + Generic getValue() { + return generic; + } +} diff --git a/jscl/src/main/java/jscl/math/function/Sgn.java b/jscl/src/main/java/jscl/math/function/Sgn.java new file mode 100644 index 00000000..d32a4815 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Sgn.java @@ -0,0 +1,94 @@ +package jscl.math.function; + +import jscl.math.*; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class Sgn extends Function { + + public Sgn(Generic generic) { + super("sgn", new Generic[]{generic}); + } + + public Generic antiDerivative(int n) throws NotIntegrableException { + return new Abs(parameters[0]).selfExpand(); + } + + public Generic derivative(int n) { + return JsclInteger.valueOf(0); + } + + public Generic selfExpand() { + final Generic result = selfEvaluate(); + + if (result == null) { + return expressionValue(); + } else { + return result; + } + + } + + @Nullable + private Generic selfEvaluate() { + Generic result = null; + + if (parameters[0].signum() < 0) { + result = new Sgn(parameters[0].negate()).selfExpand().negate(); + } else if (parameters[0].signum() == 0) { + result = JsclInteger.valueOf(0); + } + + if (result == null) { + try { + result = JsclInteger.valueOf(parameters[0].integerValue().signum()); + } catch (NotIntegerException e) { + } + } + + return result; + } + + public Generic selfElementary() { + return new Fraction(parameters[0], new Abs(parameters[0]).selfElementary()).selfElementary(); + } + + public Generic selfSimplify() { + final Generic result = selfEvaluate(); + + if (result == null) { + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Abs) { + return JsclInteger.valueOf(1); + } else if (v instanceof Sgn) { + Function f = (Function) v; + return f.selfSimplify(); + } + } catch (NotVariableException e) { + } + + return expressionValue(); + } else { + return result; + } + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).sgn(); + } + + public String toJava() { + final StringBuilder result = new StringBuilder(); + + result.append(parameters[0].toJava()); + result.append(".sgn()"); + return result.toString(); + } + + @Nonnull + public Variable newInstance() { + return new Sgn(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Sqrt.java b/jscl/src/main/java/jscl/math/function/Sqrt.java new file mode 100644 index 00000000..5c23b6ab --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Sqrt.java @@ -0,0 +1,179 @@ +package jscl.math.function; + +import jscl.math.*; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class Sqrt extends Algebraic { + + public Sqrt(Generic parameter) { + super("√", new Generic[]{parameter}); + } + + public Root rootValue() { + return new Root(new Generic[]{parameters[0].negate(), JsclInteger.valueOf(0), JsclInteger.valueOf(1)}, 0); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + Root r = rootValue(); + Generic g[] = r.getParameters(); + if (g[0].isPolynomial(variable)) { + return AntiDerivative.compute(r, variable); + } else { + throw new NotIntegrableException(this); + } + } + + public Generic derivative(int n) { + return Constants.Generic.HALF.multiply(new Inverse(selfExpand()).selfExpand()); + } + + public boolean imaginary() { + return parameters[0] != null && parameters[0].compareTo(JsclInteger.valueOf(-1)) == 0; + } + + public Generic selfExpand() { + Generic result; + + try { + final JsclInteger p = parameters[0].integerValue(); + if (p.signum() < 0) { + // result will be complex => evaluate + result = expressionValue(); + } else { + final Generic sqrt = p.sqrt(); + if (sqrt.pow(2).compareTo(p) == 0) { + result = sqrt; + } else { + result = expressionValue(); + } + } + } catch (NotIntegerException e) { + result = expressionValue(); + } + + return result; + } + + public Generic selfElementary() { + return selfExpand(); + } + + public Generic selfSimplify() { + Generic result = null; + try { + final JsclInteger p = parameters[0].integerValue(); + if (p.signum() < 0) { + return Constants.Generic.I.multiply(new Sqrt(p.negate()).selfSimplify()); + } else { + final Generic sqrt = p.sqrt(); + if (sqrt.pow(2).compareTo(p) == 0) { + return sqrt; + } + } + result = simplify0(p); + } catch (NotIntegerException e) { + result = simplify0(parameters[0]); + } + + if (result == null) { + return expressionValue(); + } else { + return result; + } + } + + @Nullable + private Generic simplifyFractions() { + final Generic n[] = Fraction.separateCoefficient(parameters[0]); + + if (n[0].compareTo(JsclInteger.valueOf(1)) != 0 || n[1].compareTo(JsclInteger.valueOf(1)) != 0) { + // n + final Generic numerator = new Sqrt(n[0]).selfSimplify(); + // d + final Generic denominator = new Sqrt(n[1]).selfSimplify(); + // fraction = n / d + final Generic fraction = new Fraction(numerator, denominator).selfSimplify(); + return new Sqrt(n[2]).selfSimplify().multiply(fraction); + } + + return null; + } + + @Nullable + private Generic simplify0(@Nonnull Generic generic) { + Generic result; + + try { + // let's try to present sqrt expression as products + final Generic products[] = generic.factorize().productValue(); + + result = JsclInteger.valueOf(1); + for (Generic product : products) { + // and try sqrt for each product + final Power power = product.powerValue(); + Generic q = power.value(true); + int c = power.exponent(); + result = result.multiply(q.pow(c / 2).multiply(new Sqrt(q).expressionValue().pow(c % 2))); + } + } catch (NotPowerException e) { + result = simplifyFractions(); + } catch (NotProductException e) { + result = simplifyFractions(); + } + + return result; + } + + public Generic selfNumeric() { + return ((NumericWrapper) parameters[0]).sqrt(); + } + + public String toJava() { + if (parameters[0].compareTo(JsclInteger.valueOf(-1)) == 0) { + return "Complex.valueOf(0, 1)"; + } else { + final StringBuilder result = new StringBuilder(); + result.append(parameters[0].toJava()); + result.append(".").append(name).append("()"); + return result.toString(); + } + } + + @Override + public String toString() { + final Generic parameter = parameters[0]; + if (parameter != null) { + try { + if (JsclInteger.ONE.negate().equals(parameter.integerValue())) { + return Constants.I.getName(); + } else { + return super.toString(); + } + } catch (NotIntegerException e) { + return super.toString(); + } + } else { + return super.toString(); + } + } + + void bodyToMathML(MathML element, boolean fenced) { + if (parameters[0].compareTo(JsclInteger.valueOf(-1)) == 0) { + MathML e1 = element.element("mi"); + e1.appendChild(element.text(/*"\u2148"*/"i")); + element.appendChild(e1); + } else { + MathML e1 = element.element("msqrt"); + parameters[0].toMathML(e1, null); + element.appendChild(e1); + } + } + + @Nonnull + public Variable newInstance() { + return new Sqrt(null); + } +} diff --git a/jscl/src/main/java/jscl/math/function/Trigonometric.java b/jscl/src/main/java/jscl/math/function/Trigonometric.java new file mode 100644 index 00000000..955510c5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/function/Trigonometric.java @@ -0,0 +1,55 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Generic; +import jscl.math.NotIntegrableException; +import jscl.math.Variable; +import jscl.math.polynomial.Polynomial; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +public abstract class Trigonometric extends Function { + + public Trigonometric(String name, Generic parameter[]) { + super(name, parameter); + } + + public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException { + if (JsclMathEngine.getInstance().getAngleUnits() != AngleUnit.rad) { + throw new NotIntegrableException(Messages.msg_20, getName()); + } + + final Generic parameter = parameters[0]; + if (parameter.isPolynomial(variable)) { + final Polynomial polynomial = Polynomial.factory(variable).valueOf(parameter); + if (polynomial.degree() == 1) { + final Generic elements[] = polynomial.elements(); + return new Inverse(elements[1]).selfExpand().multiply(antiDerivative(0)); + } else { + throw new NotIntegrableException(this); + } + } else { + throw new NotIntegrableException(this); + } + } + + public Generic identity() { +// Generic a[]=parameter[0].sumValue(); +// if(a.length>1) { +// Generic s=JsclInteger.valueOf(0); +// for(int i=1;i .0) { + result = 1; + } else if (real < .0) { + result = -1; + } else { + result = Real.signum(imaginary); + } + + return result; + } + + public double magnitude() { + return Math.sqrt(real * real + imaginary * imaginary); + } + + public double magnitude2() { + return real * real + imaginary * imaginary; + } + + public double angle() { + return Math.atan2(imaginary, real); + } + + @Nonnull + public Numeric ln() { + if (signum() == 0) { + return Real.ZERO.ln(); + } else { + return valueOf(Math.log(magnitude()), angle()); + } + } + + @Nonnull + public Numeric lg() { + if (signum() == 0) { + return Real.ZERO.lg(); + } else { + return valueOf(Math.log10(magnitude()), angle()); + } + } + + @Nonnull + public Numeric exp() { + return valueOf(Math.cos(defaultToRad(imaginary)), Math.sin(defaultToRad(imaginary))).multiply(Math.exp(real)); + } + + @Nonnull + public Numeric inverse() { + return ((Complex) conjugate()).divide(magnitude2()); + } + + Complex multiply(double d) { + return valueOf(real * d, imaginary * d); + } + + Complex divide(double d) { + return valueOf(real / d, imaginary / d); + } + + public Numeric conjugate() { + return valueOf(real, -imaginary); + } + + public double realPart() { + return real; + } + + public double imaginaryPart() { + return imaginary; + } + + public int compareTo(Complex that) { + if (imaginary < that.imaginary) { + return -1; + } else if (imaginary > that.imaginary) { + return 1; + } else if (imaginary == that.imaginary) { + if (real < that.real) { + return -1; + } else if (real > that.real) { + return 1; + } else if (real == that.real) { + return 0; + } else throw new ArithmeticException(); + } else throw new ArithmeticException(); + } + + public int compareTo(Numeric that) { + if (that instanceof Complex) { + return compareTo((Complex) that); + } else if (that instanceof Real) { + return compareTo(valueOf(that)); + } else { + return that.valueOf(this).compareTo(that); + } + } + + public Complex copyOf(@Nonnull Complex complex) { + return valueOf(complex.real, complex.imaginary); + } + + @Nonnull + public Numeric valueOf(@Nonnull Numeric numeric) { + if (numeric instanceof Complex) { + return copyOf((Complex) numeric); + } else if (numeric instanceof Real) { + Real d = (Real) numeric; + return d.toComplex(); + } else throw new ArithmeticException(); + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + if (imaginary == 0.) { + result.append(toString(real)); + } else { + if (real != 0.) { + result.append(toString(real)); + if (imaginary > 0.) { + result.append("+"); + } + } + + if (imaginary != 1.) { + if (imaginary == -1.) { + result.append("-"); + } else { + if (imaginary < 0.) { + final String imagStr = toString(imaginary); + // due to rounding we can forget sign (-0.00000000001 can be round to 0 => plus sign would not be added above and no sign will be before i) + if (imagStr.startsWith("-")) { + result.append(imagStr); + } else { + result.append("-").append(imagStr); + } + } else { + result.append(toString(imaginary)); + } + result.append("*"); + } + } + result.append("i"); + } + + return result.toString(); + } +} diff --git a/jscl/src/main/java/jscl/math/numeric/INumeric.java b/jscl/src/main/java/jscl/math/numeric/INumeric.java new file mode 100644 index 00000000..f860279e --- /dev/null +++ b/jscl/src/main/java/jscl/math/numeric/INumeric.java @@ -0,0 +1,114 @@ +package jscl.math.numeric; + +import javax.annotation.Nonnull; + +public interface INumeric> { + + @Nonnull + T pow(int exponent); + + @Nonnull + T abs(); + + @Nonnull + T negate(); + + int signum(); + + @Nonnull + T sgn(); + + @Nonnull + T ln(); + + @Nonnull + T lg(); + + @Nonnull + T exp(); + + @Nonnull + T inverse(); + + @Nonnull + T sqrt(); + + @Nonnull + T nThRoot(int n); + + /* + * ****************************************************************************************** + *

+ * TRIGONOMETRIC FUNCTIONS + *

+ * *******************************************************************************************/ + + @Nonnull + T sin(); + + @Nonnull + T cos(); + + @Nonnull + T tan(); + + @Nonnull + T cot(); + + /* + * ****************************************************************************************** + *

+ * INVERSE TRIGONOMETRIC FUNCTIONS + *

+ * *******************************************************************************************/ + + @Nonnull + T asin(); + + @Nonnull + T acos(); + + @Nonnull + T atan(); + + @Nonnull + T acot(); + + /* + * ****************************************************************************************** + *

+ * HYPERBOLIC TRIGONOMETRIC FUNCTIONS + *

+ * *******************************************************************************************/ + + @Nonnull + T sinh(); + + @Nonnull + T cosh(); + + @Nonnull + T tanh(); + + @Nonnull + T coth(); + + /* + * ****************************************************************************************** + *

+ * INVERSE HYPERBOLIC TRIGONOMETRIC FUNCTIONS + *

+ * *******************************************************************************************/ + + @Nonnull + T asinh(); + + @Nonnull + T acosh(); + + @Nonnull + T atanh(); + + @Nonnull + T acoth(); +} diff --git a/jscl/src/main/java/jscl/math/numeric/Matrix.java b/jscl/src/main/java/jscl/math/numeric/Matrix.java new file mode 100644 index 00000000..a9390e49 --- /dev/null +++ b/jscl/src/main/java/jscl/math/numeric/Matrix.java @@ -0,0 +1,312 @@ +package jscl.math.numeric; + +import jscl.math.NotDivisibleException; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; + +public class Matrix extends Numeric { + + @Nonnull + private final Numeric m[][]; + + private final int rows, cols; + + public Matrix(@Nonnull Numeric m[][]) { + this.m = m; + rows = m.length; + cols = m.length > 0 ? m[0].length : 0; + } + + public static Matrix identity(int dimension) { + return identity(dimension, dimension); + } + + public static Matrix identity(int n, int p) { + Matrix m = new Matrix(new Numeric[n][p]); + for (int i = 0; i < n; i++) { + for (int j = 0; j < p; j++) { + if (i == j) { + m.m[i][j] = Real.ONE; + } else { + m.m[i][j] = Real.ZERO; + } + } + } + return m; + } + + public Numeric[][] elements() { + return m; + } + + public Matrix add(Matrix matrix) { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].add(matrix.m[i][j]); + } + } + return m; + } + + @Nonnull + public Numeric add(@Nonnull Numeric that) { + if (that instanceof Matrix) { + return add((Matrix) that); + } else { + return add(valueOf(that)); + } + } + + public Matrix subtract(Matrix matrix) { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].subtract(matrix.m[i][j]); + } + } + return m; + } + + @Nonnull + public Numeric subtract(@Nonnull Numeric that) { + if (that instanceof Matrix) { + return subtract((Matrix) that); + } else { + return subtract(valueOf(that)); + } + } + + public Matrix multiply(Matrix matrix) { + if (cols != matrix.rows) throw new ArithmeticException(); + Matrix m = newInstance(new Numeric[rows][matrix.cols]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < matrix.cols; j++) { + m.m[i][j] = Real.ZERO; + for (int k = 0; k < cols; k++) { + m.m[i][j] = m.m[i][j].add(this.m[i][k].multiply(matrix.m[k][j])); + } + } + } + return m; + } + + @Nonnull + public Numeric multiply(@Nonnull Numeric that) { + if (that instanceof Matrix) { + return multiply((Matrix) that); + } else if (that instanceof Vector) { + Vector v = ((Vector) that).newInstance(new Numeric[rows]); + Vector v2 = (Vector) that; + if (cols != v2.n) throw new ArithmeticException(); + for (int i = 0; i < rows; i++) { + v.element[i] = Real.ZERO; + for (int k = 0; k < cols; k++) { + v.element[i] = v.element[i].add(m[i][k].multiply(v2.element[k])); + } + } + return v; + } else { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].multiply(that); + } + } + return m; + } + } + + @Nonnull + public Numeric divide(@Nonnull Numeric that) throws NotDivisibleException { + + if (that instanceof Matrix) { + return multiply(that.inverse()); + } else if (that instanceof Vector) { + throw new ArithmeticException(); + } else { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].divide(that); + } + } + return m; + } + + } + + @Nonnull + public Numeric negate() { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].negate(); + } + } + return m; + } + + public int signum() { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + int c = m[i][j].signum(); + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } + } + } + + return 0; + } + + @Nonnull + public Numeric valueOf(@Nonnull Numeric numeric) { + if (numeric instanceof Matrix || numeric instanceof Vector) { + throw new ArithmeticException(); + } else { + Matrix m = (Matrix) identity(rows, cols).multiply(numeric); + return newInstance(m.m); + } + } + + public Numeric[] vectors() { + Vector v[] = new Vector[rows]; + for (int i = 0; i < rows; i++) { + v[i] = new Vector(new Numeric[cols]); + for (int j = 0; j < cols; j++) { + v[i].element[j] = m[i][j]; + } + } + return v; + } + + public Numeric transpose() { + Matrix m = newInstance(new Numeric[cols][rows]); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[j][i] = this.m[i][j]; + } + } + return m; + } + + public Numeric trace() { + Numeric s = Real.ZERO; + for (int i = 0; i < rows; i++) { + s = s.add(m[i][i]); + } + return s; + } + + @Nonnull + public Numeric inverse() { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + m.m[i][j] = inverseElement(i, j); + } + } + return m.transpose().divide(determinant()); + } + + Numeric inverseElement(int k, int l) { + final Matrix result = newInstance(); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + if (i == k) { + result.m[i][j] = Real.valueOf(j == l ? 1 : 0); + } else { + result.m[i][j] = this.m[i][j]; + } + } + } + + return result.determinant(); + } + + public Numeric determinant() { + if (rows > 1) { + Numeric a = Real.ZERO; + for (int i = 0; i < rows; i++) { + if (m[i][0].signum() != 0) { + Matrix m = newInstance(new Numeric[rows - 1][rows - 1]); + for (int j = 0; j < rows - 1; j++) { + for (int k = 0; k < rows - 1; k++) m.m[j][k] = this.m[j < i ? j : j + 1][k + 1]; + } + if (i % 2 == 0) { + a = a.add(this.m[i][0].multiply(m.determinant())); + } else { + a = a.subtract(this.m[i][0].multiply(m.determinant())); + } + } + } + return a; + } else if (rows > 0) return m[0][0]; + else return Real.ZERO; + } + + @Nonnull + public Numeric ln() { + throw new ArithmeticException(); + } + + @Nonnull + @Override + public Numeric lg() { + throw new ArithmeticException(); + } + + @Nonnull + public Numeric exp() { + throw new ArithmeticException(); + } + + public Numeric conjugate() { + Matrix m = newInstance(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + m.m[i][j] = this.m[i][j].conjugate(); + } + } + return m; + } + + public int compareTo(Matrix matrix) { + return ArrayComparator.comparator.compare(vectors(), matrix.vectors()); + } + + public int compareTo(Numeric numeric) { + if (numeric instanceof Matrix) { + return compareTo((Matrix) numeric); + } else { + return compareTo(valueOf(numeric)); + } + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + result.append("{"); + for (int i = 0; i < rows; i++) { + result.append("{"); + for (int j = 0; j < cols; j++) { + result.append(m[i][j]).append(j < cols - 1 ? ", " : ""); + } + result.append("}").append(i < rows - 1 ? ",\n" : ""); + } + result.append("}"); + return result.toString(); + } + + protected Matrix newInstance() { + return newInstance(new Numeric[rows][cols]); + } + + protected Matrix newInstance(Numeric element[][]) { + return new Matrix(element); + } +} diff --git a/jscl/src/main/java/jscl/math/numeric/Numeric.java b/jscl/src/main/java/jscl/math/numeric/Numeric.java new file mode 100644 index 00000000..0b9a02e2 --- /dev/null +++ b/jscl/src/main/java/jscl/math/numeric/Numeric.java @@ -0,0 +1,328 @@ +package jscl.math.numeric; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Arithmetic; + +import javax.annotation.Nonnull; + +import static jscl.math.numeric.Complex.I; +import static jscl.math.numeric.Real.ONE; +import static jscl.math.numeric.Real.TWO; + +public abstract class Numeric implements Arithmetic, INumeric, Comparable { + + /*@Nonnull + public Numeric subtract(@Nonnull Numeric numeric) { + return add(numeric.negate()); + }*/ + + public static Numeric root(int subscript, Numeric parameter[]) { + throw new ArithmeticException(); + } + + protected static double defaultToRad(double value) { + return JsclMathEngine.getInstance().getAngleUnits().transform(AngleUnit.rad, value); + } + + protected static double radToDefault(double value) { + return AngleUnit.rad.transform(JsclMathEngine.getInstance().getAngleUnits(), value); + } + + @Nonnull + protected static Numeric defaultToRad(@Nonnull Numeric value) { + return JsclMathEngine.getInstance().getAngleUnits().transform(AngleUnit.rad, value); + } + + @Nonnull + protected static Numeric radToDefault(@Nonnull Numeric value) { + return AngleUnit.rad.transform(JsclMathEngine.getInstance().getAngleUnits(), value); + } + + @Override + @Nonnull + public Numeric abs() { + return signum() < 0 ? negate() : this; + } + + @Nonnull + @Override + public Numeric sgn() { + return divide(abs()); + } + + @Nonnull + @Override + public Numeric inverse() { + return ONE.divide(this); + } + + @Override + @Nonnull + public Numeric pow(int exponent) { + Numeric result = ONE; + + for (int i = 0; i < exponent; i++) { + result = result.multiply(this); + } + + return result; + } + + /* + * ****************************************************************************************** + *

+ * CONVERSION FUNCTIONS (rad to default angle units and vice versa) + *

+ * ******************************************************************************************* + */ + + public Numeric pow(@Nonnull Numeric numeric) { + if (numeric.signum() == 0) { + return ONE; + } else if (numeric.compareTo(ONE) == 0) { + return this; + } else { + return numeric.multiply(this.ln()).exp(); + } + } + + @Nonnull + @Override + public Numeric sqrt() { + return nThRoot(2); + } + + @Nonnull + @Override + public Numeric nThRoot(int n) { + return pow(Real.valueOf(1. / n)); + } + + public abstract Numeric conjugate(); + + /* + * ****************************************************************************************** + *

+ * TRIGONOMETRIC FUNCTIONS + *

+ * ******************************************************************************************* + */ + + @Nonnull + @Override + public Numeric sin() { + // e = exp(i) + final Numeric e = defaultToRad(this).multiply(I).exp(); + // e1 = exp(2ix) + final Numeric e1 = e.pow(2); + + // result = [i - i * exp(2i)] / [2exp(i)] + return I.subtract(e1.multiply(I)).divide(TWO.multiply(e)); + } + + @Nonnull + @Override + public Numeric cos() { + // e = exp(ix) + final Numeric e = defaultToRad(this).multiply(I).exp(); + // e1 = exp(2ix) + final Numeric e1 = e.pow(2); + + // result = [ 1 + exp(2ix) ] / (2 *exp(ix)) + return ONE.add(e1).divide(TWO.multiply(e)); + } + + @Nonnull + @Override + public Numeric tan() { + // e = exp(2xi) + final Numeric e = defaultToRad(this).multiply(I).exp().pow(2); + + // e1 = i * exp(2xi) + final Numeric e1 = e.multiply(I); + + // result = (i - i * exp(2xi)) / ( 1 + exp(2xi) ) + return I.subtract(e1).divide(ONE.add(e)); + } + + @Nonnull + @Override + public Numeric cot() { + // e = exp(2xi) + final Numeric e = I.multiply(defaultToRad(this)).exp().pow(2); + + // result = - (i + i * exp(2ix)) / ( 1 - exp(2xi)) + return I.add(I.multiply(e)).divide(ONE.subtract(e)).negate(); + } + + /** + * ****************************************************************************************** + *

+ * INVERSE TRIGONOMETRIC FUNCTIONS + *

+ * ******************************************************************************************* + */ + + @Nonnull + @Override + public Numeric asin() { + // e = √(1 - x^2) + final Numeric e = ONE.subtract(this.pow(2)).sqrt(); + // result = -iln[xi + √(1 - x^2)] + return radToDefault(this.multiply(I).add(e).ln().multiply(I.negate())); + } + + @Nonnull + @Override + public Numeric acos() { + // e = √(-1 + x^2) = i √(1 - x^2) + final Numeric e = I.multiply(Real.ONE.subtract(this.pow(2)).sqrt()); + + // result = -i * ln[ x + √(-1 + x^2) ] + return radToDefault(this.add(e).ln().multiply(I.negate())); + } + + @Nonnull + @Override + public Numeric atan() { + // e = ln[(i + x)/(i-x)] + final Numeric e = I.add(this).divide(I.subtract(this)).ln(); + // result = iln[(i + x)/(i-x)]/2 + return radToDefault(I.multiply(e).divide(TWO)); + } + + @Nonnull + @Override + public Numeric acot() { + // e = ln[-(i + x)/(i-x)] + final Numeric e = I.add(this).divide(I.subtract(this)).negate().ln(); + // result = iln[-(i + x)/(i-x)]/2 + return radToDefault(I.multiply(e).divide(TWO)); + } + + /** + * ****************************************************************************************** + *

+ * HYPERBOLIC TRIGONOMETRIC FUNCTIONS + *

+ * ******************************************************************************************* + */ + + @Nonnull + @Override + public Numeric sinh() { + final Numeric thisRad = defaultToRad(this); + + // e = exp(2x) + final Numeric e = thisRad.exp().pow(2); + + // e1 = 2exp(x) + final Numeric e1 = TWO.multiply(thisRad.exp()); + + // result = -[1 - exp(2x)]/[2exp(x)] + return ONE.subtract(e).divide(e1).negate(); + } + + @Nonnull + @Override + public Numeric cosh() { + final Numeric thisExpRad = defaultToRad(this).exp(); + + // e = exp(2x) + final Numeric e = thisExpRad.pow(2); + + // e1 = 2exp(x) + final Numeric e1 = TWO.multiply(thisExpRad); + + // result = [ 1 + exp(2x )] / 2exp(x) + return ONE.add(e).divide(e1); + } + + + @Nonnull + @Override + public Numeric tanh() { + // e = exp(2x) + final Numeric e = defaultToRad(this).exp().pow(2); + + // result = - (1 - exp(2x)) / (1 + exp(2x)) + return ONE.subtract(e).divide(ONE.add(e)).negate(); + } + + @Nonnull + @Override + public Numeric coth() { + // e = exp(2x) + final Numeric e = defaultToRad(this).exp().pow(2); + + // result = - (1 + exp(2x)) / (1 - exp(2x)) + return ONE.add(e).divide(ONE.subtract(e)).negate(); + } + + /** + * ****************************************************************************************** + *

+ * INVERSE HYPERBOLIC TRIGONOMETRIC FUNCTIONS + *

+ * ******************************************************************************************* + */ + + @Nonnull + @Override + public Numeric asinh() { + // e = √( 1 + x ^ 2 ) + final Numeric e = ONE.add(this.pow(2)).sqrt(); + + // result = ln [ x + √( 1 + x ^ 2 ) ] + return radToDefault(this.add(e).ln()); + } + + @Nonnull + @Override + public Numeric acosh() { + // e = √(x ^ 2 - 1) + final Numeric e = Real.valueOf(-1).add(this.pow(2)).sqrt(); + + // result = ln( x + √(x ^ 2 - 1) ) + return radToDefault(this.add(e).ln()); + } + + @Nonnull + @Override + public Numeric atanh() { + // e = 1 - x + final Numeric e = ONE.subtract(this); + + // result = ln [ ( 1 + x ) / ( 1 - x ) ] / 2 + return radToDefault(ONE.add(this).divide(e).ln().divide(TWO)); + } + + @Nonnull + @Override + public Numeric acoth() { + // e = 1 - x + final Numeric e = ONE.subtract(this); + + // result = ln [ - (1 + x) / (1 - x) ] / 2 + return radToDefault(ONE.add(this).divide(e).negate().ln().divide(TWO)); + } + + @Nonnull + public abstract Numeric valueOf(@Nonnull Numeric numeric); + + public abstract int compareTo(Numeric numeric); + + public int compareTo(Object o) { + return compareTo((Numeric) o); + } + + public boolean equals(Object obj) { + return obj instanceof Numeric && compareTo((Numeric) obj) == 0; + } + + @Nonnull + protected String toString(final double value) { + return JsclMathEngine.getInstance().format(value, JsclMathEngine.getInstance().getNumeralBase()); + } +} diff --git a/jscl/src/main/java/jscl/math/numeric/Real.java b/jscl/src/main/java/jscl/math/numeric/Real.java new file mode 100644 index 00000000..eb408992 --- /dev/null +++ b/jscl/src/main/java/jscl/math/numeric/Real.java @@ -0,0 +1,280 @@ +package jscl.math.numeric; + +import jscl.math.NotDivisibleException; + +import javax.annotation.Nonnull; + +public final class Real extends Numeric { + + public static final Real ZERO = new Real(0d); + public static final Real ONE = new Real(1d); + public static final Real TWO = new Real(2d); + private final static Real PI_DIV_BY_2_RAD = Real.valueOf(Math.PI).divide(TWO); + private final static Double PI_DIV_BY_2_RAD_DOUBLE = Math.PI / 2; + private final double content; + + Real(double val) { + content = val; + } + + public static int signum(double value) { + return value == 0. ? 0 : (value < 0. ? -1 : 1); + } + + public static Real valueOf(double value) { + if (value == 0d) { + return ZERO; + } else if (value == 1d) { + return ONE; + } else if (value == 2d) { + return TWO; + } else { + return new Real(value); + } + } + + public Real add(@Nonnull Real that) { + return new Real(content + that.content); + } + + @Nonnull + public Numeric add(@Nonnull Numeric that) { + if (that instanceof Real) { + return add((Real) that); + } else { + return that.valueOf(this).add(that); + } + } + + public Real subtract(Real that) { + return new Real(content - that.content); + } + + @Nonnull + public Numeric subtract(@Nonnull Numeric that) { + if (that instanceof Real) { + return subtract((Real) that); + } else { + return that.valueOf(this).subtract(that); + } + } + + public Real multiply(Real that) { + return new Real(content * that.content); + } + + @Nonnull + public Numeric multiply(@Nonnull Numeric that) { + if (that instanceof Real) { + return multiply((Real) that); + } else { + return that.multiply(this); + } + } + + public Real divide(Real that) throws ArithmeticException { + return new Real(content / that.content); + } + + @Nonnull + public Numeric divide(@Nonnull Numeric that) throws NotDivisibleException { + if (that instanceof Real) { + return divide((Real) that); + } else { + return that.valueOf(this).divide(that); + } + } + + @Nonnull + public Numeric negate() { + return new Real(-content); + } + + public int signum() { + return signum(content); + } + + @Nonnull + public Numeric ln() { + if (signum() >= 0) { + return new Real(Math.log(content)); + } else { + return Complex.valueOf(Math.log(-content), Math.PI); + } + } + + @Nonnull + public Numeric lg() { + if (signum() >= 0) { + return new Real(Math.log10(content)); + } else { + return Complex.valueOf(Math.log10(-content), Math.PI); + } + } + + @Nonnull + public Numeric exp() { + return new Real(Math.exp(content)); + } + + @Nonnull + public Numeric inverse() { + return new Real(1. / content); + } + + public Numeric pow(Real that) { + if (signum() < 0) { + return Complex.valueOf(content, 0).pow(that); + } else { + return new Real(Math.pow(content, that.content)); + } + } + + public Numeric pow(@Nonnull Numeric numeric) { + if (numeric instanceof Real) { + return pow((Real) numeric); + } else { + return numeric.valueOf(this).pow(numeric); + } + } + + @Nonnull + public Numeric sqrt() { + if (signum() < 0) { + return Complex.I.multiply(negate().sqrt()); + } else { + return new Real(Math.sqrt(content)); + } + } + + @Nonnull + public Numeric nThRoot(int n) { + if (signum() < 0) { + return n % 2 == 0 ? sqrt().nThRoot(n / 2) : negate().nThRoot(n).negate(); + } else { + return super.nThRoot(n); + } + } + + public Numeric conjugate() { + return this; + } + + @Nonnull + public Numeric acos() { + final Real result = new Real(radToDefault(Math.acos(content))); + if (Double.isNaN(result.content)) { + return super.acos(); + } + return result; + } + + @Nonnull + public Numeric asin() { + final Real result = new Real(radToDefault(Math.asin(content))); + if (Double.isNaN(result.content)) { + return super.asin(); + } + return result; + } + + @Nonnull + public Numeric atan() { + final Real result = new Real(radToDefault(atanRad())); + if (Double.isNaN(result.content)) { + return super.atan(); + } + return result; + } + + @Nonnull + private Double atanRad() { + return Math.atan(content); + } + + @Nonnull + @Override + public Numeric acot() { + final Real result = new Real(radToDefault(PI_DIV_BY_2_RAD_DOUBLE - atanRad())); + if (Double.isNaN(result.content)) { + return super.acot(); + } + return result; + } + + @Nonnull + public Numeric cos() { + return new Real(Math.cos(defaultToRad(content))); + } + + @Nonnull + public Numeric sin() { + return new Real(Math.sin(defaultToRad(content))); + } + + @Nonnull + public Numeric tan() { + return new Real(tan(defaultToRad(content))); + } + + private double tan(double value) { + if (value > Math.PI || value < Math.PI) { + value = value % Math.PI; + } + if (value == Math.PI / 2) { + return Double.POSITIVE_INFINITY; + } + if (value == Math.PI) { + return 0; + } + if (value == -Math.PI / 2) { + return Double.NEGATIVE_INFINITY; + } + if (value == -Math.PI) { + return 0; + } + return Math.tan(value); + } + + @Nonnull + @Override + public Numeric cot() { + return Real.ONE.divide(tan()); + } + + public Real valueOf(Real value) { + return new Real(value.content); + } + + @Nonnull + public Numeric valueOf(@Nonnull Numeric numeric) { + if (numeric instanceof Real) { + return valueOf((Real) numeric); + } else throw new ArithmeticException(); + } + + public double doubleValue() { + return content; + } + + public int compareTo(@Nonnull Real that) { + return Double.compare(this.content, that.content); + } + + public int compareTo(Numeric numeric) { + if (numeric instanceof Real) { + return compareTo((Real) numeric); + } else { + return numeric.valueOf(this).compareTo(numeric); + } + } + + public String toString() { + return toString(content); + } + + @Nonnull + public Complex toComplex() { + return Complex.valueOf(this.content, 0.); + } +} diff --git a/jscl/src/main/java/jscl/math/numeric/Vector.java b/jscl/src/main/java/jscl/math/numeric/Vector.java new file mode 100644 index 00000000..9c5becf0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/numeric/Vector.java @@ -0,0 +1,189 @@ +package jscl.math.numeric; + +import jscl.math.NotDivisibleException; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; + +public class Vector extends Numeric { + + protected final Numeric element[]; + protected final int n; + + public Vector(Numeric element[]) { + this.element = element; + n = element.length; + } + + public static Vector unity(int dimension) { + Vector v = new Vector(new Numeric[dimension]); + for (int i = 0; i < v.n; i++) { + if (i == 0) v.element[i] = Real.ONE; + else v.element[i] = Real.ZERO; + } + return v; + } + + public Numeric[] elements() { + return element; + } + + public Vector add(Vector vector) { + Vector v = newInstance(); + for (int i = 0; i < n; i++) v.element[i] = element[i].add(vector.element[i]); + return v; + } + + @Nonnull + public Numeric add(@Nonnull Numeric that) { + if (that instanceof Vector) { + return add((Vector) that); + } else { + return add(valueOf(that)); + } + } + + public Vector subtract(Vector vector) { + Vector v = newInstance(); + for (int i = 0; i < n; i++) { + v.element[i] = element[i].subtract(vector.element[i]); + } + return v; + } + + @Nonnull + public Numeric subtract(@Nonnull Numeric that) { + if (that instanceof Vector) { + return subtract((Vector) that); + } else { + return subtract(valueOf(that)); + } + } + + @Nonnull + public Numeric multiply(@Nonnull Numeric that) { + if (that instanceof Vector) { + return scalarProduct((Vector) that); + } else if (that instanceof Matrix) { + return ((Matrix) that).transpose().multiply(this); + } else { + Vector v = newInstance(); + for (int i = 0; i < n; i++) v.element[i] = element[i].multiply(that); + return v; + } + } + + @Nonnull + public Numeric divide(@Nonnull Numeric that) throws NotDivisibleException { + if (that instanceof Vector) { + throw new ArithmeticException(); + } else if (that instanceof Matrix) { + return multiply(that.inverse()); + } else { + Vector v = newInstance(); + for (int i = 0; i < n; i++) { + v.element[i] = element[i].divide(that); + } + return v; + } + } + + @Nonnull + public Numeric negate() { + Vector v = newInstance(); + for (int i = 0; i < n; i++) v.element[i] = element[i].negate(); + return v; + } + + public int signum() { + for (int i = 0; i < n; i++) { + int c = element[i].signum(); + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } + } + return 0; + } + + @Nonnull + public Numeric valueOf(@Nonnull Numeric numeric) { + if (numeric instanceof Vector || numeric instanceof Matrix) { + throw new ArithmeticException(); + } else { + Vector v = (Vector) unity(n).multiply(numeric); + return newInstance(v.element); + } + } + + public Numeric magnitude2() { + return scalarProduct(this); + } + + public Numeric scalarProduct(Vector vector) { + Numeric a = Real.ZERO; + for (int i = 0; i < n; i++) { + a = a.add(element[i].multiply(vector.element[i])); + } + return a; + } + + @Nonnull + public Numeric ln() { + throw new ArithmeticException(); + } + + @Nonnull + @Override + public Numeric lg() { + throw new ArithmeticException(); + } + + @Nonnull + public Numeric exp() { + throw new ArithmeticException(); + } + + public Numeric conjugate() { + Vector v = newInstance(); + for (int i = 0; i < n; i++) v.element[i] = element[i].conjugate(); + return v; + } + + public int compareTo(Vector vector) { + return ArrayComparator.comparator.compare(element, vector.element); + } + + public int compareTo(Numeric numeric) { + if (numeric instanceof Vector) { + return compareTo((Vector) numeric); + } else { + return compareTo(valueOf(numeric)); + } + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + result.append("["); + + for (int i = 0; i < n; i++) { + result.append(element[i]).append(i < n - 1 ? ", " : ""); + } + + result.append("]"); + + return result.toString(); + } + + @Nonnull + protected Vector newInstance() { + return newInstance(new Numeric[n]); + } + + @Nonnull + protected Vector newInstance(@Nonnull Numeric element[]) { + return new Vector(element); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/AbstractFunction.java b/jscl/src/main/java/jscl/math/operator/AbstractFunction.java new file mode 100644 index 00000000..38633e98 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/AbstractFunction.java @@ -0,0 +1,263 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Variable; +import jscl.math.function.Constant; +import jscl.mathml.MathML; +import jscl.util.ArrayComparator; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +/** + * User: serso + * Date: 11/29/11 + * Time: 9:50 PM + */ +public abstract class AbstractFunction extends Variable { + + protected static final Generic UNDEFINED_PARAMETER = JsclInteger.valueOf(Long.MIN_VALUE + 1); + private static final String DEFAULT_PARAMETER_NAMES = "xyzabcdefghijklmnopqrstuvw"; + protected Generic parameters[]; + + protected AbstractFunction(@Nonnull String name, Generic[] parameters) { + super(name); + + checkParameters(parameters); + + this.parameters = parameters; + } + + @Nullable + protected static Generic getParameter(@Nullable Generic[] parameters, final int i) { + return parameters == null ? null : (parameters.length > i ? parameters[i] : null); + } + + private void checkParameters(@Nullable Generic[] parameters) { + assert parameters == null || (getMinParameters() <= parameters.length && parameters.length <= getMaxParameters()); + } + + public Generic[] getParameters() { + return parameters; + } + + public void setParameters(@Nullable Generic[] parameters) { + checkParameters(parameters); + + this.parameters = parameters; + } + + public abstract int getMinParameters(); + + public int getMaxParameters() { + return getMinParameters(); + } + + public abstract Generic selfExpand(); + + public Generic expand() { + final AbstractFunction function = newExpandedFunction(); + + return function.selfExpand(); + } + + @Nonnull + protected AbstractFunction newExpandedFunction() { + final AbstractFunction function = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + function.parameters[i] = parameters[i].expand(); + } + return function; + } + + public Generic elementary() { + final AbstractFunction function = newElementarizedFunction(); + + return function.selfElementary(); + } + + @Nonnull + protected AbstractFunction newElementarizedFunction() { + final AbstractFunction function = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + function.parameters[i] = parameters[i].elementary(); + } + return function; + } + + public abstract Generic selfElementary(); + + public Generic factorize() { + final AbstractFunction function = newFactorizedFunction(); + + return function.expressionValue(); + } + + @Nonnull + protected AbstractFunction newFactorizedFunction() { + final AbstractFunction function = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + function.parameters[i] = parameters[i].factorize(); + } + return function; + } + + public Generic simplify() { + final AbstractFunction function = newSimplifiedFunction(); + + return function.selfSimplify(); + } + + @Nonnull + protected final AbstractFunction newSimplifiedFunction() { + final AbstractFunction function = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + function.parameters[i] = parameters[i].simplify(); + } + return function; + } + + public abstract Generic selfSimplify(); + + public Generic numeric() { + final AbstractFunction result = newNumericFunction(); + + return result.selfNumeric(); + } + + @Nonnull + protected final AbstractFunction newNumericFunction() { + final AbstractFunction result = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + result.parameters[i] = parameters[i].numeric(); + } + + return result; + } + + public abstract Generic selfNumeric(); + + public String toString() { + final StringBuilder result = new StringBuilder(); + + // f(x, y, z) + result.append(name); + result.append("("); + for (int i = 0; i < parameters.length; i++) { + result.append(formatParameter(i)); + if (i < parameters.length - 1) { + result.append(", "); + } + } + result.append(")"); + + return result.toString(); + } + + @Nonnull + protected final String formatParameter(int i) { + Generic parameter = parameters[i]; + + String result; + if (parameter != null) { + result = parameter.toString(); + } else { + result = formatUndefinedParameter(i); + } + + return result; + } + + @Nonnull + protected String formatUndefinedParameter(int i) { + return String.valueOf(DEFAULT_PARAMETER_NAMES.charAt(i - (i / DEFAULT_PARAMETER_NAMES.length()) * DEFAULT_PARAMETER_NAMES.length())); + } + + public String toJava() { + StringBuilder result = new StringBuilder(); + + result.append(parameters[0].toJava()); + result.append(".").append(name).append("()"); + + return result.toString(); + } + + public int compareTo(Variable that) { + if (this == that) return 0; + + int c = comparator.compare(this, that); + + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } else { + final AbstractFunction thatFunction = (AbstractFunction) that; + c = name.compareTo(thatFunction.name); + if (c < 0) { + return -1; + } else if (c > 0) { + return 1; + } else { + return ArrayComparator.comparator.compare(parameters, thatFunction.parameters); + } + } + } + + public Generic substitute(@Nonnull Variable variable, @Nonnull Generic generic) { + final AbstractFunction function = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + function.parameters[i] = parameters[i].substitute(variable, generic); + } + + if (function.isIdentity(variable)) { + return generic; + } else { + return function.selfExpand(); + } + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + + MathML result; + if (exponent == 1) { + nameToMathML(element); + } else { + result = element.element("msup"); + nameToMathML(result); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + result.appendChild(e2); + element.appendChild(result); + } + + result = element.element("mfenced"); + for (Generic parameter : parameters) { + parameter.toMathML(result, null); + } + + element.appendChild(result); + } + + @Nonnull + @Override + public Set getConstants() { + final Set result = new HashSet(); + + for (Generic parameter : parameters) { + result.addAll(parameter.getConstants()); + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Coefficient.java b/jscl/src/main/java/jscl/math/operator/Coefficient.java new file mode 100644 index 00000000..f604bad0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Coefficient.java @@ -0,0 +1,45 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.polynomial.Polynomial; + +import javax.annotation.Nonnull; + +public class Coefficient extends Operator { + + public static final String NAME = "coef"; + + public Coefficient(Generic expression, Generic variable) { + super(NAME, new Generic[]{expression, variable}); + } + + private Coefficient(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable = parameters[1].variableValue(); + if (parameters[0].isPolynomial(variable)) { + return new JsclVector(Polynomial.factory(variable).valueOf(parameters[0]).elements()); + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Coefficient(parameters); + } + + @Nonnull + public Variable newInstance() { + return new Coefficient(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Degree.java b/jscl/src/main/java/jscl/math/operator/Degree.java new file mode 100644 index 00000000..9e3a12ae --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Degree.java @@ -0,0 +1,53 @@ +package jscl.math.operator; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Generic; +import jscl.math.Variable; +import jscl.text.ParserUtils; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/31/11 + * Time: 10:58 PM + */ +public class Degree extends PostfixFunction { + + public static final String NAME = "°"; + + public Degree(Generic expression) { + super(NAME, new Generic[]{expression}); + } + + private Degree(Generic[] parameter) { + super(NAME, ParserUtils.copyOf(parameter, 1)); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + return AngleUnit.deg.transform(JsclMathEngine.getInstance().getAngleUnits(), parameters[0]); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Degree(parameters); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Degree((Generic) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Derivative.java b/jscl/src/main/java/jscl/math/operator/Derivative.java new file mode 100644 index 00000000..fd2b000f --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Derivative.java @@ -0,0 +1,200 @@ +package jscl.math.operator; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; +import jscl.mathml.MathML; +import jscl.text.msg.JsclMessage; +import jscl.text.msg.Messages; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; + +public class Derivative extends Operator { + + public static final String NAME = "∂"; + + public Derivative(Generic expression, Generic variable, Generic value, Generic order) { + super(NAME, new Generic[]{expression, variable, value, order}); + } + + private Derivative(Generic parameters[]) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(@Nonnull Generic[] parameters) { + final Generic[] result = new Generic[4]; + + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters.length > 2 ? parameters[2] : parameters[1]; + result[3] = parameters.length > 3 ? parameters[3] : JsclInteger.valueOf(1); + + return result; + } + + @Override + public int getMinParameters() { + return 2; + } + + @Override + public int getMaxParameters() { + return 4; + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + switch (i) { + case 0: + return "f(x)"; + case 1: + return "x"; + case 2: + return "x_point"; + case 3: + return "order"; + default: + return super.formatUndefinedParameter(i); + } + } + + public Generic selfExpand() { + if (JsclMathEngine.getInstance().getAngleUnits() != AngleUnit.rad) { + JsclMathEngine.getInstance().getMessageRegistry().addMessage(new JsclMessage(Messages.msg_25, MessageType.warning)); + } + + Variable variable = parameters[1].variableValue(); + try { + int n = parameters[3].integerValue().intValue(); + Generic a = parameters[0]; + for (int i = 0; i < n; i++) { + a = a.derivative(variable); + } + return a.substitute(variable, parameters[2]); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + // todo serso: think + /*public String toString() { + final StringBuilder result = new StringBuilder(); + int n = 4; + if (parameters[3].compareTo(JsclInteger.valueOf(1)) == 0) { + n = 3; + if (parameters[2].compareTo(parameters[1]) == 0) n = 2; + } + result.append(name); + result.append("("); + for (int i = 0; i < n; i++) { + result.append(parameters[i]).append(i < n - 1 ? ", " : ""); + } + result.append(")"); + return result.toString(); + }*/ + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) derivationToMathML(element, false); + else { + MathML e1 = element.element("msup"); + derivationToMathML(e1, true); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + MathML e1 = element.element("mfenced"); + parameters[0].toMathML(e1, null); + if (parameters[2].compareTo(parameters[1]) != 0) parameters[2].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Derivative(parameters); + } + + void derivationToMathML(MathML element, boolean fenced) { + if (fenced) { + MathML e1 = element.element("mfenced"); + derivationToMathML(e1); + element.appendChild(e1); + } else { + derivationToMathML(element); + } + } + + @Override + public Generic numeric() { + try { + parameters[3].integerValue(); + return expand().numeric(); + } catch (NotIntegerException e) { + } + + return expressionValue(); + } + + /*@Override + public Generic simplify() { + Generic result = null; + try { + result = expand().simplify(); + } catch (ArithmeticException e) { + result = super.simplify(); + } + return result; + }*/ + + void derivationToMathML(MathML element) { + Variable v = parameters[1].variableValue(); + int n = 0; + try { + n = parameters[3].integerValue().intValue(); + } catch (NotIntegerException e) { + } + if (n == 1) { + MathML e1 = element.element("mfrac"); + MathML e2 = element.element("mo"); + e2.appendChild(element.text(/*"\u2146"*/"d")); + e1.appendChild(e2); + e2 = element.element("mrow"); + MathML e3 = element.element("mo"); + e3.appendChild(element.text(/*"\u2146"*/"d")); + e2.appendChild(e3); + v.toMathML(e2, null); + e1.appendChild(e2); + element.appendChild(e1); + } else { + MathML e1 = element.element("mfrac"); + MathML e2 = element.element("msup"); + MathML e3 = element.element("mo"); + e3.appendChild(element.text(/*"\u2146"*/"d")); + e2.appendChild(e3); + parameters[3].toMathML(e2, null); + e1.appendChild(e2); + e2 = element.element("mrow"); + e3 = element.element("mo"); + e3.appendChild(element.text(/*"\u2146"*/"d")); + e2.appendChild(e3); + e3 = element.element("msup"); + parameters[1].toMathML(e3, null); + parameters[3].toMathML(e3, null); + e2.appendChild(e3); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + @Nonnull + public Variable newInstance() { + return new Derivative(null, null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Division.java b/jscl/src/main/java/jscl/math/operator/Division.java new file mode 100644 index 00000000..b4caf37d --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Division.java @@ -0,0 +1,39 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +public class Division extends Operator { + + public static final String NAME = "div"; + + public Division(Generic expression1, Generic expression2) { + super(NAME, new Generic[]{expression1, expression2}); + } + + private Division(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + return parameters[0].divideAndRemainder(parameters[1])[0]; + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Division(parameters); + } + + @Nonnull + public Variable newInstance() { + return new Division(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/DoubleFactorial.java b/jscl/src/main/java/jscl/math/operator/DoubleFactorial.java new file mode 100644 index 00000000..48054015 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/DoubleFactorial.java @@ -0,0 +1,121 @@ +package jscl.math.operator; + +import jscl.math.*; +import jscl.math.function.Pow; +import jscl.mathml.MathML; +import jscl.text.ParserUtils; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/15/11 + * Time: 10:32 PM + */ +public class DoubleFactorial extends PostfixFunction { + + public static final String NAME = "!!"; + + public DoubleFactorial(Generic expression) { + super(NAME, new Generic[]{expression}); + } + + private DoubleFactorial(Generic[] parameter) { + super(NAME, ParserUtils.copyOf(parameter, 1)); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + final Generic parameter = parameters[0]; + if (parameter.isInteger()) { + int n = parameter.integerValue().intValue(); + if (n < 0) { + //return expressionValue(); + throw new ArithmeticException("Cannot take factorial from negative integer!"); + } + + Generic result; + if (n == 0) { + result = JsclInteger.valueOf(1); + } else { + int i; + if (n % 2 != 0) { + // odd + i = 1; + } else { + // even + i = 2; + } + + result = JsclInteger.valueOf(i); + for (; i < n; i += 2) { + ParserUtils.checkInterruption(); + result = result.multiply(JsclInteger.valueOf(i + 2)); + } + } + + if (result instanceof JsclInteger) { + return new NumericWrapper(((JsclInteger) result)); + } else { + throw new NotIntegerException(); + } + + } else { + throw new NotIntegerException(); + } + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new DoubleFactorial(parameters); + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mrow"); + try { + JsclInteger en = parameters[0].integerValue(); + en.toMathML(e1, null); + } catch (NotIntegerException e) { + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Pow) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } else v.toMathML(e1, null); + } catch (NotVariableException e2) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } + } + MathML e2 = element.element("mo"); + e2.appendChild(element.text("!!")); + e1.appendChild(e2); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new DoubleFactorial((Generic) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Factorial.java b/jscl/src/main/java/jscl/math/operator/Factorial.java new file mode 100644 index 00000000..e92c6e18 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Factorial.java @@ -0,0 +1,102 @@ +package jscl.math.operator; + +import jscl.math.*; +import jscl.math.function.Pow; +import jscl.mathml.MathML; +import jscl.text.ParserUtils; + +import javax.annotation.Nonnull; + +public class Factorial extends PostfixFunction { + + public static final String NAME = "!"; + + public Factorial(Generic expression) { + super(NAME, new Generic[]{expression}); + } + + private Factorial(Generic[] parameter) { + super(NAME, ParserUtils.copyOf(parameter, 1)); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + final Generic parameter = parameters[0]; + if (parameter.isInteger()) { + int n = parameter.integerValue().intValue(); + if (n < 0) { + //return expressionValue(); + throw new ArithmeticException("Cannot take factorial from negative integer!"); + } + + Generic result = JsclInteger.valueOf(1); + for (int i = 0; i < n; i++) { + ParserUtils.checkInterruption(); + result = result.multiply(JsclInteger.valueOf(i + 1)); + } + + if (result instanceof JsclInteger) { + return new NumericWrapper(((JsclInteger) result)); + } else { + throw new NotIntegerException(); + } + + } else { + throw new NotIntegerException(); + } + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 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); + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Factorial(parameters); + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mrow"); + try { + JsclInteger en = parameters[0].integerValue(); + en.toMathML(e1, null); + } catch (NotIntegerException e) { + try { + Variable v = parameters[0].variableValue(); + if (v instanceof Pow) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } else v.toMathML(e1, null); + } catch (NotVariableException e2) { + GenericVariable.valueOf(parameters[0]).toMathML(e1, null); + } + } + MathML e2 = element.element("mo"); + e2.appendChild(element.text("!")); + e1.appendChild(e2); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Factorial((Generic) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Gcd.java b/jscl/src/main/java/jscl/math/operator/Gcd.java new file mode 100644 index 00000000..eb40f281 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Gcd.java @@ -0,0 +1,67 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/23/11 + * Time: 4:47 PM + */ +public class Gcd extends Operator { + + public Gcd(@Nonnull Generic first, @Nonnull Generic second) { + this(new Generic[]{first, second}); + } + + public Gcd() { + this(new Generic[2]); + } + + private Gcd(@Nonnull Generic[] parameters) { + super("gcd", parameters); + } + + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Gcd(parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic numeric() { + final Generic first = parameters[0]; + final Generic second = parameters[1]; + + try { + final JsclInteger firstInt = first.integerValue(); + final JsclInteger secondInt = second.integerValue(); + + return firstInt.gcd(secondInt); + } catch (NotIntegerException e) { + // ok => continue + } + + return first.gcd(second); + } + + @Nonnull + @Override + public Gcd newInstance() { + return new Gcd(); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Groebner.java b/jscl/src/main/java/jscl/math/operator/Groebner.java new file mode 100644 index 00000000..21a04873 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Groebner.java @@ -0,0 +1,178 @@ +package jscl.math.operator; + +import jscl.math.*; +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; +import jscl.text.ParseException; + +import javax.annotation.Nonnull; + +public class Groebner extends Operator { + + public static final String NAME = "groebner"; + + public Groebner(Generic generic, Generic variable, Generic ordering, Generic modulo) { + super(NAME, new Generic[]{generic, variable, ordering, modulo}); + } + + private Groebner(Generic parameters[]) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(Generic[] parameters) { + final Generic[] result = new Generic[4]; + + try { + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters.length > 2 ? parameters[2] : Expression.valueOf("lex"); + result[3] = parameters.length > 3 ? parameters[3] : JsclInteger.valueOf(0); + } catch (ParseException e) { + throw new ArithmeticException(e.getMessage()); + } + + return result; + } + + 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).getParameters(); + 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(); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Generic generic[] = ((JsclVector) parameters[0]).elements(); + Variable variable[] = toVariables((JsclVector) parameters[1]); + Ordering ord = ordering(parameters[2]); + int m = parameters[3].integerValue().intValue(); + return new PolynomialVector(Basis.compute(generic, variable, ord, m)); + } + + public Operator transmute() { + Generic p[] = new Generic[]{GenericVariable.content(parameters[0]), GenericVariable.content(parameters[1])}; + if (p[0] instanceof JsclVector && p[1] instanceof JsclVector) { + Generic generic[] = ((JsclVector) p[0]).elements(); + Variable variable[] = toVariables((JsclVector) p[1]); + Ordering ord = ordering(parameters[2]); + int m = parameters[3].integerValue().intValue(); + return new Groebner(new PolynomialVector(new Basis(generic, Polynomial.factory(variable, ord, m))), p[1], parameters[2], parameters[3]); + } + return this; + } + + // todo serso: think + /*public String toString() { + StringBuilder buffer = new StringBuilder(); + int n = 4; + if (parameters[3].signum() == 0) { + n = 3; + if (ordering(parameters[2]) == Monomial.lexicographic) n = 2; + } + buffer.append(name); + buffer.append("("); + for (int i = 0; i < n; i++) { + buffer.append(parameters[i]).append(i < n - 1 ? ", " : ""); + } + buffer.append(")"); + return buffer.toString(); + }*/ + + public void toMathML(MathML element, Object data) { + MathML e1; + int exponent = data instanceof Integer ? (Integer) data : 1; + int n = 4; + if (parameters[3].signum() == 0) { + n = 3; + if (ordering(parameters[2]) == Monomial.lexicographic) n = 2; + } + if (exponent == 1) nameToMathML(element); + else { + e1 = element.element("msup"); + nameToMathML(e1); + MathML e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + e1 = element.element("mfenced"); + for (int i = 0; i < n; i++) { + parameters[i].toMathML(e1, null); + } + element.appendChild(e1); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Groebner(parameters).transmute(); + } + + @Nonnull + public Variable newInstance() { + return new Groebner(null, null, null, null); + } +} + +class PolynomialVector extends JsclVector { + final Basis basis; + + PolynomialVector(Basis basis) { + this(basis, basis.elements()); + } + + PolynomialVector(Basis basis, Generic generic[]) { + super(generic.length > 0 ? generic : new Generic[]{JsclInteger.valueOf(0)}); + this.basis = basis; + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + result.append("["); + + for (int i = 0; i < rows; i++) { + result.append(basis.polynomial(elements[i])).append(i < rows - 1 ? ", " : ""); + } + + result.append("]"); + + return result.toString(); + } + + protected void bodyToMathML(MathML e0) { + MathML e1 = e0.element("mfenced"); + MathML e2 = e0.element("mtable"); + for (int i = 0; i < rows; i++) { + MathML e3 = e0.element("mtr"); + MathML e4 = e0.element("mtd"); + basis.polynomial(elements[i]).toMathML(e4, null); + e3.appendChild(e4); + e2.appendChild(e3); + } + e1.appendChild(e2); + e0.appendChild(e1); + } + + @Nonnull + protected Generic newInstance(@Nonnull Generic element[]) { + return new PolynomialVector(basis, element); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/IndefiniteIntegral.java b/jscl/src/main/java/jscl/math/operator/IndefiniteIntegral.java new file mode 100644 index 00000000..0399f7f5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/IndefiniteIntegral.java @@ -0,0 +1,98 @@ +package jscl.math.operator; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Generic; +import jscl.math.NotIntegrableException; +import jscl.math.Variable; +import jscl.mathml.MathML; +import jscl.text.msg.JsclMessage; +import jscl.text.msg.Messages; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; + +public class IndefiniteIntegral extends Operator { + + public static final String NAME = "∫"; + + public IndefiniteIntegral(Generic expression, Generic variable) { + super(NAME, new Generic[]{expression, variable}); + } + + protected IndefiniteIntegral(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + if (JsclMathEngine.getInstance().getAngleUnits() != AngleUnit.rad) { + JsclMathEngine.getInstance().getMessageRegistry().addMessage(new JsclMessage(Messages.msg_24, MessageType.warning)); + } + + Variable variable = parameters[1].variableValue(); + try { + return parameters[0].antiDerivative(variable); + } catch (NotIntegrableException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + switch (i) { + case 0: + return "f(x)"; + case 1: + return "x"; + default: + return super.formatUndefinedParameter(i); + } + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) bodyToMathML(element); + else { + MathML e1 = element.element("msup"); + MathML e2 = element.element("mfenced"); + bodyToMathML(e2); + e1.appendChild(e2); + e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new IndefiniteIntegral(parameters); + } + + @Nonnull + @Override + public Variable newInstance() { + return new IndefiniteIntegral(null, null); + } + + void bodyToMathML(MathML element) { + Variable v = parameters[1].variableValue(); + MathML e1 = element.element("mrow"); + MathML e2 = element.element("mo"); + e2.appendChild(element.text("\u222B")); + e1.appendChild(e2); + parameters[0].toMathML(e1, null); + e2 = element.element("mo"); + e2.appendChild(element.text(/*"\u2146"*/"d")); + e1.appendChild(e2); + v.toMathML(e1, null); + element.appendChild(e1); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Integral.java b/jscl/src/main/java/jscl/math/operator/Integral.java new file mode 100644 index 00000000..dc597c91 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Integral.java @@ -0,0 +1,106 @@ +package jscl.math.operator; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Generic; +import jscl.math.NotIntegrableException; +import jscl.math.Variable; +import jscl.mathml.MathML; +import jscl.text.msg.JsclMessage; +import jscl.text.msg.Messages; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; + +public class Integral extends Operator { + + public static final String NAME = "∫ab"; + + public Integral(Generic expression, Generic variable, Generic n1, Generic n2) { + super(NAME, new Generic[]{expression, variable, n1, n2}); + } + + protected Integral(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 4; + } + + public Generic selfExpand() { + if (JsclMathEngine.getInstance().getAngleUnits() != AngleUnit.rad) { + JsclMathEngine.getInstance().getMessageRegistry().addMessage(new JsclMessage(Messages.msg_24, MessageType.warning)); + } + + Variable variable = parameters[1].variableValue(); + try { + Generic a = parameters[0].antiDerivative(variable); + return a.substitute(variable, parameters[3]).subtract(a.substitute(variable, parameters[2])); + } catch (NotIntegrableException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + switch (i) { + case 0: + return "f(x)"; + case 1: + return "x"; + case 2: + return "a"; + case 3: + return "b"; + default: + return super.formatUndefinedParameter(i); + } + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) bodyToMathML(element); + else { + MathML e1 = element.element("msup"); + MathML e2 = element.element("mfenced"); + bodyToMathML(e2); + e1.appendChild(e2); + e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Integral(parameters); + } + + void bodyToMathML(MathML element) { + Variable v = parameters[1].variableValue(); + MathML e1 = element.element("mrow"); + MathML e2 = element.element("msubsup"); + MathML e3 = element.element("mo"); + e3.appendChild(element.text("\u222B")); + e2.appendChild(e3); + parameters[2].toMathML(e2, null); + parameters[3].toMathML(e2, null); + e1.appendChild(e2); + parameters[0].toMathML(e1, null); + e2 = element.element("mo"); + e2.appendChild(element.text(/*"\u2146"*/"d")); + e1.appendChild(e2); + v.toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Integral(null, null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Limit.java b/jscl/src/main/java/jscl/math/operator/Limit.java new file mode 100644 index 00000000..ec93824e --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Limit.java @@ -0,0 +1,115 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Variable; +import jscl.math.function.Constants; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Limit extends Operator { + + public static final String NAME = "lim"; + + public Limit(Generic expression, Generic variable, Generic limit, Generic direction) { + super(NAME, new Generic[]{expression, variable, limit, direction}); + } + + private Limit(Generic parameters[]) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(Generic[] parameters) { + final Generic[] result = new Generic[4]; + + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters[2]; + result[3] = parameters.length > 3 && (parameters[2].compareTo(Constants.Generic.INF) != 0 && parameters[2].compareTo(Constants.Generic.INF.negate()) != 0) ? JsclInteger.valueOf(parameters[3].signum()) : JsclInteger.valueOf(0); + + return result; + } + + @Override + public int getMinParameters() { + return 3; + } + + @Override + public int getMaxParameters() { + return 4; + } + + public Generic selfExpand() { + return expressionValue(); + } + + // todo serso: think + /*public String toString() { + StringBuilder result = new StringBuilder(); + int n=4; + if(parameters[3].signum()==0) n=3; + result.append(name); + result.append("("); + for(int i=0;i 0) e5.appendChild(element.text("+")); + e4.appendChild(e5); + e3.appendChild(e4); + } + e2.appendChild(e3); + e1.appendChild(e2); + parameters[0].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Limit(null, null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Modulo.java b/jscl/src/main/java/jscl/math/operator/Modulo.java new file mode 100644 index 00000000..c64ddd97 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Modulo.java @@ -0,0 +1,49 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +public class Modulo extends Operator { + + public static final String NAME = "mod"; + + public Modulo(Generic first, Generic second) { + super(NAME, new Generic[]{first, second}); + } + + private Modulo(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + try { + final JsclInteger first = parameters[0].integerValue(); + final JsclInteger second = parameters[1].integerValue(); + + return first.mod(second); + + } catch (NotIntegerException e) { + } + return parameters[0].remainder(parameters[1]); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Modulo(parameters); + } + + @Nonnull + public Variable newInstance() { + return new Modulo(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Operator.java b/jscl/src/main/java/jscl/math/operator/Operator.java new file mode 100644 index 00000000..c67908a5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Operator.java @@ -0,0 +1,68 @@ +package jscl.math.operator; + +import jscl.math.*; + +import javax.annotation.Nonnull; + +public abstract class Operator extends AbstractFunction { + + protected Operator(String name, Generic parameters[]) { + super(name, parameters); + } + + @Nonnull + protected static Variable[] toVariables(@Nonnull Generic vector) throws NotVariableException { + return toVariables((JsclVector) vector); + } + + @Nonnull + protected static Variable[] toVariables(@Nonnull JsclVector vector) throws NotVariableException { + final Generic element[] = vector.elements(); + final Variable variable[] = new Variable[element.length]; + + for (int i = 0; i < element.length; i++) { + variable[i] = element[i].variableValue(); + } + + return variable; + } + + public Generic antiDerivative(Variable variable) throws NotIntegrableException { + throw new NotIntegrableException(this); + } + + @Nonnull + public Generic derivative(Variable variable) { + if (isIdentity(variable)) { + return JsclInteger.valueOf(1); + } else { + return JsclInteger.valueOf(0); + } + } + + @Override + public Generic selfElementary() { + return expressionValue(); + } + + @Override + public Generic selfSimplify() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + return numeric(); + } + + public Generic numeric() { + throw new ArithmeticException(); + } + + public boolean isConstant(Variable variable) { + return !isIdentity(variable); + } + + @Nonnull + public abstract Operator newInstance(@Nonnull Generic[] parameters); +} diff --git a/jscl/src/main/java/jscl/math/operator/Percent.java b/jscl/src/main/java/jscl/math/operator/Percent.java new file mode 100644 index 00000000..99df8f7f --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Percent.java @@ -0,0 +1,83 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Variable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 11/14/11 + * Time: 2:05 PM + */ +public class Percent extends PostfixFunction { + + public static final String NAME = "%"; + + public Percent(Generic content, Generic previousSumElement) { + super(NAME, new Generic[]{content, previousSumElement}); + } + + private Percent(Generic[] parameters) { + super(NAME, createParameters(getParameter(parameters, 0), getParameter(parameters, 1))); + } + + private static Generic[] createParameters(@Nullable Generic content, @Nullable Generic previousSumElement) { + final Generic[] result; + + if (previousSumElement == null) { + result = new Generic[]{content, UNDEFINED_PARAMETER}; + } else { + result = new Generic[]{content, previousSumElement}; + } + + return result; + } + + @Override + public int getMinParameters() { + return 1; + } + + @Override + public int getMaxParameters() { + return 2; + } + + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic simplify() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + Generic percentValue = parameters[0]; + + final Generic normalizedPercentage = percentValue.divide(JsclInteger.valueOf(100)); + if (UNDEFINED_PARAMETER != parameters[1]) { + Generic previousSumElement = parameters[1]; + + return previousSumElement.multiply(normalizedPercentage); + } else { + return normalizedPercentage; + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Percent(parameters); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Percent(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/PostfixFunction.java b/jscl/src/main/java/jscl/math/operator/PostfixFunction.java new file mode 100644 index 00000000..1b1e8a8c --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/PostfixFunction.java @@ -0,0 +1,65 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.Variable; + +/** + * User: serso + * Date: 11/2/11 + * Time: 11:07 AM + */ +abstract class PostfixFunction extends Operator { + + PostfixFunction(String name, Generic[] parameter) { + super(name, parameter); + } + + public String toString() { + final StringBuilder result = new StringBuilder(); + + /*try {*/ + result.append(formatParameter(0)); + /*} catch (NotIntegerException e) { + try { + final Variable v = parameters[0].variableValue(); + if (v instanceof Frac || v instanceof Pow) { + result.append(GenericVariable.valueOf(parameters[0])); + } else { + result.append(v); + } + } catch (NotVariableException e2) { + result.append(GenericVariable.valueOf(parameters[0])); + } + }*/ + result.append(getName()); + + return result.toString(); + } + + public final Generic numeric() { + final AbstractFunction result = (AbstractFunction) newInstance(); + + for (int i = 0; i < parameters.length; i++) { + result.parameters[i] = parameters[i].numeric(); + } + + return result.selfNumeric(); + } + + public abstract Generic selfNumeric(); + + public boolean isConstant(Variable variable) { + boolean result = !isIdentity(variable); + + if (result) { + for (Generic parameter : parameters) { + if (!parameter.isConstant(variable)) { + result = false; + break; + } + } + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Product.java b/jscl/src/main/java/jscl/math/operator/Product.java new file mode 100644 index 00000000..44d827ca --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Product.java @@ -0,0 +1,104 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Product extends Operator { + + public static final String NAME = "∏"; + + public Product(Generic expression, Generic variable, Generic n1, Generic n2) { + super(NAME, new Generic[]{expression, variable, n1, n2}); + } + + private Product(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 4; + } + + public Generic selfExpand() { + Variable variable = parameters[1].variableValue(); + try { + int n1 = parameters[2].integerValue().intValue(); + int n2 = parameters[3].integerValue().intValue(); + Generic a = JsclInteger.valueOf(1); + for (int i = n1; i <= n2; i++) { + a = a.multiply(parameters[0].substitute(variable, JsclInteger.valueOf(i))); + } + return a; + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + protected String formatUndefinedParameter(int i) { + switch (i) { + case 0: + return "f(i)"; + case 1: + return "i"; + case 2: + return "from"; + case 3: + return "to"; + default: + return super.formatUndefinedParameter(i); + } + } + + 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"); + MathML e2 = element.element("mfenced"); + bodyToMathML(e2); + e1.appendChild(e2); + e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Product(parameters); + } + + void bodyToMathML(MathML element) { + MathML e1 = element.element("mrow"); + MathML e2 = element.element("munderover"); + MathML e3 = element.element("mo"); + e3.appendChild(element.text("\u220F")); + e2.appendChild(e3); + e3 = element.element("mrow"); + parameters[1].toMathML(e3, null); + MathML e4 = element.element("mo"); + e4.appendChild(element.text("=")); + e3.appendChild(e4); + parameters[2].toMathML(e3, null); + e2.appendChild(e3); + parameters[3].toMathML(e2, null); + e1.appendChild(e2); + parameters[0].toMathML(e1, null); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Product(null, null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Rand.java b/jscl/src/main/java/jscl/math/operator/Rand.java new file mode 100644 index 00000000..813224c9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Rand.java @@ -0,0 +1,72 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.NumericWrapper; +import jscl.math.TimeDependent; +import jscl.math.Variable; +import jscl.math.numeric.Real; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/26/11 + * Time: 9:54 AM + */ +public class Rand extends Operator implements TimeDependent { + + public static final String NAME = "rand"; + + public Rand() { + super(NAME, new Generic[0]); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Rand(); + } + + @Override + public int getMinParameters() { + return 0; + } + + @Override + public Generic selfExpand() { + return new NumericWrapper(Real.valueOf(Math.random())); + } + + @Override + public Generic numeric() { + return selfExpand().numeric(); + } + + @Nonnull + @Override + public Variable newInstance() { + return new Rand(); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public int compareTo(Object that) { + if (this == that) return 0; + return -1; + } + + @Override + public int compareTo(Variable that) { + if (this == that) return 0; + return -1; + } +} diff --git a/jscl/src/main/java/jscl/math/operator/Solve.java b/jscl/src/main/java/jscl/math/operator/Solve.java new file mode 100644 index 00000000..2e89e77f --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/Solve.java @@ -0,0 +1,101 @@ +package jscl.math.operator; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Variable; +import jscl.math.function.Root; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.UnivariatePolynomial; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Solve extends Operator { + + public static final String NAME = "solve"; + + public Solve(Generic expression, Generic variable, Generic subscript) { + super(NAME, new Generic[]{expression, variable, subscript}); + } + + public Solve(Generic parameters[]) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(Generic[] parameters) { + final Generic[] result = new Generic[3]; + + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0); + + return result; + } + + @Override + public int getMinParameters() { + return 2; + } + + @Override + public int getMaxParameters() { + return 3; + } + + public Generic selfExpand() { + final Variable variable = parameters[1].variableValue(); + + int subscript = parameters[2].integerValue().intValue(); + if (parameters[0].isPolynomial(variable)) { + return new Root((UnivariatePolynomial) Polynomial.factory(variable).valueOf(parameters[0]), subscript).selfExpand(); + } + + return expressionValue(); + } + + // todo serso: think + /*public String toString() { + StringBuilder result = new StringBuilder(); + int n=3; + if(parameters[2].signum()==0) n=2; + result.append(name); + result.append("("); + for(int i=0;i { + + private final static OperatorsRegistry instance = new OperatorsRegistry(); + + static { + instance.add(new Derivative(null, null, null, null)); + //instance.add(new Grad(null, null)); + //instance.add(new Divergence(null, null)); + //instance.add(new Curl(null, null)); + //instance.add(new Jacobian(null, null)); + //instance.add(new Laplacian(null, null)); + //instance.add(new Dalembertian(null, null)); + //instance.add(new Del(null, null, null)); + //instance.add(new VectorProduct(null, null)); + //instance.add(new ComplexProduct(null, null)); + //instance.add(new QuaternionProduct(null, null)); + //instance.add(new GeometricProduct(null, null, null)); + //instance.add(new MatrixProduct(null, null)); + //instance.add(new TensorProduct(null, null)); + //instance.add(new Transpose(null)); + //instance.add(new Trace(null)); + //instance.add(new Determinant(null)); + //instance.add(new Coefficient(null, null)); + //instance.add(new Solve(null, null, null)); + //instance.add(new Substitute(null, null, null)); + //instance.add(new Limit(null, null, null, null)); + instance.add(new Sum(null, null, null, null)); + instance.add(new Product(null, null, null, null)); + //instance.add(new Groebner(null, null, null, null)); + //instance.add(new Division(null, null)); + instance.add(new Modulo(null, null)); + //instance.add(new ModPow(null, null, null)); + //instance.add(new ModInverse(null, null)); + //instance.add(new EulerPhi(null)); + instance.add(new Integral(null, null, null, null)); + instance.add(new IndefiniteIntegral(null, null)); + //instance.add(new Rand()); + //instance.add(new Mean(null)); + //instance.add(new Min(null)); + //instance.add(new Max(null)); + //instance.add(new MeanSquareDeviation(null)); + //instance.add(new StandardDeviation(null)); + //instance.add(new PrimitiveRoots(null)); + } + + /* if (operatorName.compareTo("d") == 0) + v = new Derivative(parameters[0], parameters[1], parameters.length > 2 ? parameters[2] : parameters[1], parameters.length > 3 ? parameters[3] : JsclInteger.valueOf(1)); + else if (operatorName.compareTo("grad") == 0) v = new Grad(parameters[0], parameters[1]); + else if (operatorName.compareTo("diverg") == 0) v = new Divergence(parameters[0], parameters[1]); + else if (operatorName.compareTo("curl") == 0) v = new Curl(parameters[0], parameters[1]); + else if (operatorName.compareTo("jacobian") == 0) v = new Jacobian(parameters[0], parameters[1]); + else if (operatorName.compareTo("laplacian") == 0) v = new Laplacian(parameters[0], parameters[1]); + else if (operatorName.compareTo("dalembertian") == 0) v = new Dalembertian(parameters[0], parameters[1]); + else if (operatorName.compareTo("del") == 0) + v = new Del(parameters[0], parameters[1], parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0)); + else if (operatorName.compareTo("vector") == 0) v = new VectorProduct(parameters[0], parameters[1]); + else if (operatorName.compareTo("complex") == 0) v = new ComplexProduct(parameters[0], parameters[1]); + else if (operatorName.compareTo("quaternion") == 0) v = new QuaternionProduct(parameters[0], parameters[1]); + else if (operatorName.compareTo("geometric") == 0) + v = new GeometricProduct(parameters[0], parameters[1], parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0)); + else if (operatorName.compareTo("matrix") == 0) v = new MatrixProduct(parameters[0], parameters[1]); + else if (operatorName.compareTo("tensor") == 0) v = new TensorProduct(parameters[0], parameters[1]); + else if (operatorName.compareTo("tran") == 0) v = new Transpose(parameters[0]); + else if (operatorName.compareTo("trace") == 0) v = new Trace(parameters[0]); + else if (operatorName.compareTo("det") == 0) v = new Determinant(parameters[0]); + else if (operatorName.compareTo("coef") == 0) v = new Coefficient(parameters[0], parameters[1]); + else if (operatorName.compareTo("solve") == 0) + v = new Solve(parameters[0], parameters[1], parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0)); + else if (operatorName.compareTo("subst") == 0) + v = new Substitute(parameters[0], parameters[1], parameters[2]).transmute(); + else if (operatorName.compareTo("lim") == 0) + v = new Limit(parameters[0], parameters[1], parameters[2], parameters.length > 3 && (parameters[2].compareTo(Constant.infinity) != 0 && parameters[2].compareTo(Constant.infinity.negate()) != 0) ? JsclInteger.valueOf(parameters[3].signum()) : JsclInteger.valueOf(0)); + else if (operatorName.compareTo("sum") == 0) + v = new Sum(parameters[0], parameters[1], parameters[2], parameters[3]); + else if (operatorName.compareTo("prod") == 0) + v = new Product(parameters[0], parameters[1], parameters[2], parameters[3]); + else if (operatorName.compareTo("integral") == 0) + v = parameters.length > 2 ? new Integral(parameters[0], parameters[1], parameters[2], parameters[3]) : new IndefiniteIntegral(parameters[0], parameters[1]); + else if (operatorName.compareTo("groebner") == 0) + v = new Groebner(parameters[0], parameters[1], parameters.length > 2 ? parameters[2] : Expression.valueOf("lex"), parameters.length > 3 ? parameters[3] : JsclInteger.valueOf(0)).transmute(); + else if (operatorName.compareTo("div") == 0) v = new Division(parameters[0], parameters[1]); + else if (operatorName.compareTo("mod") == 0) v = new Modulo(parameters[0], parameters[1]); + else if (operatorName.compareTo("modpow") == 0) v = new ModPow(parameters[0], parameters[1], parameters[2]); + else if (operatorName.compareTo("modinv") == 0) v = new ModInverse(parameters[0], parameters[1]); + else if (operatorName.compareTo("eulerphi") == 0) v = new EulerPhi(parameters[0]); + else if (operatorName.compareTo("primitiveroots") == 0) v = new PrimitiveRoots(parameters[0]);*/ + + @Nonnull + public static OperatorsRegistry getInstance() { + return instance; + } + + @Nullable + public Operator get(@Nonnull String name, @Nonnull Generic[] parameters) { + final Operator operator = super.get(name); + if (operator == null) { + return null; + } else { + if (operator.getMinParameters() <= parameters.length && operator.getMaxParameters() >= parameters.length) { + return operator.newInstance(parameters); + } else { + return null; + } + } + } + + @Override + public Operator get(@Nonnull String name) { + final Operator operator = super.get(name); + return operator == null ? null : FunctionsRegistry.copy(operator); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/matrix/Trace.java b/jscl/src/main/java/jscl/math/operator/matrix/Trace.java new file mode 100644 index 00000000..58dc15c9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/matrix/Trace.java @@ -0,0 +1,65 @@ +package jscl.math.operator.matrix; + +import jscl.math.Generic; +import jscl.math.Matrix; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Trace extends Operator { + + public static final String NAME = "trace"; + + public Trace(Generic matrix) { + super(NAME, new Generic[]{matrix}); + } + + private Trace(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + if (parameters[0] instanceof Matrix) { + Matrix matrix = (Matrix) parameters[0]; + return matrix.trace(); + } + return expressionValue(); + } + + public void toMathML(MathML element, Object data) { + int exponent = data instanceof Integer ? (Integer) data : 1; + if (exponent == 1) { + MathML e1 = element.element("mo"); + e1.appendChild(element.text("tr")); + element.appendChild(e1); + } else { + MathML e1 = element.element("msup"); + MathML e2 = element.element("mo"); + e2.appendChild(element.text("tr")); + e1.appendChild(e2); + e2 = element.element("mn"); + e2.appendChild(element.text(String.valueOf(exponent))); + e1.appendChild(e2); + element.appendChild(e1); + } + parameters[0].toMathML(element, null); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Trace(parameters); + } + + @Nonnull + public Variable newInstance() { + return new Trace((Matrix) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/matrix/Transpose.java b/jscl/src/main/java/jscl/math/operator/matrix/Transpose.java new file mode 100644 index 00000000..585c908d --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/matrix/Transpose.java @@ -0,0 +1,68 @@ +package jscl.math.operator.matrix; + +import jscl.math.Generic; +import jscl.math.Matrix; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Transpose extends Operator { + + public static final String NAME = "tran"; + + public Transpose(Generic matrix) { + super(NAME, new Generic[]{matrix}); + } + + private Transpose(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + if (parameters[0] instanceof Matrix) { + Matrix matrix = (Matrix) parameters[0]; + return matrix.transpose(); + } + return expressionValue(); + } + + 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("msup"); + parameters[0].toMathML(e1, null); + MathML e2 = element.element("mo"); + e2.appendChild(element.text("T")); + e1.appendChild(e2); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Transpose((Matrix) null); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Transpose(parameters); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/number/EulerPhi.java b/jscl/src/main/java/jscl/math/operator/number/EulerPhi.java new file mode 100644 index 00000000..cc408b81 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/number/EulerPhi.java @@ -0,0 +1,54 @@ +package jscl.math.operator.number; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class EulerPhi extends Operator { + + public static final String NAME = "eulerphi"; + + public EulerPhi(Generic integer) { + super(NAME, new Generic[]{integer}); + } + + private EulerPhi(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + try { + JsclInteger en = parameters[0].integerValue(); + return en.phi(); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + protected void nameToMathML(MathML element) { + MathML e1 = element.element("mi"); + e1.appendChild(element.text("\u03C6")); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new EulerPhi((Generic) null); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new EulerPhi(parameters); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/number/ModInverse.java b/jscl/src/main/java/jscl/math/operator/number/ModInverse.java new file mode 100644 index 00000000..2fba61cb --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/number/ModInverse.java @@ -0,0 +1,50 @@ +package jscl.math.operator.number; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +public class ModInverse extends Operator { + + public static final String NAME = "modinv"; + + public ModInverse(Generic integer, Generic modulo) { + super(NAME, new Generic[]{integer, modulo}); + } + + private ModInverse(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + try { + JsclInteger en = parameters[0].integerValue(); + JsclInteger modulo = parameters[1].integerValue(); + return en.modInverse(modulo); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new ModInverse(parameters); + } + + @Nonnull + public Variable newInstance() { + return new ModInverse(null, null); + } + + +} diff --git a/jscl/src/main/java/jscl/math/operator/number/ModPow.java b/jscl/src/main/java/jscl/math/operator/number/ModPow.java new file mode 100644 index 00000000..fc1377b0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/number/ModPow.java @@ -0,0 +1,49 @@ +package jscl.math.operator.number; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.Variable; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +public class ModPow extends Operator { + + public static final String NAME = "modpow"; + + public ModPow(Generic integer, Generic exponent, Generic modulo) { + super(NAME, new Generic[]{integer, exponent, modulo}); + } + + private ModPow(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 3; + } + + public Generic selfExpand() { + try { + JsclInteger en = parameters[0].integerValue(); + JsclInteger exponent = parameters[1].integerValue(); + JsclInteger modulo = parameters[2].integerValue(); + return en.modPow(exponent, modulo); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new ModPow(parameters); + } + + @Nonnull + public Variable newInstance() { + return new ModPow(null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/number/PrimitiveRoots.java b/jscl/src/main/java/jscl/math/operator/number/PrimitiveRoots.java new file mode 100644 index 00000000..00996280 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/number/PrimitiveRoots.java @@ -0,0 +1,45 @@ +package jscl.math.operator.number; + +import jscl.math.*; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +public class PrimitiveRoots extends Operator { + + public static final String NAME = "primitiveroots"; + + public PrimitiveRoots(Generic integer) { + super(NAME, new Generic[]{integer}); + } + + private PrimitiveRoots(Generic parameters[]) { + super(NAME, parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + public Generic selfExpand() { + try { + JsclInteger en = parameters[0].integerValue(); + Generic a[] = en.primitiveRoots(); + return new JsclVector(a.length > 0 ? a : new Generic[]{JsclInteger.valueOf(0)}); + } catch (NotIntegerException e) { + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new PrimitiveRoots(parameters); + } + + @Nonnull + public Variable newInstance() { + return new PrimitiveRoots((Generic) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/product/ComplexProduct.java b/jscl/src/main/java/jscl/math/operator/product/ComplexProduct.java new file mode 100644 index 00000000..41cfb0a9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/product/ComplexProduct.java @@ -0,0 +1,53 @@ +package jscl.math.operator.product; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class ComplexProduct extends VectorOperator { + + public static final String NAME = "complex"; + + public ComplexProduct(Generic vector1, Generic vector2) { + super(NAME, new Generic[]{vector1, vector2}); + } + + private ComplexProduct(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + if (parameters[0] instanceof JsclVector && parameters[1] instanceof JsclVector) { + JsclVector v1 = (JsclVector) parameters[0]; + JsclVector v2 = (JsclVector) parameters[1]; + return v1.complexProduct(v2); + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new ComplexProduct(parameters); + } + + protected void bodyToMathML(MathML element) { + parameters[0].toMathML(element, null); + parameters[1].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new ComplexProduct(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/product/GeometricProduct.java b/jscl/src/main/java/jscl/math/operator/product/GeometricProduct.java new file mode 100644 index 00000000..dec1a3da --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/product/GeometricProduct.java @@ -0,0 +1,93 @@ +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.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class GeometricProduct extends VectorOperator { + + public static final String NAME = "geometric"; + + public GeometricProduct(Generic vector1, Generic vector2, Generic algebra) { + super(NAME, new Generic[]{vector1, vector2, algebra}); + } + + private GeometricProduct(@Nonnull Generic[] parameters) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(@Nonnull Generic[] parameters) { + final Generic[] result = new Generic[3]; + + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0); + + return result; + } + + public static int[] algebra(Generic generic) { + if (generic.signum() == 0) return null; + Variable v = generic.variableValue(); + if (v instanceof ImplicitFunction) { + Generic g[] = ((ImplicitFunction) v).getParameters(); + 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(); + } + + @Override + public int getMinParameters() { + return 3; + } + + public Generic selfExpand() { + int algebra[] = algebra(parameters[2]); + if (parameters[0] instanceof JsclVector && parameters[1] instanceof JsclVector) { + JsclVector v1 = (JsclVector) parameters[0]; + JsclVector v2 = (JsclVector) parameters[1]; + return v1.geometricProduct(v2, algebra); + } + return expressionValue(); + } + + // todo serso: think + /*public String toString() { + StringBuffer buffer=new StringBuffer(); + int n=3; + if(parameters[2].signum()==0) n=2; + buffer.append(name); + buffer.append("("); + for(int i=0;i 0) { + result = candidate; + } + } + + return result; + } + } else { + return expressionValue(); + } + } + + @Nonnull + @Override + public Variable newInstance() { + return new Max((JsclVector) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/stat/Mean.java b/jscl/src/main/java/jscl/math/operator/stat/Mean.java new file mode 100644 index 00000000..6fdb0c38 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/stat/Mean.java @@ -0,0 +1,68 @@ +package jscl.math.operator.stat; + +import jscl.math.*; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/26/11 + * Time: 11:09 AM + */ +public class Mean extends AbstractStatFunction { + + public static final String NAME = "mean"; + + public Mean(JsclVector vector) { + this(new Generic[]{vector}); + } + + private Mean(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Mean(parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + if (parameters[0] instanceof JsclVector) { + final JsclVector vector = (JsclVector) parameters[0]; + final Generic[] elements = vector.elements(); + + if (elements.length == 0) { + return new NumericWrapper(JsclInteger.ZERO); + } else if (elements.length == 1) { + return elements[0]; + } else { + Generic result = elements[0].numeric(); + for (int i = 1; i < elements.length; i++) { + result = result.add(elements[i].numeric()); + } + return result.divide(JsclInteger.valueOf(elements.length).numeric()); + } + } else { + return expressionValue(); + } + } + + @Nonnull + @Override + public Variable newInstance() { + return new Mean((JsclVector) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/stat/MeanSquareDeviation.java b/jscl/src/main/java/jscl/math/operator/stat/MeanSquareDeviation.java new file mode 100644 index 00000000..74991263 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/stat/MeanSquareDeviation.java @@ -0,0 +1,71 @@ +package jscl.math.operator.stat; + +import jscl.math.*; +import jscl.math.function.Sqrt; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/26/11 + * Time: 11:09 AM + */ +public class MeanSquareDeviation extends AbstractStatFunction { + + public static final String NAME = "mean_sq_dev"; + + public MeanSquareDeviation(JsclVector vector) { + this(new Generic[]{vector}); + } + + private MeanSquareDeviation(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new MeanSquareDeviation(parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + if (parameters[0] instanceof JsclVector) { + final JsclVector vector = (JsclVector) parameters[0]; + final Generic[] elements = vector.elements(); + + if (elements.length == 0) { + return new NumericWrapper(JsclInteger.ZERO); + } else if (elements.length == 1) { + return new NumericWrapper(JsclInteger.ZERO); + } else { + final Generic mean = new Mean(vector).numeric(); + + Generic result = new NumericWrapper(JsclInteger.ZERO); + for (int i = 0; i < elements.length; i++) { + result = result.add(elements[i].numeric().subtract(mean).pow(2)); + } + return new Sqrt(result.divide(JsclInteger.valueOf(elements.length).numeric())).numeric(); + } + } else { + return expressionValue(); + } + } + + @Nonnull + @Override + public Variable newInstance() { + return new MeanSquareDeviation((JsclVector) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/stat/Min.java b/jscl/src/main/java/jscl/math/operator/stat/Min.java new file mode 100644 index 00000000..a8693ea6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/stat/Min.java @@ -0,0 +1,74 @@ +package jscl.math.operator.stat; + +import jscl.math.*; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/26/11 + * Time: 11:09 AM + */ +public class Min extends AbstractStatFunction { + + public static final String NAME = "min"; + + public Min(JsclVector vector) { + this(new Generic[]{vector}); + } + + private Min(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Min(parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + if (parameters[0] instanceof JsclVector) { + final JsclVector vector = (JsclVector) parameters[0]; + final Generic[] elements = vector.elements(); + + if (elements.length == 0) { + return new NumericWrapper(JsclInteger.ZERO); + } else if (elements.length == 1) { + return elements[0]; + } else { + Generic result = elements[0].numeric(); + + for (int i = 1; i < elements.length; i++) { + final Generic candidate = elements[i].numeric(); + if (result.subtract(candidate).signum() < 0) { + result = candidate; + } + } + + return result; + } + } else { + return expressionValue(); + } + + } + + @Nonnull + @Override + public Variable newInstance() { + return new Min((JsclVector) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/stat/StandardDeviation.java b/jscl/src/main/java/jscl/math/operator/stat/StandardDeviation.java new file mode 100644 index 00000000..1d93f4da --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/stat/StandardDeviation.java @@ -0,0 +1,71 @@ +package jscl.math.operator.stat; + +import jscl.math.*; +import jscl.math.function.Sqrt; +import jscl.math.operator.Operator; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 12/26/11 + * Time: 11:09 AM + */ +public class StandardDeviation extends AbstractStatFunction { + + public static final String NAME = "st_dev"; + + public StandardDeviation(JsclVector vector) { + this(new Generic[]{vector}); + } + + private StandardDeviation(@Nonnull Generic[] parameters) { + super(NAME, parameters); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new StandardDeviation(parameters); + } + + @Override + public int getMinParameters() { + return 1; + } + + @Override + public Generic selfExpand() { + return expressionValue(); + } + + @Override + public Generic selfNumeric() { + if (parameters[0] instanceof JsclVector) { + final JsclVector vector = (JsclVector) parameters[0]; + final Generic[] elements = vector.elements(); + + if (elements.length == 0) { + return new NumericWrapper(JsclInteger.ZERO); + } else if (elements.length == 1) { + return new NumericWrapper(JsclInteger.ZERO); + } else { + final Generic mean = new Mean(vector).numeric(); + + Generic result = new NumericWrapper(JsclInteger.ZERO); + for (int i = 0; i < elements.length; i++) { + result = result.add(elements[i].numeric().subtract(mean).pow(2)); + } + return new Sqrt(result.divide(JsclInteger.valueOf(elements.length).numeric().subtract(JsclInteger.ONE.negate().numeric()))).numeric(); + } + } else { + return expressionValue(); + } + } + + @Nonnull + @Override + public Variable newInstance() { + return new StandardDeviation((JsclVector) null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Curl.java b/jscl/src/main/java/jscl/math/operator/vector/Curl.java new file mode 100644 index 00000000..a3bd3339 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Curl.java @@ -0,0 +1,56 @@ +package jscl.math.operator.vector; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Curl extends VectorOperator { + + public static final String NAME = "curl"; + + public Curl(Generic vector, Generic variable) { + super(NAME, new Generic[]{vector, variable}); + } + + private Curl(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables((JsclVector) parameters[1]); + if (parameters[0] instanceof JsclVector) { + JsclVector vector = (JsclVector) parameters[0]; + return vector.curl(variable); + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Curl(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "nabla"); + MathML e1 = element.element("mo"); + e1.appendChild(element.text("\u2227")); + element.appendChild(e1); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Curl(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Dalembertian.java b/jscl/src/main/java/jscl/math/operator/vector/Dalembertian.java new file mode 100644 index 00000000..34e99b40 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Dalembertian.java @@ -0,0 +1,51 @@ +package jscl.math.operator.vector; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Dalembertian extends VectorOperator { + + public static final String NAME = "dalembertian"; + + public Dalembertian(Generic vector, Generic variable) { + super(NAME, new Generic[]{vector, variable}); + } + + private Dalembertian(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables((JsclVector) parameters[1]); + Expression expression = parameters[0].expressionValue(); + return expression.dalembertian(variable); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Dalembertian(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "square"); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Dalembertian(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Del.java b/jscl/src/main/java/jscl/math/operator/vector/Del.java new file mode 100644 index 00000000..759dc6a0 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Del.java @@ -0,0 +1,80 @@ +package jscl.math.operator.vector; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.math.operator.product.GeometricProduct; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Del extends VectorOperator { + + public static final String NAME = "del"; + + public Del(Generic vector, Generic variable, Generic algebra) { + super(NAME, new Generic[]{vector, variable, algebra}); + } + + private Del(@Nonnull Generic parameters[]) { + super(NAME, createParameters(parameters)); + } + + private static Generic[] createParameters(@Nonnull Generic[] parameters) { + final Generic[] result = new Generic[3]; + + result[0] = parameters[0]; + result[1] = parameters[1]; + result[2] = parameters.length > 2 ? parameters[2] : JsclInteger.valueOf(0); + + return result; + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables((JsclVector) parameters[1]); + int algebra[] = GeometricProduct.algebra(parameters[2]); + if (parameters[0] instanceof JsclVector) { + JsclVector vector = (JsclVector) parameters[0]; + return vector.del(variable, algebra); + } + return expressionValue(); + } + + // todo serso: think + /*public String toString() { + final StringBuilder result = new StringBuilder(); + int n = 3; + if (parameters[2].signum() == 0) n = 2; + result.append(name); + result.append("("); + for (int i = 0; i < n; i++) { + result.append(parameters[i]).append(i < n - 1 ? ", " : ""); + } + result.append(")"); + return result.toString(); + }*/ + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Del(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "nabla"); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Del(null, null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Divergence.java b/jscl/src/main/java/jscl/math/operator/vector/Divergence.java new file mode 100644 index 00000000..1b646e1f --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Divergence.java @@ -0,0 +1,53 @@ +package jscl.math.operator.vector; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Divergence extends VectorOperator { + + public static final String NAME = "diverg"; + + public Divergence(Generic vector, Generic variable) { + super(NAME, new Generic[]{vector, variable}); + } + + private Divergence(@Nonnull Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables((JsclVector) parameters[1]); + if (parameters[0] instanceof JsclVector) { + JsclVector vector = (JsclVector) parameters[0]; + return vector.divergence(variable); + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Divergence(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "nabla"); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Divergence(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Grad.java b/jscl/src/main/java/jscl/math/operator/vector/Grad.java new file mode 100644 index 00000000..587d2353 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Grad.java @@ -0,0 +1,51 @@ +package jscl.math.operator.vector; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Grad extends VectorOperator { + + public static final String NAME = "grad"; + + public Grad(Generic expression, Generic variable) { + super(NAME, new Generic[]{expression, variable}); + } + + private Grad(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables((JsclVector) parameters[1]); + Expression expression = parameters[0].expressionValue(); + return expression.grad(variable); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Grad(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "nabla"); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Grad(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Jacobian.java b/jscl/src/main/java/jscl/math/operator/vector/Jacobian.java new file mode 100644 index 00000000..7531ad1e --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Jacobian.java @@ -0,0 +1,73 @@ +package jscl.math.operator.vector; + +import jscl.math.Generic; +import jscl.math.GenericVariable; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.function.Constant; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Jacobian extends VectorOperator { + + public static final String NAME = "jacobian"; + + public Jacobian(Generic vector, Generic variable) { + super(NAME, new Generic[]{vector, variable}); + } + + private Jacobian(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables(parameters[1]); + if (parameters[0] instanceof JsclVector) { + JsclVector vector = (JsclVector) parameters[0]; + return vector.jacobian(variable); + } + return expressionValue(); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Jacobian(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "nabla"); + MathML e1 = element.element("msup"); + parameters[0].toMathML(e1, null); + MathML e2 = element.element("mo"); + e2.appendChild(element.text("T")); + e1.appendChild(e2); + element.appendChild(e1); + } + + protected void operator(MathML element, String name) { + Variable variable[] = toVariables(GenericVariable.content(parameters[1])); + MathML e1 = element.element("msubsup"); + new Constant(name).toMathML(e1, null); + MathML e2 = element.element("mrow"); + for (int i = 0; i < variable.length; i++) variable[i].expressionValue().toMathML(e2, null); + e1.appendChild(e2); + e2 = element.element("mo"); + e2.appendChild(element.text("T")); + e1.appendChild(e2); + element.appendChild(e1); + } + + @Nonnull + public Variable newInstance() { + return new Jacobian(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/operator/vector/Laplacian.java b/jscl/src/main/java/jscl/math/operator/vector/Laplacian.java new file mode 100644 index 00000000..a30c29e2 --- /dev/null +++ b/jscl/src/main/java/jscl/math/operator/vector/Laplacian.java @@ -0,0 +1,50 @@ +package jscl.math.operator.vector; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.Variable; +import jscl.math.operator.Operator; +import jscl.math.operator.VectorOperator; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; + +public class Laplacian extends VectorOperator { + + public static final String NAME = "laplacian"; + + public Laplacian(Generic vector, Generic variable) { + super(NAME, new Generic[]{vector, variable}); + } + + private Laplacian(Generic parameter[]) { + super(NAME, parameter); + } + + @Override + public int getMinParameters() { + return 2; + } + + public Generic selfExpand() { + Variable variable[] = toVariables(parameters[1]); + Expression expression = parameters[0].expressionValue(); + return expression.laplacian(variable); + } + + @Nonnull + @Override + public Operator newInstance(@Nonnull Generic[] parameters) { + return new Laplacian(parameters); + } + + protected void bodyToMathML(MathML element) { + operator(element, "Delta"); + parameters[0].toMathML(element, null); + } + + @Nonnull + public Variable newInstance() { + return new Laplacian(null, null); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomial.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomial.java new file mode 100644 index 00000000..f2f98b8a --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomial.java @@ -0,0 +1,332 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Literal; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +final class ArrayPolynomial extends Polynomial { + Term content[]; + int size; + int degree; + + ArrayPolynomial(Monomial monomialFactory, Generic coefFactory) { + super(monomialFactory, coefFactory); + } + + ArrayPolynomial(int size, Monomial monomialFactory, Generic coefFactory) { + this(monomialFactory, coefFactory); + init(size); + } + + public int size() { + return size; + } + + void init(int size) { + content = new Term[size]; + this.size = size; + } + + void resize(int size) { + int length = content.length; + if (size < length) { + Term content[] = new Term[size]; + System.arraycopy(this.content, length - size, content, 0, size); + this.content = content; + this.size = size; + } + } + + public Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction, current); + } + + int indexOf(Monomial monomial, boolean direction) { + if (monomial == null) return direction ? size : 0; + int n = Arrays.binarySearch(content, new Term(monomial, null)); + return n < 0 ? -n - 1 : direction ? n : n + 1; + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + ArrayPolynomial q = (ArrayPolynomial) that; + 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] : 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; + } + + @Nonnull + public Polynomial multiply(@Nonnull Polynomial that) { + Polynomial p = valueOf(JsclInteger.valueOf(0)); + for (int i = 0; i < size; i++) { + Term t = content[i]; + p = p.multiplyAndSubtract(t.monomial(), t.coef().negate(), that); + } + return p; + } + + public Polynomial multiply(Generic generic) { + if (generic.signum() == 0) return valueOf(JsclInteger.valueOf(0)); + if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; + ArrayPolynomial p = newinstance(size); + for (int i = 0; i < size; i++) p.content[i] = content[i].multiply(generic); + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial multiply(Monomial monomial) { + if (defined) throw new UnsupportedOperationException(); + if (monomial.degree() == 0) return this; + ArrayPolynomial p = newinstance(size); + for (int i = 0; i < size; i++) p.content[i] = content[i].multiply(monomial); + 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; + ArrayPolynomial p = newinstance(size); + for (int i = 0; i < size; i++) p.content[i] = content[i].divide(generic); + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + if (monomial.degree() == 0) return this; + ArrayPolynomial p = newinstance(size); + for (int i = 0; i < size; i++) p.content[i] = content[i].divide(monomial); + p.degree = degree - monomial.degree(); + p.sugar = sugar - monomial.degree(); + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public Generic gcd() { + if (field) return coefficient(tail()); + Generic a = coefficient(JsclInteger.valueOf(0)); + for (int i = size - 1; 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; i < size; i++) m = m.gcd(content[i].monomial()); + return m; + } + + public int degree() { + return degree; + } + + public Polynomial valueOf(Polynomial polynomial) { + ArrayPolynomial p = newinstance(0); + p.init(polynomial); + return p; + } + + public Polynomial valueOf(Generic generic) { + ArrayPolynomial p = newinstance(0); + p.init(generic); + return p; + } + + public Polynomial valueOf(Monomial monomial) { + ArrayPolynomial p = newinstance(0); + p.init(monomial); + return p; + } + + public Polynomial freeze() { + return this; + } + + public Term head() { + return size > 0 ? 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; i < n; i++) { + Literal l = expression.literal(i); + JsclInteger en = expression.coef(i); + Monomial m = monomial(l); + l = l.divide(m.literalValue()); + Generic a2 = coefficient(l.degree() > 0 ? 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; i < size; i++) { + Map.Entry e = (Map.Entry) it.next(); + Monomial m = (Monomial) e.getKey(); + Generic a = (Generic) e.getValue(); + content[i] = 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) { + init(1); + content[0] = new Term(monomial(Literal.newInstance()), a); + } else init(0); + degree = 0; + sugar = 0; + } + } + + void init(Monomial monomial) { + init(1); + content[0] = new Term(monomial, coefficient(JsclInteger.valueOf(1))); + degree = monomial.degree(); + sugar = monomial.degree(); + } + + protected ArrayPolynomial newinstance(int n) { + return new ArrayPolynomial(n, monomialFactory, coefFactory); + } + + class ContentIterator implements Iterator { + final boolean direction; + int index; + + ContentIterator(boolean direction, Monomial current) { + this.direction = direction; + index = indexOf(current, direction); + } + + public boolean hasNext() { + return direction ? index > 0 : index < size; + } + + public Object next() { + return direction ? content[--index] : content[index++]; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialBoolean.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialBoolean.java new file mode 100644 index 00000000..aab03dfa --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialBoolean.java @@ -0,0 +1,115 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.JsclBoolean; +import jscl.math.JsclInteger; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +class ArrayPolynomialBoolean extends ArrayPolynomialModular { + ArrayPolynomialBoolean(Monomial monomialFactory) { + super(monomialFactory, JsclBoolean.factory); + } + + ArrayPolynomialBoolean(int size, Monomial monomialFactory) { + this(monomialFactory); + init(size); + } + + void init(int size) { + monomial = new Monomial[size]; + this.size = size; + } + + void resize(int size) { + int length = monomial.length; + if (size < length) { + Monomial monomial[] = new Monomial[size]; + System.arraycopy(this.monomial, length - size, monomial, 0, size); + this.monomial = monomial; + this.size = size; + } + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + ArrayPolynomialBoolean q = (ArrayPolynomialBoolean) that; + ArrayPolynomialBoolean p = (ArrayPolynomialBoolean) 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) { + 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; i < size; i++) { + Monomial m = this.monomial[i].multiply(monomial); + if (map.containsKey(m)) map.remove(m); + else map.put(m, null); + } + ArrayPolynomialBoolean p = (ArrayPolynomialBoolean) newinstance(map.size()); + Iterator it = map.keySet().iterator(); + for (int i = 0; i < p.size; i++) p.monomial[i] = (Monomial) it.next(); + p.degree = degree(p); + p.sugar = sugar + monomial.degree(); + return p; + } else { + if (monomial.degree() == 0) return this; + ArrayPolynomialBoolean p = (ArrayPolynomialBoolean) newinstance(size); + for (int i = 0; i < size; i++) p.monomial[i] = this.monomial[i].multiply(monomial); + p.degree = degree + monomial.degree(); + p.sugar = sugar + monomial.degree(); + return p; + } + } + + protected Generic getCoef(int n) { + return new JsclBoolean(1); + } + + protected void setCoef(int n, Generic generic) { + } + + protected ArrayPolynomialGeneric newinstance(int n) { + return new ArrayPolynomialBoolean(n, monomialFactory); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialGeneric.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialGeneric.java new file mode 100644 index 00000000..1b2e98f1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialGeneric.java @@ -0,0 +1,429 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Literal; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +class ArrayPolynomialGeneric extends Polynomial { + Generic coef[]; + Monomial monomial[]; + int size; + int degree; + + ArrayPolynomialGeneric(Monomial monomialFactory, Generic coefFactory) { + super(monomialFactory, coefFactory); + } + + ArrayPolynomialGeneric(int size, Monomial monomialFactory, Generic coefFactory) { + this(monomialFactory, coefFactory); + init(size); + } + + public int size() { + return size; + } + + void init(int size) { + monomial = new Monomial[size]; + coef = new Generic[size]; + this.size = size; + } + + void resize(int size) { + int length = monomial.length; + if (size < length) { + Monomial monomial[] = new Monomial[size]; + Generic coef[] = new Generic[size]; + System.arraycopy(this.monomial, length - size, monomial, 0, size); + System.arraycopy(this.coef, length - size, coef, 0, size); + this.monomial = monomial; + this.coef = coef; + this.size = size; + } + } + + public Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction, current); + } + + Term term(final int index) { + return new Term(monomial[index], null) { + public Generic coef() { + return coef == null ? getCoef(index) : coef; + } + }; + } + + int indexOf(Monomial monomial, boolean direction) { + if (monomial == null) return direction ? size : 0; + int n = Arrays.binarySearch(this.monomial, monomial, ordering); + return n < 0 ? -n - 1 : direction ? n : n + 1; + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) that; + 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).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; + } + + @Nonnull + public Polynomial multiply(@Nonnull Polynomial that) { + Polynomial p = newinstance(0); + for (int i = 0; i < size; i++) p = p.multiplyAndSubtract(monomial[i], getCoef(i).negate(), that); + return p; + } + + public Polynomial multiply(Generic generic) { + if (generic.signum() == 0) return valueOf(JsclInteger.valueOf(0)); + if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; + ArrayPolynomialGeneric p = newinstance(size); + System.arraycopy(monomial, 0, p.monomial, 0, size); + for (int i = 0; i < size; i++) p.setCoef(i, getCoef(i).multiply(generic)); + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial multiply(Monomial monomial) { + if (defined) throw new UnsupportedOperationException(); + if (monomial.degree() == 0) return this; + ArrayPolynomialGeneric p = newinstance(size); + for (int i = 0; i < size; i++) { + p.monomial[i] = this.monomial[i].multiply(monomial); + p.setCoef(i, getCoef(i)); + } + 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; + ArrayPolynomialGeneric p = newinstance(size); + System.arraycopy(monomial, 0, p.monomial, 0, size); + for (int i = 0; i < size; i++) p.setCoef(i, getCoef(i).divide(generic)); + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + if (monomial.degree() == 0) return this; + ArrayPolynomialGeneric p = newinstance(size); + for (int i = 0; i < size; i++) { + p.monomial[i] = this.monomial[i].divide(monomial); + p.setCoef(i, getCoef(i)); + } + p.degree = degree - monomial.degree(); + p.sugar = sugar - monomial.degree(); + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public Generic gcd() { + if (field) return coefficient(tail()); + Generic a = coefficient(JsclInteger.valueOf(0)); + for (int i = size - 1; 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; i < size; i++) m = m.gcd(monomial[i]); + return m; + } + + public int degree() { + return degree; + } + + public Polynomial valueOf(Polynomial polynomial) { + ArrayPolynomialGeneric p = newinstance(0); + p.init(polynomial); + return p; + } + + public Polynomial valueOf(Generic generic) { + ArrayPolynomialGeneric p = newinstance(0); + p.init(generic); + return p; + } + + public Polynomial valueOf(Monomial monomial) { + ArrayPolynomialGeneric p = newinstance(0); + p.init(monomial); + return p; + } + + public Polynomial freeze() { + return this; + } + + public Term head() { + return size > 0 ? 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; i < size; i++) { + Monomial m = monomial[i]; + Generic a = getCoef(i).expressionValue(); + s = s.add(m.degree() > 0 ? a.multiply(Expression.valueOf(m.literalValue())) : a); + } + return s; + } + + public Generic[] elements() { + Generic a[] = new Generic[size]; + for (int i = 0; i < size; i++) a[i] = getCoef(i); + return a; + } + + public int compareTo(Polynomial polynomial) { + ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) polynomial; + int i1 = size; + int i2 = q.size; + Monomial m1 = i1 == 0 ? null : monomial[--i1]; + Monomial m2 = i2 == 0 ? null : q.monomial[--i2]; + while (m1 != null || m2 != null) { + int c = m1 == null ? -1 : (m2 == null ? 1 : ordering.compare(m1, m2)); + if (c < 0) return -1; + else if (c > 0) 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; i < size; i++) setCoef(i, q.getCoef(i)); + degree = q.degree; + sugar = q.sugar; + } + + void init(Expression expression) { + Map map = new TreeMap(ordering); + int n = expression.size(); + for (int i = 0; i < n; i++) { + Literal l = expression.literal(i); + JsclInteger en = expression.coef(i); + Monomial m = monomial(l); + l = l.divide(m.literalValue()); + Generic a2 = coefficient(l.degree() > 0 ? 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; i < size; i++) { + Map.Entry e = (Map.Entry) it.next(); + Monomial m = (Monomial) e.getKey(); + Generic a = (Generic) e.getValue(); + monomial[i] = m; + setCoef(i, 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) { + init(1); + monomial[0] = monomial(Literal.newInstance()); + setCoef(0, a); + } else init(0); + degree = 0; + sugar = 0; + } + } + + void init(Monomial monomial) { + init(1); + this.monomial[0] = monomial; + setCoef(0, coefficient(JsclInteger.valueOf(1))); + degree = monomial.degree(); + sugar = monomial.degree(); + } + + protected ArrayPolynomialGeneric newinstance(int n) { + return new ArrayPolynomialGeneric(n, monomialFactory, coefFactory); + } + + class ContentIterator implements Iterator { + final boolean direction; + int index; + + ContentIterator(boolean direction, Monomial current) { + this.direction = direction; + index = indexOf(current, direction); + } + + public boolean hasNext() { + return direction ? index > 0 : index < size; + } + + public Object next() { + return direction ? term(--index) : term(index++); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialInteger.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialInteger.java new file mode 100644 index 00000000..86967712 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialInteger.java @@ -0,0 +1,231 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.JsclInteger; + +import javax.annotation.Nonnull; +import java.math.BigInteger; + +class ArrayPolynomialInteger extends ArrayPolynomialGeneric { + BigInteger coef[]; + + ArrayPolynomialInteger(Monomial monomialFactory) { + super(monomialFactory, JsclInteger.factory); + } + + ArrayPolynomialInteger(int size, Monomial monomialFactory) { + this(monomialFactory); + init(size); + } + + void init(int size) { + monomial = new Monomial[size]; + coef = new BigInteger[size]; + this.size = size; + } + + void resize(int size) { + int length = monomial.length; + if (size < length) { + Monomial monomial[] = new Monomial[size]; + BigInteger coef[] = new BigInteger[size]; + System.arraycopy(this.monomial, length - size, monomial, 0, size); + System.arraycopy(this.coef, length - size, coef, 0, size); + this.monomial = monomial; + this.coef = coef; + this.size = size; + } + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + ArrayPolynomialInteger q = (ArrayPolynomialInteger) that; + 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].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 < size; i++) { + p.monomial[i] = monomial[i]; + p.coef[i] = coef[i].multiply(g); + } + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial multiply(Monomial monomial) { + if (defined) throw new UnsupportedOperationException(); + if (monomial.degree() == 0) return this; + ArrayPolynomialInteger p = (ArrayPolynomialInteger) newinstance(size); + for (int i = 0; i < size; i++) { + p.monomial[i] = this.monomial[i].multiply(monomial); + p.coef[i] = coef[i]; + } + p.degree = degree + monomial.degree(); + p.sugar = sugar + monomial.degree(); + return p; + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + BigInteger g = generic.integerValue().content(); + if (g.compareTo(BigInteger.valueOf(1)) == 0) return this; + ArrayPolynomialInteger p = (ArrayPolynomialInteger) newinstance(size); + for (int i = 0; i < size; i++) { + p.monomial[i] = monomial[i]; + p.coef[i] = coef[i].divide(g); + } + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial gcd(Polynomial polynomial) { + return valueOf(genericValue().gcd(polynomial.genericValue())); + } + + public Generic gcd() { + BigInteger a = BigInteger.valueOf(0); + for (int i = size - 1; 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/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialModular.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialModular.java new file mode 100644 index 00000000..538cd58f --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialModular.java @@ -0,0 +1,210 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.ModularInteger; + +import javax.annotation.Nonnull; + +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 (size < length) { + Monomial monomial[] = new Monomial[size]; + int coef[] = new int[size]; + System.arraycopy(this.monomial, length - size, monomial, 0, size); + System.arraycopy(this.coef, length - size, coef, 0, size); + this.monomial = monomial; + this.coef = coef; + this.size = size; + } + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + ArrayPolynomialModular q = (ArrayPolynomialModular) that; + 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]) % 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; i < size; i++) { + p.monomial[i] = monomial[i]; + p.coef[i] = (int) (((long) coef[i] * (long) g) % modulo); + } + p.degree = degree; + p.sugar = sugar; + return p; + } + + public Polynomial multiply(Monomial monomial) { + if (defined) throw new UnsupportedOperationException(); + if (monomial.degree() == 0) return this; + ArrayPolynomialModular p = (ArrayPolynomialModular) newinstance(size); + for (int i = 0; i < size; i++) { + p.monomial[i] = this.monomial[i].multiply(monomial); + p.coef[i] = coef[i]; + } + p.degree = degree + monomial.degree(); + p.sugar = sugar + monomial.degree(); + return p; + } + + protected Generic coefficient(Generic generic) { + return coefFactory.valueOf(generic); + } + + protected Generic getCoef(int n) { + return new ModularInteger(coef[n], modulo); + } + + protected void setCoef(int n, Generic generic) { + coef[n] = generic.integerValue().intValue(); + } + + protected ArrayPolynomialGeneric newinstance(int n) { + return new ArrayPolynomialModular(n, monomialFactory, coefFactory); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialRational.java b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialRational.java new file mode 100644 index 00000000..fce09a89 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ArrayPolynomialRational.java @@ -0,0 +1,52 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.Rational; + +class ArrayPolynomialRational extends ArrayPolynomialGeneric { + Rational coef[]; + + ArrayPolynomialRational(Monomial monomialFactory) { + super(monomialFactory, Rational.factory); + } + + ArrayPolynomialRational(int size, Monomial monomialFactory) { + this(monomialFactory); + init(size); + } + + void init(int size) { + monomial = new Monomial[size]; + coef = new Rational[size]; + this.size = size; + } + + void resize(int size) { + int length = monomial.length; + if (size < length) { + Monomial monomial[] = new Monomial[size]; + Rational coef[] = new Rational[size]; + System.arraycopy(this.monomial, length - size, monomial, 0, size); + System.arraycopy(this.coef, length - size, coef, 0, size); + this.monomial = monomial; + this.coef = coef; + this.size = size; + } + } + + protected Generic coefficient(Generic generic) { + return coefFactory.valueOf(generic); + } + + protected Generic getCoef(int n) { + return coef[n]; + } + + protected void setCoef(int n, Generic generic) { + coef[n] = (Rational) generic; + } + + protected ArrayPolynomialGeneric newinstance(int n) { + return new ArrayPolynomialRational(n, monomialFactory); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/Basis.java b/jscl/src/main/java/jscl/math/polynomial/Basis.java new file mode 100644 index 00000000..101a400e --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/Basis.java @@ -0,0 +1,129 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Variable; +import jscl.math.polynomial.groebner.Standard; +import jscl.util.ArrayUtils; + +import java.util.ArrayList; +import java.util.List; + +public class Basis { + public static final int DATA_STRUCT = 0x3; + public static final int ARRAY_DECLINED = 0x0; + public static final int ARRAY = 0x1; + public static final int TREE = 0x2; + public static final int LIST = 0x3; + public static final int DEGREE = 0x4; + public static final int DEFINING_EQS = 0x8; + public static final int POWER_SIZE = 0x30; + public static final int POWER_32 = 0x00; + public static final int POWER_8 = 0x10; + public static final int POWER_2 = 0x20; + public static final int POWER_2_DEFINED = 0x30; + public static final int GEO_BUCKETS = 0x40; + public static final int ALGORITHM = 0x180; + public static final int BUCHBERGER = 0x000; + public static final int F4 = 0x080; + public static final int BLOCK = 0x100; + public static final int INSTRUMENTED = 0x200; + public static final int GM_SETTING = 0x400; + public static final int SUGAR = 0x800; + public static final int FUSSY = 0x1000; + public static final int F4_SIMPLIFY = 0x2000; + static final int DEFAULT = GM_SETTING | SUGAR; + final Polynomial factory; + final Generic element[]; + + public Basis(Generic element[], Polynomial factory) { + this.element = element; + this.factory = factory; + } + + public static Basis compute(Generic generic[], Variable unknown[]) { + return compute(generic, unknown, Monomial.lexicographic); + } + + public static Basis compute(Generic generic[], Variable unknown[], Ordering ordering) { + return compute(generic, unknown, ordering, 0); + } + + public static Basis compute(Generic generic[], Variable unknown[], Ordering ordering, int modulo) { + return compute(generic, unknown, ordering, modulo, 0); + } + + public static Basis compute(Generic generic[], Variable unknown[], Ordering ordering, int modulo, int flags) { + flags ^= DEFAULT; + return compute(generic, unknown, ordering, modulo, flags, (flags & Basis.DEGREE) > 0, (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 static Generic[] defining(Variable unknown[], int modulo) { + Generic a[] = new Generic[unknown.length]; + for (int i = 0; i < unknown.length; i++) { + Generic s = unknown[i].expressionValue(); + a[i] = s.subtract(s.pow(modulo)); + } + return a; + } + + public static boolean compatible(Generic generic[]) { + return !(generic.length > 0 && 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 (Variable anUnknown : unknown) l.add(anUnknown); + int n = 0; + for (int i = 0; i < va.length; i++) { + Variable v = va[i]; + if (!l.contains(v)) { + l.add(n++, v); + } + } + return (Variable[]) ArrayUtils.toArray(l, new Variable[l.size()]); + } + + public Basis valueof(Generic generic[]) { + return new Basis(generic, factory); + } + + public Basis modulo(int modulo) { + return new Basis(element, Polynomial.factory(factory, modulo)); + } + + public Generic[] elements() { + return element; + } + + public Ordering ordering() { + return factory.ordering(); + } + + public Polynomial polynomial(Generic generic) { + return factory.valueOf(generic).normalize().freeze(); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("{"); + for (int i = 0; i < element.length; i++) { + buffer.append(polynomial(element[i])).append(i < element.length - 1 ? ", " : ""); + } + buffer.append("}"); + buffer.append(", " + ArrayUtils.toString(factory.monomialFactory.unknown())); + return buffer.toString(); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/BooleanMonomial.java b/jscl/src/main/java/jscl/math/polynomial/BooleanMonomial.java new file mode 100644 index 00000000..16d7bb41 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/BooleanMonomial.java @@ -0,0 +1,112 @@ +package jscl.math.polynomial; + +import jscl.math.NotDivisibleException; +import jscl.math.Variable; + +class BooleanMonomial extends SmallMonomial { + static final int log2n = 1; + static final int log2p = 5 - log2n; + static final int nmask = (1 << (1 << log2n)) - 1; + static final int pmask = (1 << log2p) - 1; + + BooleanMonomial(Variable unknown[], Ordering ordering) { + this(((unknown.length - 1) >> 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 < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = a + b; + if (c > nmask) throw new ArithmeticException(); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public boolean multiple(Monomial monomial, boolean strict) { + boolean equal = true; + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + if (a < b) return false; + equal &= a == b; + } + return !strict || !equal; + } + + public Monomial divide(Monomial monomial) throws ArithmeticException { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = a - b; + if (c < 0) throw new NotDivisibleException(); + m.element[q] |= c << r; + } + m.degree = degree - monomial.degree; + return m; + } + + public Monomial gcd(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = Math.min(a, b); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public Monomial scm(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = Math.max(a, b); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public int element(int n) { + if (reverse()) n = unknown.length - 1 - n; + int q = n >> log2p; + int r = (n & pmask) << log2n; + return (element[q] >> r) & nmask; + } + + void put(int n, int integer) { + if (reverse()) n = unknown.length - 1 - n; + int q = n >> log2p; + int r = (n & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int c = a + integer; + if (c > nmask) throw new ArithmeticException(); + element[q] |= c << r; + degree += c - a; + } + + protected Monomial newinstance() { + return new BooleanMonomial(element.length, unknown, ordering); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/DefinedBooleanMonomial.java b/jscl/src/main/java/jscl/math/polynomial/DefinedBooleanMonomial.java new file mode 100644 index 00000000..7ad1ddf9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/DefinedBooleanMonomial.java @@ -0,0 +1,32 @@ +package jscl.math.polynomial; + +import jscl.math.Variable; + +class DefinedBooleanMonomial extends BooleanMonomial { + DefinedBooleanMonomial(Variable unknown[], Ordering ordering) { + super(unknown, ordering); + } + + DefinedBooleanMonomial(int length, Variable unknown[], Ordering ordering) { + super(length, unknown, ordering); + } + + public Monomial multiply(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = a + b; + if (c > 1) c = 1; + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + protected Monomial newinstance() { + return new DefinedBooleanMonomial(element.length, unknown, ordering); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/DegreeOrdering.java b/jscl/src/main/java/jscl/math/polynomial/DegreeOrdering.java new file mode 100644 index 00000000..1614f3e7 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/DegreeOrdering.java @@ -0,0 +1,4 @@ +package jscl.math.polynomial; + +public interface DegreeOrdering { +} diff --git a/jscl/src/main/java/jscl/math/polynomial/GeoBucket.java b/jscl/src/main/java/jscl/math/polynomial/GeoBucket.java new file mode 100644 index 00000000..121b954d --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/GeoBucket.java @@ -0,0 +1,357 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.util.Iterator; + +final class GeoBucket extends Polynomial { + final Polynomial factory; + Polynomial content[]; + int size; + boolean mutable = true; + boolean canonicalized = true; + + GeoBucket(Polynomial factory) { + super(factory.monomialFactory, factory.coefFactory); + this.factory = factory; + } + + GeoBucket(int size, Polynomial factory) { + this(factory); + init(size); + } + + static int log(int n) { + int i; + for (i = 0; n > 3; n >>= 2) i++; + return i; + } + + public int size() { + return size; + } + + void init(int size) { + content = new Polynomial[size]; + this.size = size; + } + + void resize(int size) { + Polynomial content[] = new Polynomial[size]; + System.arraycopy(this.content, 0, content, 0, Math.min(this.size, size)); + this.content = content; + this.size = size; + } + + public Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction, current); + } + + 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; i < size; i++) { + Polynomial p = content[i]; + if (p == null) continue; + s = s.add(p); + sugar = Math.max(sugar, p.sugar()); + content[i] = null; + } + resize(log(s.size()) + 1); + set(s.normalize()); + canonicalized = true; + setSugar(sugar); + mutable = false; + } + + Polynomial polynomial() { + if (canonicalized) return content[size - 1]; + else throw new UnsupportedOperationException(); + } + + void set(Polynomial polynomial) { + content[size - 1] = polynomial; + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (mutable) { + Polynomial q = ((GeoBucket) that).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 < log(s.size())) { + n++; + if (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(that); + } + + 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 < log(s.size())) { + n++; + if (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 < log(s.size())) { + n++; + if (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; i < size; i++) { + Polynomial p = content[i]; + if (p != null) content[i] = p.multiply(generic); + } + normalized = false; + return this; + } else return copy().multiply(generic); + } + + public Polynomial multiply(Monomial monomial) { + if (mutable) { + set(polynomial().multiply(monomial)); + return this; + } else return copy().multiply(monomial); + } + + public Polynomial divide(Generic generic) throws ArithmeticException { + if (mutable) { + if (canonicalized) set(polynomial().divide(generic)); + else for (int i = 0; i < size; i++) { + Polynomial p = content[i]; + if (p != null) content[i] = p.divide(generic); + } + normalized = false; + return this; + } else return copy().divide(generic); + } + + public Polynomial divide(Monomial monomial) throws ArithmeticException { + if (mutable) { + set(polynomial().divide(monomial)); + return this; + } else return copy().divide(monomial); + } + + public Polynomial gcd(Polynomial polynomial) { + throw new UnsupportedOperationException(); + } + + public Generic gcd() { + if (field) return coefficient(tail()); + return canonicalized ? polynomial().gcd() : coefficient(JsclInteger.valueOf(0)); + } + + public int degree() { + return polynomial().degree(); + } + + public Polynomial valueof(GeoBucket bucket) { + return valueOf(bucket.polynomial().copy()); + } + + public Polynomial valueOf(Polynomial polynomial) { + if (polynomial instanceof GeoBucket) { + return valueof((GeoBucket) polynomial); + } else { + GeoBucket b = new GeoBucket(log(polynomial.size()) + 1, factory); + b.set(polynomial); + return b; + } + } + + public Polynomial valueOf(Generic generic) { + return valueOf(factory.valueOf(generic)); + } + + public Polynomial valueOf(Monomial monomial) { + return valueOf(factory.valueOf(monomial)); + } + + public Polynomial freeze() { + canonicalize(); + return this; + } + + public Term head() { + return canonicalized ? polynomial().head() : super.head(); + } + + public Term tail() { + return canonicalized ? polynomial().tail() : super.tail(); + } + + public Generic coefficient(Monomial monomial) { + return canonicalized ? polynomial().coefficient(monomial) : super.coefficient(monomial); + } + + public int sugar() { + return polynomial().sugar(); + } + + public int index() { + return polynomial().index(); + } + + public void setSugar(int n) { + polynomial().setSugar(n); + } + + public void setIndex(int n) { + polynomial().setIndex(n); + } + + public Generic genericValue() { + return polynomial().genericValue(); + } + + public Generic[] elements() { + return polynomial().elements(); + } + + public int compareTo(GeoBucket bucket) { + return polynomial().compareTo(bucket.polynomial()); + } + + public int compareTo(Polynomial polynomial) { + return compareTo((GeoBucket) polynomial); + } + + public String toString() { + if (canonicalized) return polynomial().toString(); + else { + StringBuffer buffer = new StringBuffer(); + buffer.append("{"); + for (int i = 0; i < size; i++) { + Polynomial p = content[i]; + buffer.append(p == null ? factory.valueOf(JsclInteger.valueOf(0)) : p).append(i < size - 1 ? ", " : ""); + } + buffer.append("}"); + return buffer.toString(); + } + } + + public void toMathML(MathML element, Object data) { + if (canonicalized) polynomial().toMathML(element, data); + else { + MathML e1 = element.element("mfenced"); + MathML e2 = element.element("mtable"); + for (int i = 0; i < size; i++) { + MathML e3 = element.element("mtr"); + MathML e4 = element.element("mtd"); + Polynomial p = content[i]; + (p == null ? factory.valueOf(JsclInteger.valueOf(0)) : p).toMathML(e4, null); + e3.appendChild(e4); + e2.appendChild(e3); + } + e1.appendChild(e2); + element.appendChild(e1); + } + } + + class ContentIterator implements Iterator { + final boolean direction; + Term term; + + ContentIterator(boolean direction, Monomial current) { + this.direction = direction; + term = new Term(current, coefficient(JsclInteger.valueOf(0))); + seek(); + } + + void seek() { + while (true) { + int n = 0; + Term t = null; + for (int i = 0; i < size; i++) { + Polynomial p = content[i]; + if (p == null) continue; + Iterator it = p.iterator(direction, term.monomial()); + Term u = it.hasNext() ? (Term) it.next() : null; + if (u == null) continue; + if (t == null || (direction ? -1 : 1) * ordering.compare(t.monomial(), u.monomial()) > 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(); + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/ListPolynomial.java b/jscl/src/main/java/jscl/math/polynomial/ListPolynomial.java new file mode 100644 index 00000000..340f8142 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/ListPolynomial.java @@ -0,0 +1,322 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Literal; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.*; + +final class ListPolynomial extends Polynomial { + final List content = new LinkedList(); + int degree; + boolean mutable = true; + + ListPolynomial(Monomial monomialFactory, Generic coefFactory) { + super(monomialFactory, coefFactory); + } + + public int size() { + return content.size(); + } + + public final Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction, current); + } + + int indexOf(Monomial monomial, boolean direction) { + if (monomial == null) return direction ? content.size() : 0; + int n = ArrayUtils.binarySearch(content, new Term(monomial, null)); + return n < 0 ? -n - 1 : direction ? n : n + 1; + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + if (mutable) { + ListPolynomial q = (ListPolynomial) that; + 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() : 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() : null; + } + } + degree = degree(this); + sugar = Math.max(sugar, q.sugar); + normalized = false; + return this; + } else return copy().subtract(that); + } + + 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; i < n; i++) { + Literal l = expression.literal(i); + JsclInteger en = expression.coef(i); + Monomial m = monomial(l); + l = l.divide(m.literalValue()); + Generic a2 = coefficient(l.degree() > 0 ? 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.newInstance()), 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); + } + + class ContentIterator implements ListIterator { + final ListIterator iterator; + final boolean direction; + + ContentIterator(boolean direction, Monomial current) { + this.direction = direction; + iterator = content.listIterator(indexOf(current, direction)); + } + + public boolean hasNext() { + return direction ? iterator.hasPrevious() : iterator.hasNext(); + } + + public Object next() { + return direction ? iterator.previous() : iterator.next(); + } + + public boolean hasPrevious() { + return direction ? iterator.hasNext() : iterator.hasPrevious(); + } + + public Object previous() { + return direction ? iterator.next() : iterator.previous(); + } + + public int nextIndex() { + return direction ? iterator.previousIndex() : iterator.nextIndex(); + } + + public int previousIndex() { + return direction ? iterator.nextIndex() : iterator.previousIndex(); + } + + public void remove() { + iterator.remove(); + } + + public void set(Object o) { + iterator.set(o); + } + + public void add(Object o) { + iterator.add(o); + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/Monomial.java b/jscl/src/main/java/jscl/math/polynomial/Monomial.java new file mode 100644 index 00000000..43715ed9 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/Monomial.java @@ -0,0 +1,410 @@ +package jscl.math.polynomial; + +import jscl.math.Literal; +import jscl.math.NotDivisibleException; +import jscl.math.Variable; +import jscl.math.function.Fraction; +import jscl.math.function.Pow; +import jscl.mathml.MathML; + +import java.util.Iterator; + +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); + } + + static Monomial factory(Variable unknown[]) { + return factory(unknown, lexicographic); + } + + static Monomial factory(Variable unknown[], Ordering ordering) { + return factory(unknown, ordering, 0); + } + + static Monomial factory(Variable unknown[], Ordering ordering, int power_size) { + switch (power_size) { + case Basis.POWER_8: + return new SmallMonomial(unknown, small(ordering)); + case Basis.POWER_2: + return new BooleanMonomial(unknown, small(ordering)); + case Basis.POWER_2_DEFINED: + return new DefinedBooleanMonomial(unknown, small(ordering)); + default: + return new Monomial(unknown, ordering); + } + } + + static Ordering small(Ordering ordering) { + if (ordering == lexicographic) return SmallMonomial.lexicographic; + else if (ordering == totalDegreeLexicographic) return SmallMonomial.totalDegreeLexicographic; + else if (ordering == degreeReverseLexicographic) return SmallMonomial.degreeReverseLexicographic; + else throw new UnsupportedOperationException(); + } + + static int variable(Variable v, Variable unknown[]) { + int i = 0; + for (; i < unknown.length; i++) if (unknown[i].equals(v)) break; + return i; + } + + public Variable[] unknown() { + return unknown; + } + + public Ordering ordering() { + return ordering; + } + + public Monomial multiply(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + m.element[i] = element[i] + monomial.element[i]; + } + m.degree = degree + monomial.degree; + return m; + } + + public boolean multiple(Monomial monomial) { + return multiple(monomial, false); + } + + public boolean multiple(Monomial monomial, boolean strict) { + boolean equal = true; + for (int i = 0; i < unknown.length; i++) { + if (element[i] < monomial.element[i]) return false; + equal &= element[i] == monomial.element[i]; + } + return strict ? !equal : true; + } + + public Monomial divide(Monomial monomial) throws ArithmeticException { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int n = element[i] - monomial.element[i]; + if (n < 0) throw new NotDivisibleException(); + m.element[i] = n; + } + m.degree = degree - monomial.degree; + return m; + } + + public Monomial gcd(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int n = Math.min(element[i], monomial.element[i]); + m.element[i] = n; + m.degree += n; + } + return m; + } + + public Monomial scm(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int n = Math.max(element[i], monomial.element[i]); + m.element[i] = n; + m.degree += n; + } + return m; + } + + public int degree() { + return degree; + } + + public Monomial valueof(Monomial monomial) { + Monomial m = newinstance(); + System.arraycopy(monomial.element, 0, m.element, 0, m.element.length); + m.degree = monomial.degree; + return m; + } + + public Monomial valueof(Literal literal) { + Monomial m = newinstance(); + m.init(literal); + return m; + } + + public Literal literalValue() { + return Literal.valueOf(this); + } + + public int element(int n) { + return element[n]; + } + + public Iterator iterator() { + return iterator(newinstance()); + } + + public Iterator iterator(Monomial beginning) { + return new MonomialIterator(beginning, this); + } + + public Iterator divisor() { + return divisor(newinstance()); + } + + public Iterator divisor(Monomial beginning) { + return new MonomialDivisor(beginning, this); + } + + public int compareTo(Monomial monomial) { + return ordering.compare(this, monomial); + } + + public int compareTo(Object o) { + return compareTo((Monomial) o); + } + + void init(Literal literal) { + int s = literal.size(); + for (int i = 0; i < s; i++) { + Variable v = literal.getVariable(i); + int c = literal.getPower(i); + int n = variable(v, unknown); + if (n < unknown.length) put(n, c); + } + } + + void put(int n, int integer) { + element[n] += integer; + degree += integer; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + if (degree == 0) buffer.append("1"); + boolean b = false; + for (int i = 0; i < unknown.length; i++) { + int c = element(i); + if (c > 0) { + if (b) buffer.append("*"); + else b = true; + Variable v = unknown[i]; + if (c == 1) buffer.append(v); + else { + if (v instanceof Fraction || 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; i < unknown.length; i++) { + int c = element(i); + if (c > 0) { + 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 (n < current.element.length && current.element[n] == 0) n++; + if (n < current.element.length) { + s = current.element[n]; + current.element[n] = 0; + n++; + } + if (n < current.element.length) { + current.element[n]++; + fill(s - 1); + } else { + current.degree++; + fill(s + 1); + } + } + + private void fill(int s) { + current.element[0] = s; + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} + +class MonomialDivisor extends MonomialIterator { + MonomialDivisor(Monomial beginning, Monomial monomial) { + super(beginning, monomial); + if (hasNext()) seek(); + } + + void seek() { + int n = current.element.length; + while (n > 0) { + 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 (p < current.element.length && current.element[p] > monomial.element[p]) increment(); + } + + void increment() { + int s = 0; + int n = 0; + while (n < current.element.length && current.element[n] == 0) n++; + if (n < current.element.length) { + s = current.element[n]; + current.element[n] = 0; + n++; + } + while (n < current.element.length && current.element[n] == monomial.element[n]) { + s += current.element[n]; + current.element[n] = 0; + n++; + } + if (n < current.element.length) { + current.element[n]++; + fill(s - 1); + } else { + current.degree++; + fill(s + 1); + } + } + + private void fill(int s) { + for (int i = 0; i < current.element.length; i++) { + int d = Math.min(monomial.element[i] - current.element[i], s); + current.element[i] += d; + s -= d; + } + } +} + +class Lexicographic extends Ordering { + public static final Ordering ordering = new Lexicographic(); + + Lexicographic() { + } + + public int compare(Monomial m1, Monomial m2) { + int c1[] = m1.element; + int c2[] = m2.element; + int n = c1.length; + for (int i = n - 1; i >= 0; i--) { + if (c1[i] < c2[i]) return -1; + else 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.degree < m2.degree) return -1; + else if (m1.degree > m2.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.degree < m2.degree) return -1; + else if (m1.degree > m2.degree) return 1; + else { + int c1[] = m1.element; + int c2[] = m2.element; + int n = c1.length; + for (int i = 0; i < n; i++) { + if (c1[i] > c2[i]) return -1; + else if (c1[i] < c2[i]) return 1; + } + return 0; + } + } +} + +class KthElimination extends Ordering { + final int k; + + KthElimination(int k, int direction) { + this.k = k; + } + + public int compare(Monomial m1, Monomial m2) { + int c1[] = m1.element; + int c2[] = m2.element; + int n = c1.length; + int k = n - this.k; + for (int i = n - 1; i >= k; i--) { + if (c1[i] < c2[i]) return -1; + else if (c1[i] > c2[i]) return 1; + } + return DegreeReverseLexicographic.ordering.compare(m1, m2); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/NestedPolynomial.java b/jscl/src/main/java/jscl/math/polynomial/NestedPolynomial.java new file mode 100644 index 00000000..9be03e37 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/NestedPolynomial.java @@ -0,0 +1,236 @@ +package jscl.math.polynomial; + +import jscl.math.*; +import jscl.math.function.Constant; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import java.util.Set; + +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; + } + + public static Generic factory(Variable variable[]) { + if (variable.length > 1) { + Variable var[] = new Variable[variable.length - 1]; + for (int i = 0; i < var.length; i++) var[i] = variable[i + 1]; + return new PolynomialWrapper(NestedPolynomial.factory(var)); + } else return null; + } + + Polynomial content() { + return content; + } + + public PolynomialWrapper add(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.add(wrapper.content)); + } + + @Nonnull + public Generic add(@Nonnull Generic that) { + if (that instanceof PolynomialWrapper) { + return add((PolynomialWrapper) that); + } else { + return add(valueOf(that)); + } + } + + public PolynomialWrapper subtract(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.subtract(wrapper.content)); + } + + @Nonnull + public Generic subtract(@Nonnull Generic that) { + if (that instanceof PolynomialWrapper) { + return subtract((PolynomialWrapper) that); + } else { + return subtract(valueOf(that)); + } + } + + public PolynomialWrapper multiply(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.multiply(wrapper.content)); + } + + @Nonnull + public Generic multiply(@Nonnull Generic that) { + if (that instanceof PolynomialWrapper) { + return multiply((PolynomialWrapper) that); + } else { + return multiply(valueOf(that)); + } + } + + public PolynomialWrapper divide(PolynomialWrapper wrapper) throws ArithmeticException { + return new PolynomialWrapper(content.divide(wrapper.content)); + } + + @Nonnull + public Generic divide(@Nonnull Generic that) throws NotDivisibleException { + if (that instanceof PolynomialWrapper) { + return divide((PolynomialWrapper) that); + } else { + return divide(valueOf(that)); + } + } + + public PolynomialWrapper gcd(PolynomialWrapper wrapper) { + return new PolynomialWrapper(content.gcd(wrapper.content)); + } + + public Generic gcd(@Nonnull Generic generic) { + if (generic instanceof PolynomialWrapper) { + return gcd((PolynomialWrapper) generic); + } else { + return gcd(valueOf(generic)); + } + } + + @Nonnull + 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(@Nonnull Variable variable) throws NotIntegrableException { + return null; + } + + public Generic derivative(@Nonnull Variable variable) { + return null; + } + + public Generic substitute(@Nonnull 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(); + } + + @Override + public boolean isInteger() { + return false; + } + + public Variable variableValue() throws NotVariableException { + throw new NotVariableException(); + } + + public Variable[] variables() { + return new Variable[0]; + } + + public boolean isPolynomial(@Nonnull Variable variable) { + return false; + } + + public boolean isConstant(@Nonnull 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 String toString() { + StringBuffer buffer = new StringBuffer(); + if (signum() < 0) buffer.append("-").append(negate()); + else buffer.append("(").append(content).append(")"); + return buffer.toString(); + } + + public String toJava() { + return null; + } + + public void toMathML(MathML element, Object data) { + } + + @Nonnull + @Override + public Set getConstants() { + return content.getConstants(); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/Ordering.java b/jscl/src/main/java/jscl/math/polynomial/Ordering.java new file mode 100644 index 00000000..7ce72b14 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/Ordering.java @@ -0,0 +1,11 @@ +package jscl.math.polynomial; + +import java.util.Comparator; + +public abstract class Ordering implements Comparator { + public abstract int compare(Monomial m1, Monomial m2); + + public int compare(Object o1, Object o2) { + return compare((Monomial) o1, (Monomial) o2); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/Polynomial.java b/jscl/src/main/java/jscl/math/polynomial/Polynomial.java new file mode 100644 index 00000000..dda6af2c --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/Polynomial.java @@ -0,0 +1,494 @@ +package jscl.math.polynomial; + +import jscl.math.*; +import jscl.math.function.Constant; +import jscl.mathml.MathML; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +public abstract class Polynomial implements Arithmetic, Comparable { + final Monomial monomialFactory; + final Generic coefFactory; + final Ordering ordering; + final boolean defined; + final boolean field; + boolean normalized; + int sugar; + int index = -1; + + Polynomial(Monomial monomialFactory, Generic coefFactory) { + this.monomialFactory = monomialFactory; + this.coefFactory = coefFactory; + ordering = monomialFactory.ordering(); + defined = monomialFactory instanceof DefinedBooleanMonomial; + field = coefFactory instanceof Field; + } + + static int degree(Polynomial polynomial) { + return polynomial.monomial(polynomial.head()).degree(); + } + + public static Polynomial factory(Variable variable) { + return new UnivariatePolynomial(variable); + } + + public static Polynomial factory(Variable variable[]) { + return new NestedPolynomial(variable); + } + + public static Polynomial factory(Variable unknown[], Ordering ordering) { + return factory(unknown, ordering, 0); + } + + public static Polynomial factory(Variable unknown[], Ordering ordering, int modulo) { + return factory(unknown, ordering, modulo, 0); + } + + public static Polynomial factory(Variable unknown[], Ordering ordering, int modulo, int flags) { + return factory(Monomial.factory(unknown, ordering, flags & Basis.POWER_SIZE), modulo, flags & Basis.DATA_STRUCT, (flags & Basis.GEO_BUCKETS) > 0); + } + + 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 abstract int size(); + + public Ordering ordering() { + return ordering; + } + + public final Iterator iterator() { + return iterator(false); + } + + public final Iterator iterator(boolean direction) { + return iterator(direction, null); + } + + public final Iterator iterator(Monomial current) { + return iterator(true, current); + } + + public abstract Iterator iterator(boolean direction, Monomial current); + + @Nonnull + public Polynomial add(@Nonnull Polynomial that) { + return multiplyAndSubtract(coefficient(JsclInteger.valueOf(-1)), that); + } + + @Nonnull + public abstract Polynomial subtract(@Nonnull Polynomial that); + + /* public Arithmetic add(@Nonnull Arithmetic arithmetic) { + return add((Polynomial)arithmetic); + } + + public Arithmetic subtract(@Nonnull Arithmetic arithmetic) { + return subtract((Polynomial)arithmetic); + } + + public Arithmetic multiply(@Nonnull Arithmetic arithmetic) { + return multiply((Polynomial)arithmetic); + } + + public Arithmetic divide(@Nonnull Arithmetic arithmetic) throws ArithmeticException { + return divide((Polynomial)arithmetic); + }*/ + + public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { + return subtract(polynomial.multiply(generic)); + } + + public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { + return subtract(polynomial.multiply(monomial).multiply(generic)); + } + + @Nonnull + public Polynomial multiply(@Nonnull Polynomial that) { + Polynomial p = valueOf(JsclInteger.valueOf(0)); + Iterator it = iterator(); + while (it.hasNext()) { + Term t = (Term) it.next(); + p = p.multiplyAndSubtract(t.monomial(), t.coef().negate(), that); + } + return p; + } + + public abstract Polynomial multiply(Generic generic); + + public abstract Polynomial multiply(Monomial monomial); + + public boolean multiple(Polynomial polynomial) throws ArithmeticException { + return remainder(polynomial).signum() == 0; + } + + @Nonnull + public Polynomial divide(@Nonnull Polynomial that) throws NotDivisibleException { + Polynomial p[] = divideAndRemainder(that); + if (p[1].signum() == 0) return p[0]; + else throw new NotDivisibleException(); + } + + public abstract Polynomial divide(Generic generic) throws ArithmeticException; + + public abstract Polynomial divide(Monomial monomial) throws ArithmeticException; + + public Polynomial[] divideAndRemainder(Polynomial polynomial) throws ArithmeticException { + Polynomial p[] = {valueOf(JsclInteger.valueOf(0)), this}; + Polynomial q = polynomial; + Iterator it = p[1].iterator(true); + while (it.hasNext()) { + Term t = (Term) it.next(); + Monomial m1 = t.monomial(); + Monomial m2 = q.head().monomial(); + if (m1.multiple(m2)) { + Monomial m = m1.divide(m2); + Generic c1 = t.coef(); + Generic c2 = q.head().coef(); + Generic c = c1.divide(c2); + p[0] = p[0].multiplyAndSubtract(m, c, valueOf(JsclInteger.valueOf(-1))); + p[1] = p[1].multiplyAndSubtract(m, c, q); + it = p[1].iterator(true); + } + } + return p; + } + + public Polynomial remainder(Polynomial polynomial) throws ArithmeticException { + return divideAndRemainder(polynomial)[1]; + } + + public Polynomial remainderUpToCoefficient(Polynomial polynomial) throws ArithmeticException { + Polynomial p = this; + Polynomial q = polynomial; + Iterator it = p.iterator(true); + while (it.hasNext()) { + Term t = (Term) it.next(); + Monomial m1 = t.monomial(); + Monomial m2 = q.head().monomial(); + if (m1.multiple(m2)) { + Monomial m = m1.divide(m2); + Generic c1 = t.coef(); + Generic c2 = q.head().coef(); +// Generic c=c1.gcd(c2); +// c1=c1.divide(c); +// c2=c2.divide(c); + p = p.multiply(c2).multiplyAndSubtract(m, c1, q); + it = p.iterator(true); + } + } + return p; + } + + public abstract Polynomial gcd(Polynomial polynomial); + + public Polynomial scm(Polynomial polynomial) { + return divide(gcd(polynomial)).multiply(polynomial); + } + + public Generic gcd() { + if (field) return coefficient(tail()); + Generic a = coefficient(JsclInteger.valueOf(0)); + for (Iterator it = iterator(); it.hasNext(); ) a = a.gcd(((Term) it.next()).coef()); + return a.signum() == signum() ? a : a.negate(); + } + + public final Polynomial[] gcdAndNormalize() { + Generic gcd = gcd(); + return new Polynomial[]{valueOf(gcd), gcd.signum() == 0 ? this : divide(gcd)}; + } + + public final Polynomial normalize() { + if (normalized) return this; + else { + Polynomial p = gcdAndNormalize()[1]; + p.normalized = true; + return p; + } + } + + public Monomial monomialGcd() { + Monomial m = monomial(tail()); + for (Iterator it = iterator(); it.hasNext(); ) m = m.gcd(((Term) it.next()).monomial()); + return m; + } + + public Polynomial pow(int exponent) { + Polynomial a = valueOf(JsclInteger.valueOf(1)); + for (int i = 0; i < exponent; i++) a = a.multiply(this); + return a; + } + + public Polynomial abs() { + return signum() < 0 ? negate() : this; + } + + public Polynomial negate() { + return multiply(coefficient(JsclInteger.valueOf(-1))); + } + + public final int signum() { + return coefficient(tail()).signum(); + } + + public abstract int degree(); + + public abstract Polynomial valueOf(Polynomial polynomial); + + public abstract Polynomial valueOf(Generic generic); + + public abstract Polynomial valueOf(Monomial monomial); + + public final Polynomial copy() { + return valueOf(this); + } + + public abstract Polynomial freeze(); + + public Term head() { + Iterator it = iterator(true); + return it.hasNext() ? (Term) it.next() : null; + } + + public Term tail() { + Iterator it = iterator(); + return it.hasNext() ? (Term) it.next() : null; + } + + public Generic coefficient(Monomial monomial) { + Iterator it = iterator(false, monomial); + Term t = it.hasNext() ? (Term) it.next() : null; + return coefficient(t == null || ordering.compare(t.monomial(), monomial) == 0 ? t : null); + } + + Monomial monomial(Term term) { + return term == null ? monomial(Literal.newInstance()) : term.monomial(); + } + + Generic coefficient(Term term) { + return term == null ? coefficient(JsclInteger.valueOf(0)) : term.coef(); + } + + protected Monomial monomial(Literal literal) { + return monomialFactory.valueof(literal); + } + + protected Generic coefficient(Generic generic) { + return coefFactory == null ? generic : coefFactory.valueOf(generic); + } + + public Polynomial reduce(Collection ideal, boolean tail) { + Polynomial p = this; + Iterator it = tail ? p.iterator(p.head().monomial()) : p.iterator(true); + loop: + while (it.hasNext()) { + Term t = (Term) it.next(); + Monomial m1 = t.monomial(); + Iterator iq = ideal.iterator(); + while (iq.hasNext()) { + Polynomial q = (Polynomial) iq.next(); + Monomial m2 = q.head().monomial(); + if (m1.multiple(m2)) { + Monomial m = m1.divide(m2); + p = p.reduce(t.coef(), m, q); + it = tail ? p.iterator(m1) : p.iterator(true); + continue loop; + } + } + tail = true; + } + return p; + } + + public Polynomial reduce(Generic generic, Monomial monomial, Polynomial polynomial) { + if (field) return multiplyAndSubtract(monomial, generic.divide(polynomial.head().coef()), polynomial); + else { + Generic c1 = generic; + Generic c2 = polynomial.head().coef(); + Generic c = c1.gcd(c2); + c1 = c1.divide(c); + c2 = c2.divide(c); + return multiply(c2).multiplyAndSubtract(monomial, c1, polynomial).normalize(); + } + } + + public Polynomial reduce(Generic generic, Polynomial polynomial) { + return reduce(generic, monomial(Literal.newInstance()), polynomial); + } + + public int sugar() { + return sugar; + } + + public int index() { + return index; + } + + public void setSugar(int n) { + sugar = n; + } + + public void setIndex(int n) { + if (index != -1) throw new ArithmeticException(); + index = n; + } + + public Generic genericValue() { + Generic s = JsclInteger.valueOf(0); + Iterator it = iterator(); + while (it.hasNext()) { + Term t = (Term) it.next(); + Monomial m = t.monomial(); + Generic a = t.coef().expressionValue(); + s = s.add(m.degree() > 0 ? 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; i < size; i++) a[i] = ((Term) it.next()).coef(); + return a; + } + + 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, @Nullable 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); + } + + // todo serso: make abstract and implement in extensions + @Nonnull + public Set getConstants() { + return Collections.emptySet(); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/SmallMonomial.java b/jscl/src/main/java/jscl/math/polynomial/SmallMonomial.java new file mode 100644 index 00000000..85ec6657 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/SmallMonomial.java @@ -0,0 +1,177 @@ +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 << log2n)) - 1; + static final int pmask = (1 << log2p) - 1; + + SmallMonomial(Variable unknown[], Ordering ordering) { + this(((unknown.length - 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 < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = a + b; + if (c > nmask) throw new ArithmeticException(); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public boolean multiple(Monomial monomial, boolean strict) { + boolean equal = true; + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + if (a < b) return false; + equal &= a == b; + } + return strict ? !equal : true; + } + + public Monomial divide(Monomial monomial) throws ArithmeticException { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = a - b; + if (c < 0) throw new NotDivisibleException(); + m.element[q] |= c << r; + } + m.degree = degree - monomial.degree; + return m; + } + + public Monomial gcd(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = Math.min(a, b); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public Monomial scm(Monomial monomial) { + Monomial m = newinstance(); + for (int i = 0; i < unknown.length; i++) { + int q = i >> log2p; + int r = (i & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int b = (monomial.element[q] >> r) & nmask; + int c = Math.max(a, b); + m.element[q] |= c << r; + m.degree += c; + } + return m; + } + + public int element(int n) { + if (reverse()) n = unknown.length - 1 - n; + int q = n >> log2p; + int r = (n & pmask) << log2n; + return (element[q] >> r) & nmask; + } + + void put(int n, int integer) { + if (reverse()) n = unknown.length - 1 - n; + int q = n >> log2p; + int r = (n & pmask) << log2n; + int a = (element[q] >> r) & nmask; + int c = a + integer; + if (c > nmask) throw new ArithmeticException(); + element[q] |= c << r; + degree += c - a; + } + + boolean reverse() { + return ordering instanceof DegreeReverseLexicographic; + } + + protected Monomial newinstance() { + return new SmallMonomial(element.length, unknown, ordering); + } +} + +class SmallLexicographic extends Ordering { + public static final Ordering ordering = new SmallLexicographic(); + + SmallLexicographic() { + } + + public int compare(Monomial m1, Monomial m2) { + 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 (l1 > l2) 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.degree < m2.degree) return -1; + else if (m1.degree > m2.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.degree < m2.degree) return -1; + else if (m1.degree > m2.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 (l1 < l2) return 1; + } + return 0; + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/Term.java b/jscl/src/main/java/jscl/math/polynomial/Term.java new file mode 100644 index 00000000..3dc3d877 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/Term.java @@ -0,0 +1,65 @@ +package jscl.math.polynomial; + +import jscl.math.Generic; + +public class Term implements Comparable { + final Monomial monomial; + final Generic coef; + + public Term(Monomial monomial, Generic coef) { + this.monomial = monomial; + this.coef = coef; + } + + public Term subtract(Term term) { + return new Term(monomial, coef.subtract(term.coef)); + } + + public Term multiply(Generic generic) { + return new Term(monomial, coef.multiply(generic)); + } + + public Term multiply(Monomial monomial, Generic generic) { + return new Term(this.monomial.multiply(monomial), coef.multiply(generic)); + } + + public Term multiply(Monomial monomial) { + return new Term(this.monomial.multiply(monomial), coef); + } + + public Term divide(Generic generic) { + return new Term(monomial, coef.divide(generic)); + } + + public Term divide(Monomial monomial) { + return new Term(this.monomial.divide(monomial), coef); + } + + public Term negate() { + return new Term(monomial, coef.negate()); + } + + public int signum() { + return coef.signum(); + } + + public Monomial monomial() { + return monomial; + } + + public Generic coef() { + return coef; + } + + public int compareTo(Term term) { + return monomial.compareTo(term.monomial); + } + + public int compareTo(Object o) { + return compareTo((Term) o); + } + + public String toString() { + return "(" + coef + ", " + monomial + ")"; + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/TreePolynomial.java b/jscl/src/main/java/jscl/math/polynomial/TreePolynomial.java new file mode 100644 index 00000000..447daa7e --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/TreePolynomial.java @@ -0,0 +1,306 @@ +package jscl.math.polynomial; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.Literal; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +final class TreePolynomial extends Polynomial { + final SortedMap content; + int degree; + boolean mutable = true; + + TreePolynomial(Monomial monomialFactory, Generic coefFactory) { + super(monomialFactory, coefFactory); + content = new TreeMap(ordering); + } + + public int size() { + return content.size(); + } + + public Iterator iterator(boolean direction, Monomial current) { + return new ContentIterator(direction, current); + } + + 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); + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + if (that.signum() == 0) return this; + if (mutable) { + TreePolynomial q = (TreePolynomial) that; + 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(that); + } + + 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; i < n; i++) { + Literal l = expression.literal(i); + JsclInteger en = expression.coef(i); + Monomial m = monomial(l); + l = l.divide(m.literalValue()); + Generic a2 = coefficient(l.degree() > 0 ? 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.newInstance()), 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); + } + + class ContentIterator implements Iterator { + final boolean direction; + final Iterator iterator; + SortedMap map; + + ContentIterator(boolean direction, Monomial current) { + this.direction = direction; + if (direction) { + iterator = null; + map = subContent(current, true); + } else { + iterator = (subContent(current, false)).entrySet().iterator(); + if (current != null && content.containsKey(current)) iterator.next(); + } + } + + public boolean hasNext() { + return direction ? map.size() > 0 : 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(); + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/UnivariatePolynomial.java b/jscl/src/main/java/jscl/math/polynomial/UnivariatePolynomial.java new file mode 100644 index 00000000..c373eaca --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/UnivariatePolynomial.java @@ -0,0 +1,493 @@ +package jscl.math.polynomial; + +import jscl.math.*; +import jscl.math.function.Inverse; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +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); + } + + 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(); + } + + @Nonnull + public Polynomial add(@Nonnull Polynomial that) { + UnivariatePolynomial p = newinstance(); + UnivariatePolynomial q = (UnivariatePolynomial) that; + 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; + } + + @Nonnull + public Polynomial subtract(@Nonnull Polynomial that) { + UnivariatePolynomial p = newinstance(); + UnivariatePolynomial q = (UnivariatePolynomial) that; + 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; + } + + @Nonnull + public Polynomial multiply(@Nonnull Polynomial that) { + UnivariatePolynomial p = newinstance(); + UnivariatePolynomial q = (UnivariatePolynomial) that; + 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.degree < q.degree) { + UnivariatePolynomial r = p; + p = q; + q = r; + } + int d = p.degree - q.degree; + Generic phi = JsclInteger.valueOf(-1); + Generic beta = JsclInteger.valueOf(-1).pow(d + 1); + Polynomial a1[] = p.gcdAndNormalize(); + Polynomial a2[] = q.gcdAndNormalize(); + Generic gcd1 = a1[0].genericValue(); + Generic gcd2 = a2[0].genericValue(); + p = (UnivariatePolynomial) a1[1]; + q = (UnivariatePolynomial) a2[1]; + while (q.degree > 0) { + 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 Inverse(get(1)).selfExpand()).negate(); + } else return null; + } + + public Generic[] identification(UnivariatePolynomial polynomial) { + UnivariatePolynomial p = this; + UnivariatePolynomial q = polynomial; + if (p.degree < q.degree || (p.degree == 0 && q.signum() == 0)) { + UnivariatePolynomial r = p; + p = q; + q = r; + } + UnivariatePolynomial r = (UnivariatePolynomial) p.remainderUpToCoefficient(q); + Generic a[] = new Generic[r.degree + 1]; + for (int i = r.degree; i >= 0; i--) a[r.degree - i] = r.get(i); + return a; + } + + public Generic resultant(UnivariatePolynomial polynomial) { + UnivariatePolynomial p = this; + UnivariatePolynomial q = polynomial; + if (p.degree < q.degree || (p.degree == 0 && q.signum() == 0)) { + UnivariatePolynomial r = p; + p = q; + q = r; + } + int d = p.degree - q.degree; + Generic phi = JsclInteger.valueOf(-1); + Generic beta = JsclInteger.valueOf(-1).pow(d + 1); + while (q.degree > 0) { + 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.degree < q.degree || (p.degree == 0 && q.signum() == 0)) { + UnivariatePolynomial r = p; + p = q; + q = r; + } + UnivariatePolynomial s[] = new UnivariatePolynomial[q.degree + 1]; + s[q.degree] = q; + int d = p.degree - q.degree; + Generic phi = JsclInteger.valueOf(-1); + Generic beta = JsclInteger.valueOf(-1).pow(d + 1); + while (q.degree > 0) { + 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 Inverse(JsclInteger.valueOf(i + 1)).selfExpand())); + } + 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; i < generic.length; i++) put(i, coefficient(generic[i])); + } + + void init(Expression expression) { + int n = expression.size(); + for (int i = 0; i < n; i++) { + Literal l = expression.literal(i); + JsclInteger en = expression.coef(i); + Monomial m = monomial(l); + l = l.divide(m.literalValue()); + if (l.degree() > 0) 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 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(); + } + } +} + +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/jscl/src/main/java/jscl/math/polynomial/groebner/Block.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Block.java new file mode 100644 index 00000000..a1369aa5 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Block.java @@ -0,0 +1,61 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.Debug; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.DegreeOrdering; +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +class Block extends Standard { + boolean degree; + + Block(Ordering ordering, int flags) { + super(flags); + degree = ordering instanceof DegreeOrdering; + } + + void compute() { + Debug.println("evaluate"); + 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/jscl/src/main/java/jscl/math/polynomial/groebner/F4.java b/jscl/src/main/java/jscl/math/polynomial/groebner/F4.java new file mode 100644 index 00000000..77fcb7d1 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/F4.java @@ -0,0 +1,36 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.polynomial.Ordering; +import jscl.math.polynomial.Polynomial; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +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/jscl/src/main/java/jscl/math/polynomial/groebner/F4Reduction.java b/jscl/src/main/java/jscl/math/polynomial/groebner/F4Reduction.java new file mode 100644 index 00000000..42a5873b --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/F4Reduction.java @@ -0,0 +1,95 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.Debug; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; +import jscl.math.polynomial.Term; + +import java.util.*; + +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; i < pr.length; i++) + if (!proj.containsKey(pr[i])) { + add(pr[i].simplify(list)); + proj.put(pr[i], null); + } + } + + void add(Projection projection) { + Polynomial p = projection.mult(); + Monomial scm = projection.scm(); + head.put(scm, null); + Iterator it = p.iterator(scm); + while (it.hasNext()) { + Term t = (Term) it.next(); + Monomial m1 = t.monomial(); + if (considered.containsKey(m1)) continue; + else considered.put(m1, null); + Iterator iq = ideal.iterator(); + while (iq.hasNext()) { + Polynomial q = (Polynomial) iq.next(); + Monomial m2 = q.head().monomial(); + if (m1.multiple(m2)) { + Monomial m = m1.divide(m2); + add(new Projection(m, q).simplify(list)); + break; + } + } + } + content.add(p); + } + + void process() { + List list = ReducedRowEchelonForm.compute(content); + content.clear(); + int n = list.size(); + for (int i = 0; i < n; i++) { + Polynomial p = (Polynomial) list.get(i); + if (p.signum() != 0) { + Monomial m = p.head().monomial(); + if (!head.containsKey(m)) content.add(p); + else { + if (p.index() != -1) p = p.copy(); + p.setIndex(polys.size()); + polys.add(p); + } + } + } + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/groebner/Instrumented.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Instrumented.java new file mode 100644 index 00000000..8caac796 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Instrumented.java @@ -0,0 +1,45 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.Generic; +import jscl.math.polynomial.Basis; +import jscl.math.polynomial.Polynomial; + +import java.util.ArrayList; +import java.util.List; + +class Instrumented extends Standard { + final List aux = new ArrayList(); + + Instrumented(int flags) { + super(flags); + } + + void populate(Basis basis) { + Basis aux = basis.modulo(2147483647); + Generic a[] = basis.elements(); + for (int i = 0; i < a.length; i++) { + Polynomial p = basis.polynomial(a[i]); + Polynomial x = aux.polynomial(a[i]); + if (x.signum() != 0 && p.signum() != 0) add(p, x); + } + } + + void process(Pair pair) { + if (criterion(pair)) return; + Polynomial x = reduce(new Pair(new Polynomial[]{auxiliary(pair.polynomial[0]), auxiliary(pair.polynomial[1])}), aux); + if (x.signum() != 0) { + Polynomial p = reduce(pair, polys); + if (p.signum() != 0) add(p, x); + } + npairs++; + } + + void add(Polynomial polynomial, Polynomial auxiliary) { + add(polynomial); + aux.add(auxiliary); + } + + Polynomial auxiliary(Polynomial polynomial) { + return (Polynomial) aux.get(polynomial.index()); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/groebner/Natural.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Natural.java new file mode 100644 index 00000000..8bb7e291 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Natural.java @@ -0,0 +1,18 @@ +package jscl.math.polynomial.groebner; + +import java.util.Comparator; + +class Natural implements Comparator { + public static final Comparator comparator = new Natural(); + + private Natural() { + } + + public int compare(Pair pa1, Pair pa2) { + return pa1.compareTo(pa2); + } + + public int compare(Object o1, Object o2) { + return compare((Pair) o1, (Pair) o2); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/groebner/Pair.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Pair.java new file mode 100644 index 00000000..880ab38f --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Pair.java @@ -0,0 +1,54 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; + +class Pair implements Comparable { + final Polynomial polynomial[]; + final Monomial monomial[]; + final Monomial scm; + final int sugar; + boolean coprime; + boolean reduction; + Polynomial principal; + + Pair(Polynomial p1, Polynomial p2) { + this(new Polynomial[]{p1, p2}); + coprime = monomial[0].gcd(monomial[1]).degree() == 0; + int index[] = monomial[0].compareTo(monomial[1]) < 0 ? new int[]{0, 1} : new int[]{1, 0}; + reduction = monomial[index[1]].multiple(monomial[index[0]]); + principal = polynomial[index[1]]; + } + + Pair(Polynomial polynomial[]) { + this.polynomial = polynomial; + monomial = new Monomial[]{polynomial[0].head().monomial(), polynomial[1].head().monomial()}; + scm = monomial[0].scm(monomial[1]); + sugar = Math.max(polynomial[0].sugar() - polynomial[0].degree(), polynomial[1].sugar() - polynomial[1].degree()) + scm.degree(); + } + + public int compareTo(Pair pair) { + int c = scm.compareTo(pair.scm); + if (c < 0) return -1; + else if (c > 0) 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/jscl/src/main/java/jscl/math/polynomial/groebner/Projection.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Projection.java new file mode 100644 index 00000000..de50aeea --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Projection.java @@ -0,0 +1,74 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +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; i < n; i++) { + Collection ideal = ((F4Reduction) list.get(i)).polys; + Iterator it = ideal.iterator(); + while (it.hasNext()) { + Polynomial p = (Polynomial) it.next(); + Monomial u = p.head().monomial(); + if (u.multiple(m, true)) { + u = u.divide(m); + if (t.multiple(u, true)) { + Projection pr = new Projection(t.divide(u), p).simplify(list); + return pr; + } + } + } + } + } + return this; + } + + public int compareTo(Projection proj) { + int c = monomial.compareTo(proj.monomial); + if (c < 0) return -1; + else if (c > 0) 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/jscl/src/main/java/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java b/jscl/src/main/java/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java new file mode 100644 index 00000000..b769dc69 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/ReducedRowEchelonForm.java @@ -0,0 +1,58 @@ +package jscl.math.polynomial.groebner; + +import jscl.math.Generic; +import jscl.math.polynomial.Monomial; +import jscl.math.polynomial.Polynomial; + +import java.util.ArrayList; +import java.util.List; + +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 < n; i++) reduce(i, false); + for (int i = n - 1; 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; i < n; i++) { + Polynomial q = polynomial(i); + Generic a = q.coefficient(m); + if (a.signum() != 0) content.set(i, q.reduce(a, p)); + } + } + + Polynomial polynomial(int n) { + return (Polynomial) content.get(n); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("{"); + int n = content.size(); + for (int i = 0; i < n; i++) { + Polynomial p = polynomial(i); + buffer.append(i > 0 ? ", " : "").append(p); + } + buffer.append("}"); + return buffer.toString(); + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/groebner/Standard.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Standard.java new file mode 100644 index 00000000..064004e6 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Standard.java @@ -0,0 +1,222 @@ +package jscl.math.polynomial.groebner; + +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; + +import java.util.*; + +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); + } + } + + static Polynomial reduce(Pair pair, Collection ideal) { + Debug.println(pair); + return s_polynomial(pair.polynomial[0], pair.polynomial[1]).reduce(ideal, false).normalize().freeze(); + } + + static Polynomial s_polynomial(Polynomial p1, Polynomial p2) { + Monomial m1 = p1.head().monomial(); + Monomial m2 = p2.head().monomial(); + Monomial m = m1.gcd(m2); + m1 = m1.divide(m); + m2 = m2.divide(m); + return p1.multiply(m2).reduce(p1.head().coef(), m1, p2); + } + + 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; i < a.length; i++) list.add(basis.polynomial(a[i])); + add(list); + } + + void add(List list) { + Iterator it = list.iterator(); + while (it.hasNext()) { + Polynomial p = (Polynomial) it.next(); + if (p.signum() != 0) add(p); + } + } + + void compute() { + Debug.println("evaluate"); + while (!pairs.isEmpty()) { + Pair pa = (Pair) pairs.keySet().iterator().next(); + process(pa); + remove(pa); + } + } + + void process(Pair pair) { + if (criterion(pair)) return; + Polynomial p = reduce(pair, polys); + if (p.signum() != 0) add(p); + npairs++; + } + + void remove(Pair pair) { + pairs.remove(pair); + if (pair.reduction) removed.put(pair.principal, null); + } + + void add(Polynomial polynomial) { + polynomial.setIndex(polys.size()); + Debug.println("(" + polynomial.head().monomial() + ", " + polynomial.index() + ")"); + if ((flags & Basis.GM_SETTING) > 0) 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() < p2.index() ? new Polynomial[]{p1, p2} : new Polynomial[]{p2, p1}; + } + + void makePairsGM(Polynomial polynomial) { + List list = new ArrayList(); + Iterator it = pairs.keySet().iterator(); + while (it.hasNext()) { + Pair pa = (Pair) it.next(); + Pair p1 = new Pair(new Polynomial[]{pa.polynomial[0], polynomial}); + Pair p2 = new Pair(new Polynomial[]{pa.polynomial[1], polynomial}); + if (multiple(pa, p1) && multiple(pa, p2)) list.add(pa); + } + int n = list.size(); + for (int i = 0; i < n; i++) { + Pair pa = (Pair) list.get(i); + remove(pa); + } + Map map = new TreeMap((flags & Basis.SUGAR) > 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.toList(map.keySet()); + n = list.size(); + for (int i = 0; i < n; i++) { + Pair pa = (Pair) list.get(i); + for (int j = i + 1; j < n; j++) { + Pair pa2 = (Pair) list.get(j); + if (pa2.scm.multiple(pa.scm)) remove(pa2); + } + if (pa.coprime) remove(pa); + } + } + + boolean multiple(Pair p1, Pair p2) { + return p1.scm.multiple(p2.scm, true) && ((flags & Basis.SUGAR) > 0 && (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; i < size; i++) { + Polynomial p = (Polynomial) polys.get(i); + polys.set(i, p = p.reduce(polys, true).normalize().freeze()); + Debug.println("(" + p.head().monomial() + ")"); + map.put(p, null); + } + polys.clear(); + polys.addAll(map.keySet()); + } + + Generic[] elements() { + int size = polys.size(); + Generic a[] = new Generic[size]; + for (int i = 0; i < size; i++) { + a[i] = ((Polynomial) polys.get(i)).genericValue(); + } + return a; + } +} diff --git a/jscl/src/main/java/jscl/math/polynomial/groebner/Sugar.java b/jscl/src/main/java/jscl/math/polynomial/groebner/Sugar.java new file mode 100644 index 00000000..d1015629 --- /dev/null +++ b/jscl/src/main/java/jscl/math/polynomial/groebner/Sugar.java @@ -0,0 +1,20 @@ +package jscl.math.polynomial.groebner; + +import java.util.Comparator; + +class Sugar implements Comparator { + public static final Comparator comparator = new Sugar(); + + private Sugar() { + } + + public int compare(Pair pa1, Pair pa2) { + if (pa1.sugar < pa2.sugar) return -1; + else if (pa1.sugar > pa2.sugar) return 1; + else return pa1.compareTo(pa2); + } + + public int compare(Object o1, Object o2) { + return compare((Pair) o1, (Pair) o2); + } +} diff --git a/jscl/src/main/java/jscl/mathml/MathML.java b/jscl/src/main/java/jscl/mathml/MathML.java new file mode 100644 index 00000000..a0f0aae4 --- /dev/null +++ b/jscl/src/main/java/jscl/mathml/MathML.java @@ -0,0 +1,68 @@ +package jscl.mathml; + +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; + +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 java.io.ByteArrayOutputStream; + +public class MathML { + static Transformer xhtml; + Node node; + + MathML(Node node) { + this.node = node; + } + + 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)); + } + + static Transformer transformer() throws TransformerException { + return xhtml == null ? xhtml = TransformerFactory.newInstance().newTransformer() : xhtml; + } + + public Document document() { + return node instanceof CoreDocumentImpl ? (Document) node : node.getOwnerDocument(); + } + + 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); + } +} diff --git a/jscl/src/main/java/jscl/text/AbstractConverter.java b/jscl/src/main/java/jscl/text/AbstractConverter.java new file mode 100644 index 00000000..3b6d5928 --- /dev/null +++ b/jscl/src/main/java/jscl/text/AbstractConverter.java @@ -0,0 +1,13 @@ +package jscl.text; + +import javax.annotation.Nonnull; + +abstract class AbstractConverter implements Parser { + @Nonnull + protected final Parser parser; + + AbstractConverter(@Nonnull Parser parser) { + this.parser = parser; + } + +} diff --git a/jscl/src/main/java/jscl/text/BracketedExpression.java b/jscl/src/main/java/jscl/text/BracketedExpression.java new file mode 100644 index 00000000..c7fa511c --- /dev/null +++ b/jscl/src/main/java/jscl/text/BracketedExpression.java @@ -0,0 +1,32 @@ +package jscl.text; + +import jscl.math.ExpressionVariable; +import jscl.math.Generic; + +import javax.annotation.Nonnull; + +public class BracketedExpression implements Parser { + + public static final Parser parser = new BracketedExpression(); + + private BracketedExpression() { + } + + public ExpressionVariable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.tryToParse(p, pos0, '('); + + Generic result; + try { + result = ExpressionParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + ParserUtils.tryToParse(p, pos0, ')'); + + return new ExpressionVariable(result); + } +} diff --git a/jscl/src/main/java/jscl/text/CommaAndExpression.java b/jscl/src/main/java/jscl/text/CommaAndExpression.java new file mode 100644 index 00000000..036cf451 --- /dev/null +++ b/jscl/src/main/java/jscl/text/CommaAndExpression.java @@ -0,0 +1,24 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CommaAndExpression implements Parser { + + public static final Parser parser = new CommaAndExpression(); + + private CommaAndExpression() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + ParserUtils.tryToParse(p, pos0, ','); + + return ParserUtils.parseWithRollback(ExpressionParser.parser, pos0, previousSumElement, p); + } +} diff --git a/jscl/src/main/java/jscl/text/CommaAndVector.java b/jscl/src/main/java/jscl/text/CommaAndVector.java new file mode 100644 index 00000000..009f5d1e --- /dev/null +++ b/jscl/src/main/java/jscl/text/CommaAndVector.java @@ -0,0 +1,26 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.JsclVector; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CommaAndVector implements Parser { + + public static final Parser parser = new CommaAndVector(); + + private CommaAndVector() { + } + + @Nonnull + public JsclVector parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + ParserUtils.tryToParse(p, pos0, ','); + + return ParserUtils.parseWithRollback(VectorParser.parser, pos0, previousSumElement, p); + } +} diff --git a/jscl/src/main/java/jscl/text/CompoundIdentifier.java b/jscl/src/main/java/jscl/text/CompoundIdentifier.java new file mode 100644 index 00000000..1a793094 --- /dev/null +++ b/jscl/src/main/java/jscl/text/CompoundIdentifier.java @@ -0,0 +1,66 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CompoundIdentifier implements Parser { + + public static final Parser parser = new CompoundIdentifier(); + + private CompoundIdentifier() { + } + + @Nonnull + public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + try { + String s = Identifier.parser.parse(p, previousSumElement); + result.append(s); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + while (true) { + try { + final String dotAndId = DotAndIdentifier.parser.parse(p, previousSumElement); + // NOTE: '.' must be appended after parsing + result.append(".").append(dotAndId); + } catch (ParseException e) { + break; + } + } + + return result.toString(); + } +} + +class DotAndIdentifier implements Parser { + + public static final Parser parser = new DotAndIdentifier(); + + private DotAndIdentifier() { + } + + public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.tryToParse(p, pos0, '.'); + + String result; + try { + result = Identifier.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/ConstantParser.java b/jscl/src/main/java/jscl/text/ConstantParser.java new file mode 100644 index 00000000..06073fb0 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ConstantParser.java @@ -0,0 +1,84 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.Constant; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ConstantParser implements Parser { + + public static final Parser parser = new ConstantParser(); + + private ConstantParser() { + } + + public Constant parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + + final String name = CompoundIdentifier.parser.parse(p, previousSumElement); + + List l = new ArrayList(); + while (true) { + try { + l.add(Subscript.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + Integer prime = 0; + try { + prime = Prime.parser.parse(p, previousSumElement); + } catch (ParseException e) { + } + + return new Constant(name, prime, ArrayUtils.toArray(l, new Generic[l.size()])); + } +} + +class Prime implements Parser { + + public static final Parser parser = new Prime(); + + private static final ArrayList> parsers = new ArrayList>(Arrays.asList( + PrimeCharacters.parser, + Superscript.parser)); + + private static final Parser internalParser = new MultiTryParser(parsers); + + private Prime() { + } + + public Integer parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return internalParser.parse(p, previousSumElement); + } +} + +class Superscript implements Parser { + public static final Parser parser = new Superscript(); + + private Superscript() { + } + + public Integer parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + + ParserUtils.tryToParse(p, pos0, '{'); + + int result; + try { + result = IntegerParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + ParserUtils.tryToParse(p, pos0, '}'); + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/Digits.java b/jscl/src/main/java/jscl/text/Digits.java new file mode 100644 index 00000000..d44c9f4d --- /dev/null +++ b/jscl/src/main/java/jscl/text/Digits.java @@ -0,0 +1,41 @@ +package jscl.text; + +import jscl.NumeralBase; +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class Digits implements Parser { + + @Nonnull + private final NumeralBase nb; + + public Digits(@Nonnull NumeralBase nb) { + this.nb = nb; + } + + // returns digit + public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && nb.getAcceptableCharacters().contains(p.getExpression().charAt(p.getPosition().intValue()))) { + result.append(p.getExpression().charAt(p.getPosition().intValue())); + p.getPosition().increment(); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_9); + } + + while (p.getPosition().intValue() < p.getExpression().length() && nb.getAcceptableCharacters().contains(p.getExpression().charAt(p.getPosition().intValue()))) { + result.append(p.getExpression().charAt(p.getPosition().intValue())); + p.getPosition().increment(); + } + + return result.toString(); + } +} diff --git a/jscl/src/main/java/jscl/text/DoubleParser.java b/jscl/src/main/java/jscl/text/DoubleParser.java new file mode 100644 index 00000000..d6ee5b58 --- /dev/null +++ b/jscl/src/main/java/jscl/text/DoubleParser.java @@ -0,0 +1,215 @@ +package jscl.text; + +import jscl.NumeralBase; +import jscl.math.Generic; +import jscl.math.NumericWrapper; +import jscl.math.numeric.Real; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class DoubleParser implements Parser { + + public static final Parser parser = new DoubleParser(); + + private static final List> parsers = Arrays.asList( + Singularity.parser, + FloatingPointLiteral.parser); + + private DoubleParser() { + } + + @Nonnull + public NumericWrapper parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + final Parser multiTryParser = new MultiTryParser(new ArrayList>(parsers)); + return new NumericWrapper(Real.valueOf(multiTryParser.parse(p, previousSumElement))); + } +} + +class Singularity implements Parser { + + public static final Parser parser = new Singularity(); + + private Singularity() { + } + + @Nonnull + public Double parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + double result = 0d; + + String s = Identifier.parser.parse(p, previousSumElement); + if (s.equals("NaN")) { + result = Double.NaN; + } else if (s.equals("Infinity") || s.equals("∞")) { + result = Double.POSITIVE_INFINITY; + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_10, "NaN", "∞"); + } + + return result; + } +} + +class FloatingPointLiteral implements Parser { + + public static final Parser parser = new FloatingPointLiteral(); + + private FloatingPointLiteral() { + } + + public Double parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement); + + final StringBuilder result = new StringBuilder(); + + boolean digits = false; + boolean point = false; + boolean exponent = false; + + final Digits digitsParser = new Digits(nb); + + try { + result.append(digitsParser.parse(p, previousSumElement)); + digits = true; + } catch (ParseException e) { + } + + try { + DecimalPoint.parser.parse(p, previousSumElement); + result.append("."); + point = true; + } catch (ParseException e) { + if (!digits) { + p.getPosition().setValue(pos0); + throw e; + } + } + + if (point && nb != NumeralBase.dec) { + ParserUtils.throwParseException(p, pos0, Messages.msg_15); + } + + try { + result.append(digitsParser.parse(p, previousSumElement)); + } catch (ParseException e) { + if (!digits) { + p.getPosition().setValue(pos0); + throw e; + } + } + + try { + result.append(ExponentPart.parser.parse(p, previousSumElement)); + exponent = true; + } catch (ParseException e) { + if (!point) { + p.getPosition().setValue(pos0); + throw e; + } + } + + if (exponent && nb != NumeralBase.dec) { + ParserUtils.throwParseException(p, pos0, Messages.msg_15); + } + + final String doubleString = result.toString(); + try { + return nb.toDouble(doubleString); + } catch (NumberFormatException e) { + throw new ParseException(Messages.msg_8, p.getPosition().intValue(), p.getExpression(), doubleString); + } + } +} + +class DecimalPoint implements Parser { + + public static final Parser parser = new DecimalPoint(); + + private DecimalPoint() { + } + + @Nullable + public Void parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + ParserUtils.tryToParse(p, pos0, '.'); + + return null; + } +} + +class ExponentPart implements Parser { + + public static final Parser parser = new ExponentPart(); + + private ExponentPart() { + } + + @Nonnull + public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && (p.getExpression().charAt(p.getPosition().intValue()) == 'e' || p.getExpression().charAt(p.getPosition().intValue()) == 'E')) { + char c = p.getExpression().charAt(p.getPosition().intValue()); + p.getPosition().increment(); + result.append(c); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_10, 'e', 'E'); + } + + try { + result.append(SignedInteger.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + return result.toString(); + } +} + +class SignedInteger implements Parser { + + public static final Parser parser = new SignedInteger(); + + private SignedInteger() { + } + + @Nonnull + public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && (p.getExpression().charAt(p.getPosition().intValue()) == '+' || p.getExpression().charAt(p.getPosition().intValue()) == '-')) { + char c = p.getExpression().charAt(p.getPosition().intValue()); + p.getPosition().increment(); + result.append(c); + } + + try { + result.append(IntegerParser.parser.parse(p, previousSumElement).intValue()); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + return result.toString(); + } +} diff --git a/jscl/src/main/java/jscl/text/DoubleVariableParser.java b/jscl/src/main/java/jscl/text/DoubleVariableParser.java new file mode 100644 index 00000000..a51aa887 --- /dev/null +++ b/jscl/src/main/java/jscl/text/DoubleVariableParser.java @@ -0,0 +1,20 @@ +package jscl.text; + +import jscl.math.DoubleVariable; +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +public class DoubleVariableParser implements Parser { + + public static final Parser parser = new DoubleVariableParser(); + + private DoubleVariableParser() { + } + + @Nonnull + public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return new DoubleVariable(DoubleParser.parser.parse(p, previousSumElement)); + } +} diff --git a/jscl/src/main/java/jscl/text/ExponentParser.java b/jscl/src/main/java/jscl/text/ExponentParser.java new file mode 100644 index 00000000..2861a7f0 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ExponentParser.java @@ -0,0 +1,28 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class ExponentParser implements Parser { + + public static final Parser parser = new ExponentParser(); + + private ExponentParser() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + boolean sign = MinusParser.parser.parse(p, previousSumElement).isSign(); + + final Generic result = ParserUtils.parseWithRollback(UnsignedExponent.parser, pos0, previousSumElement, p); + return sign ? result.negate() : result; + } +} diff --git a/jscl/src/main/java/jscl/text/ExpressionParser.java b/jscl/src/main/java/jscl/text/ExpressionParser.java new file mode 100644 index 00000000..2a61851e --- /dev/null +++ b/jscl/src/main/java/jscl/text/ExpressionParser.java @@ -0,0 +1,36 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ExpressionParser implements Parser { + + public static final Parser parser = new ExpressionParser(); + + private ExpressionParser() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + + boolean sign = MinusParser.parser.parse(p, previousSumElement).isSign(); + + Generic result = TermParser.parser.parse(p, previousSumElement); + + if (sign) { + result = result.negate(); + } + + while (true) { + try { + result = result.add(PlusOrMinusTerm.parser.parse(p, result)); + } catch (ParseException e) { + break; + } + } + + return result; + } +} + diff --git a/jscl/src/main/java/jscl/text/Factor.java b/jscl/src/main/java/jscl/text/Factor.java new file mode 100644 index 00000000..d2f05150 --- /dev/null +++ b/jscl/src/main/java/jscl/text/Factor.java @@ -0,0 +1,28 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class Factor implements Parser { + + public static final Parser parser = new Factor(); + + private Factor() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + + boolean sign = MinusParser.parser.parse(p, previousSumElement).isSign(); + + final Generic result = (Generic) UnsignedFactor.parser.parse(p, previousSumElement); + + return sign ? result.negate() : result; + } +} diff --git a/jscl/src/main/java/jscl/text/FunctionParser.java b/jscl/src/main/java/jscl/text/FunctionParser.java new file mode 100644 index 00000000..f4babd76 --- /dev/null +++ b/jscl/src/main/java/jscl/text/FunctionParser.java @@ -0,0 +1,27 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.Function; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FunctionParser implements Parser { + + public static final Parser parser = new FunctionParser(); + + private static final List> parsers = Arrays.asList( + UsualFunctionParser.parser, + RootParser.parser, + ImplicitFunctionParser.parser); + + private FunctionParser() { + } + + public Function parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return new MultiTryParser(new ArrayList>(parsers)).parse(p, previousSumElement); + } +} + diff --git a/jscl/src/main/java/jscl/text/Identifier.java b/jscl/src/main/java/jscl/text/Identifier.java new file mode 100644 index 00000000..67992664 --- /dev/null +++ b/jscl/src/main/java/jscl/text/Identifier.java @@ -0,0 +1,53 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; + +public class Identifier implements Parser { + + public static final Parser parser = new Identifier(); + private final static List allowedCharacters = Arrays.asList('√', '∞', 'π', '∂', '∏', 'Σ', '∫'); + + private Identifier() { + } + + private static boolean isValidFirstCharacter(char ch) { + return Character.isLetter(ch) || allowedCharacters.contains(ch); + } + + private static boolean isValidNotFirstCharacter(@Nonnull String string, @Nonnull MutableInt position) { + final char ch = string.charAt(position.intValue()); + return Character.isLetter(ch) || Character.isDigit(ch) || ch == '_'; + } + + // returns getVariable/constant getName + @Nonnull + public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && isValidFirstCharacter(p.getExpression().charAt(p.getPosition().intValue()))) { + result.append(p.getExpression().charAt(p.getPosition().intValue())); + p.getPosition().increment(); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_5); + } + + while (p.getPosition().intValue() < p.getExpression().length() && isValidNotFirstCharacter(p.getExpression(), p.getPosition())) { + result.append(p.getExpression().charAt(p.getPosition().intValue())); + p.getPosition().increment(); + } + + return result.toString(); + } + + +} diff --git a/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java b/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java new file mode 100644 index 00000000..78c42212 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java @@ -0,0 +1,132 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.Function; +import jscl.math.function.FunctionsRegistry; +import jscl.math.function.ImplicitFunction; +import jscl.math.operator.matrix.OperatorsRegistry; +import jscl.text.msg.Messages; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class ImplicitFunctionParser implements Parser { + public static final Parser parser = new ImplicitFunctionParser(); + + private ImplicitFunctionParser() { + } + + public Function parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + Generic a[]; + + final String name = ParserUtils.parseWithRollback(CompoundIdentifier.parser, pos0, previousSumElement, p); + if (FunctionsRegistry.getInstance().getNames().contains(name) || OperatorsRegistry.getInstance().getNames().contains(name)) { + p.getPosition().setValue(pos0); + throw new ParseException(Messages.msg_6, p.getPosition().intValue(), p.getExpression(), name); + } + + final List subscripts = new ArrayList(); + while (true) { + try { + subscripts.add(Subscript.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + int b[]; + try { + b = Derivation.parser.parse(p, previousSumElement); + } catch (ParseException e) { + b = new int[0]; + } + try { + a = ParameterListParser.parser1.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + int derivations[] = new int[a.length]; + for (int i = 0; i < a.length && i < b.length; i++) { + derivations[i] = b[i]; + } + + return new ImplicitFunction(name, a, derivations, ArrayUtils.toArray(subscripts, new Generic[subscripts.size()])); + } +} + +class Derivation implements Parser { + + public static final Parser parser = new Derivation(); + + private Derivation() { + } + + public int[] parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + + int result[]; + try { + result = new int[]{PrimeCharacters.parser.parse(p, previousSumElement)}; + } catch (ParseException e) { + result = SuperscriptList.parser.parse(p, previousSumElement); + } + + return result; + } +} + +class SuperscriptList implements Parser { + + public static final Parser parser = new SuperscriptList(); + + private SuperscriptList() { + } + + public int[] parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.tryToParse(p, pos0, '{'); + + final List result = new ArrayList(); + try { + result.add(IntegerParser.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + while (true) { + try { + result.add(CommaAndInteger.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + ParserUtils.tryToParse(p, pos0, '}'); + + ParserUtils.skipWhitespaces(p); + + return ArrayUtils.toArray(result, new int[result.size()]); + } +} + +class CommaAndInteger implements Parser { + + public static final Parser parser = new CommaAndInteger(); + + private CommaAndInteger() { + } + + public Integer parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + return ParserUtils.parseWithRollback(IntegerParser.parser, pos0, previousSumElement, p); + } +} diff --git a/jscl/src/main/java/jscl/text/IntegerParser.java b/jscl/src/main/java/jscl/text/IntegerParser.java new file mode 100644 index 00000000..ceff45d6 --- /dev/null +++ b/jscl/src/main/java/jscl/text/IntegerParser.java @@ -0,0 +1,65 @@ +package jscl.text; + +import jscl.NumeralBase; +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class IntegerParser implements Parser { + + public static final Parser parser = new IntegerParser(); + + private IntegerParser() { + } + + public Integer parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + /*int n; + + ParserUtils.skipWhitespaces(expression, position); + if (position.intValue() < expression.length() && Character.isDigit(expression.charAt(position.intValue()))) { + char c = expression.charAt(position.intValue()); + position.increment(); + n = c - '0'; + } else { + position.setValue(pos0); + throw new ParseException(); + } + + while (position.intValue() < expression.length() && Character.isDigit(expression.charAt(position.intValue()))) { + char c = expression.charAt(position.intValue()); + position.increment(); + n = 10 * n + (c - '0'); + }*/ + + final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement); + + final StringBuilder result = new StringBuilder(); + + ParserUtils.skipWhitespaces(p); + if (p.getPosition().intValue() < p.getExpression().length() && nb.getAcceptableCharacters().contains(p.getExpression().charAt(p.getPosition().intValue()))) { + char c = p.getExpression().charAt(p.getPosition().intValue()); + p.getPosition().increment(); + result.append(c); + } else { + p.getPosition().setValue(pos0); + throw new ParseException(Messages.msg_7, p.getPosition().intValue(), p.getExpression()); + } + + while (p.getPosition().intValue() < p.getExpression().length() && nb.getAcceptableCharacters().contains(p.getExpression().charAt(p.getPosition().intValue()))) { + char c = p.getExpression().charAt(p.getPosition().intValue()); + p.getPosition().increment(); + result.append(c); + } + + final String number = result.toString(); + try { + return nb.toInteger(number); + } catch (NumberFormatException e) { + throw new ParseException(Messages.msg_8, p.getPosition().intValue(), p.getExpression(), number); + } + } +} diff --git a/jscl/src/main/java/jscl/text/JsclIntegerParser.java b/jscl/src/main/java/jscl/text/JsclIntegerParser.java new file mode 100644 index 00000000..c1f19c42 --- /dev/null +++ b/jscl/src/main/java/jscl/text/JsclIntegerParser.java @@ -0,0 +1,39 @@ +package jscl.text; + +import jscl.NumeralBase; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class JsclIntegerParser implements Parser { + + public static final Parser parser = new JsclIntegerParser(); + + private JsclIntegerParser() { + } + + public JsclInteger parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement); + + final StringBuilder result = new StringBuilder(); + + try { + result.append(new Digits(nb).parse(p, previousSumElement)); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + final String number = result.toString(); + try { + return nb.toJsclInteger(number); + } catch (NumberFormatException e) { + throw new ParseException(Messages.msg_8, p.getPosition().intValue(), p.getExpression(), number); + } + } +} diff --git a/jscl/src/main/java/jscl/text/MatrixParser.java b/jscl/src/main/java/jscl/text/MatrixParser.java new file mode 100644 index 00000000..5721f594 --- /dev/null +++ b/jscl/src/main/java/jscl/text/MatrixParser.java @@ -0,0 +1,45 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Matrix; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class MatrixParser implements Parser { + + public static final Parser parser = new MatrixParser(); + + private MatrixParser() { + } + + public Matrix parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final List vectors = new ArrayList(); + + ParserUtils.tryToParse(p, pos0, '['); + + try { + vectors.add(VectorParser.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + while (true) { + try { + vectors.add(CommaAndVector.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + ParserUtils.tryToParse(p, pos0, ']'); + + return Matrix.frame((JsclVector[]) ArrayUtils.toArray(vectors, new JsclVector[vectors.size()])).transpose(); + } +} diff --git a/jscl/src/main/java/jscl/text/MatrixVariableParser.java b/jscl/src/main/java/jscl/text/MatrixVariableParser.java new file mode 100644 index 00000000..c8e233da --- /dev/null +++ b/jscl/src/main/java/jscl/text/MatrixVariableParser.java @@ -0,0 +1,25 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.Matrix; +import jscl.math.MatrixVariable; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +class MatrixVariableParser implements Parser { + public static final Parser parser = new MatrixVariableParser(); + + private MatrixVariableParser() { + } + + public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + Matrix m; + try { + m = (Matrix) MatrixParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + throw e; + } + return new MatrixVariable(m); + } +} diff --git a/jscl/src/main/java/jscl/text/MinusParser.java b/jscl/src/main/java/jscl/text/MinusParser.java new file mode 100644 index 00000000..e9017e88 --- /dev/null +++ b/jscl/src/main/java/jscl/text/MinusParser.java @@ -0,0 +1,50 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:44 PM + */ +class MinusParser implements Parser { + + public static final Parser parser = new MinusParser(); + + private MinusParser() { + } + + @Nonnull + public Result parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) { + final boolean result; + + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().charAt(p.getPosition().intValue()) == '-') { + result = true; + p.getPosition().increment(); + } else { + result = false; + p.getPosition().setValue(pos0); + } + + return new Result(result); + } + + public static class Result { + private final boolean sign; + + public Result(boolean sign) { + this.sign = sign; + } + + public boolean isSign() { + return sign; + } + } +} diff --git a/jscl/src/main/java/jscl/text/MultiTryParser.java b/jscl/src/main/java/jscl/text/MultiTryParser.java new file mode 100644 index 00000000..335b80d9 --- /dev/null +++ b/jscl/src/main/java/jscl/text/MultiTryParser.java @@ -0,0 +1,41 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.List; + +public class MultiTryParser implements Parser { + + @Nonnull + private final List> parsers; + + public MultiTryParser(@Nonnull List> parsers) { + this.parsers = parsers; + } + + public T parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + T result = null; + + for (final Iterator> it = parsers.iterator(); it.hasNext(); ) { + try { + final Parser parser = it.next(); + result = parser.parse(p, previousSumElement); + } catch (ParseException e) { + + p.addException(e); + + if (!it.hasNext()) { + throw e; + } + } + + if (result != null) { + break; + } + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/MultiplyOrDivideFactor.java b/jscl/src/main/java/jscl/text/MultiplyOrDivideFactor.java new file mode 100644 index 00000000..7f69cce7 --- /dev/null +++ b/jscl/src/main/java/jscl/text/MultiplyOrDivideFactor.java @@ -0,0 +1,37 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class MultiplyOrDivideFactor implements Parser { + + public static final Parser multiply = new MultiplyOrDivideFactor(true); + + public static final Parser divide = new MultiplyOrDivideFactor(false); + + boolean multiplication; + + private MultiplyOrDivideFactor(boolean multiplication) { + this.multiplication = multiplication; + } + + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + if (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().charAt(p.getPosition().intValue()) == (multiplication ? '*' : '/')) { + p.getPosition().increment(); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_10, '*', '/'); + } + + return ParserUtils.parseWithRollback(Factor.parser, pos0, previousSumElement, p); + } +} diff --git a/jscl/src/main/java/jscl/text/MutableInt.java b/jscl/src/main/java/jscl/text/MutableInt.java new file mode 100644 index 00000000..c6106efe --- /dev/null +++ b/jscl/src/main/java/jscl/text/MutableInt.java @@ -0,0 +1,268 @@ +package jscl.text; + +/** + * User: serso + * Date: 10/27/11 + * Time: 11:30 PM + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A mutable int wrapper. + * + * @version $Id: MutableInt.java 437554 2006-08-28 06:21:41Z bayard $ + * @see Integer + * @since 2.1 + */ +public class MutableInt extends Number implements Comparable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 512176391864L; + + /** + * The mutable value. + */ + private int value; + + /** + * Constructs a new MutableInt with the default value of zero. + */ + public MutableInt() { + super(); + } + + /** + * Constructs a new MutableInt with the specified value. + * + * @param value a value. + */ + public MutableInt(int value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableInt with the specified value. + * + * @param value a value. + * @throws NullPointerException if the object is null + */ + public MutableInt(Number value) { + super(); + this.value = value.intValue(); + } + + //----------------------------------------------------------------------- + + /** + * Gets the value as a Integer instance. + * + * @return the value as a Integer + */ + public Object getValue() { + return new Integer(this.value); + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set + * @throws NullPointerException if the object is null + * @throws ClassCastException if the type is not a {@link Number} + */ + public void setValue(Object value) { + setValue(((Number) value).intValue()); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(int value) { + this.value = value; + } + + //----------------------------------------------------------------------- + + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + //----------------------------------------------------------------------- + + /** + * Adds a value. + * + * @param operand the value to add + * @since Commons Lang 2.2 + */ + public void add(int operand) { + this.value += operand; + } + + /** + * Adds a value. + * + * @param operand the value to add + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(Number operand) { + this.value += operand.intValue(); + } + + /** + * Subtracts a value. + * + * @param operand the value to add + * @since Commons Lang 2.2 + */ + public void subtract(int operand) { + this.value -= operand; + } + + /** + * Subtracts a value. + * + * @param operand the value to add + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(Number operand) { + this.value -= operand.intValue(); + } + + //----------------------------------------------------------------------- + // shortValue and bytValue rely on Number implementation + + /** + * Returns the value of this MutableInt as a int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + public int intValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + public long longValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + + /** + * Gets this mutable as an instance of Integer. + * + * @return a Integer instance containing the value from this mutable + */ + public Integer toInteger() { + return new Integer(intValue()); + } + + //----------------------------------------------------------------------- + + /** + * Compares this object to the specified object. The result is true if and only if the argument is + * not null and is an MutableInt object that contains the same int value + * as this object. + * + * @param obj the object to compare with. + * @return true if the objects are the same; false otherwise. + */ + public boolean equals(Object obj) { + if (obj instanceof MutableInt) { + return value == ((MutableInt) obj).intValue(); + } + return false; + } + + /** + * Returns a suitable hashcode for this mutable. + * + * @return a suitable hashcode + */ + public int hashCode() { + return value; + } + + /** + * Compares this mutable to another in ascending order. + * + * @param obj the mutable to compare to + * @return negative if this is less, zero if equal, positive if greater + * @throws ClassCastException if the argument is not a MutableInt + */ + public int compareTo(Object obj) { + MutableInt other = (MutableInt) obj; + int anotherVal = other.value; + return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1); + } + + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + public String toString() { + return String.valueOf(value); + } + +} + diff --git a/jscl/src/main/java/jscl/text/NumeralBaseParser.java b/jscl/src/main/java/jscl/text/NumeralBaseParser.java new file mode 100644 index 00000000..9a1b5eb3 --- /dev/null +++ b/jscl/src/main/java/jscl/text/NumeralBaseParser.java @@ -0,0 +1,36 @@ +package jscl.text; + +import jscl.NumeralBase; +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class NumeralBaseParser implements Parser { + + public static final Parser parser = new NumeralBaseParser(); + + private NumeralBaseParser() { + } + + public NumeralBase parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) { + int pos0 = p.getPosition().intValue(); + + NumeralBase result = p.getMathContext().getNumeralBase(); + + ParserUtils.skipWhitespaces(p); + + for (NumeralBase numeralBase : NumeralBase.values()) { + try { + final String jsclPrefix = numeralBase.getJsclPrefix(); + ParserUtils.tryToParse(p, pos0, jsclPrefix); + result = numeralBase; + break; + } catch (ParseException e) { + } + } + + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/OperatorParser.java b/jscl/src/main/java/jscl/text/OperatorParser.java new file mode 100644 index 00000000..d3558e77 --- /dev/null +++ b/jscl/src/main/java/jscl/text/OperatorParser.java @@ -0,0 +1,49 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.operator.Operator; +import jscl.math.operator.matrix.OperatorsRegistry; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class OperatorParser implements Parser { + + public static final Parser parser = new OperatorParser(); + + private OperatorParser() { + } + + static boolean valid(@Nullable String name) { + return name != null && OperatorsRegistry.getInstance().getNames().contains(name); + } + + @Nonnull + public Operator parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final String operatorName = Identifier.parser.parse(p, previousSumElement); + if (!valid(operatorName)) { + ParserUtils.throwParseException(p, pos0, Messages.msg_3, operatorName); + } + + final Operator operator = OperatorsRegistry.getInstance().get(operatorName); + + Operator result = null; + if (operator != null) { + final Generic parameters[] = ParserUtils.parseWithRollback(new ParameterListParser(operator.getMinParameters()), pos0, previousSumElement, p); + + result = OperatorsRegistry.getInstance().get(operatorName, parameters); + if (result == null) { + ParserUtils.throwParseException(p, pos0, Messages.msg_2, operatorName); + } + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_3, operatorName); + } + + assert result != null; + return result; + } + +} diff --git a/jscl/src/main/java/jscl/text/ParameterListParser.java b/jscl/src/main/java/jscl/text/ParameterListParser.java new file mode 100644 index 00000000..eca5d07b --- /dev/null +++ b/jscl/src/main/java/jscl/text/ParameterListParser.java @@ -0,0 +1,53 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class ParameterListParser implements Parser { + + public static final Parser parser1 = new ParameterListParser(); + private final int minNumberOfParameters; + + private ParameterListParser() { + this.minNumberOfParameters = 1; + } + + public ParameterListParser(int minNumberOfParameters) { + this.minNumberOfParameters = minNumberOfParameters; + } + + @Nonnull + public Generic[] parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final List result = new ArrayList(); + + ParserUtils.tryToParse(p, pos0, '('); + + try { + result.add(ExpressionParser.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + if (minNumberOfParameters > 0) { + p.getPosition().setValue(pos0); + throw e; + } + } + + while (true) { + try { + result.add(CommaAndExpression.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + ParserUtils.tryToParse(p, pos0, ')'); + + + return ArrayUtils.toArray(result, new Generic[result.size()]); + } +} diff --git a/jscl/src/main/java/jscl/text/ParseException.java b/jscl/src/main/java/jscl/text/ParseException.java new file mode 100644 index 00000000..4b3dba8e --- /dev/null +++ b/jscl/src/main/java/jscl/text/ParseException.java @@ -0,0 +1,86 @@ +package jscl.text; + +import jscl.text.msg.JsclMessage; +import org.solovyev.common.msg.Message; +import org.solovyev.common.msg.MessageLevel; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Locale; + +public class ParseException extends Exception implements Message { + + @Nonnull + private final Message message; + + private final int position; + + @Nonnull + private final String expression; + + public ParseException(@Nonnull String messageCode, int position, @Nonnull String expression, Object... parameters) { + this.message = new JsclMessage(messageCode, MessageType.error, parameters); + this.position = position; + this.expression = expression; + } + + public ParseException(@Nonnull Message message, int position, @Nonnull String expression) { + this.message = message; + this.position = position; + this.expression = expression; + } + + @Nonnull + public String getMessageCode() { + return this.message.getMessageCode(); + } + + @Nonnull + public List getParameters() { + return this.message.getParameters(); + } + + @Nonnull + @Override + public MessageLevel getMessageLevel() { + return this.message.getMessageLevel(); + } + + @Nonnull + @Override + public String getLocalizedMessage(@Nonnull Locale locale) { + return this.message.getLocalizedMessage(locale); + } + + public int getPosition() { + return position; + } + + @Nonnull + public String getExpression() { + return expression; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ParseException that = (ParseException) o; + + if (position != that.position) return false; + if (!expression.equals(that.expression)) return false; + if (!message.equals(that.message)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = message.hashCode(); + result = 31 * result + position; + result = 31 * result + expression.hashCode(); + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/ParseInterruptedException.java b/jscl/src/main/java/jscl/text/ParseInterruptedException.java new file mode 100644 index 00000000..2b09f715 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ParseInterruptedException.java @@ -0,0 +1,24 @@ +package jscl.text; + +/** + * User: serso + * Date: 10/27/11 + * Time: 11:39 PM + */ +public class ParseInterruptedException extends RuntimeException { + + public ParseInterruptedException() { + } + + public ParseInterruptedException(String message) { + super(message); + } + + public ParseInterruptedException(String message, Throwable cause) { + super(message, cause); + } + + public ParseInterruptedException(Throwable cause) { + super(cause); + } +} diff --git a/jscl/src/main/java/jscl/text/Parser.java b/jscl/src/main/java/jscl/text/Parser.java new file mode 100644 index 00000000..3ed0ecf5 --- /dev/null +++ b/jscl/src/main/java/jscl/text/Parser.java @@ -0,0 +1,85 @@ +package jscl.text; + +import jscl.MathContext; +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Main parser interface. + *

+ * Aim of parser is to convert input string expression into java objects + * + * @param type of result object of parser + */ +public interface Parser { + + /** + * @param p parse parameters + * @param previousSumElement sum element to the left of last + sign + * @return parsed object of type T + * @throws ParseException occurs if object could not be parsed from the string + */ + T parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException; + + static class Parameters { + + @Nonnull + private final String expression; + + @Nonnull + private final MutableInt position; + + @Nonnull + private final List exceptions = new ArrayList(); + + @Nonnull + private final MathContext mathContext; + + /** + * @param expression expression to be parsed + * @param position current position of expression. Side effect: if parsing is successful this parameter should be increased on the number of parsed letters (incl whitespaces etc) + * @param mathContext math engine to be used in parsing + */ + Parameters(@Nonnull String expression, @Nonnull MutableInt position, @Nonnull MathContext mathContext) { + this.expression = expression; + this.position = position; + this.mathContext = mathContext; + } + + @Nonnull + public static Parameters newInstance(@Nonnull String expression, @Nonnull MutableInt position, @Nonnull final MathContext mathEngine) { + return new Parameters(expression, position, mathEngine); + } + + @Nonnull + public String getExpression() { + return expression; + } + + @Nonnull + public MutableInt getPosition() { + return position; + } + + public void addException(@Nonnull ParseException e) { + if (!exceptions.contains(e)) { + exceptions.add(e); + } + } + + @Nonnull + public MathContext getMathContext() { + return mathContext; + } + + @Nonnull + public List getExceptions() { + return Collections.unmodifiableList(exceptions); + } + } +} diff --git a/jscl/src/main/java/jscl/text/ParserUtils.java b/jscl/src/main/java/jscl/text/ParserUtils.java new file mode 100644 index 00000000..c847eb40 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ParserUtils.java @@ -0,0 +1,110 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.reflect.Array; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:40 PM + */ +public class ParserUtils { + + public static void checkInterruption() { + if (Thread.currentThread().isInterrupted()) { + throw new ParseInterruptedException("Interrupted!"); + } + } + + public static void skipWhitespaces(@Nonnull Parser.Parameters p) { + final MutableInt position = p.getPosition(); + final String expression = p.getExpression(); + + while (position.intValue() < expression.length() && Character.isWhitespace(expression.charAt(position.intValue()))) { + position.increment(); + } + } + + public static void tryToParse(@Nonnull Parser.Parameters p, + int pos0, + char ch) throws ParseException { + skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length()) { + char actual = p.getExpression().charAt(p.getPosition().intValue()); + if (actual == ch) { + p.getPosition().increment(); + } else { + throwParseException(p, pos0, Messages.msg_12, ch); + } + } else { + throwParseException(p, pos0, Messages.msg_12, ch); + } + } + + public static void tryToParse(@Nonnull Parser.Parameters p, + int pos0, + @Nonnull String s) throws ParseException { + skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length()) { + if (p.getExpression().startsWith(s, p.getPosition().intValue())) { + p.getPosition().add(s.length()); + } else { + throwParseException(p, pos0, Messages.msg_11, s); + } + } else { + throwParseException(p, pos0, Messages.msg_11, s); + } + } + + public static void throwParseException(@Nonnull Parser.Parameters p, + int pos0, + @Nonnull String messageId, + Object... parameters) throws ParseException { + final MutableInt position = p.getPosition(); + final ParseException parseException = new ParseException(messageId, position.intValue(), p.getExpression(), parameters); + position.setValue(pos0); + throw parseException; + } + + + @Nonnull + static T parseWithRollback(@Nonnull Parser parser, + int initialPosition, + @Nullable final Generic previousSumParser, + @Nonnull final Parser.Parameters p) throws ParseException { + T result; + + try { + result = parser.parse(p, previousSumParser); + } catch (ParseException e) { + p.getPosition().setValue(initialPosition); + throw e; + } + + return result; + } + + public static T[] copyOf(@Nonnull T[] array, int newLength) { + return (T[]) copyOf(array, newLength, array.getClass()); + } + + public static T[] copyOf(@Nonnull T[] array) { + return (T[]) copyOf(array, array.length, array.getClass()); + } + + public static T[] copyOf(U[] array, int newLength, Class newType) { + T[] copy = ((Object) newType == (Object) Object[].class) + ? (T[]) new Object[newLength] + : (T[]) Array.newInstance(newType.getComponentType(), newLength); + + System.arraycopy(array, 0, copy, 0, Math.min(array.length, newLength)); + + return copy; + } +} diff --git a/jscl/src/main/java/jscl/text/PlusOrMinusTerm.java b/jscl/src/main/java/jscl/text/PlusOrMinusTerm.java new file mode 100644 index 00000000..943c75c1 --- /dev/null +++ b/jscl/src/main/java/jscl/text/PlusOrMinusTerm.java @@ -0,0 +1,38 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:44 PM + */ +class PlusOrMinusTerm implements Parser { + + public static final Parser parser = new PlusOrMinusTerm(); + + private PlusOrMinusTerm() { + } + + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + boolean sign = false; + if (p.getPosition().intValue() < p.getExpression().length() && (p.getExpression().charAt(p.getPosition().intValue()) == '+' || p.getExpression().charAt(p.getPosition().intValue()) == '-')) { + sign = p.getExpression().charAt(p.getPosition().intValue()) == '-'; + p.getPosition().increment(); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_10, '+', '-'); + } + + final Generic result = ParserUtils.parseWithRollback(TermParser.parser, pos0, previousSumElement, p); + + return sign ? result.negate() : result; + } + +} diff --git a/jscl/src/main/java/jscl/text/PostfixFunctionParser.java b/jscl/src/main/java/jscl/text/PostfixFunctionParser.java new file mode 100644 index 00000000..30cc8206 --- /dev/null +++ b/jscl/src/main/java/jscl/text/PostfixFunctionParser.java @@ -0,0 +1,61 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +public class PostfixFunctionParser implements Parser { + + @Nonnull + private final String postfixFunctionName; + + protected PostfixFunctionParser(@Nonnull String postfixFunctionName) { + this.postfixFunctionName = postfixFunctionName; + } + + @Nonnull + public Result parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final boolean postfixFunction; + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().startsWith(postfixFunctionName, p.getPosition().intValue())) { + p.getPosition().add(postfixFunctionName.length()); + postfixFunction = true; + } else { + p.getPosition().setValue(pos0); + postfixFunction = false; + } + + return new Result(postfixFunctionName, postfixFunction); + } + + public static class Result { + + @Nonnull + private final String postfixFunctionName; + + private final boolean postfixFunction; + + public Result(@Nonnull String postfixFunctionName, boolean postfixFunction) { + this.postfixFunctionName = postfixFunctionName; + this.postfixFunction = postfixFunction; + } + + public boolean isPostfixFunction() { + return postfixFunction; + } + + @Nonnull + public String getPostfixFunctionName() { + return postfixFunctionName; + } + } +} diff --git a/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java b/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java new file mode 100644 index 00000000..8ca2762b --- /dev/null +++ b/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java @@ -0,0 +1,72 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.PostfixFunctionsRegistry; +import jscl.math.operator.Operator; +import jscl.math.operator.TripleFactorial; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +/** + * User: serso + * Date: 10/31/11 + * Time: 11:20 PM + */ +public class PostfixFunctionsParser implements Parser { + + @Nonnull + private final Generic content; + + public PostfixFunctionsParser(@Nonnull Generic content) { + this.content = content; + } + + private static Generic parsePostfix(@Nonnull List parsers, + Generic content, + @Nullable final Generic previousSumElement, + @Nonnull final Parameters parseParameters) throws ParseException { + Generic result = content; + + for (PostfixFunctionParser parser : parsers) { + final PostfixFunctionParser.Result postfixResult = parser.parse(parseParameters, previousSumElement); + if (postfixResult.isPostfixFunction()) { + final Operator postfixFunction; + + if (previousSumElement == null) { + postfixFunction = PostfixFunctionsRegistry.getInstance().get(postfixResult.getPostfixFunctionName(), new Generic[]{content}); + } else { + postfixFunction = PostfixFunctionsRegistry.getInstance().get(postfixResult.getPostfixFunctionName(), new Generic[]{content, previousSumElement}); + } + + if (postfixFunction == null) { + if (TripleFactorial.NAME.equals(postfixResult.getPostfixFunctionName())) { + throw new ParseException(Messages.msg_18, parseParameters.getPosition().intValue(), parseParameters.getExpression()); + } else { + throw new ParseException(Messages.msg_4, parseParameters.getPosition().intValue(), parseParameters.getExpression(), postfixResult.getPostfixFunctionName()); + } + } + + result = parsePostfix(parsers, postfixFunction.expressionValue(), previousSumElement, parseParameters); + } + } + + return result; + } + + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + + final List postfixFunctionNames = PostfixFunctionsRegistry.getInstance().getNames(); + + final List parsers = new ArrayList(postfixFunctionNames.size()); + parsers.add(new PostfixFunctionParser(TripleFactorial.NAME)); + for (String postfixFunctionName : postfixFunctionNames) { + parsers.add(new PostfixFunctionParser(postfixFunctionName)); + } + + return parsePostfix(parsers, content, previousSumElement, p); + } +} diff --git a/jscl/src/main/java/jscl/text/PowerExponentParser.java b/jscl/src/main/java/jscl/text/PowerExponentParser.java new file mode 100644 index 00000000..e7488cdf --- /dev/null +++ b/jscl/src/main/java/jscl/text/PowerExponentParser.java @@ -0,0 +1,40 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class PowerExponentParser implements Parser { + + public static final Parser parser = new PowerExponentParser(); + + private PowerExponentParser() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + try { + PowerParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + Generic result; + try { + result = ExponentParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/PowerParser.java b/jscl/src/main/java/jscl/text/PowerParser.java new file mode 100644 index 00000000..960f9afc --- /dev/null +++ b/jscl/src/main/java/jscl/text/PowerParser.java @@ -0,0 +1,45 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class PowerParser implements Parser { + + public static final Parser parser = new PowerParser(); + + private PowerParser() { + } + + @Nullable + public Void parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().charAt(p.getPosition().intValue()) == '^') { + p.getPosition().increment(); + } else { + if (isDoubleStar(p.getExpression(), p.getPosition())) { + p.getPosition().increment(); + p.getPosition().increment(); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_10, '^', "**"); + } + } + + return null; + } + + private boolean isDoubleStar(@Nonnull String string, @Nonnull MutableInt position) { + final int i = position.intValue(); + return i < string.length() && i + 1 < string.length() && string.charAt(i) == '*' && string.charAt(i + 1) == '*'; + } +} diff --git a/jscl/src/main/java/jscl/text/PrimaryExpressionParser.java b/jscl/src/main/java/jscl/text/PrimaryExpressionParser.java new file mode 100644 index 00000000..c7edaac3 --- /dev/null +++ b/jscl/src/main/java/jscl/text/PrimaryExpressionParser.java @@ -0,0 +1,37 @@ +package jscl.text; + +import jscl.math.ExpressionVariable; +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +public class PrimaryExpressionParser implements Parser { + + public static final Parser parser = new PrimaryExpressionParser(); + + private static final List> parsers = Arrays.asList( + new VariableConverter(DoubleVariableParser.parser), + JsclIntegerParser.parser, + new VariableConverter(VariableParser.parser), + new VariableConverter(MatrixVariableParser.parser), + new VariableConverter(VectorVariableParser.parser), + new VariableConverter(BracketedExpression.parser)); + + private static final Parser internalParser = new MultiTryParser(new ArrayList>(parsers)); + + private PrimaryExpressionParser() { + } + + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return internalParser.parse(p, previousSumElement); + } +} diff --git a/jscl/src/main/java/jscl/text/PrimeCharacters.java b/jscl/src/main/java/jscl/text/PrimeCharacters.java new file mode 100644 index 00000000..6e38a76c --- /dev/null +++ b/jscl/src/main/java/jscl/text/PrimeCharacters.java @@ -0,0 +1,37 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class PrimeCharacters implements Parser { + public static final Parser parser = new PrimeCharacters(); + + private PrimeCharacters() { + } + + public Integer parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + + int pos0 = p.getPosition().intValue(); + + int result = 0; + + ParserUtils.skipWhitespaces(p); + + if (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().charAt(p.getPosition().intValue()) == '\'') { + p.getPosition().increment(); + result = 1; + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_12, '\''); + } + + while (p.getPosition().intValue() < p.getExpression().length() && p.getExpression().charAt(p.getPosition().intValue()) == '\'') { + p.getPosition().increment(); + result++; + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/RootParser.java b/jscl/src/main/java/jscl/text/RootParser.java new file mode 100644 index 00000000..5c95bd42 --- /dev/null +++ b/jscl/src/main/java/jscl/text/RootParser.java @@ -0,0 +1,29 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.Function; +import jscl.math.function.Root; +import jscl.text.msg.Messages; + +import javax.annotation.Nonnull; + +public class RootParser implements Parser { + public static final Parser parser = new RootParser(); + + private RootParser() { + } + + public Function parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final String name = Identifier.parser.parse(p, previousSumElement); + if (name.compareTo("root") != 0) { + ParserUtils.throwParseException(p, pos0, Messages.msg_11, "root"); + } + + final Generic subscript = ParserUtils.parseWithRollback(Subscript.parser, pos0, previousSumElement, p); + final Generic parameters[] = ParserUtils.parseWithRollback(ParameterListParser.parser1, pos0, previousSumElement, p); + + return new Root(parameters, subscript); + } +} diff --git a/jscl/src/main/java/jscl/text/Subscript.java b/jscl/src/main/java/jscl/text/Subscript.java new file mode 100644 index 00000000..9bfd56d6 --- /dev/null +++ b/jscl/src/main/java/jscl/text/Subscript.java @@ -0,0 +1,33 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class Subscript implements Parser { + + public static final Parser parser = new Subscript(); + + private Subscript() { + } + + public Generic parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.tryToParse(p, pos0, '['); + + Generic a; + try { + a = ExpressionParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + ParserUtils.tryToParse(p, pos0, ']'); + + return a; + } + +} diff --git a/jscl/src/main/java/jscl/text/TermParser.java b/jscl/src/main/java/jscl/text/TermParser.java new file mode 100644 index 00000000..c062fa37 --- /dev/null +++ b/jscl/src/main/java/jscl/text/TermParser.java @@ -0,0 +1,50 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.GenericVariable; +import jscl.math.JsclInteger; +import jscl.math.function.Fraction; +import jscl.math.function.Inverse; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class TermParser implements Parser { + + public static final Parser parser = new TermParser(); + + private TermParser() { + } + + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + Generic result = JsclInteger.valueOf(1); + + Generic s = (Generic) UnsignedFactor.parser.parse(p, previousSumElement); + + while (true) { + try { + Generic b = MultiplyOrDivideFactor.multiply.parse(p, null); + result = result.multiply(s); + s = b; + } catch (ParseException e) { + try { + Generic b = MultiplyOrDivideFactor.divide.parse(p, null); + if (s.compareTo(JsclInteger.valueOf(1)) == 0) + s = new Inverse(GenericVariable.content(b, true)).expressionValue(); + else + s = new Fraction(GenericVariable.content(s, true), GenericVariable.content(b, true)).expressionValue(); + } catch (ParseException e2) { + break; + } + } + } + + result = result.multiply(s); + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/UnsignedExponent.java b/jscl/src/main/java/jscl/text/UnsignedExponent.java new file mode 100644 index 00000000..304ed2d4 --- /dev/null +++ b/jscl/src/main/java/jscl/text/UnsignedExponent.java @@ -0,0 +1,23 @@ +package jscl.text; + +import jscl.math.Generic; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class UnsignedExponent implements Parser { + + public static final Parser parser = new UnsignedExponent(); + + private UnsignedExponent() { + } + + public Generic parse(@Nonnull Parameters p, final Generic previousSumElement) throws ParseException { + final Generic content = PrimaryExpressionParser.parser.parse(p, previousSumElement); + return new PostfixFunctionsParser(content).parse(p, previousSumElement); + } +} diff --git a/jscl/src/main/java/jscl/text/UnsignedFactor.java b/jscl/src/main/java/jscl/text/UnsignedFactor.java new file mode 100644 index 00000000..46cfb0f7 --- /dev/null +++ b/jscl/src/main/java/jscl/text/UnsignedFactor.java @@ -0,0 +1,58 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.GenericVariable; +import jscl.math.JsclInteger; +import jscl.math.NotIntegerException; +import jscl.math.function.Pow; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +/** + * User: serso + * Date: 10/27/11 + * Time: 2:45 PM + */ +class UnsignedFactor implements Parser { + public static final Parser parser = new UnsignedFactor(); + + private UnsignedFactor() { + } + + public Object parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + final List list = new ArrayList(); + + Generic generic = UnsignedExponent.parser.parse(p, previousSumElement); + + list.add(generic); + + while (true) { + try { + list.add(PowerExponentParser.parser.parse(p, null)); + } catch (ParseException e) { + break; + } + } + + final ListIterator it = list.listIterator(list.size()); + generic = it.previous(); + while (it.hasPrevious()) { + Generic b = it.previous(); + try { + int c = generic.integerValue().intValue(); + if (c < 0) { + generic = new Pow(GenericVariable.content(b, true), JsclInteger.valueOf(c)).expressionValue(); + } else { + generic = b.pow(c); + } + } catch (NotIntegerException e) { + generic = new Pow(GenericVariable.content(b, true), GenericVariable.content(generic, true)).expressionValue(); + } + } + + return generic; + } +} diff --git a/jscl/src/main/java/jscl/text/UsualFunctionParser.java b/jscl/src/main/java/jscl/text/UsualFunctionParser.java new file mode 100644 index 00000000..d0009814 --- /dev/null +++ b/jscl/src/main/java/jscl/text/UsualFunctionParser.java @@ -0,0 +1,55 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.function.Function; +import jscl.math.function.FunctionsRegistry; +import jscl.text.msg.Messages; +import org.solovyev.common.math.MathRegistry; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 10/29/11 + * Time: 1:05 PM + */ +class UsualFunctionParser implements Parser { + + public static final Parser parser = new UsualFunctionParser(); + + private MathRegistry functionsRegistry = FunctionsRegistry.getInstance(); + + private UsualFunctionParser() { + } + + static boolean valid(@Nullable String name) { + return name != null && FunctionsRegistry.getInstance().getNames().contains(name); + } + + public Function parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + final String name = Identifier.parser.parse(p, previousSumElement); + + if (!valid(name)) { + ParserUtils.throwParseException(p, pos0, Messages.msg_13); + } + + final Function result = functionsRegistry.get(name); + + if (result != null) { + final Generic parameters[] = ParserUtils.parseWithRollback(new ParameterListParser(result.getMinParameters()), pos0, previousSumElement, p); + + if (result.getMinParameters() <= parameters.length && result.getMaxParameters() >= parameters.length) { + result.setParameters(parameters); + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_14, parameters.length); + } + } else { + ParserUtils.throwParseException(p, pos0, Messages.msg_13); + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/text/VariableConverter.java b/jscl/src/main/java/jscl/text/VariableConverter.java new file mode 100644 index 00000000..5cb66b31 --- /dev/null +++ b/jscl/src/main/java/jscl/text/VariableConverter.java @@ -0,0 +1,23 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/27/11 + * Time: 3:21 PM + */ +class VariableConverter extends AbstractConverter { + + VariableConverter(@Nonnull Parser variableParser) { + super(variableParser); + } + + @Override + public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return this.parser.parse(p, previousSumElement).expressionValue(); + } +} diff --git a/jscl/src/main/java/jscl/text/VariableParser.java b/jscl/src/main/java/jscl/text/VariableParser.java new file mode 100644 index 00000000..47c7e244 --- /dev/null +++ b/jscl/src/main/java/jscl/text/VariableParser.java @@ -0,0 +1,28 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.Variable; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class VariableParser implements Parser { + + public static final Parser parser = new VariableParser(); + + private final static List> parsers = Arrays.asList( + OperatorParser.parser, + FunctionParser.parser, + ConstantParser.parser); + + private final static MultiTryParser internalParser = new MultiTryParser(new ArrayList>(parsers)); + + private VariableParser() { + } + + public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + return internalParser.parse(p, previousSumElement); + } +} diff --git a/jscl/src/main/java/jscl/text/VectorParser.java b/jscl/src/main/java/jscl/text/VectorParser.java new file mode 100644 index 00000000..0a97fa55 --- /dev/null +++ b/jscl/src/main/java/jscl/text/VectorParser.java @@ -0,0 +1,47 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.util.ArrayUtils; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class VectorParser implements Parser { + + public static final Parser parser = new VectorParser(); + + private VectorParser() { + } + + public JsclVector parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + int pos0 = p.getPosition().intValue(); + + ParserUtils.skipWhitespaces(p); + + ParserUtils.tryToParse(p, pos0, '['); + + final List result = new ArrayList(); + try { + result.add(ExpressionParser.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + p.getPosition().setValue(pos0); + throw e; + } + + while (true) { + try { + result.add(CommaAndExpression.parser.parse(p, previousSumElement)); + } catch (ParseException e) { + break; + } + } + + ParserUtils.skipWhitespaces(p); + + ParserUtils.tryToParse(p, pos0, ']'); + + return new JsclVector(ArrayUtils.toArray(result, new Generic[result.size()])); + } +} diff --git a/jscl/src/main/java/jscl/text/VectorVariableParser.java b/jscl/src/main/java/jscl/text/VectorVariableParser.java new file mode 100644 index 00000000..93a696b3 --- /dev/null +++ b/jscl/src/main/java/jscl/text/VectorVariableParser.java @@ -0,0 +1,25 @@ +package jscl.text; + +import jscl.math.Generic; +import jscl.math.JsclVector; +import jscl.math.Variable; +import jscl.math.VectorVariable; + +import javax.annotation.Nonnull; + +public class VectorVariableParser implements Parser { + public static final Parser parser = new VectorVariableParser(); + + private VectorVariableParser() { + } + + public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { + JsclVector result; + try { + result = VectorParser.parser.parse(p, previousSumElement); + } catch (ParseException e) { + throw e; + } + return new VectorVariable(result); + } +} diff --git a/jscl/src/main/java/jscl/text/msg/JsclMessage.java b/jscl/src/main/java/jscl/text/msg/JsclMessage.java new file mode 100644 index 00000000..47fab93e --- /dev/null +++ b/jscl/src/main/java/jscl/text/msg/JsclMessage.java @@ -0,0 +1,35 @@ +package jscl.text.msg; + +import org.solovyev.common.msg.AbstractMessage; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * User: serso + * Date: 11/26/11 + * Time: 11:20 AM + */ +public class JsclMessage extends AbstractMessage { + + public JsclMessage(@Nonnull String messageCode, + @Nonnull MessageType messageType, + @javax.annotation.Nullable Object... parameters) { + super(messageCode, messageType, parameters); + } + + public JsclMessage(@Nonnull String messageCode, + @Nonnull MessageType messageType, + @Nonnull List parameters) { + super(messageCode, messageType, parameters); + } + + @Override + protected String getMessagePattern(@Nonnull Locale locale) { + final ResourceBundle rb = ResourceBundle.getBundle("jscl/text/msg/messages", locale); + return rb.getString(getMessageCode()); + } +} diff --git a/jscl/src/main/java/jscl/text/msg/Messages.java b/jscl/src/main/java/jscl/text/msg/Messages.java new file mode 100644 index 00000000..fba38b54 --- /dev/null +++ b/jscl/src/main/java/jscl/text/msg/Messages.java @@ -0,0 +1,120 @@ +package jscl.text.msg; + +/** + * User: serso + * Date: 11/24/11 + * Time: 5:47 PM + */ +public final class Messages { + + /** + * Parsing error near {0} symbol: {1} + */ + public static final String msg_0 = "msg_0"; + /** + * Parsing error occurred near {0} symbol: check expression validity + */ + public static final String msg_1 = "msg_1"; + /** + * There is no operator with name: {0} + */ + public static final String msg_2 = "msg_2"; + /** + * Operator name is not valid: {0} + */ + public static final String msg_3 = "msg_3"; + /** + * Postfix function with name {0} doesn't exist + */ + public static final String msg_4 = "msg_4"; + /** + * Constant name must start with character + */ + public static final String msg_5 = "msg_5"; + /** + * Cannot be implicit function - usual function or operator with same name is defined: {0} + */ + public static final String msg_6 = "msg_6"; + /** + * Digit is expected + */ + public static final String msg_7 = "msg_7"; + /** + * Invalid number: {0} + */ + public static final String msg_8 = "msg_8"; + /** + * First letter of number must be digit + */ + public static final String msg_9 = "msg_9"; + /** + * Expected characters are {0} or {1} + */ + public static final String msg_10 = "msg_10"; + /** + * Expected characters are {0} + */ + public static final String msg_11 = "msg_11"; + /** + * Expected character is {0} + */ + public static final String msg_12 = "msg_12"; + /** + * Function name is not valid: {0} + */ + public static final String msg_13 = "msg_13"; + /** + * Expected number of parameters differs from actual {0} + */ + public static final String msg_14 = "msg_14"; + /** + * Only decimal numeral base supports decimal numbers + */ + public static final String msg_15 = "msg_15"; + /** + * Next errors occurred while calculations: + */ + public static final String msg_16 = "msg_16"; + /** + * Unable to convert numeral base of {0}. Change default numeral base to decimal and try again. + */ + public static final String msg_17 = "msg_17"; + /** + * Calculation of triple factorial is not supported! + */ + public static final String msg_18 = "msg_18"; + /** + * Custom function with name {0} could not be calculated due to next error: {1} + */ + public static final String msg_19 = "msg_19"; + /** + * Function {0} cannot be integrated for not radian angle units! + */ + public static final String msg_20 = "msg_20"; + /** + * Integration is not supported for {0} + */ + public static final String msg_21 = "msg_21"; + /** + * Integration is not supported + */ + public static final String msg_22 = "msg_22"; + /** + * Complex number computation in not RAD mode can lead to unexpected results! + */ + public static final String msg_23 = "msg_23"; + /** + * Integration in not RAD mode can lead to unexpected results! + */ + public static final String msg_24 = "msg_24"; + /** + * Differentiation in not RAD mode can lead to unexpected results! + */ + public static final String msg_25 = "msg_25"; + static final int COUNT = 26; + + // not intended for instantiation + private Messages() { + throw new AssertionError(); + } +} diff --git a/jscl/src/main/java/jscl/util/AbstractExpressionGenerator.java b/jscl/src/main/java/jscl/util/AbstractExpressionGenerator.java new file mode 100644 index 00000000..06fd565a --- /dev/null +++ b/jscl/src/main/java/jscl/util/AbstractExpressionGenerator.java @@ -0,0 +1,111 @@ +package jscl.util; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class AbstractExpressionGenerator { + + public static final double MAX_VALUE = Math.pow(10, 4); + private final int depth; + + protected AbstractExpressionGenerator() { + this(10); + } + public AbstractExpressionGenerator(int depth) { + this.depth = depth; + } + + public int getDepth() { + return depth; + } + + @Nonnull + public abstract T generate(); + + protected boolean generateBrackets() { + return Math.random() > 0.8d; + } + + @Nonnull + protected Operation generateOperation() { + final int operationId = (int) (Math.random() * 4d); + final Operation result = Operation.getOperationById(operationId); + if (result == null) { + throw new UnsupportedOperationException("Check!"); + } + return result; + } + + @Nullable + protected Function generateFunction() { + final int functionId = (int) (Math.random() * 8d); + return Function.getFunctionById(functionId); + } + + // only positive values (as - operator exists) + @Nonnull + protected Double generateNumber() { + return Math.random() * MAX_VALUE; + } + + protected static enum Operation { + addition(0, "+"), + subtraction(1, "-"), + multiplication(2, "*"), + division(3, "/"); + + private final int operationId; + private final String token; + + Operation(int operationId, @Nonnull String token) { + this.operationId = operationId; + this.token = token; + } + + @Nullable + public static Operation getOperationById(int operationId) { + for (Operation operation : Operation.values()) { + if (operation.operationId == operationId) { + return operation; + } + } + + return null; + } + + + public String getToken() { + return token; + } + } + + protected static enum Function { + sin(0, "sin"), + cos(1, "cos"), + sqrt(2, "√"), + ln(3, "ln"); + + private final int functionId; + private final String token; + + Function(int functionId, @Nonnull String token) { + this.functionId = functionId; + this.token = token; + } + + @Nullable + public static Function getFunctionById(int functionId) { + for (Function function : Function.values()) { + if (function.functionId == functionId) { + return function; + } + } + + return null; + } + + public String getToken() { + return token; + } + } +} diff --git a/jscl/src/main/java/jscl/util/ArrayComparator.java b/jscl/src/main/java/jscl/util/ArrayComparator.java new file mode 100644 index 00000000..a5917214 --- /dev/null +++ b/jscl/src/main/java/jscl/util/ArrayComparator.java @@ -0,0 +1,35 @@ +package jscl.util; + +import java.util.Comparator; + +public class ArrayComparator implements Comparator { + + public static final Comparator comparator = new ArrayComparator(); + + private ArrayComparator() { + } + + public int compare(Comparable l[], Comparable r[]) { + if (l.length < r.length) { + return -1; + } else if (l.length > r.length) { + return 1; + } + + for (int i = l.length - 1; i >= 0; i--) { + if (l[i] == null && r[i] == null) { + // continue + } else if (l[i] != null && r[i] == null) { + return -1; + } else if (l[i] == null && r[i] != null) { + return 1; + } else if (l[i].compareTo(r[i]) < 0) { + return -1; + } else if (l[i].compareTo(r[i]) > 0) { + return 1; + } + } + + return 0; + } +} diff --git a/jscl/src/main/java/jscl/util/ArrayUtils.java b/jscl/src/main/java/jscl/util/ArrayUtils.java new file mode 100644 index 00000000..fb9dbadd --- /dev/null +++ b/jscl/src/main/java/jscl/util/ArrayUtils.java @@ -0,0 +1,116 @@ +package jscl.util; + +import javax.annotation.Nonnull; +import java.util.*; + +public class ArrayUtils { + + private static final int BINARY_SEARCH_THRESHOLD = 5000; + + 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 T[] toArray(@Nonnull List list, T res[]) { + int n = list.size(); + + for (int i = 0; i < n; i++) { + res[i] = list.get(i); + } + + return res; + } + + public static int[] toArray(@Nonnull List list, @Nonnull int result[]) { + int n = list.size(); + + for (int i = 0; i < n; i++) { + result[i] = list.get(i); + } + + return result; + } + + public static List toList(@Nonnull Collection collection) { + return new ArrayList(collection); + } + + public static String toString(@Nonnull Object array[]) { + final StringBuilder result = new StringBuilder(); + result.append("{"); + for (int i = 0; i < array.length; i++) { + result.append(array[i]).append(i < array.length - 1 ? ", " : ""); + } + result.append("}"); + return result.toString(); + } + + public static > int binarySearch(@Nonnull List list, @Nonnull T key) { + if (list instanceof RandomAccess || list.size() < BINARY_SEARCH_THRESHOLD) + return indexedBinarySearch(list, key); + else + return iteratorBinarySearch(list, key); + } + + private static > int indexedBinarySearch(@Nonnull List list, @Nonnull T key) { + int low = 0; + int high = list.size() - 1; + + while (low <= high) { + int mid = (low + high) >> 1; + T midVal = list.get(mid); + int cmp = 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(@Nonnull List list, @Nonnull T key) { + int low = 0; + int high = list.size() - 1; + final ListIterator it = list.listIterator(); + + while (low <= high) { + int mid = (low + high) >> 1; + T midVal = get(it, mid); + int cmp = 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 + } + + @Nonnull + private static T get(@Nonnull ListIterator it, int index) { + T result; + + int pos = it.nextIndex(); + if (pos <= index) { + do { + result = it.next(); + } while (pos++ < index); + } else { + do { + result = it.previous(); + } while (--pos > index); + } + + return result; + } +} diff --git a/jscl/src/main/java/jscl/util/ExpressionGenerator.java b/jscl/src/main/java/jscl/util/ExpressionGenerator.java new file mode 100644 index 00000000..f2c6f03d --- /dev/null +++ b/jscl/src/main/java/jscl/util/ExpressionGenerator.java @@ -0,0 +1,51 @@ +package jscl.util; + +import javax.annotation.Nonnull; + +public class ExpressionGenerator extends AbstractExpressionGenerator { + + public ExpressionGenerator() { + super(); + } + + public ExpressionGenerator(int depth) { + super(depth); + } + + public static void main(String... args) { + System.out.println(new ExpressionGenerator(20).generate()); + } + + @Nonnull + @Override + public String generate() { + StringBuilder result = new StringBuilder(); + + result.append(generateNumber()); + + int i = 0; + while (i < getDepth()) { + + final Operation operation = generateOperation(); + final Function function = generateFunction(); + final boolean brackets = generateBrackets(); + + result.append(operation.getToken()); + + if (function == null) { + result.append(generateNumber()); + } else { + result.append(function.getToken()).append("(").append(generateNumber()).append(")"); + } + + if (brackets) { + result = new StringBuilder("(").append(result).append(")"); + } + + i++; + } + + return result.toString(); + } + +} diff --git a/jscl/src/main/java/jscl/util/ExpressionGeneratorWithInput.java b/jscl/src/main/java/jscl/util/ExpressionGeneratorWithInput.java new file mode 100644 index 00000000..c5ceed7b --- /dev/null +++ b/jscl/src/main/java/jscl/util/ExpressionGeneratorWithInput.java @@ -0,0 +1,69 @@ +package jscl.util; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class ExpressionGeneratorWithInput extends AbstractExpressionGenerator> { + + @Nonnull + private final List subExpressions; + + public ExpressionGeneratorWithInput(@Nonnull List subExpressions) { + this(subExpressions, 10); + } + + public ExpressionGeneratorWithInput(@Nonnull List subExpressions, int depth) { + super(depth); + this.subExpressions = new ArrayList(subExpressions); + } + + public static void main(String... args) { + final ArrayList input = new ArrayList(); + input.add("3"); + input.add("0x:fed"); + input.add("0b:101"); + for (String expression : new ExpressionGeneratorWithInput(input, 20).generate()) { + System.out.println(expression); + } + } + + @Nonnull + public List generate() { + final List expressions = new ArrayList(); + for (String subExpression : subExpressions) { + expressions.add(new StringBuilder(subExpression)); + } + + int i = 0; + while (i < getDepth()) { + + final Operation operation = generateOperation(); + final Function function = generateFunction(); + final boolean brackets = generateBrackets(); + + for (int j = 0; j < subExpressions.size(); j++) { + final StringBuilder expression = expressions.get(j); + expression.append(operation.getToken()); + + if (function == null) { + expression.append(subExpressions.get(j)); + } else { + expression.append(function.getToken()).append("(").append(subExpressions.get(j)).append(")"); + } + + if (brackets) { + expressions.set(j, new StringBuilder("(").append(expression).append(")")); + } + } + i++; + } + + final List result = new ArrayList(); + for (StringBuilder expression : expressions) { + result.add(expression.toString()); + } + + return result; + } +} diff --git a/jscl/src/main/java/org/solovyev/common/math/AbstractMathEntity.java b/jscl/src/main/java/org/solovyev/common/math/AbstractMathEntity.java new file mode 100644 index 00000000..d7400e8a --- /dev/null +++ b/jscl/src/main/java/org/solovyev/common/math/AbstractMathEntity.java @@ -0,0 +1,46 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --------------------------------------------------------------------- + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.common.math; + + +import javax.annotation.Nonnull; + +public abstract class AbstractMathEntity implements MathEntity { + + @Nonnull + private String name; + + private boolean system; + + protected AbstractMathEntity() { + } + + @Nonnull + public String getName() { + return this.name; + } + + public boolean isSystem() { + return system; + } +} diff --git a/jscl/src/main/java/org/solovyev/common/math/AbstractMathRegistry.java b/jscl/src/main/java/org/solovyev/common/math/AbstractMathRegistry.java new file mode 100644 index 00000000..402652a2 --- /dev/null +++ b/jscl/src/main/java/org/solovyev/common/math/AbstractMathRegistry.java @@ -0,0 +1,198 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --------------------------------------------------------------------- + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.common.math; + +import org.solovyev.common.JBuilder; +import org.solovyev.common.JPredicate; +import org.solovyev.common.collections.SortedList; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +import static org.solovyev.common.collections.Collections.find; +import static org.solovyev.common.collections.Collections.removeFirst; + +/** + * User: serso + * Date: 9/29/11 + * Time: 4:57 PM + */ +public abstract class AbstractMathRegistry implements MathRegistry { + + private static final MathEntityComparator MATH_ENTITY_COMPARATOR = new MathEntityComparator(); + @GuardedBy("this") + @Nonnull + private static volatile Integer counter = 0; + @GuardedBy("this") + @Nonnull + protected final SortedList entities = SortedList.newInstance(new ArrayList(30), MATH_ENTITY_COMPARATOR); + @GuardedBy("this") + @Nonnull + protected final SortedList systemEntities = SortedList.newInstance(new ArrayList(30), MATH_ENTITY_COMPARATOR); + + protected AbstractMathRegistry() { + } + + @Nonnull + private static synchronized Integer count() { + final Integer result = counter; + counter++; + return result; + } + + @Nonnull + public List getEntities() { + synchronized (this) { + return java.util.Collections.unmodifiableList(new ArrayList(entities)); + } + } + + @Nonnull + public List getSystemEntities() { + synchronized (this) { + return java.util.Collections.unmodifiableList(new ArrayList(systemEntities)); + } + } + + protected void add(@Nonnull T entity) { + synchronized (this) { + if (entity.isSystem()) { + if (contains(entity.getName(), this.systemEntities)) { + throw new IllegalArgumentException("Trying to add two system entities with same name: " + entity.getName()); + } + + this.systemEntities.add(entity); + } + + if (!contains(entity.getName(), this.entities)) { + addEntity(entity, this.entities); + } + } + } + + private void addEntity(@Nonnull T entity, @Nonnull List list) { + assert Thread.holdsLock(this); + + entity.setId(count()); + list.add(entity); + } + + public T add(@Nonnull JBuilder builder) { + synchronized (this) { + final T entity = builder.create(); + + T varFromRegister; + + if (entity.isIdDefined()) { + varFromRegister = getById(entity.getId()); + } else { + varFromRegister = get(entity.getName()); + } + + if (varFromRegister == null) { + varFromRegister = entity; + + addEntity(entity, this.entities); + if (entity.isSystem()) { + this.systemEntities.add(entity); + } + + } else { + varFromRegister.copy(entity); + this.entities.sort(); + this.systemEntities.sort(); + } + + return varFromRegister; + } + } + + public void remove(@Nonnull T entity) { + synchronized (this) { + if (!entity.isSystem()) { + removeFirst(this.entities, new MathEntity.Finder(entity.getName())); + } + } + } + + @Nonnull + public List getNames() { + final List result = new ArrayList(entities.size()); + + synchronized (this) { + for (T entity : entities) { + result.add(entity.getName()); + } + } + + return result; + } + + @Nullable + public T get(@Nonnull final String name) { + synchronized (this) { + return find(entities, new MathEntity.Finder(name)); + } + } + + public T getById(@Nonnull final Integer id) { + synchronized (this) { + return find(entities, new JPredicate() { + public boolean apply(@Nullable T t) { + return t != null && t.getId().equals(id); + } + }); + } + } + + public boolean contains(@Nonnull final String name) { + synchronized (this) { + return contains(name, this.entities); + } + } + + private boolean contains(final String name, @Nonnull Collection entities) { + synchronized (this) { + return find(entities, new MathEntity.Finder(name)) != null; + } + } + + static class MathEntityComparator implements Comparator { + + MathEntityComparator() { + } + + public int compare(T l, T r) { + int result = r.getName().length() - l.getName().length(); + if (result == 0) { + result = l.getName().compareTo(r.getName()); + } + return result; + } + } +} diff --git a/jscl/src/main/java/org/solovyev/common/math/MathEntity.java b/jscl/src/main/java/org/solovyev/common/math/MathEntity.java new file mode 100644 index 00000000..9625b064 --- /dev/null +++ b/jscl/src/main/java/org/solovyev/common/math/MathEntity.java @@ -0,0 +1,59 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --------------------------------------------------------------------- + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.common.math; + +import org.solovyev.common.JPredicate; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface MathEntity { + + @Nonnull + String getName(); + + boolean isSystem(); + + @Nonnull + Integer getId(); + + void setId(@Nonnull Integer id); + + boolean isIdDefined(); + + void copy(@Nonnull MathEntity that); + + class Finder implements JPredicate { + + @Nonnull + private final String name; + + public Finder(@Nonnull String name) { + this.name = name; + } + + public boolean apply(@Nullable T entity) { + return entity != null && name.equals(entity.getName()); + } + } +} diff --git a/jscl/src/main/java/org/solovyev/common/math/MathRegistry.java b/jscl/src/main/java/org/solovyev/common/math/MathRegistry.java new file mode 100644 index 00000000..d89b1f3d --- /dev/null +++ b/jscl/src/main/java/org/solovyev/common/math/MathRegistry.java @@ -0,0 +1,53 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --------------------------------------------------------------------- + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.common.math; + +import org.solovyev.common.JBuilder; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public interface MathRegistry { + + @Nonnull + List getEntities(); + + @Nonnull + List getSystemEntities(); + + T add(@Nonnull JBuilder JBuilder); + + void remove(@Nonnull T var); + + @Nonnull + List getNames(); + + boolean contains(@Nonnull final String name); + + @Nullable + T get(@Nonnull String name); + + @Nullable + T getById(@Nonnull Integer id); +} diff --git a/jscl/src/main/resources/jscl/text/msg/messages.properties b/jscl/src/main/resources/jscl/text/msg/messages.properties new file mode 100644 index 00000000..6b64fa37 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Parsing error near {0} symbol\: {1} +msg_1=Parsing error occurred near {0} symbol\: check expression validity +msg_2=There is no operator with name\: {0} +msg_3=Operator name is not valid\: {0} +msg_4=Postfix function with name {0} doesn''t exist +msg_5=Constant name must start with a character +msg_6=Function or operator with the same name is already defined\: {0} +msg_7=Digit is expected +msg_8=Invalid number\: {0} +msg_9=The first letter of the number must be a digit +msg_10=Expected characters are {0} or {1} +msg_11=Expected characters are {0} +msg_12=Expected character is {0} +msg_13=Function name is not valid\: {0} +msg_14=Expected number of parameters differs from actual {0} +msg_15=Only decimal numeral base supports decimal numbers +msg_16=Following errors occurred while calculations\: +msg_17=Unable to convert numeral base of {0}. Change default numeral base to decimal and try again. +msg_18=Calculation of a triple factorial is not supported\! +msg_19=Custom function with name {0} could not be calculated due to the following error\: {1} +msg_20=Function {0} cannot be integrated for not radian angle units\! +msg_21=Integration is not supported for {0} +msg_22=Integration is not supported +msg_23=Complex number computation in non-RAD mode can lead to unexpected results\! +msg_24=Integration in non-RAD mode can lead to unexpected results\! +msg_25=Differentiation in non-RAD mode can lead to unexpected results\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_ar.properties b/jscl/src/main/resources/jscl/text/msg/messages_ar.properties new file mode 100644 index 00000000..5a1acafa --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_ar.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u062a\u062d\u0644\u064a\u0644 \u062e\u0637\u0623 \u0628\u0627\u0644\u0642\u0631\u0628 \u0645\u0646 {0} \u0627\u0644\u0631\u0645\u0632\: {1} +msg_1=\u062a\u062d\u0644\u064a\u0644 \u062e\u0637\u0623 \u0648\u0642\u0639 \u0628\u0627\u0644\u0642\u0631\u0628 \u0645\u0646 {0} \u0627\u0644\u0631\u0645\u0632\: \u0627\u0644\u062a\u062d\u0642\u0642 \u0645\u0646 \u0635\u062d\u0629 \u0627\u0644\u0645\u0639\u0627\u062f\u0644\u0629 +msg_2=\u0644\u0627 \u064a\u0648\u062c\u062f \u0623\u064a \u0645\u062e\u062f\u0651\u0645 \u0628\u0627\u0633\u0645\: {0} +msg_3=\u0627\u0633\u0645 \u0627\u0644\u0639\u0645\u0644\u064a\u0647 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d\: {0} +msg_4=\u062f\u0627\u0644\u0651\u0629 \u0628\u0648\u0633\u062a \u0641\u0643\u0633 \u0628\u0627\u0633\u0645 {0} \u063a\u064a\u0631 \u0645\u0648\u062c\u0648\u062f\u0629 +msg_5=\u064a\u062c\u0628 \u0623\u0646 \u064a\u0628\u062f\u0623 \u0627\u0644\u0627\u0633\u0645 \u0627\u0644\u062b\u0627\u0628\u062a \u0628\u062d\u0631\u0641 +msg_6=\u062a\u0645 \u0628\u0627\u0644\u0641\u0639\u0644 \u062a\u0639\u0631\u064a\u0641 \u0627\u0644\u062f\u0627\u0644\u0651\u0629 \u0623\u0648 \u0627\u0644\u0639\u0645\u0644\u064a\u0647 \u0630\u0648\u0627\u062a \u0627\u0644\u0627\u0633\u0645 \u0646\u0641\u0633\u0647 \u0628\u0640\: {0} +msg_7=\u0627\u0644\u0631\u0642\u0645 \u0645\u062a\u0648\u0642\u0639 +msg_8=\u0627\u0644\u0631\u0642\u0645 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d\: {0} +msg_9=\u0627\u0644\u062d\u0631\u0641 \u0627\u0644\u0623\u0648\u0644 \u064a\u062c\u0628 \u0623\u0646 \u064a\u0643\u0648\u0646 \u0631\u0642\u0645\u0627\u064b +msg_10=\u0627\u0644\u062d\u0631\u0641 \u0627\u0644\u0645\u062a\u0648\u0642\u0639\u0629 \u0647\u064a {0} \u0623\u0648 {1} +msg_11=\u0627\u0644\u062d\u0631\u0641 \u0627\u0644\u0645\u062a\u0648\u0642\u0639\u0629 \u0647\u064a {0} +msg_12=\u0627\u0644\u062d\u0631\u0641 \u0627\u0644\u0645\u062a\u0648\u0642\u0639 \u0647\u0648 {0} +msg_13=\u0627\u0633\u0645 \u0627\u0644\u062f\u0627\u0644\u0629 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d\: {0} +msg_14=\u0627\u0644\u0639\u062f\u062f \u0627\u0644\u0645\u062a\u0648\u0642\u0639 \u0641\u064a \u0627\u0644\u0645\u0639\u0627\u062f\u0644\u0629 \u064a\u062e\u062a\u0644\u0641 \u0639\u0646 \u0627\u0644\u062d\u0642\u064a\u0642\u0629 {0} +msg_15=\u0641\u0642\u0637 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0627\u0644\u0639\u0634\u0631\u064a\u0629 \u062a\u062f\u0639\u0645 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0627\u0644\u0639\u0634\u0631\u064a\u0629 +msg_16=\u0627\u0644\u062e\u0637\u0623 \u0627\u0644\u062a\u0627\u0644\u064a \u062d\u062f\u062b \u0623\u062b\u0646\u0627\u0621 \u0627\u0644\u0639\u0645\u0644\u064a\u0627\u062a \u0627\u0644\u062d\u0633\u0627\u0628\u064a\u0629\: +msg_17=\u063a\u064a\u0631 \u0642\u0627\u062f\u0631 \u0639\u0644\u0649 \u062a\u062d\u0648\u064a\u0644 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 {0}. \u0642\u0645 \u0628\u062a\u063a\u064a\u064a\u0631 \u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0625\u0644\u0649 \u0627\u0644\u0642\u0627\u0639\u062f\u0629 \u0627\u0644\u0639\u0634\u0631\u064a\u0629 \u0648\u062d\u0627\u0648\u0644 \u0645\u062c\u062f\u062f\u0627\u064b. +msg_18=\u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0636\u0627\u0639\u0641\u0629 \u0628\u062b\u0644\u0627\u062b\u0629 \u063a\u064a\u0631 \u0645\u062f\u0639\u0651\u0645\! +msg_19=\u0644\u0627 \u064a\u0645\u0643\u0646 \u062d\u0633\u0627\u0628 \u0627\u0644\u062f\u0627\u0644\u0629 \u0627\u0644\u0645\u0633\u0645\u0651\u0627\u0629 {0} \u0628\u0633\u0628\u0628 \u0627\u0644\u062e\u0637\u0623 \u0627\u0644\u062a\u0627\u0644\u064a\: {1} +msg_20=\u0627\u0644\u062f\u0627\u0644\u0651\u0629 {0} \u0644\u0627\u062a\u0633\u0637\u064a\u0639 \u062a\u062a\u0643\u0627\u0645\u0644 \u0644\u0623\u0646 \u0627\u0644\u0632\u0648\u0627\u064a\u0629 \u0644\u064a\u0633\u062a \u0632\u0627\u0648\u064a\u0629 \u0631\u0627\u062f\u064a\u0627\u0646\! +msg_21=\u0644\u0627 \u064a\u062a\u0645 \u062f\u0639\u0645 \u0627\u0644\u062a\u0643\u0627\u0645\u0644 \u0628\u0633\u0628\u0628 {0} +msg_22=\u0644\u0627 \u064a\u062f\u0639\u0645 \u0627\u0644\u062a\u0643\u0627\u0645\u0644 +msg_23=\u062d\u0633\u0627\u0628 \u0627\u0644\u0639\u062f\u062f \u0627\u0644\u0645\u0631\u0643\u0628 \u0641\u064a \u0648\u0636\u0639 \u063a\u064a\u0631 \u0631\u0627\u062f\u064a\u0627\u0646 \u064a\u0645\u0643\u0646 \u0623\u0646 \u064a\u0624\u062f\u064a \u0625\u0644\u0649 \u0646\u062a\u0627\u0626\u062c \u063a\u064a\u0631 \u0645\u062a\u0648\u0642\u0639\u0629\! +msg_24=\u0627\u0644\u062a\u0643\u0627\u0645\u0644 \u0641\u064a \u0648\u0636\u0639 \u063a\u064a\u0631 \u0631\u0627\u062f\u064a\u0627\u0646 \u064a\u0645\u0643\u0646 \u0623\u0646 \u064a\u0624\u062f\u064a \u0625\u0644\u0649 \u0646\u062a\u0627\u0626\u062c \u063a\u064a\u0631 \u0645\u062a\u0648\u0642\u0639\u0629\! +msg_25=\u0627\u0644\u062a\u0645\u0627\u064a\u0632 \u0641\u064a \u0627\u0644\u0648\u0636\u0639 \u063a\u064a\u0631 \u0631\u0627\u062f\u064a\u0627\u0646 \u064a\u0645\u0643\u0646 \u0623\u0646 \u064a\u0624\u062f\u064a \u0625\u0644\u0649 \u0646\u062a\u0627\u0626\u062c \u063a\u064a\u0631 \u0645\u062a\u0648\u0642\u0639\u0629\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_cs.properties b/jscl/src/main/resources/jscl/text/msg/messages_cs.properties new file mode 100644 index 00000000..58675a54 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_cs.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Parsovac\u00ed chyba pobl\u00ed\u017e {0} symbol\: {1} +msg_1=Parsovac\u00ed chyba pobl\u00ed\u017e symbolu {0}\: zkontrolujte platnost v\u00fdrazu +msg_2=Neexistuje \u017e\u00e1dn\u00fd oper\u00e1tor s n\u00e1zvem\: {0} +msg_3=N\u00e1zev oper\u00e1toru nen\u00ed platn\u00fd\: {0} +msg_4=Postfixov\u00e1 funkce s n\u00e1zvem {0} neexistuje +msg_5=Jm\u00e9no konstanty mus\u00ed za\u010d\u00ednat znakem +msg_6=Funkce nebo oper\u00e1tor se stejn\u00fdm n\u00e1zvem je ji\u017e definov\u00e1n\: {0} +msg_7=O\u010dek\u00e1v\u00e1 se \u010d\u00edslice +msg_8=Neplatn\u00e9 \u010d\u00edslo\: {0} +msg_9=Prvn\u00ed p\u00edsmeno \u010d\u00edsla mus\u00ed b\u00fdt \u010d\u00edslice +msg_10=O\u010dek\u00e1van\u00e9 jsou znaky {0} nebo {1} +msg_11=O\u010dek\u00e1van\u00e9 jsou znaky {0} +msg_12=Je o\u010dek\u00e1van\u00fd znak {0} +msg_13=N\u00e1zev funkce nen\u00ed platn\u00fd\: {0} +msg_14=O\u010dek\u00e1van\u00fd po\u010det parametr\u016f se li\u0161\u00ed od zadan\u00fdch {0} +msg_15=Pouze des\u00edtkov\u00e1 soustava podporuje desetinn\u00e1 \u010d\u00edsla +msg_16=P\u0159i v\u00fdpo\u010dtech do\u0161lo k n\u00e1sleduj\u00edc\u00edm chyb\u00e1m\: +msg_17=Nepoda\u0159ilo se p\u0159ev\u00e9st \u010d\u00edselnou soustavu {0}. Zm\u011b\u0148te v\u00fdchoz\u00ed \u010d\u00edselnou soustavu na des\u00edtkov\u016f a zopakujte akci. +msg_18=V\u00fdpo\u010det trojit\u00e9ho faktori\u00e1lu nen\u00ed podporov\u00e1n\! +msg_19=Vlastn\u00ed funkci s n\u00e1zvem {0} nelze vypo\u010d\u00edtat kv\u016fli n\u00e1sleduj\u00edc\u00ed chyb\u011b\: {1} +msg_20=Funkce {0} m\u016f\u017ee b\u00fdt integrov\u00e1na jenom pro \u00fahlov\u00e9 jednotky v radi\u00e1nech\! +msg_21=Integrace nen\u00ed podporov\u00e1na pro {0} +msg_22=Integrace nen\u00ed podporov\u00e1na +msg_23=V\u00fdpo\u010det komplexn\u00edch \u010d\u00edsel v re\u017eimu non-RAD m\u016f\u017ee v\u00e9st k neo\u010dek\u00e1van\u00fdm v\u00fdsledk\u016fm\! +msg_24=Integrace v re\u017eimu non-RAD m\u016f\u017ee v\u00e9st k neo\u010dek\u00e1van\u00fdm v\u00fdsledk\u016fm\! +msg_25=V\u00fdpo\u010det diferenc\u00ed v re\u017eimu non-RAD m\u016f\u017ee v\u00e9st k neo\u010dek\u00e1van\u00fdm v\u00fdsledk\u016fm\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_de.properties b/jscl/src/main/resources/jscl/text/msg/messages_de.properties new file mode 100644 index 00000000..6da1232b --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_de.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u00dcbersetzungsfehler in der N\u00e4he vom ''{0}''-Symbol\: {1} +msg_1=\u00dcbersetzungsfehler ist in der N\u00e4he vom ''{0}''-Symbol passiert\: \u00dcberpr\u00fcfen Sie die G\u00fcltigkeit des Ausdrucks +msg_2=Es gibt keinen Operator mit dem Namen\: {0} +msg_3=Operatorname ist ung\u00fcltig\: {0} +msg_4=Postfixfunktion mit dem Namen {0} existiert nicht +msg_5=Konstantenname muss mit Buchstaben beginnen +msg_6=Funktion oder Operator mit dem gleichen Namen ist bereits definiert\: {0} +msg_7=Ziffer erwartet +msg_8=Ung\u00fcltige Zahl\: {0} +msg_9=Erstes Zeichen der Zahl muss eine Ziffer sein +msg_10=Erwartete Zeichen sind {0} oder {1} +msg_11=Erwartete Zeichen sind {0} +msg_12=Erwartetes Zeichen ist {0} +msg_13=Funktionsname ist nicht g\u00fcltig\: {0} +msg_14=Erwartete Anzahl der Parameter unterscheidet sich von den angegebenen {0} +msg_15=Nur dezimale Zifferbasis unterst\u00fctzt Dezimalzahlen +msg_16=Folgende Fehler sind w\u00e4hrend des Berechnungsvorgangs aufgetreten\: +msg_17=Konvertieren der Basis {0} nicht m\u00f6glich. \u00c4ndern Sie die Standardbasis auf Dezimal und versuchen Sie es noch einmal. +msg_18=Berechnung der dreifachen Fakult\u00e4t wird nicht unterst\u00fctzt\! +msg_19=Benutzerdefinierte Funktion mit dem Namen {0} konnte nicht berechnet werden aufgrund des folgenden Fehlers\: {1} +msg_20=Funktion {0} kann nur f\u00fcr Bogenma\u00df integriert werden\! +msg_21=Integration f\u00fcr {0} nicht unterst\u00fctzt +msg_22=Integration wird nicht unterst\u00fctzt +msg_23=Berechnungen mit komplexen Zahlen, welche nicht im RAD-Modus durchgef\u00fchrt werden, k\u00f6nnen zu unerwarteten Ergebnissen f\u00fchren\! +msg_24=Integrationen, welche nicht im RAD-Modus durchgef\u00fchrt werden, k\u00f6nnen zu unerwarteten Ergebnissen f\u00fchren\! +msg_25=Differenzierungen, welche nicht im RAD-Modus durchgef\u00fchrt werden, k\u00f6nnen zu unerwarteten Ergebnissen f\u00fchren\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_es_ES.properties b/jscl/src/main/resources/jscl/text/msg/messages_es_ES.properties new file mode 100644 index 00000000..fb58c161 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_es_ES.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Error de an\u00e1lisis cerca del s\u00edmbolo {0}\: {1} +msg_1=Ha ocurrido un error de an\u00e1lisis cerca del s\u00edmbolo {0}\: verifique que sea una expresi\u00f3n v\u00e1lida +msg_2=No existe ning\u00fan operador con el nombre {0} +msg_3=El nombre del operador no es v\u00e1lido\: {0} +msg_4=No existe ninguna funci\u00f3n de sufijo con el nombre {0} +msg_5=El primer caracter del nombre de la constante debe ser una letra +msg_6=Ya existe una funci\u00f3n u operador con el mismo nombre\: {0} +msg_7=Se esperaba un d\u00edgito +msg_8=N\u00famero no v\u00e1lido\: {0} +msg_9=El primer car\u00e1cter del n\u00famero debe ser un d\u00edgito +msg_10=Los caracteres esperados son {0} o {1} +msg_11=Los caracteres esperados son {0} +msg_12=El car\u00e1cter esperado es {0} +msg_13=El nombre de la funci\u00f3n no es v\u00e1lido\: {0} +msg_14=El n\u00famero de par\u00e1metros esperado difiere del actual {0} +msg_15=S\u00f3lo la base de n\u00fameros decimal admite n\u00fameros decimales +msg_16=Al realizar los c\u00e1lculos han tenido lugar los siguientes errores\: +msg_17=No se puede convertir la base num\u00e9rica de {0}. Cambia la base num\u00e9rica predeterminada a base decimal, e int\u00e9ntelo de nuevo. +msg_18=\u00a1El c\u00e1lculo factorial triple no est\u00e1 admitido\! +msg_19=La funci\u00f3n personalizada con nombre {0} no pudo calcularse debido al siguiente error\: {1} +msg_20=\u00a1S\u00f3lo se puede integrar la funci\u00f3n {0} si la unidad de \u00e1ngulos es el Radi\u00e1n\! +msg_21=No se admite la integraci\u00f3n para {0} +msg_22=No se admite la integraci\u00f3n +msg_23=\u00a1Las operaciones con n\u00fameros complejos en un modo que no sea el RAD pueden provocar resultados inesperados\! +msg_24=\u00a1El c\u00e1lculo integral con n\u00fameros complejos en un modo que no sea el RAD puede provocar resultados inesperados\! +msg_25=\u00a1El c\u00e1lculo diferencial en un modo que no sea el RAD puede provocar resultados inesperados\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_fi.properties b/jscl/src/main/resources/jscl/text/msg/messages_fi.properties new file mode 100644 index 00000000..5b75f483 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_fi.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=J\u00e4sennysvirhe l\u00e4hell\u00e4 {0} symboli\: {1} +msg_1=J\u00e4sennysvirhe tapahtui l\u00e4hell\u00e4 {0} symbolia\: tarkista lausekkeen kelpoisuus +msg_2=Operaattoria ei ole olemassa\: {0} +msg_3=Ep\u00e4kelpo operaattorin nimi\: {0} +msg_4=J\u00e4lkiliitefunktiota nimell\u00e4 {0} ei ole olemassa +msg_5=Muuttumattoman nimen t\u00e4ytyy alkaa kirjainmerkill\u00e4 +msg_6=Funktio tai operaattori, jolla on sama nimi on jo m\u00e4\u00e4ritetty\: {0} +msg_7=Numeromerkki odotettu +msg_8=Ep\u00e4kelpo numero\: {0} +msg_9=Luvun ensimm\u00e4isen kirjaimen on oltava numero +msg_10=Kelvot kirjaimet ovat {0} ja {1} +msg_11=Kelvot kirjaimet ovat {0} +msg_12=Kelpo kirjain on {0} +msg_13=Ep\u00e4kelpo funktion nimi\: {0} +msg_14=Parametrien odotettu m\u00e4\u00e4r\u00e4 poikkeaa todellisesta {0} +msg_15=Vain desimaalilukuj\u00e4rjestelm\u00e4 tukee desimaalinumeroita +msg_16=Seuraavat virheet tapahtuivat laskuissa\: +msg_17=Ei voi muuntaa numeroiden pohjaan {0}. Muuttaa oletuksena numero pohja desimaaliluvuksi ja yrit\u00e4 uudelleen. +msg_18=Kolminkertaiskerrantojen laskemista ei tueta\! +msg_19=Mukautetun toiminnon nimelt\u00e4 {0} ei voitu laskea seuraavan virheen vuoksi\: {1} +msg_20=Toimintoa {0} ei voi integroida radian kulman yksik\u00f6t\! +msg_21=Integraatio ei tueta kohteelle {0} +msg_22=Integraatio ei tueta +msg_23=Kompleksiluvun laskenta-RAD-tilassa voi johtaa odottamattomiin tuloksiin\! +msg_24=Integraatio-RAD-tilassa voi johtaa odottamattomiin tuloksiin\! +msg_25=Eriytt\u00e4minen-RAD-tilassa voi johtaa odottamattomiin tuloksiin\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_fr.properties b/jscl/src/main/resources/jscl/text/msg/messages_fr.properties new file mode 100644 index 00000000..ff0ae431 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_fr.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Erreur d''analyse pr\u00e8s du symbole {0} \: {1} +msg_1=Erreur d''analyse pr\u00e8s du symbole {0} \: v\u00e9rifiez que l''expression est valide +msg_2=Il n''y a pas d''op\u00e9rateur avec le nom \: {0} +msg_3=Le nom de l''op\u00e9rateur n''est pas valide \: {0} +msg_4=La fonction post-fixe avec le nom {0} n''existe pas +msg_5=Un nom de constante doit commencer par une lettre +msg_6=Une fonction ou un op\u00e9rateur avec le m\u00eame nom est d\u00e9j\u00e0 d\u00e9fini \: {0} +msg_7=Chiffre attendu +msg_8=Nombre non valide \: {0} +msg_9=La premi\u00e8re lettre d''un nombre doit \u00eatre un chiffre (0-9) +msg_10=Caract\u00e8res attendus \: {0} ou {1} +msg_11=Caract\u00e8res attendus \: {0} +msg_12=Caract\u00e8re attendu \: {0} +msg_13=Nom de la fonction non valide \: {0} +msg_14=Le nombre de param\u00e8tres attendus est diff\u00e9rent de celui entr\u00e9 {0} +msg_15=Seuls les nombres en base d\u00e9cimale supportent les d\u00e9cimales +msg_16=Les erreurs suivantes sont apparues pendant le calcul \: +msg_17=Impossible de convertir la base num\u00e9rique de {0}. D\u00e9finissez la base d\u00e9cimale par d\u00e9faut et r\u00e9essayez. +msg_18=Le calcul des triples factorielles n''est pas support\u00e9 \! +msg_19=La fonction personnalis\u00e9e avec le nom {0} n''a pas pu \u00eatre calcul\u00e9e en raison de l''erreur suivante \: {1} +msg_20=La fonction {0} ne peut \u00eatre int\u00e9gr\u00e9e avec une unit\u00e9 autre que des radians \! +msg_21=Int\u00e9gration non prise en charge pour {0} +msg_22=Int\u00e9gration non prise en charge +msg_23=Le calcul de nombres complexes en mode autre que radian peut provoquer des r\u00e9sultats inattendus \! +msg_24=Une int\u00e9grale en mode autre que radian peut provoquer des r\u00e9sultats inattendus \! +msg_25=Une diff\u00e9rentielle en mode autre que radian peut provoquer des r\u00e9sultats inattendus \! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_it.properties b/jscl/src/main/resources/jscl/text/msg/messages_it.properties new file mode 100644 index 00000000..6bb03cca --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_it.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Errore di elaborazione vicino {0} simbolo\: {1} +msg_1=Si \u00e8 verificato un errore di elaborazione vicino {0} \:controllare la validit\u00e0 dell''espressione +msg_2=Non esistono operatori con il nome\: {0} +msg_3=Il nome dell''operatore non \u00e8 valido\: {0} +msg_4=Il suffisso della funzione {0} non esiste +msg_5=I nomi delle costanti devono cominciare con una lettera +msg_6=Una funzione o un operatore con lo stesso nome esistono gi\u00e0\: {0} +msg_7=\u00e9 previsto l''inserimento di una cifra +msg_8=Numero invalido\: {0} +msg_9=La prima lettera di un numero deve essere un numero +msg_10=Caratteri previsti\: {0} o {1} +msg_11=I caratteri previsti sono {0} +msg_12=Il carattere previsto \u00e8 {0} +msg_13=Il nome della funzione non \u00e8 valido\: {0} +msg_14=\u00e9 previsto un numero o un parametro diverso rispetto l''attuale {0} +msg_15=Solo i numeri in base dieci supportano i numeri decimali +msg_16=Sono stati trovati i seguenti errori durante il calcolo\: +msg_17=Non \u00e8 possibile convertire la base numerica di {0}. Cambiare la base numerica di default in decimale e riprovare. +msg_18=Il calcolo di fattoriali tripli non \u00e8 consentito\! +msg_19=La funzione con nome {0} non pu\u00f2 essere calcolata per il seguente errore\: {1} +msg_20=La funzione {0} non pu\u00f2 essere integrata per unit\u00e0 diverse da radianti\! +msg_21=L''integrazione per {0} non \u00e8 supportata +msg_22=Integrazione non supportata +msg_23=Il calcolo complesso in non-RAD mode pu\u00f2 produrre risultati imprevisti\! +msg_24=L''integrazione in non-RAD mode pu\u00f2 produrre risultati imprevisti\! +msg_25=Derivare in non-RAD mode pu\u00f2 produrre risultati imprevisti\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_ja.properties b/jscl/src/main/resources/jscl/text/msg/messages_ja.properties new file mode 100644 index 00000000..2bb29063 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_ja.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u5834\u6240 {0}\u30b7\u30f3\u30dc\u30eb\: {1}\u3067\u306e\u89e3\u6790\u30a8\u30e9\u30fc +msg_1={0} \u8a18\u53f7\u4ed8\u8fd1\u306b\u767a\u751f\u3057\u305f\u89e3\u6790\u30a8\u30e9\u30fc\: \u5f0f\u306e\u59a5\u5f53\u6027\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044 +msg_2=\u4ee5\u4e0b\u306e\u540d\u524d\u306e\u6f14\u7b97\u5b50\u306f\u3042\u308a\u307e\u305b\u3093\: {0} +msg_3=\u6f14\u7b97\u5b50\u540d\u304c\u7121\u52b9\u3067\u3059\: {0} +msg_4={0} \u3068\u3044\u3046\u540d\u524d\u306e\u5f8c\u7f6e\u95a2\u6570\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 +msg_5=\u5b9a\u6570\u540d\u306f\u6587\u5b57\u3067\u958b\u59cb\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +msg_6=\u540c\u3058\u540d\u524d\u306e\u95a2\u6570\u307e\u305f\u306f\u6f14\u7b97\u5b50\u304c\u65e2\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059\: {0} +msg_7=\u6570\u5b57\u304c\u5fc5\u8981\u3067\u3059 +msg_8=\u6570\u304c\u7121\u52b9\u3067\u3059\: {0} +msg_9=\u6700\u521d\u306e\u6570\u306e\u6587\u5b57\u306f\u6570\u5b57\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +msg_10=\u671f\u5f85\u3057\u305f\u6587\u5b57\u306f\u3001{0} \u307e\u305f\u306f {1} \u3067\u3059\u3002 +msg_11=\u671f\u5f85\u3057\u305f\u6587\u5b57\u306f {0}\u3067\u3059 +msg_12=\u671f\u5f85\u3057\u305f\u6587\u5b57\u306f {0}\u3067\u3059 +msg_13=\u95a2\u6570\u540d\u304c\u7121\u52b9\u3067\u3059\: {0} +msg_14=\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u304b\u3089\u4e88\u6e2c\u3055\u308c\u305f\u6570\u5b57\u304c\u5b9f\u969b\u306e{0}\u3068\u7570\u306a\u308a\u307e\u3059 +msg_15=10\u9032\u6cd5\u3067\u306e\u307f10\u9032\u6570\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u3059 +msg_16=\u8a08\u7b97\u4e2d\u306b\u6b21\u306e\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\: +msg_17={0}\u306e\u9032\u6cd5\u3092\u5909\u63db\u3067\u304d\u307e\u305b\u3093\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u9032\u6cd5\u309210\u9032\u6cd5\u306b\u3057\u3066\u3082\u3046\u4e00\u5ea6\u8a66\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +msg_18=3\u4e57\u306e\u8a08\u7b97\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\! +msg_19=\u30ab\u30b9\u30bf\u30e0\u95a2\u6570{0}\u306f\u4ee5\u4e0b\u306e\u30a8\u30e9\u30fc\u304c\u539f\u56e0\u3067\u8a08\u7b97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\: {1} +msg_20=\u95a2\u6570{0}\u306f\u89d2\u5ea6\u306e\u5358\u4f4d\u304c\u30e9\u30b8\u30a2\u30f3\u3067\u306a\u3044\u305f\u3081\u7a4d\u5206\u3067\u304d\u307e\u305b\u3093\! +msg_21={0}\u3067\u306f\u7a4d\u5206\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +msg_22=\u7a4d\u5206\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +msg_23=\u30e9\u30b8\u30a2\u30f3\u30e2\u30fc\u30c9\u4ee5\u5916\u3067\u306e\u8907\u7d20\u6570\u8a08\u7b97\u306f\u4e88\u671f\u3057\u306a\u3044\u7d50\u679c\u3068\u306a\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\! +msg_24=\u30e9\u30b8\u30a2\u30f3\u30e2\u30fc\u30c9\u4ee5\u5916\u3067\u306e\u7a4d\u5206\u8a08\u7b97\u306f\u4e88\u671f\u3057\u306a\u3044\u7d50\u679c\u3068\u306a\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\! +msg_25=\u30e9\u30b8\u30a2\u30f3\u30e2\u30fc\u30c9\u4ee5\u5916\u3067\u306e\u5fae\u5206\u306f\u4e88\u671f\u3057\u306a\u3044\u7d50\u679c\u3068\u306a\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_nl.properties b/jscl/src/main/resources/jscl/text/msg/messages_nl.properties new file mode 100644 index 00000000..0bcd4d86 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_nl.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Parseerfout in de buurt van {0} symbool\: {1} +msg_1=Parseerfout opgetreden in de buurt van {0} symbool\: controleer expressie geldigheid +msg_2=Er is geen operator met naam\: {0} +msg_3=Operatornaam is niet geldig\: {0} +msg_4=Postfix functie met de naam {0} bestaat niet +msg_5=Naamconstante moet beginnen met een karakter +msg_6=Functie of operator met dezelfde naam is al gedefinieerd\: {0} +msg_7=Cijfer wordt verwacht +msg_8=Ongeldig getal\: {0} +msg_9=De eerste letter van het getal moet een cijfer zijn +msg_10=Verwachte tekens zijn {0} of {1} +msg_11=Verwachte tekens zijn {0} +msg_12=Verwacht teken is {0} +msg_13=Functienaam is niet geldig\: {0} +msg_14=Verwachte aantal parameters verschilt van werkelijke {0} +msg_15=Enkel een decimale cijfer basis ondersteunt decimale getallen +msg_16=Volgende fouten zijn opgetreden tijdens de berekeningen\: +msg_17=Onmogelijk om het volgende numeriek stelsel te converteren\:{0}.\nVerander het standaard numeriek stelsel naar decimaal en probeer opnieux. +msg_18=Berekening van een drievoudige faculteit wordt niet ondersteund\! +msg_19=Zelfgemaakte functie met de naam {0} kon niet worden berekend door de volgende fout\: {1} +msg_20=Functie {0} kan niet worden ge\u00efntegreerd voor niet radiale hoekeenheden\! +msg_21=Integratie wordt niet ondersteund voor {0} +msg_22=Integratie wordt niet ondersteund +msg_23=Berekeningen met complexe getallen in niet-RAD modus kunnen leiden tot onverwachte resultaten\! +msg_24=Integreren in de niet-RAD modus kan leiden tot onverwachte resultaten\! +msg_25=Differentiatie in de niet-RAD modus kan leiden tot onverwachte resultaten\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_pl.properties b/jscl/src/main/resources/jscl/text/msg/messages_pl.properties new file mode 100644 index 00000000..c63afbb3 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_pl.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=B\u0142\u0105d przetwarzania przy {0} symbolu\: {1} +msg_1=Wyst\u0105pi\u0142 b\u0142\u0105d przetwarzania przy {0}. symbolu\: sprawd\u017a poprawno\u015b\u0107 wyra\u017cenia +msg_2=Brak operatora o nazwie\: {0} +msg_3=Nazwa operatora jest nieprawid\u0142owa\: {0} +msg_4=Funkcja o nazwie {0} nie istnieje +msg_5=Nazwa sta\u0142ej musi si\u0119 zaczyna\u0107 od litery +msg_6=Funkcja lub operator o tej samej nazwie jest ju\u017c zdefiniowany\: {0} +msg_7=Oczekiwana jest cyfra +msg_8=Nieprawid\u0142owy numer\: {0} +msg_9=Pierwszy znak numeru musi by\u0107 cyfr\u0105 +msg_10=Oczekiwane znaki to {0} lub {1} +msg_11=Oczekiwane znaki to {0} +msg_12=Oczekiwany znak to {0} +msg_13=Nazwa funkcji jest nieprawid\u0142owa\: {0} +msg_14=Oczekiwana liczba parametr\u00f3w r\u00f3\u017cni si\u0119 od bie\u017c\u0105cej {0} +msg_15=Tylko dziesi\u0119tny system liczbowy obs\u0142uguje liczby dziesi\u0119tne +msg_16=Wyst\u0105pi\u0142y b\u0142\u0119dy podczas oblicze\u0144\: +msg_17=Nie mo\u017cna przekonwertowa\u0107 systemu liczbowego o podstawie {0}. Zmie\u0144 podstawowy system liczbowy na dziesi\u0119tny i spr\u00f3buj ponownie. +msg_18=Silnia potr\u00f3jna nie jest obs\u0142ugiwana\! +msg_19=W\u0142asna funkcja o nazwie {0} nie mo\u017ce zosta\u0107 obliczona z powodu b\u0142\u0119du\: {1} +msg_20=Funkcja {0} nie mo\u017ce zosta\u0107 sca\u0142kowana dla jednostek wielko\u015bci k\u0105t\u00f3w innych ni\u017c radiany\! +msg_21=Ca\u0142kowanie nie jest obs\u0142ugiwane dla {0} +msg_22=Ca\u0142kowanie nie jest obs\u0142ugiwane +msg_23=Operacje na liczbach zespolonych w trybie innym ni\u017c RAD mog\u0105 prowadzi\u0107 do nieoczekiwanych rezultat\u00f3w\! +msg_24=Ca\u0142kowanie w trybie innym ni\u017c RAD mo\u017ce prowadzi\u0107 do nieoczekiwanych rezultat\u00f3w\! +msg_25=R\u00f3\u017cniczkowanie w trybie innym ni\u017c RAD mo\u017ce prowadzi\u0107 do nieoczekiwanych rezultat\u00f3w\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_pt_BR.properties b/jscl/src/main/resources/jscl/text/msg/messages_pt_BR.properties new file mode 100644 index 00000000..b36a9578 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_pt_BR.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Erro de an\u00e1lise pr\u00f3ximo do s\u00edmbolo {0}\: {1} +msg_1=Ocorreu um erro de an\u00e1lise pr\u00f3ximo do s\u00edmbolo {0}\: verifique a validade da express\u00e3o +msg_2=N\u00e3o h\u00e1 nenhum operador com o nome\: {0} +msg_3=O nome do operador n\u00e3o \u00e9 v\u00e1lido\: {0} +msg_4=N\u00e3o existe fun\u00e7\u00e3o postfix com nome {0} +msg_5=O nome de uma constante deve come\u00e7ar com um caractere +msg_6=Fun\u00e7\u00e3o ou operador com o mesmo nome j\u00e1 definido\: {0} +msg_7=Um d\u00edgito \u00e9 esperado +msg_8=N\u00famero inv\u00e1lido\: {0} +msg_9=A primeira letra do n\u00famero deve ser um d\u00edgito +msg_10=Os caracteres esperados s\u00e3o {0} {1} +msg_11=Os caracteres esperados s\u00e3o {0} +msg_12=O caractere esperado \u00e9 {0} +msg_13=O nome da fun\u00e7\u00e3o n\u00e3o \u00e9 v\u00e1lido\: {0} +msg_14=O n\u00famero esperado de par\u00e2metros difere do atual {0} +msg_15=S\u00f3 a base decimal suporta n\u00fameros decimais +msg_16=Ocorreram os seguintes erros durante os c\u00e1lculos\: +msg_17=N\u00e3o \u00e9 poss\u00edvel converter um numeral de base {0}. Altere a base de numera\u00e7\u00e3o padr\u00e3o para a base decimal e tente novamente. +msg_18=O c\u00e1lculo de um fatorial triplo n\u00e3o \u00e9 suportado\! +msg_19=A fun\u00e7\u00e3o personalizada com o nome {0} n\u00e3o pode ser calculada devido ao seguinte erro\: {1} +msg_20=A fun\u00e7\u00e3o {0} n\u00e3o pode ser integrada para a unidade de \u00e2ngulo radiano\! +msg_21=A integra\u00e7\u00e3o n\u00e3o \u00e9 suportada para {0} +msg_22=A integra\u00e7\u00e3o n\u00e3o \u00e9 suportada +msg_23=O c\u00e1lculo de n\u00fameros complexos no modo n\u00e3o-RAD pode levar a resultados inesperados\! +msg_24=Integra\u00e7\u00e3o no modo n\u00e3o-RAD pode levar a resultados inesperados\! +msg_25=Diferencia\u00e7\u00e3o no modo n\u00e3o-RAD pode levar a resultados inesperados\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_pt_PT.properties b/jscl/src/main/resources/jscl/text/msg/messages_pt_PT.properties new file mode 100644 index 00000000..99cb39ac --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_pt_PT.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Erro de an\u00e1lise perto de {0} s\u00edmbolo\:{1} +msg_1=Erro de an\u00e1lise perto de {0} s\u00edmbolo\: verificar validade da express\u00e3o +msg_2=N\u00e3o existe nenhum operador com o nome\: {0} +msg_3=Nome do operador n\u00e3o \u00e9 v\u00e1lido\: {0} +msg_4=A fun\u00e7\u00e3o posfixa com o nome {0} n\u00e3o existe +msg_5=Nome da constante deve come\u00e7ar com um car\u00e1cter +msg_6=Fun\u00e7\u00e3o ou operador com o mesmo nome j\u00e1 definida\: {0} +msg_7=Esperado um d\u00edgito +msg_8=N\u00famero inv\u00e1lido\: {0} +msg_9=A primeira letra do n\u00famero deve ser um d\u00edgito +msg_10=Caracteres esperados s\u00e3o {0} ou {1} +msg_11=Caracteres esperados s\u00e3o {0} +msg_12=Caractere esperado \u00e9 {0} +msg_13=O nome da fun\u00e7\u00e3o n\u00e3o \u00e9 v\u00e1lido\: {0} +msg_14=O n\u00famero de par\u00e2metros esperados difere do actual {0} +msg_15=Apenas a base num\u00e9rica decimal suporta n\u00fameros decimais +msg_16=O seguintes erros ocorreram durante os c\u00e1lculos\: +msg_17=Incapaz de converter a base num\u00e9rica de base {0}. Altere a base num\u00e9rica para decimal e tende de novo. +msg_18=C\u00e1lculo de um factorial triplo n\u00e3o \u00e9 suportado\! +msg_19=A fun\u00e7\u00e3o personalizada de nome {0} n\u00e3o pode ser calculada devido ao seguinte erro\:{1} +msg_20=A fun\u00e7\u00e3o {0} n\u00e3o pode ser integrada para unidades de \u00e2ngulo n\u00e3o radianas\! +msg_21=Integra\u00e7\u00e3o n\u00e3o \u00e9 suportada para {0} +msg_22=Integra\u00e7\u00e3o n\u00e3o \u00e9 suportada +msg_23=Computa\u00e7\u00e3o num\u00e9rica complexa em modo n\u00e3o-RAD pode levar a resultados imprevis\u00edveis\! +msg_24=Integra\u00e7\u00e3o em modo n\u00e3o-RAD pode levar a resultados inesperados\! +msg_25=Diferencia\u00e7\u00e3o em modo n\u00e3o-RAD pode levar a resultados inesperados\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_ru.properties b/jscl/src/main/resources/jscl/text/msg/messages_ru.properties new file mode 100644 index 00000000..e30a6e8f --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_ru.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u043e\u043a\u043e\u043b\u043e {0} \u0441\u0438\u043c\u0432\u043e\u043b\u0430\: {1} +msg_1=\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u043e\u043a\u043e\u043b\u043e {0} \u0441\u0438\u043c\u0432\u043e\u043b\u0430\: \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f +msg_2=\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c {0} \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 +msg_3=\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\: {0} +msg_4=\u041f\u043e\u0441\u0442\u0444\u0438\u043a\u0441\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 {0} \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 +msg_5=\u0418\u043c\u044f \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 \u0431\u0443\u043a\u0432\u044b +msg_6=\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0441 \u0442\u0430\u043a\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\: {0} +msg_7=\u041e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0446\u0438\u0444\u0440\u0430 +msg_8=\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e\: {0} +msg_9=\u041f\u0435\u0440\u0432\u044b\u0439 \u0441\u0438\u043c\u0432\u043e\u043b \u0447\u0438\u0441\u043b\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0446\u0438\u0444\u0440\u043e\u0439 +msg_10=\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b {0} \u0438\u043b\u0438 {1} +msg_11=\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b {0} +msg_12=\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0441\u0438\u043c\u0432\u043e\u043b {0} +msg_13=\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438\: {0} +msg_14=\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e {0} +msg_15=\u0422\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435 \u0446\u0435\u043b\u044b\u0435 \u0447\u0438\u0441\u043b\u0430 +msg_16=\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043f\u0440\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f\u0445\: +msg_17=\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u044f {0}. \u041f\u043e\u043c\u0435\u043d\u044f\u0439\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0430 \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u0443\u044e \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f. +msg_18=\u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u043e\u0439\u043d\u043e\u0433\u043e \u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f\! +msg_19=\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u0438\u043c\u0435\u043d\u0435\u043c {0} \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0430 \u0438\u0437-\u0437\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043e\u0448\u0438\u0431\u043a\u0438\: {1} +msg_20=\u0424\u0443\u043d\u043a\u0446\u0438\u044f {0} \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0434\u043b\u044f \u0443\u0433\u043b\u043e\u0432\u044b\u0445 \u0435\u0434\u0438\u043d\u0438\u0446 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0445 \u043e\u0442 \u0440\u0430\u0434\u0438\u0430\u043d\! +msg_21=\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043b\u044f {0} +msg_22=\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f +msg_23=\u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u044b\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u043c \u043e\u0442 RAD \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\! +msg_24=\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u043c \u043e\u0442 RAD \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\! +msg_25=\u0414\u0438\u0444\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u043c \u043e\u0442 RAD \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_uk.properties b/jscl/src/main/resources/jscl/text/msg/messages_uk.properties new file mode 100644 index 00000000..3433991f --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_uk.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u041f\u043e\u0431\u043b\u0438\u0437\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u0443 {0} \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u043d\u0430 \u043f\u043e\u043c\u0438\u043b\u043a\u0430\: {1} +msg_1=\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u043d\u0430 \u043f\u043e\u043c\u0438\u043b\u043a\u0430 \u043f\u043e\u0431\u043b\u0438\u0437\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u0443 {0}\: \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435 \u0442\u0435\u043a\u0441\u0442 \u0432\u0438\u0440\u0430\u0437\u0443 +msg_2=\u0412\u043a\u0430\u0437\u0430\u043d\u0438\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u043d\u0435 \u0456\u0441\u043d\u0443\u0454\: {0} +msg_3=\u0406\u043c''\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0443 \u0454 \u043d\u0435\u043f\u0440\u0438\u043f\u0443\u0441\u0442\u0438\u043c\u0438\u043c\: {0} +msg_4=\u041f\u043e\u0441\u0442\u0444\u0456\u043a\u0441\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0456\u044f \u043d\u0435 \u0456\u0441\u043d\u0443\u0454\: {0} +msg_5=\u0406\u043c''\u044f \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0438 \u043c\u0430\u0454 \u043f\u043e\u0447\u0438\u043d\u0430\u0442\u0438\u0441\u044f \u0437 \u043b\u0456\u0442\u0435\u0440\u0438 +msg_6=\u0424\u0443\u043d\u043a\u0446\u0456\u044f \u0430\u0431\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0437 \u0442\u0430\u043a\u0438\u043c \u0456\u043c\u0435\u043d\u0435\u043c \u0443\u0436\u0435 \u0456\u0441\u043d\u0443\u0454\: {0} +msg_7=\u041e\u0447\u0456\u043a\u0443\u0454\u0442\u044c\u0441\u044f \u0446\u0438\u0444\u0440\u0430 +msg_8=\u041d\u0435\u043f\u0440\u0438\u043f\u0443\u0441\u0442\u0438\u043c\u0435 \u0447\u0438\u0441\u043b\u043e\: {0} +msg_9=\u041f\u0435\u0440\u0448\u0430 \u043b\u0456\u0442\u0435\u0440\u0430 \u0447\u0438\u0441\u043b\u0430 \u043c\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0438\u0444\u0440\u043e\u044e +msg_10=\u041e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0456 \u0441\u0438\u043c\u0432\u043e\u043b\u0438\: {0} \u0430\u0431\u043e {1} +msg_11=\u041e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0456 \u0441\u0438\u043c\u0432\u043e\u043b\u0438\: {0} +msg_12=\u041e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0438\u0439 \u0441\u0438\u043c\u0432\u043e\u043b\: {0} +msg_13=\u041d\u0435\u043f\u0440\u0438\u043f\u0443\u0441\u0442\u0438\u043c\u0435 \u0456\u043c''\u044f \u0444\u0443\u043d\u043a\u0446\u0456\u0457\: {0} +msg_14=\u041e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0430 \u043a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0456\u0432 \u0432\u0456\u0434\u0440\u0456\u0437\u043d\u044f\u0454\u0442\u044c\u0441\u044f \u0432\u0456\u0434 \u0444\u0430\u043a\u0442\u0438\u0447\u043d\u043e\u0433\u043e\: {0} +msg_15=\u041b\u0438\u0448\u0435 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454 \u0440\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u0456 \u0447\u0438\u0441\u043b\u0430 +msg_16=\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0456 \u043f\u043e\u043c\u0438\u043b\u043a\u0438 \u0432\u0438\u043d\u0438\u043a\u043b\u0438 \u043f\u0456\u0434 \u0447\u0430\u0441 \u043e\u0431\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f\: +msg_17=\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u043f\u0435\u0440\u0435\u0442\u0432\u043e\u0440\u0438\u0442\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u0434\u043b\u044f {0}. \u0417\u043c\u0456\u043d\u0456\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u0437\u0430 \u0437\u0430\u043c\u043e\u0432\u0447\u0443\u0432\u0430\u043d\u043d\u044f\u043c \u043d\u0430 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432\u0443 \u0442\u0430 \u0441\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0449\u0435 \u0440\u0430\u0437. +msg_18=\u0420\u043e\u0437\u0440\u0430\u0445\u0443\u043d\u043e\u043a \u043f\u043e\u0442\u0440\u0456\u0439\u043d\u043e\u0433\u043e \u0444\u0430\u043a\u0442\u043e\u0440\u0456\u0430\u043b\u0443 \u043d\u0435 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454\u0442\u044c\u0441\u044f\! +msg_19=\u0424\u0443\u043d\u043a\u0446\u0456\u0457 \u0437 \u0456\u043c\u0435\u043d\u0435\u043c {0} \u043d\u0435 \u043c\u043e\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0438\u0440\u0430\u0445\u0443\u0432\u0430\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 \u043f\u043e\u043c\u0438\u043b\u043a\u0443\: {1} +msg_20=\u0424\u0443\u043d\u043a\u0446\u0456\u0457 {0} \u043d\u0435 \u043c\u043e\u0436\u0435 \u0431\u0443\u0442\u0438 \u0456\u043d\u0442\u0435\u0433\u0440\u043e\u0432\u0430\u043d\u0430 \u0434\u043b\u044f \u043e\u0434\u0438\u043d\u0438\u0446\u044c \u0432\u0438\u043c\u0456\u0440\u0443 \u043a\u0443\u0442\u0456\u0432 \u0432\u0456\u0434\u043c\u0456\u043d\u043d\u0438\u0445 \u0432\u0456\u0434 \u0440\u0430\u0434\u0456\u0430\u043d\! +msg_21=\u041e\u0431\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u0456\u043d\u0442\u0435\u0433\u0440\u0430\u043b\u0443 \u043d\u0435 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454\u0442\u044c\u0441\u044f \u0434\u043b\u044f {0} +msg_22=\u041e\u0431\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u0456\u043d\u0442\u0435\u0433\u0440\u0430\u043b\u0443 \u043d\u0435 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454\u0442\u044c\u0441\u044f +msg_23=\u041e\u0431\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0443 \u0440\u0435\u0436\u0438\u043c\u0456 \u0432\u0456\u0434\u043c\u0456\u043d\u043d\u043e\u043c\u0443 \u0432\u0456\u0434 RAD \u043c\u043e\u0436\u0435 \u043f\u0440\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e \u043d\u0435\u043e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456\u0432\! +msg_24=\u041e\u0431\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044f \u0456\u043d\u0442\u0435\u0433\u0440\u0430\u043b\u0456\u0432 \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0432\u0456\u0434\u043c\u0456\u043d\u043d\u043e\u043c\u0443 \u0432\u0456\u0434 RAD \u043c\u043e\u0436\u0435 \u043f\u0440\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e \u043d\u0435\u043e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456\u0432\! +msg_25=\u0414\u0438\u0444\u0435\u0440\u0435\u043d\u0446\u0456\u044e\u0432\u0430\u043d\u043d\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0432\u0456\u0434\u043c\u0456\u043d\u043d\u043e\u043c\u0443 \u0432\u0456\u0434 RAD \u043c\u043e\u0436\u0435 \u043f\u0440\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e \u043d\u0435\u043e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0456\u0432\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_vi.properties b/jscl/src/main/resources/jscl/text/msg/messages_vi.properties new file mode 100644 index 00000000..b1e232d8 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_vi.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=Ph\u00e2n t\u00edch c\u00fa ph\u00e1p l\u1ed7i g\u1ea7n {0} bi\u1ec3u t\u01b0\u1ee3ng\: {1} +msg_1=Ph\u00e2n t\u00edch c\u00fa ph\u00e1p l\u1ed7i x\u1ea3y ra g\u1ea7n {0} bi\u1ec3u t\u01b0\u1ee3ng\: ki\u1ec3m tra t\u00ednh h\u1ee3p l\u1ec7 bi\u1ec3u th\u1ee9c +msg_2=Kh\u00f4ng c\u00f3 to\u00e1n t\u1eed v\u1edbi t\u00ean\: {0} +msg_3=T\u00ean to\u00e1n t\u1eed kh\u00f4ng h\u1ee3p l\u1ec7\: {0} +msg_4=Postfix h\u00e0m v\u1edbi t\u00ean {0} kh\u00f4ng t\u1ed3n t\u1ea1i +msg_5=T\u00ean h\u1eb1ng s\u1ed1 ph\u1ea3i b\u1eaft \u0111\u1ea7u b\u1eb1ng k\u00fd t\u1ef1 +msg_6=H\u00e0m ho\u1eb7c to\u00e1n t\u1eed c\u00f3 c\u00f9ng t\u00ean \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u1ecbnh ngh\u0129a\: {0} +msg_7=Ch\u1eef s\u1ed1 \u0111\u01b0\u1ee3c y\u00eau c\u1ea7u +msg_8=S\u1ed1 kh\u00f4ng h\u1ee3p l\u1ec7\: {0} +msg_9=Ch\u1eef c\u00e1i \u0111\u1ea7u ti\u00ean c\u1ee7a s\u1ed1 ph\u1ea3i l\u00e0 m\u1ed9t ch\u1eef s\u1ed1 +msg_10=Y\u00eau c\u1ea7u c\u00e1c k\u00fd t\u1ef1 l\u00e0 {0} ho\u1eb7c {1} +msg_11=Y\u00eau c\u1ea7u c\u00e1c k\u00fd t\u1ef1 l\u00e0 {0} +msg_12=Y\u00eau c\u1ea7u k\u00fd t\u1ef1 l\u00e0 {0} +msg_13=T\u00ean h\u00e0m kh\u00f4ng h\u1ee3p l\u1ec7\: {0} +msg_14=S\u1ed1 l\u01b0\u1ee3ng tham s\u1ed1 y\u00eau c\u1ea7u kh\u00e1c v\u1edbi th\u1ef1c t\u1ebf {0} +msg_15=Ch\u1ec9 c\u00f3 c\u01a1 s\u1ed1 th\u1eadp ph\u00e2n m\u1edbi h\u1ed7 tr\u1ee3 s\u1ed1 th\u1eadp ph\u00e2n +msg_16=C\u00e1c l\u1ed7i sau \u0111\u00e3 x\u1ea3y ra trong khi t\u00ednh to\u00e1n\: +msg_17=Kh\u00f4ng th\u1ec3 chuy\u1ec3n \u0111\u1ed5i c\u00e1c c\u01a1 s\u1ed1 c\u1ee7a {0}. Thay \u0111\u1ed5i c\u01a1 s\u1ed1 m\u1eb7c \u0111\u1ecbnh c\u01a1 b\u1ea3n qua h\u1ec7 c\u01a1 s\u1ed1 th\u1eadp ph\u00e2n v\u00e0 th\u1eed l\u1ea1i. +msg_18=T\u00ednh to\u00e1n c\u1ee7a m\u1ed9t giai th\u1eeba ba kh\u00f4ng \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3\! +msg_19=H\u00e0m t\u00f9y ch\u1ec9nh v\u1edbi t\u00ean {0} kh\u00f4ng \u0111\u01b0\u1ee3c t\u00ednh to\u00e1n do l\u1ed7i sau\: {1} +msg_20=H\u00e0m {0} kh\u00f4ng th\u1ec3 \u0111\u01b0\u1ee3c t\u00edch h\u1ee3p cho \u0111\u01a1n v\u1ecb g\u00f3c kh\u00f4ng ph\u1ea3i l\u00e0 radian\! +msg_21=T\u00edch ph\u00e2n kh\u00f4ng \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 cho {0} +msg_22=T\u00edch ph\u00e2n kh\u00f4ng \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 +msg_23=T\u00ednh to\u00e1n s\u1ed1 ph\u1ee9c trong ch\u1ebf \u0111\u1ed9 kh\u00f4ng RAD c\u00f3 th\u1ec3 d\u1eabn \u0111\u1ebfn k\u1ebft qu\u1ea3 kh\u00f4ng \u0111\u00fang\! +msg_24=T\u00edch ph\u00e2n trong ch\u1ebf \u0111\u1ed9 kh\u00e1c RAD c\u00f3 th\u1ec3 d\u1eabn \u0111\u1ebfn k\u1ebft qu\u1ea3 sai\! +msg_25=Vi ph\u00e2n trong ch\u1ebf \u0111\u1ed9 kh\u00e1c RAD c\u00f3 th\u1ec3 d\u1eabn \u0111\u1ebfn k\u1ebft qu\u1ea3 kh\u00f4ng \u0111\u00fang\! + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_zh_CN.properties b/jscl/src/main/resources/jscl/text/msg/messages_zh_CN.properties new file mode 100644 index 00000000..9c4e1937 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_zh_CN.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0=\u5728 {0} \u7b26\u53f7\u9644\u8fd1\u53d1\u751f\u89e3\u6790\u9519\u8bef\uff1a{1} +msg_1=\u5728 {0} \u7b26\u53f7\u9644\u8fd1\u51fa\u73b0\u89e3\u6790\u9519\u8bef\uff1a\u8bf7\u68c0\u67e5\u8868\u8fbe\u5f0f\u662f\u5426\u6709\u6548 +msg_2=\u6ca1\u6709\u8fd0\u7b97\u7b26\u540d\u79f0\uff1a{0} +msg_3=\u8fd0\u7b97\u7b26\u540d\u79f0\u65e0\u6548\uff1a{0} +msg_4=\u540e\u7f00\u51fd\u6570\u540d\u79f0 {0} \u4e0d\u5b58\u5728 +msg_5=\u5e38\u91cf\u540d\u79f0\u5fc5\u987b\u4ee5\u5b57\u7b26\u5f00\u59cb +msg_6=\u5df2\u5b9a\u4e49\u76f8\u540c\u540d\u79f0\u7684\u51fd\u6570\u6216\u8fd0\u7b97\u7b26\uff1a{0} +msg_7=\u4f4d\u6570\u4f30\u8ba1\u4e3a +msg_8=\u6570\u5b57\u65e0\u6548\uff1a{0} +msg_9=\u6570\u5b57\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u5fc5\u987b\u662f\u4e00\u4f4d\u6570\u5b57 +msg_10=\u952e\u5165\u7684\u53c2\u6570\u9700\u4e3a {0} \u6216 {1} +msg_11=\u952e\u5165\u7684\u53c2\u6570\u9700\u4e3a {0} +msg_12=\u952e\u5165\u7684\u53c2\u6570\u9700\u4e3a {0} +msg_13=\u51fd\u6570\u540d\u79f0\u65e0\u6548\uff1a{0} +msg_14=\u952e\u5165\u7684\u53c2\u53d8\u91cf\u5e94\u4e0d\u540c\u4e8e\u5b9e\u9645\u7684 {0} +msg_15=\u53ea\u6709\u5341\u8fdb\u5236\u624d\u80fd\u652f\u6301\u5341\u8fdb\u5236\u6570\u5b57 +msg_16=\u8ba1\u7b97\u65f6\u51fa\u73b0\u4ee5\u4e0b\u9519\u8bef\uff1a +msg_17=\u65e0\u6cd5\u8f6c\u6362\u6570\u5b57 {0} \u7684\u8fdb\u5236\u3002\u8bf7\u5c06\u9ed8\u8ba4\u8fdb\u5236\u6539\u4e3a\u5341\u8fdb\u5236\u540e\u518d\u8bd5\u8bd5\u3002 +msg_18=\u4e0d\u652f\u6301\u7684\u4e09\u6b21\u9636\u4e58\u8ba1\u7b97\uff01 +msg_19=\u7531\u4e8e\u4ee5\u4e0b\u9519\u8bef\u81ea\u5b9a\u4e49\u540d\u79f0\u51fd\u6570 {0} \u65e0\u6cd5\u8ba1\u7b97\uff1a {1} +msg_20=\u51fd\u6570 {0} \u4e0d\u80fd\u7528\u975e\u5f27\u5ea6\u5355\u4f4d\u8fdb\u884c\u79ef\u5206\u8fd0\u7b97 +msg_21=\u4e0d\u652f\u6301 {0} \u7684\u79ef\u5206 +msg_22=\u4e0d\u652f\u6301\u79ef\u5206 +msg_23=\u5728\u975eRAD\u6a21\u5f0f\u4e0b\u8fdb\u884c\u590d\u6570\u8ba1\u7b97\u53ef\u80fd\u4f1a\u5f97\u4e0d\u5230\u7406\u60f3\u7ed3\u679c\uff01 +msg_24=\u975eRAD\u6a21\u5f0f\u4e0b\u7684\u79ef\u5206\u8ba1\u7b97\u53ef\u80fd\u4e0d\u4f1a\u5f97\u5230\u7406\u60f3\u7ed3\u679c\uff01 +msg_25=\u975eRAD\u6a21\u5f0f\u4e0b\u7684\u5fae\u5206\u8ba1\u7b97\u53ef\u80fd\u4e0d\u4f1a\u5f97\u5230\u7406\u60f3\u7ed3\u679c\uff01 + + diff --git a/jscl/src/main/resources/jscl/text/msg/messages_zh_TW.properties b/jscl/src/main/resources/jscl/text/msg/messages_zh_TW.properties new file mode 100644 index 00000000..0af22f25 --- /dev/null +++ b/jscl/src/main/resources/jscl/text/msg/messages_zh_TW.properties @@ -0,0 +1,30 @@ +#X-Generator: crowdin.com +#X-Generator: crowdin.net +msg_0={0} \u7b26\u865f\u9644\u8fd1\u8a9e\u6cd5\u932f\u8aa4\uff1a{1} +msg_1={0} \u7b26\u865f\u9644\u8fd1\u767c\u751f\u8a9e\u6cd5\u932f\u8aa4\uff1a\u6aa2\u67e5\u7b97\u5f0f\u662f\u5426\u6709\u6548 +msg_2=\u6c92\u6709\u904b\u7b97\u5b50\u540d\u7a31\uff1a{0} +msg_3=\u904b\u7b97\u5b50\u540d\u7a31\u7121\u6548\uff1a{0} +msg_4=\u5f8c\u7db4\u51fd\u6578\u540d\u7a31 {0} \u4e0d\u5b58\u5728 +msg_5=\u5e38\u6578\u540d\u7a31\u5fc5\u9808\u4ee5\u5b57\u5143\u958b\u982d +msg_6=\u76f8\u540c\u540d\u7a31\u7684\u51fd\u6578\u6216\u904b\u7b97\u5b50\u5df2\u7d93\u88ab\u5b9a\u7fa9\uff1a{0} +msg_7=\u61c9\u70ba\u6578\u5b57 +msg_8=\u6578\u76ee\u7121\u6548\uff1a{0} +msg_9=\u6578\u76ee\u7684\u7b2c\u4e00\u500b\u5b57\u5fc5\u9808\u70ba\u6578\u5b57 +msg_10=\u5b57\u5143\u61c9\u70ba {0} \u6216 {1} +msg_11=\u5b57\u5143\u61c9\u70ba {0} +msg_12=\u5b57\u5143\u61c9\u70ba {0} +msg_13=\u51fd\u6578\u540d\u7a31\u7121\u6548\uff1a{0} +msg_14=\u5be6\u969b\u7684\u53c3\u6578\u6578\u91cf {0} \u8207\u9810\u671f\u4e0d\u7b26 +msg_15=\u53ea\u6709\u5341\u9032\u4f4d\u5236\u652f\u63f4\u5341\u9032\u4f4d\u7684\u6578\u5b57 +msg_16=\u8a08\u7b97\u6642\u767c\u751f\u4ee5\u4e0b\u932f\u8aa4\uff1a +msg_17=\u7121\u6cd5\u8f49\u63db {0} \u7684\u9032\u4f4d\u5236\u3002\u5c07\u9810\u8a2d\u9032\u4f4d\u5236\u6539\u70ba\u5341\u9032\u4f4d\u5f8c\u518d\u8a66\u4e00\u6b21\u3002 +msg_18=\u4e0d\u652f\u63f4\u4e09\u6b21\u968e\u5c64\u8a08\u7b97\uff01 +msg_19=\u4ee5\u4e0b\u932f\u8aa4\u5c0e\u81f4\u81ea\u8a02\u51fd\u6578\u540d\u7a31 {0} \u7121\u6cd5\u8a08\u7b97\uff1a{1} +msg_20=\u51fd\u6578 {0} \u4e0d\u80fd\u4ee5\u975e\u5f27\u5ea6\u55ae\u4f4d\u7a4d\u5206\uff01 +msg_21={0} \u4e0d\u652f\u63f4\u7a4d\u5206 +msg_22=\u4e0d\u652f\u63f4\u7a4d\u5206 +msg_23=\u975e\u5f27\u5ea6\u6a21\u5f0f\u7684\u8907\u6578\u8a08\u7b97\u53ef\u80fd\u5c0e\u81f4\u975e\u9810\u671f\u7684\u8a08\u7b97\u7d50\u679c\uff01 +msg_24=\u975e\u5f27\u5ea6\u6a21\u5f0f\u7684\u7a4d\u5206\u53ef\u80fd\u53ef\u80fd\u5c0e\u81f4\u975e\u9810\u671f\u7684\u8a08\u7b97\u7d50\u679c\uff01 +msg_25=\u975e\u5f27\u5ea6\u6a21\u5f0f\u7684\u5fae\u5206\u53ef\u80fd\u53ef\u80fd\u5c0e\u81f4\u975e\u9810\u671f\u7684\u8a08\u7b97\u7d50\u679c\uff01 + + diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java new file mode 100644 index 00000000..c308c968 --- /dev/null +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -0,0 +1,84 @@ +package jscl; + +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 12/15/11 + * Time: 11:25 AM + */ +public class JsclMathEngineTest { + @Test + public void testFormat() throws Exception { + final MathContext me = JsclMathEngine.getInstance(); + + try { + me.setUseGroupingSeparator(true); + Assert.assertEquals("1", me.format(1d, NumeralBase.bin)); + Assert.assertEquals("10", me.format(2d, NumeralBase.bin)); + Assert.assertEquals("11", me.format(3d, NumeralBase.bin)); + Assert.assertEquals("100", me.format(4d, NumeralBase.bin)); + Assert.assertEquals("101", me.format(5d, NumeralBase.bin)); + Assert.assertEquals("110", me.format(6d, NumeralBase.bin)); + Assert.assertEquals("111", me.format(7d, NumeralBase.bin)); + Assert.assertEquals("1000", me.format(8d, NumeralBase.bin)); + Assert.assertEquals("1001", me.format(9d, NumeralBase.bin)); + Assert.assertEquals("1 0001", me.format(17d, NumeralBase.bin)); + Assert.assertEquals("1 0100", me.format(20d, NumeralBase.bin)); + Assert.assertEquals("1 0100", me.format(20d, NumeralBase.bin)); + Assert.assertEquals("1 1111", me.format(31d, NumeralBase.bin)); + + me.setRoundResult(true); + me.setPrecision(10); + + Assert.assertEquals("111 1111 0011 0110", me.format(32566d, NumeralBase.bin)); + Assert.assertEquals("100.0100 1100 11", me.format(4.3d, NumeralBase.bin)); + Assert.assertEquals("1 0001 0101 0011.0101 0101 10", me.format(4435.33423d, NumeralBase.bin)); + Assert.assertEquals("1100.0101 0101 01", me.format(12.3333d, NumeralBase.bin)); + Assert.assertEquals("1 0011 1101 1110 0100 0011 0101 0101.0001 1111 00", me.format(333333333.1212213321d, NumeralBase.bin)); + + Assert.assertEquals("0.EE EE EE EE EE", me.format(14d / 15d, NumeralBase.hex)); + Assert.assertEquals("7F 36", me.format(32566d, NumeralBase.hex)); + Assert.assertEquals("24", me.format(36d, NumeralBase.hex)); + Assert.assertEquals("8", me.format(8d, NumeralBase.hex)); + Assert.assertEquals("1 3D", me.format(317d, NumeralBase.hex)); + Assert.assertEquals("13 DE 43 55.1F 08 5B EF 14", me.format(333333333.1212213321d, NumeralBase.hex)); + Assert.assertEquals("D 25 0F 77 0A.6F 73 18 FC 50", me.format(56456345354.43534534523459999d, NumeralBase.hex)); + Assert.assertEquals("3 E7.4C CC CC CC CC", me.format(999.3d, NumeralBase.hex)); + + me.setRoundResult(false); + Assert.assertEquals("0.00 00 00 00 00 00 00 00 00 6C", me.format(0.00000000000000000000009d, NumeralBase.hex)); + Assert.assertEquals("0.00 00 00 00 00 00 00 00 00 0A", me.format(0.000000000000000000000009d, NumeralBase.hex)); + + } finally { + me.setUseGroupingSeparator(false); + } + + Assert.assertEquals("1", me.format(1d, NumeralBase.bin)); + Assert.assertEquals("10", me.format(2d, NumeralBase.bin)); + Assert.assertEquals("11", me.format(3d, NumeralBase.bin)); + Assert.assertEquals("100", me.format(4d, NumeralBase.bin)); + Assert.assertEquals("101", me.format(5d, NumeralBase.bin)); + Assert.assertEquals("110", me.format(6d, NumeralBase.bin)); + Assert.assertEquals("111", me.format(7d, NumeralBase.bin)); + Assert.assertEquals("1000", me.format(8d, NumeralBase.bin)); + Assert.assertEquals("1001", me.format(9d, NumeralBase.bin)); + Assert.assertEquals("10001", me.format(17d, NumeralBase.bin)); + Assert.assertEquals("10100", me.format(20d, NumeralBase.bin)); + Assert.assertEquals("10100", me.format(20d, NumeralBase.bin)); + Assert.assertEquals("11111", me.format(31d, NumeralBase.bin)); + Assert.assertEquals("111111100110110", me.format(32566d, NumeralBase.bin)); + + Assert.assertEquals("7F36", me.format(32566d, NumeralBase.hex)); + Assert.assertEquals("24", me.format(36d, NumeralBase.hex)); + Assert.assertEquals("8", me.format(8d, NumeralBase.hex)); + Assert.assertEquals("13D", me.format(317d, NumeralBase.hex)); + } + + @Test + public void testPiComputation() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + Assert.assertEquals("-1+122.46467991473532E-18*i", me.evaluate("exp(√(-1)*Π)")); + } +} diff --git a/jscl/src/test/java/jscl/NumeralBaseTest.java b/jscl/src/test/java/jscl/NumeralBaseTest.java new file mode 100644 index 00000000..ba2ebb24 --- /dev/null +++ b/jscl/src/test/java/jscl/NumeralBaseTest.java @@ -0,0 +1,91 @@ +package jscl; + +import jscl.math.function.Constant; +import jscl.math.function.ExtendedConstant; +import jscl.math.function.IConstant; +import jscl.text.ParseException; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/29/11 + * Time: 12:20 PM + */ +public class NumeralBaseTest { + + @Test + public void testEvaluation() throws Exception { + MathEngine me = JsclMathEngine.getInstance(); + + Assert.assertEquals("3", me.evaluate("0b:1+0b:10")); + Assert.assertEquals("5", me.evaluate("0b:1+0b:100")); + Assert.assertEquals("8", me.evaluate("0b:1+0b:100+(0b:1+0b:10)")); + Assert.assertEquals("18", me.evaluate("0b:1+0b:100+(0b:1+0b:10)+10")); + Assert.assertEquals("18.5", me.evaluate("0b:1+0b:100+(0b:1+0b:10)+10.5")); + try { + me.evaluate("0b:1+0b:100.+(0b:1+0b:10)+10.5"); + Assert.fail(); + } catch (ParseException e) { + } + + try { + me.evaluate("0b:1+0b:100E-2+(0b:1+0b:10)+10.5"); + Assert.fail(); + } catch (ParseException e) { + } + + Assert.assertEquals("2748", me.evaluate("0x:ABC")); + + try { + me.evaluate("0x:"); + Assert.fail(); + } catch (ParseException e) { + } + + Assert.assertEquals("0", me.evaluate("0x:0")); + + IConstant constant = null; + try { + constant = me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("a"), 2d)); + Assert.assertEquals("2748", me.evaluate("0x:ABC")); + Assert.assertEquals("5496", me.evaluate("0x:ABC*a")); + Assert.assertEquals("27480", me.evaluate("0x:ABC*0x:A")); + } finally { + if (constant != null) { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("a"), (String) null)); + } + } + } + + @Test + public void testNumeralBases() throws Exception { + MathEngine me = JsclMathEngine.getInstance(); + + final NumeralBase defaultNumeralBase = me.getNumeralBase(); + try { + me.setNumeralBase(NumeralBase.bin); + Assert.assertEquals("∞", me.evaluate("∞")); + Assert.assertEquals("-1011010+110101111.10000110101100011010*i", me.evaluate("asin(-1110100101)")); + Assert.assertEquals("11", me.evaluate("0b:1+0b:10")); + Assert.assertEquals("10", me.evaluate("0d:2")); + Assert.assertEquals("11", me.evaluate("0d:3")); + Assert.assertEquals("100", me.evaluate("0d:4")); + Assert.assertEquals("11111111", me.evaluate("0d:255")); + Assert.assertEquals("11", me.evaluate("1+10")); + Assert.assertEquals("-1", me.evaluate("1-10")); + Assert.assertEquals("11-i", me.evaluate("1+i+10-10*i")); + Assert.assertEquals("11111110", me.evaluate("111001+11000101")); + Assert.assertEquals("1101100100101111", me.evaluate("11011001001011110/10")); + Assert.assertEquals("1001000011001010", me.evaluate("11011001001011110/11")); + Assert.assertEquals("0.10101010101010101010", me.evaluate("10/11")); + + me.setNumeralBase(NumeralBase.hex); + org.junit.Assert.assertEquals("637B", me.evaluate("56CE+CAD")); + org.junit.Assert.assertEquals("637B", me.simplify("56CE+CAD")); + + } finally { + me.setNumeralBase(defaultNumeralBase); + } + } +} diff --git a/jscl/src/test/java/jscl/math/ExpressionTest.java b/jscl/src/test/java/jscl/math/ExpressionTest.java new file mode 100644 index 00000000..e63628c8 --- /dev/null +++ b/jscl/src/test/java/jscl/math/ExpressionTest.java @@ -0,0 +1,833 @@ +package jscl.math; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.MathEngine; +import jscl.NumeralBase; +import jscl.math.function.Constant; +import jscl.math.function.ExtendedConstant; +import jscl.math.function.IConstant; +import jscl.text.ParseException; +import junit.framework.Assert; +import org.junit.Test; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Set; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; + +/** + * User: serso + * Date: 10/27/11 + * Time: 3:54 PM + */ +public class ExpressionTest { + + private static final String expressions = "-24.37581129610191-((2699.798527427213-4032.781981216783)*√(4657.120529143301)/6202.47137988087-ln(4435.662292261872)*sin(5134.044125137488)-sin(5150.617980207194)+sin(1416.6029070906816))\n" + + "1.6796699432963022E11-((5709.375015847543-√(9582.238699996864))*3622.6983393324695*8262.5649407951-4677.148654973858*ln(7443.120012194502)*ln(8771.583007058995)-7796.8909039525515)\n" + + "73260.62134636212-(((8211.239143650871+9653.120869092472/7201.080677271473-3675.134705789929/sin(7383.23886608315))+sin(8201.936690357508)/9797.420229466312/4487.554672699577))\n" + + "7835770.323315129-(3053.1562785415554*2564.6140313677965+ln(3376.462881190876)/2722.807595157415+cos(1654.053577173823)/4481.384989253306+cos(8539.28578313432)+5603.074520175994)\n" + + "7.219848990044144E11-((((9742.199604684844*8637.637793906879)-8613.230244786755+√(1026.016931180783))*8580.654028379886+ln(391.54269092744664)/√(4341.52889100337))+sin(508.2338437131828))\n" + + "6685.424634765305-((3746.8598111083793*sin(4784.284503822155)-ln(2218.167104685851)-sin(4794.102351616163))+3063.0457850324233-9545.89841181986/7482.886158430515/√(4001.7788453452417))\n" + + "4108.351107289166-((4102.493099763215-cos(5125.896955144614))+cos(3540.5378825149537)/5495.082697662915-8681.097948569084/cos(8032.923414105565)/4501.859274666647-cos(2711.854814853617))\n" + + "-1.0620650024203222-(((750.111466515082-9102.643276012855+3065.780766976849+2861.8661641038534)*3536.5716528042535/1106.4220238862831/7308.354645022433/sin(1173.0557272435349)))\n" + + "76379.44709543366-(((9932.156860771898+ln(7185.939808298219)*7687.141207402175)+cos(8185.971595673607)+ln(3977.781005305916)+cos(2376.681088176604)*2201.8644681719-√(3135.5682620873513)))\n" + + "635.3559760598341-((8075.628923197531/8255.66812901165+√(2936.433021287237)*sin(7502.632251185349)*sin(3225.272171990918)+613.2028126347367+ln(8485.99141046724))-cos(8518.190742544848))\n" + + "-7.51034737891574E7-(4640.543920377892/√(4363.843503017953)*√(7152.285785189239)*sin(7908.617128515873)*√(6906.317696310425)*6562.864387786373/ln(4988.784292770342)-sin(5488.826440303076))\n" + + "-5932.595870545627-(((3010.4402565484047-3218.3878293708044)+sin(9074.010686307622))/cos(7656.587621759453)/cos(1187.7115449548426)+cos(2207.5981975517957)/sin(7170.633198376899)+cos(129.16231777575283))\n" + + "14603.51285508874-((1505.6670065700584-ln(7760.688872668162)-cos(1521.0119520475184)+5874.745001223881+sin(5672.757849045151)*sin(9740.028947007728)+7239.645067283123)-ln(1198.788813287901))\n" + + "13789.681143529104-(4837.182498312745-sin(8683.238702053257)+9725.382455542274-ln(6866.318581911774)*√(7639.899860231787)-cos(8486.508690243441)/√(3325.7578426126165)/sin(5655.089763857597))\n" + + "5.9142041337333955E7-((((6945.350108837433-6875.255304556105-5503.241468583639*ln(4882.916231493727)-8221.764146581652)*4816.727562192865)-47.13141200212378)*sin(7032.925165237175))\n" + + "5.307098467139001E7-((((1472.5507104204128-2244.0144093640956)/337.94074333738934-6119.909773145814/4030.814210676087)+7955.59068044787)*6674.093078737379+cos(1072.8762639281485))\n" + + "2.4791276864495695E8-(((4650.104984872984*5990.69176729321*ln(7326.221240600894)-√(4166.293207980269)-cos(2930.9607978551735))+4892.051672831694)-√(4643.4262014756005)*ln(4322.391733256239))\n" + + "1.000473116354486E7-((1856.1678375267843*3375.5973472957558+8102.216834762455*460.5133278219642)+ln(1077.2976545272872)+9836.94091820254/cos(561.8742170542756)*sin(9587.941076809435))\n" + + "1.043950271691602E7-((((3594.0668967195334*2903.435684617801-ln(431.72508853349336)+√(2631.9717706394795)+4315.178672680215)+sin(1034.406679999502)/cos(7200.345388541185))+sin(8030.470700471927)))\n" + + "-4612.867091103858-(((117.31001770566519/6314.371065466436/5793.914918630644*1016.2707467350263*8539.984705173652)/3647.0016733225143*8871.091071924995-4680.559579608435))"; + + public static void main(String[] args) { + System.out.println("Result: " + getWolframAlphaResult("APP_ID", "-24.37581129610191-((2699.798527427213-4032.781981216783)*√(4657.120529143301)/6202.47137988087-ln(4435.662292261872)*sin(5134.044125137488)-sin(5150.617980207194)+sin(1416.6029070906816))")); + /*final StringTokenizer st = new StringTokenizer(expressions, "\n"); + if ( st.hasMoreTokens() ) { + final String expression = st.nextToken(); + final String result = getWolframAlphaResult("APP_ID", expression); + System.out.println("Expression: " + expression); + System.out.println("Result: " + result); + try { + final Double value = Double.valueOf(result); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + }*/ + } + + @Nullable + public static String getWolframAlphaResult(@Nonnull String appId, @Nonnull String expression) { + String result = null; + + URL wolframAlphaUrl; + try { + wolframAlphaUrl = new URL("http://api.wolframalpha.com/v2/query?input=" + expression + "&appid=" + appId + "&format=plaintext&podtitle=Decimal+approximation"); + + final URLConnection connection = wolframAlphaUrl.openConnection(); + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + String line; + while ((line = in.readLine()) != null) { + System.out.println(line); + if (line.contains("

")) { + result = line.replace("<plaintext>", "").replace("</plaintext>", "").replace("...", "").trim(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (in != null) { + in.close(); + } + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } + + @Test + public void testImag() throws Exception { + Assert.assertEquals("-i", Expression.valueOf("i^3").numeric().toString()); + } + + @Test + public void testConstants() throws Exception { + Assert.assertTrue(Expression.valueOf("3+4").getConstants().isEmpty()); + + Set<? extends Constant> constants = Expression.valueOf("3+4*t").getConstants(); + Assert.assertTrue(constants.size() == 1); + Assert.assertTrue(constants.contains(new Constant("t"))); + + IConstant constant = null; + + final JsclMathEngine me = JsclMathEngine.getInstance(); + try { + constant = me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("t_0"), 1d)); + + constants = Expression.valueOf("3+4*t_0+t_0+t_1").getConstants(); + Assert.assertTrue(constants.size() == 2); + Assert.assertTrue(constants.contains(new Constant("t_0"))); + Assert.assertTrue(constants.contains(new Constant("t_1"))); + + final Expression expression = Expression.valueOf("2*t_0+5*t_1"); + + Assert.assertEquals("7", expression.substitute(new Constant("t_1"), Expression.valueOf(1.0)).numeric().toString()); + Assert.assertEquals("12", expression.substitute(new Constant("t_1"), Expression.valueOf(2.0)).numeric().toString()); + Assert.assertEquals("27", expression.substitute(new Constant("t_1"), Expression.valueOf(5.0)).numeric().toString()); + + } finally { + if (constant != null) { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant(constant.getName()), (String) null)); + } + } + } + + @Test + public void testExpressions() throws Exception { + Assert.assertEquals("3", Expression.valueOf("3").numeric().toString()); + Assert.assertEquals("0.6931471805599453", Expression.valueOf("ln(2)").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("lg(10)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("eq(0, 1)").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("eq(1, 1)").numeric().toString()); + + Assert.assertEquals("24", Expression.valueOf("4!").numeric().toString()); + try { + Expression.valueOf("(-3+2)!").numeric().toString(); + fail(); + } catch (ArithmeticException e) { + + } + Assert.assertEquals("24", Expression.valueOf("(2+2)!").numeric().toString()); + Assert.assertEquals("120", Expression.valueOf("(2+2+1)!").numeric().toString()); + Assert.assertEquals("24", Expression.valueOf("(2.0+2.0)!").numeric().toString()); + Assert.assertEquals("24", Expression.valueOf("4.0!").numeric().toString()); + Assert.assertEquals("48", Expression.valueOf("2*4.0!").numeric().toString()); + Assert.assertEquals("40320", Expression.valueOf("(2*4.0)!").numeric().toString()); + + final JsclMathEngine me = JsclMathEngine.getInstance(); + final AngleUnit angleUnits = me.getAngleUnits(); + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("-0.9055783620066238", Expression.valueOf("sin(4!)").numeric().toString()); + } finally { + me.setAngleUnits(angleUnits); + } + Assert.assertEquals("1", Expression.valueOf("(3.14/3.14)!").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("2/2!").numeric().toString()); + try { + Assert.assertEquals("3.141592653589793!", Expression.valueOf("3.141592653589793!").numeric().toString()); + fail(); + } catch (NotIntegerException e) { + + } + Assert.assertEquals("0.5235987755982988", Expression.valueOf("3.141592653589793/3!").numeric().toString()); + try { + Assert.assertEquals("3.141592653589793/3.141592653589793!", Expression.valueOf("3.141592653589793/3.141592653589793!").numeric().toString()); + fail(); + } catch (ArithmeticException e) { + + } + try { + Assert.assertEquals("7.2!", Expression.valueOf("7.2!").numeric().toString()); + fail(); + } catch (NotIntegerException e) { + } + + try { + Assert.assertEquals("ln(7.2!)", Expression.valueOf("ln(7.2!)").numeric().toString()); + fail(); + } catch (NotIntegerException e) { + } + + Assert.assertEquals("ln(7.2!)", Expression.valueOf("ln(7.2!)").simplify().toString()); + + + Assert.assertEquals("36", Expression.valueOf("3!^2").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("(π/π)!").numeric().toString()); + Assert.assertEquals("720", Expression.valueOf("(3!)!").numeric().toString()); + Assert.assertEquals("36", Expression.valueOf("3!*3!").numeric().toString()); + + Assert.assertEquals("100", Expression.valueOf("0.1E3").numeric().toString()); + + final AngleUnit defaultAngleUnits = me.getAngleUnits(); + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("0.017453292519943295", Expression.valueOf("1°").numeric().toString()); + Assert.assertEquals("0.03490658503988659", Expression.valueOf("2°").numeric().toString()); + Assert.assertEquals("0.05235987755982989", Expression.valueOf("3°").numeric().toString()); + Assert.assertEquals("0.26179938779914946", Expression.valueOf("3°*5").numeric().toString()); + Assert.assertEquals("0.0027415567780803775", Expression.valueOf("3°^2").numeric().toString()); + Assert.assertEquals("0.01096622711232151", Expression.valueOf("3!°^2").numeric().toString()); + Assert.assertEquals("0.0009138522593601259", Expression.valueOf("3°°").numeric().toString()); + Assert.assertEquals("0.08726646259971647", Expression.valueOf("5°").numeric().toString()); + Assert.assertEquals("2.0523598775598297", Expression.valueOf("2+3°").numeric().toString()); + } finally { + me.setAngleUnits(defaultAngleUnits); + } + + try { + me.setAngleUnits(AngleUnit.deg); + Assert.assertEquals("1", Expression.valueOf("1°").numeric().toString()); + Assert.assertEquals("2", Expression.valueOf("2°").numeric().toString()); + Assert.assertEquals("3", Expression.valueOf("3°").numeric().toString()); + Assert.assertEquals("15", Expression.valueOf("3°*5").numeric().toString()); + Assert.assertEquals("9", Expression.valueOf("3°^2").numeric().toString()); + Assert.assertEquals("36", Expression.valueOf("3!°^2").numeric().toString()); + Assert.assertEquals("3", Expression.valueOf("3°°").numeric().toString()); + Assert.assertEquals("5", Expression.valueOf("5°").numeric().toString()); + Assert.assertEquals("5", Expression.valueOf("2+3°").numeric().toString()); + } finally { + me.setAngleUnits(defaultAngleUnits); + } + + Assert.assertEquals("6", Expression.valueOf("2*∂(3*x,x)").expand().toString()); + Assert.assertEquals("3", Expression.valueOf("∂(3*x,x)").expand().toString()); + Assert.assertEquals("12", Expression.valueOf("∂(x^3,x,2)").expand().toString()); + Assert.assertEquals("3*a", Expression.valueOf("∂(3*x*a,x)").expand().toString()); + Assert.assertEquals("0", Expression.valueOf("∂(3*x*a,x,0.011,2)").expand().toString()); + Assert.assertEquals("0", Expression.valueOf("2*∂(3*x*a,x,0.011,2)").expand().toString()); + Assert.assertEquals("ln(8)+lg(8)*ln(8)", Expression.valueOf("ln(8)*lg(8)+ln(8)").expand().toString()); + Assert.assertEquals("3.9573643765059856", Expression.valueOf("ln(8)*lg(8)+ln(8)").numeric().toString()); + + Assert.assertEquals("4!", Expression.valueOf("4.0!").simplify().toString()); + Assert.assertEquals("4°", Expression.valueOf("4.0°").simplify().toString()); + Assert.assertEquals("30°", Expression.valueOf("30°").simplify().toString()); + + + Assert.assertEquals("1", Expression.valueOf("abs(1)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("abs(0)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("abs(-0)").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("abs(-1)").numeric().toString()); + Assert.assertEquals("∞", Expression.valueOf("abs(-∞)").numeric().toString()); + + Assert.assertEquals("1", Expression.valueOf("abs(i)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("abs(0+0*i)").numeric().toString()); + Assert.assertEquals("1", Expression.valueOf("abs(-i)").numeric().toString()); + Assert.assertEquals("2.23606797749979", Expression.valueOf("abs(2-i)").numeric().toString()); + Assert.assertEquals("2.23606797749979", Expression.valueOf("abs(2+i)").numeric().toString()); + Assert.assertEquals("2.8284271247461903", Expression.valueOf("abs(2+2*i)").numeric().toString()); + Assert.assertEquals("2.8284271247461903", Expression.valueOf("abs(2-2*i)").numeric().toString()); + + try { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("k"), 2.8284271247461903)); + Assert.assertEquals("k", Expression.valueOf("k").numeric().toString()); + Assert.assertEquals("k", Expression.valueOf("k").simplify().toString()); + Assert.assertEquals("k", Expression.valueOf("k").simplify().toString()); + Assert.assertEquals("k^3", Expression.valueOf("k*k*k").simplify().toString()); + Assert.assertEquals("22.627416997969526", Expression.valueOf("k*k*k").numeric().toString()); + } finally { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("k"), (String) null)); + } + + try { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("k_1"), 3d)); + Assert.assertEquals("k_1", Expression.valueOf("k_1").numeric().toString()); + Assert.assertEquals("k_1", Expression.valueOf("k_1[0]").numeric().toString()); + Assert.assertEquals("k_1", Expression.valueOf("k_1[2]").numeric().toString()); + } finally { + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("k_1"), (String) null)); + } + + Generic expression = me.simplifyGeneric("cos(t)+∂(cos(t),t)"); + Generic substituted = expression.substitute(new Constant("t"), Expression.valueOf(100d)); + Assert.assertEquals("-1.1584559306791382", substituted.numeric().toString()); + + expression = me.simplifyGeneric("abs(t)^2+2!"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("102", substituted.numeric().toString()); + + + expression = me.simplifyGeneric("abs(t)^2+10%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("110", substituted.numeric().toString()); + + expression = me.simplifyGeneric("abs(t)^2-10%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("90", substituted.numeric().toString()); + + expression = me.simplifyGeneric("(abs(t)^2)*10%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("10", substituted.numeric().toString()); + + expression = me.simplifyGeneric("(abs(t)^2)/10%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("1000", substituted.numeric().toString()); + + expression = me.simplifyGeneric("abs(t)^2+t%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("110", substituted.numeric().toString()); + + expression = me.simplifyGeneric("abs(t)^2-t%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("90", substituted.numeric().toString()); + + expression = me.simplifyGeneric("(abs(t)^2)*t%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("10", substituted.numeric().toString()); + + expression = me.simplifyGeneric("(abs(t)^2)/t%"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("1000", substituted.numeric().toString()); + + expression = me.simplifyGeneric("Σ(t, t, 0, 10)"); + Assert.assertEquals("55", expression.numeric().toString()); + + expression = me.simplifyGeneric("Σ(t, t, 0, 10)"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("55", substituted.numeric().toString()); + + expression = me.simplifyGeneric("10*Σ(t, t, 0, 10)"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("550", substituted.numeric().toString()); + + expression = me.simplifyGeneric("t*Σ(t, t, 0, 10)"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("550", substituted.numeric().toString()); + + expression = me.simplifyGeneric("t*Σ(t+100%, t, 0, 10)"); + substituted = expression.substitute(new Constant("t"), Expression.valueOf(10d)); + Assert.assertEquals("1100", substituted.numeric().toString()); + + Assert.assertEquals("i*t", Expression.valueOf("i*t").expand().simplify().toString()); + Assert.assertEquals("t", Expression.valueOf("t").simplify().toString()); + Assert.assertEquals("t^3", Expression.valueOf("t*t*t").simplify().toString()); + + try { + Expression.valueOf("t").numeric(); + fail(); + } catch (ArithmeticException e) { + } + + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("t"), (String) null)); + try { + Expression.valueOf("t").numeric(); + fail(); + } catch (ArithmeticException e) { + } + + Assert.assertEquals("√(1+t)/(1+t)", Expression.valueOf("1/√(1+t)").simplify().toString()); + + Assert.assertEquals("t", Expression.valueOf("t").simplify().toString()); + Assert.assertEquals("t^3", Expression.valueOf("t*t*t").simplify().toString()); + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("0.6931471805599453+Π*i", Expression.valueOf("ln(-2)").numeric().toString()); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + Assert.assertEquals("-2/57", Expression.valueOf("1/(-57/2)").simplify().toString()); + Assert.assertEquals("sin(30)", Expression.valueOf("sin(30)").expand().toString()); + Assert.assertEquals("sin(n)", Expression.valueOf("sin(n)").expand().toString()); + Assert.assertEquals("sin(n!)", Expression.valueOf("sin(n!)").expand().toString()); + Assert.assertEquals("sin(n°)", Expression.valueOf("sin(n°)").expand().toString()); + Assert.assertEquals("sin(30°)", Expression.valueOf("sin(30°)").expand().toString()); + Assert.assertEquals("0.49999999999999994", Expression.valueOf("sin(30°)").expand().numeric().toString()); + Assert.assertEquals("sin(2!)", Expression.valueOf("sin(2!)").expand().toString()); + + Assert.assertEquals("12", Expression.valueOf("3*(3+1)").expand().toString()); + Assert.assertEquals("114.59155902616465", Expression.valueOf("deg(2)").numeric().toString()); + try { + Assert.assertEquals("-0.1425465430742778", Expression.valueOf("∏(tan(3))").numeric().toString()); + fail(); + } catch (ParseException e) { + } + try { + Assert.assertEquals("-0.14255", Expression.valueOf("sin(2,2)").expand().numeric().toString()); + fail(); + } catch (ParseException e) { + } + try { + Assert.assertEquals("114.59155902616465", Expression.valueOf("deg(2,2)").numeric().toString()); + fail(); + } catch (ParseException e) { + } + + Assert.assertEquals("0.49999999999999994", Expression.valueOf("sin(30°)").numeric().toString()); + Assert.assertEquals("π", Expression.valueOf("√(π)^2").simplify().toString()); + Assert.assertEquals("π", Expression.valueOf("√(π^2)").simplify().toString()); + Assert.assertEquals("π^2", Expression.valueOf("√(π^2*π^2)").simplify().toString()); + Assert.assertEquals("π^3", Expression.valueOf("√(π^4*π^2)").simplify().toString()); + Assert.assertEquals("e*π^2", Expression.valueOf("√(π^4*e^2)").simplify().toString()); + + Assert.assertEquals("1", Expression.valueOf("(π/π)!").numeric().toString()); + + // in deg mode π=180 and factorial of 180 is calculating + Assert.assertEquals("0", Expression.valueOf("Π/Π!").numeric().toString()); + + Assert.assertEquals("122.46467991473532E-18*i", Expression.valueOf("exp((Π*i))+1").numeric().toString()); + Assert.assertEquals("20*x^3", Expression.valueOf("∂(5*x^4, x)").expand().simplify().toString()); + Assert.assertEquals("25*x", Expression.valueOf("5*x*5").expand().simplify().toString()); + Assert.assertEquals("20*x", Expression.valueOf("5*x*4").expand().simplify().toString()); + + try { + me.evaluate("0b:π"); + fail(); + } catch (ParseException e) { + // ok + } + + try { + me.evaluate("0b:10π"); + fail(); + } catch (ParseException e) { + // ok + } + + try { + me.setNumeralBase(NumeralBase.hex); + + Assert.assertEquals("0.EEEEEEEEEEEEEC880AB7", me.evaluate("0x:E/0x:F")); + Assert.assertEquals("E/F", me.simplify("0x:E/0x:F")); + + Assert.assertEquals("0.EEEEEEEEEEEEEC880AB7", me.evaluate("E/F")); + Assert.assertEquals("E/F", me.simplify("E/F")); + + } finally { + me.setNumeralBase(NumeralBase.dec); + } + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("-1.5707963267948966+2.993222846126381*i", me.evaluate("asin(-10)")); + Assert.assertEquals("-1.5707963267948966+1.3169578969248166*i", me.evaluate("asin(-2)")); + Assert.assertEquals("-1.5707963267948966", me.evaluate("asin(-1)")); + Assert.assertEquals("0", me.evaluate("asin(0)")); + Assert.assertEquals("1.5707963267948966", me.evaluate("asin(1)")); + Assert.assertEquals("1.5707963267948966-1.3169578969248166*i", me.evaluate("asin(2)")); + Assert.assertEquals("1.5707963267948966-2.993222846126381*i", me.evaluate("asin(10)")); + + Assert.assertEquals("Π-2.9932228461263786*i", me.evaluate("acos(-10)")); + Assert.assertEquals("Π-1.3169578969248164*i", me.evaluate("acos(-2)")); + Assert.assertEquals("Π", me.evaluate("acos(-1)")); + Assert.assertEquals("1.5707963267948966", me.evaluate("acos(0)")); + Assert.assertEquals("0", me.evaluate("acos(1)")); + Assert.assertEquals("1.3169578969248164*i", me.evaluate("acos(2)")); + Assert.assertEquals("2.9932228461263786*i", me.evaluate("acos(10)")); + + Assert.assertEquals("-1.4711276743037347", me.evaluate("atan(-10)")); + Assert.assertEquals("-1.1071487177940904", me.evaluate("atan(-2)")); + Assert.assertEquals("-0.7853981633974483", me.evaluate("atan(-1)")); + Assert.assertEquals("0", me.evaluate("atan(0)")); + Assert.assertEquals("0.7853981633974483", me.evaluate("atan(1)")); + Assert.assertEquals("1.1071487177940904", me.evaluate("atan(2)")); + Assert.assertEquals("1.4711276743037347", me.evaluate("atan(10)")); + + for (int i = -10; i < 10; i++) { + Assert.assertEquals(me.evaluate("3.14159265358979323846/2 - atan(" + i + ")"), me.evaluate("acot(" + i + ")")); + } + + Assert.assertEquals("3.0419240010986313", me.evaluate("3.14159265358979323846/2 - atan(-10)")); + Assert.assertEquals("3.0419240010986313", me.evaluate("acot(-10)")); + Assert.assertEquals("1.5707963267948966", me.evaluate("acot(0)")); + Assert.assertEquals("2.677945044588987", me.evaluate("acot(-2)")); + Assert.assertEquals("2.356194490192345", me.evaluate("acot(-1)")); + Assert.assertEquals("0.7853981633974483", me.evaluate("acot(1)")); + Assert.assertEquals("0.46364760900080615", me.evaluate("acot(2)")); + Assert.assertEquals("0.09966865249116186", me.evaluate("acot(10)")); + + Assert.assertEquals("Π", me.evaluate("π")); + Assert.assertEquals("Π", me.evaluate("3.14159265358979323846")); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + + Assert.assertEquals("180", me.evaluate("Π")); + Assert.assertEquals("180", me.evaluate("200-10%")); + + Assert.assertEquals("∞", me.evaluate("1/0")); + Assert.assertEquals("-∞", me.evaluate("-1/0")); + Assert.assertEquals("-∞", me.evaluate("-1/0")); + Assert.assertEquals("∞", me.evaluate("(1 + 2) / (5 - 3 - 2)")); + Assert.assertEquals("∞", me.evaluate("(1 + 2) / (5.1 - 3.1 - 2.0 )")); + Assert.assertEquals("∞", me.evaluate("1/0")); + } + + @Test + public void testAngleUnits() throws Exception { + final MathEngine mathEngine = JsclMathEngine.getInstance(); + + final AngleUnit defaultAngleUnits = mathEngine.getAngleUnits(); + + for (AngleUnit angleUnits : AngleUnit.values()) { + try { + mathEngine.setAngleUnits(angleUnits); + mathEngine.evaluate("sin(2)"); + mathEngine.evaluate("asin(2)"); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + } + + try { + mathEngine.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("Π", mathEngine.evaluate("π")); + Assert.assertEquals("π/2", mathEngine.simplify("π/2")); + Assert.assertEquals(mathEngine.evaluate("0.9092974268256816953960198659117448427022549714478902683789"), mathEngine.evaluate("sin(2)")); + Assert.assertEquals(mathEngine.evaluate("0.1411200080598672221007448028081102798469332642522655841518"), mathEngine.evaluate("sin(3)")); + Assert.assertEquals(mathEngine.evaluate("0"), mathEngine.evaluate("sin(0)")); + + Assert.assertEquals(mathEngine.evaluate("1"), mathEngine.evaluate("cos(0)")); + Assert.assertEquals(mathEngine.evaluate("0.8623188722876839341019385139508425355100840085355108292801"), mathEngine.evaluate("cos(100)")); + Assert.assertEquals(mathEngine.evaluate("-0.416146836547142386997568229500762189766000771075544890755"), mathEngine.evaluate("cos(2)")); + + Assert.assertEquals(mathEngine.evaluate("-2.185039863261518991643306102313682543432017746227663164562"), mathEngine.evaluate("tan(2)")); + Assert.assertEquals(mathEngine.evaluate("-0.142546543074277805295635410533913493226092284901804647633"), mathEngine.evaluate("tan(3)")); + Assert.assertEquals(mathEngine.evaluate("0.6483608274590872"), mathEngine.evaluate("tan(10)")); + + Assert.assertEquals(mathEngine.evaluate("0.6420926159343306"), mathEngine.evaluate("cot(1)")); + Assert.assertEquals(mathEngine.evaluate("-0.457657554360285763750277410432047276428486329231674329641"), mathEngine.evaluate("cot(2)")); + Assert.assertEquals(mathEngine.evaluate("-7.015252551434533469428551379526476578293103352096353838156"), mathEngine.evaluate("cot(3)")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.deg); + Assert.assertEquals(mathEngine.evaluate("0.9092974268256816953960198659117448427022549714478902683789"), mathEngine.evaluate("sin(deg(2))")); + Assert.assertEquals(mathEngine.evaluate("0.1411200080598672221007448028081102798469332642522655841518"), mathEngine.evaluate("sin(deg(3))")); + Assert.assertEquals(mathEngine.evaluate("0"), mathEngine.evaluate("sin(deg(0))")); + + Assert.assertEquals(mathEngine.evaluate("1"), mathEngine.evaluate("cos(deg(0))")); + Assert.assertEquals(mathEngine.evaluate("0.8623188722876839341019385139508425355100840085355108292801"), mathEngine.evaluate("cos(deg(100))")); + Assert.assertEquals(mathEngine.evaluate("-0.416146836547142386997568229500762189766000771075544890755"), mathEngine.evaluate("cos(deg(2))")); + + Assert.assertEquals(mathEngine.evaluate("-2.185039863261518991643306102313682543432017746227663164562"), mathEngine.evaluate("tan(deg(2))")); + Assert.assertEquals(mathEngine.evaluate("-0.142546543074277805295635410533913493226092284901804647633"), mathEngine.evaluate("tan(deg(3))")); + Assert.assertEquals(mathEngine.evaluate("0.6483608274590872"), mathEngine.evaluate("tan(deg(10))")); + + Assert.assertEquals(mathEngine.evaluate("0.6420926159343306"), mathEngine.evaluate("cot(deg(1))")); + Assert.assertEquals(mathEngine.evaluate("-0.457657554360285763750277410432047276428486329231674329641"), mathEngine.evaluate("cot(deg(2))")); + Assert.assertEquals(mathEngine.evaluate("-7.015252551434533469428551379526476578293103352096353838156"), mathEngine.evaluate("cot(deg(3))")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.rad); + Assert.assertEquals(mathEngine.evaluate("-0.5235987755982989"), mathEngine.evaluate("asin(-0.5)")); + Assert.assertEquals(mathEngine.evaluate("-0.47349551215005636"), mathEngine.evaluate("asin(-0.456)")); + Assert.assertEquals(mathEngine.evaluate("0.32784124364198347"), mathEngine.evaluate("asin(0.322)")); + + Assert.assertEquals(mathEngine.evaluate("1.2429550831529133"), mathEngine.evaluate("acos(0.322)")); + Assert.assertEquals(mathEngine.evaluate("1.5587960387762325"), mathEngine.evaluate("acos(0.012)")); + Assert.assertEquals(mathEngine.evaluate("1.6709637479564563"), mathEngine.evaluate("acos(-0.1)")); + + Assert.assertEquals(mathEngine.evaluate("0.3805063771123649"), mathEngine.evaluate("atan(0.4)")); + Assert.assertEquals(mathEngine.evaluate("0.09966865249116204"), mathEngine.evaluate("atan(0.1)")); + Assert.assertEquals(mathEngine.evaluate("-0.5404195002705842"), mathEngine.evaluate("atan(-0.6)")); + + Assert.assertEquals(mathEngine.evaluate("1.0603080048781206"), mathEngine.evaluate("acot(0.56)")); + // todo serso: wolfram alpha returns -0.790423 instead of 2.3511694068615325 (-PI) + Assert.assertEquals(mathEngine.evaluate("2.3511694068615325"), mathEngine.evaluate("acot(-0.99)")); + // todo serso: wolfram alpha returns -1.373401 instead of 1.7681918866447774 (-PI) + Assert.assertEquals(mathEngine.evaluate("1.7681918866447774"), mathEngine.evaluate("acot(-0.2)")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.deg); + Assert.assertEquals(mathEngine.evaluate("deg(-0.5235987755982989)"), mathEngine.evaluate("asin(-0.5)")); + Assert.assertEquals(mathEngine.evaluate("-27.129294464583623"), mathEngine.evaluate("asin(-0.456)")); + Assert.assertEquals(mathEngine.evaluate("18.783919611005786"), mathEngine.evaluate("asin(0.322)")); + + Assert.assertEquals(mathEngine.evaluate("71.21608038899423"), mathEngine.evaluate("acos(0.322)")); + Assert.assertEquals(mathEngine.evaluate("89.31243414358914"), mathEngine.evaluate("acos(0.012)")); + Assert.assertEquals(mathEngine.evaluate("95.73917047726678"), mathEngine.evaluate("acos(-0.1)")); + + Assert.assertEquals(mathEngine.evaluate("deg(0.3805063771123649)"), mathEngine.evaluate("atan(0.4)")); + Assert.assertEquals(mathEngine.evaluate("deg(0.09966865249116204)"), mathEngine.evaluate("atan(0.1)")); + Assert.assertEquals(mathEngine.evaluate("deg(-0.5404195002705842)"), mathEngine.evaluate("atan(-0.6)")); + + Assert.assertEquals(mathEngine.evaluate("deg(1.0603080048781206)"), mathEngine.evaluate("acot(0.56)")); + // todo serso: wolfram alpha returns -0.790423 instead of 2.3511694068615325 (-PI) + Assert.assertEquals(mathEngine.evaluate("134.7120839334429"), mathEngine.evaluate("acot(-0.99)")); + // todo serso: wolfram alpha returns -1.373401 instead of 1.7681918866447774 (-PI) + Assert.assertEquals(mathEngine.evaluate("deg(1.7681918866447774)"), mathEngine.evaluate("acot(-0.2)")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.deg); + Assert.assertEquals(mathEngine.evaluate("0.0348994967025009716459951816253329373548245760432968714250"), mathEngine.evaluate("(sin(2))")); + Assert.assertEquals(mathEngine.evaluate("0.0523359562429438327221186296090784187310182539401649204835"), mathEngine.evaluate("(sin(3))")); + Assert.assertEquals(mathEngine.evaluate("0"), mathEngine.evaluate("sin(0)")); + + Assert.assertEquals(mathEngine.evaluate("1"), mathEngine.evaluate("cos(0)")); + Assert.assertEquals(mathEngine.evaluate("-0.1736481776669303"), mathEngine.evaluate("(cos(100))")); + Assert.assertEquals(mathEngine.evaluate("0.9993908270190958"), mathEngine.evaluate("(cos(2))")); + + Assert.assertEquals(mathEngine.evaluate("0.03492076949174773"), mathEngine.evaluate("(tan(2))")); + Assert.assertEquals(mathEngine.evaluate("0.05240777928304121"), mathEngine.evaluate("(tan(3))")); + Assert.assertEquals(mathEngine.evaluate("0.17632698070846498"), mathEngine.evaluate("(tan(10))")); + + Assert.assertEquals(mathEngine.evaluate("57.28996163075943"), mathEngine.evaluate("(cot(1))")); + Assert.assertEquals(mathEngine.evaluate("28.636253282915604"), mathEngine.evaluate("(cot(2))")); + Assert.assertEquals(mathEngine.evaluate("19.081136687728208"), mathEngine.evaluate("(cot(3))")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.rad); + testSinEqualsToSinh(mathEngine, 0d); + testSinEqualsToSinh(mathEngine, 1d, "0.8414709848078965"); + testSinEqualsToSinh(mathEngine, 3d, "0.1411200080598672"); + testSinEqualsToSinh(mathEngine, 6d); + testSinEqualsToSinh(mathEngine, -1d, "-0.8414709848078965"); + testSinEqualsToSinh(mathEngine, -3.3d, "0.1577456941432482"); + testSinEqualsToSinh(mathEngine, -232.2d, "0.27429486373689577"); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.deg); + testSinEqualsToSinh(mathEngine, 0d); + testSinEqualsToSinh(mathEngine, 1d, "0.01745240643728351"); + testSinEqualsToSinh(mathEngine, 3d, "0.052335956242943835"); + testSinEqualsToSinh(mathEngine, 6d, "0.10452846326765347"); + testSinEqualsToSinh(mathEngine, -1d, "-0.01745240643728351"); + testSinEqualsToSinh(mathEngine, -3.3d, "-0.05756402695956728"); + testSinEqualsToSinh(mathEngine, -232.2d, "0.7901550123756904"); + Assert.assertEquals("Π/2", mathEngine.simplify("Π/2")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + try { + mathEngine.setAngleUnits(AngleUnit.rad); + Assert.assertEquals(mathEngine.evaluate("1.5707963267948966-0.8813735870195429*i"), mathEngine.evaluate("acos(i)")); + Assert.assertEquals(mathEngine.evaluate("0.9045568943023814-1.0612750619050357*i"), mathEngine.evaluate("acos(1+i)")); + Assert.assertEquals(mathEngine.evaluate("0.9999999999999999-0.9999999999999998*i"), mathEngine.evaluate("cos(acos(1-i))")); + Assert.assertEquals(mathEngine.evaluate("-0.9045568943023814-1.0612750619050355*i"), mathEngine.evaluate("-acos(1-i)")); + } finally { + mathEngine.setAngleUnits(defaultAngleUnits); + } + + } + + private void testSinEqualsToSinh(@Nonnull MathEngine mathEngine, @Nonnull Double x) throws ParseException { + testSinEqualsToSinh(mathEngine, x, null); + } + + private void testSinEqualsToSinh(@Nonnull MathEngine mathEngine, @Nonnull Double x, @Nullable String expected) throws ParseException { + if (expected == null) { + Assert.assertEquals(mathEngine.evaluate("sinh(i*" + x + ")/i"), mathEngine.evaluate("sin(" + x + ")")); +// Assert.assertEquals(mathEngine.evaluate("exp("+x+")-sinh(" + x + ")"), mathEngine.evaluate("cosh(" + x + ")")); + } else { + Assert.assertEquals(expected, mathEngine.evaluate("sin(" + x + ")")); + Assert.assertEquals(expected, mathEngine.evaluate("(exp(i * " + x + ") - cos(" + x + "))/i")); + Assert.assertEquals(expected, mathEngine.evaluate("(exp(i * " + x + ") - cos(" + x + "))/i")); + } + } + + @Test + public void testName() throws Exception { + Expression.valueOf("a*c+b*sin(c)").toString(); + } + + @Test + public void testIntegrals() throws Exception { + Assert.assertEquals("50", Expression.valueOf("∫ab(x, x, 0, 10)").expand().numeric().toString()); + Assert.assertEquals("1/2*a^2", Expression.valueOf("∫ab(x, x, 0, a)").expand().toString()); + try { + Assert.assertEquals("∫ab(x, x, 0)", Expression.valueOf("∫ab(x, x, 0)").expand().toString()); + fail(); + } catch (ParseException e) { + } + try { + Assert.assertEquals("∫ab(x, x)", Expression.valueOf("∫ab(x, x)").expand().simplify().toString()); + fail(); + } catch (ParseException e) { + } + Assert.assertEquals("x^2/2", Expression.valueOf("∫(x, x)").expand().simplify().toString()); + try { + Assert.assertEquals("x^2/2", Expression.valueOf("∫(x, x)").expand().numeric().toString()); + fail(); + } catch (ArithmeticException e) { + } + + Assert.assertEquals("x^2/2", Expression.valueOf("∫(x, x)").expand().simplify().toString()); + Assert.assertEquals("ln(x)", Expression.valueOf("∫(1/x, x)").expand().simplify().toString()); + try { + JsclMathEngine.getInstance().setAngleUnits(AngleUnit.rad); + Assert.assertEquals("2*ln(2)+ln(cosh(x))", Expression.valueOf("∫(tanh(x), x)").expand().simplify().toString()); + Assert.assertEquals("2*ln(2)+ln(sin(x))", Expression.valueOf("∫(cot(x), x)").expand().simplify().toString()); + Assert.assertEquals("-2*ln(2)-ln(cos(x))", Expression.valueOf("∫(tan(x), x)").expand().simplify().toString()); + } finally { + JsclMathEngine.getInstance().setAngleUnits(AngleUnit.deg); + } + } + + @Test + public void testDerivations() throws Exception { + final AngleUnit defaultAngleUnits = JsclMathEngine.getInstance().getAngleUnits(); + try { + JsclMathEngine.getInstance().setAngleUnits(AngleUnit.rad); + Assert.assertEquals("-0.9092974268256817", Expression.valueOf("∂(cos(t),t,2)").numeric().toString()); + Assert.assertEquals("∂(cos(t), t, 2, 1)", Expression.valueOf("∂(cos(t),t,2)").simplify().toString()); + Assert.assertEquals("-2.234741690198506", Expression.valueOf("∂(t*cos(t),t,2)").numeric().toString()); + Assert.assertEquals("-4.469483380397012", Expression.valueOf("2*∂(t*cos(t),t,2)").numeric().toString()); + Assert.assertEquals("-sin(2)", Expression.valueOf("∂(cos(t),t,2)").expand().toString()); + Assert.assertEquals("-sin(t)", Expression.valueOf("∂(cos(t),t)").expand().toString()); + assertEquals("-sin(t)", Expression.valueOf("∂(cos(t),t,t,1)").expand().simplify().toString()); + assertEquals("∂(cos(t), t, t, 1°)", Expression.valueOf("∂(cos(t),t,t,1°)").expand().simplify().toString()); + } finally { + JsclMathEngine.getInstance().setAngleUnits(defaultAngleUnits); + } + + assertEquals("∂(cos(t), t, t, 1°)", Expression.valueOf("∂(cos(t),t,t,1°)").expand().numeric().toString()); + } + + @Test + public void testSum() throws Exception { + Assert.assertEquals("3", Expression.valueOf("Σ(n,n,1,2)").expand().toString()); + Assert.assertEquals("200", Expression.valueOf("Σ(n/n,n,1,200)").expand().toString()); + Assert.assertEquals("1/3", Expression.valueOf("Σ((n-1)/(n+1),n,1,2)").expand().toString()); + Assert.assertEquals("sin(1)", Expression.valueOf("Σ(sin(n),n,1,1)").expand().toString()); + Assert.assertEquals("1/1!", Expression.valueOf("Σ(n/n!,n,1,1)").expand().toString()); + Assert.assertEquals("2", Expression.valueOf("Σ(n/n!,n,1,2)").expand().numeric().toString()); + Assert.assertEquals("2.7182818284590455", Expression.valueOf("Σ(n/n!,n,1,200)").expand().numeric().toString()); + Assert.assertEquals("2.718281828459046", Expression.valueOf("Σ(n/(2*n/2)!,n,1,200)").expand().numeric().toString()); + Assert.assertEquals(Expression.valueOf("3").numeric().toString(), Expression.valueOf("Σ(n°,n,1,2)").expand().numeric().toString()); + Assert.assertEquals("200", Expression.valueOf("Σ(n°/n°,n,1,200)").expand().numeric().toString()); + Assert.assertEquals("-sin(1)-sin(2)", Expression.valueOf("Σ(∂(cos(t),t,n),n,1,2)").expand().toString()); + Assert.assertEquals("-0.05235190313978448", Expression.valueOf("Σ(∂(cos(t),t,n),n,1,2)").expand().numeric().toString()); + } + + @Test + public void testNumeralBases() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + //final NumeralBase defaultNumeralBase = me.getDefaultNumeralBase(); + try { + //me.setDefaultNumeralBase(NumeralBase.bin); + Assert.assertEquals("10", me.evaluate("0b:01010")); + Assert.assertEquals("10", me.evaluate("0b:1010")); + Assert.assertEquals("520", me.evaluate("0o:1010")); + Assert.assertEquals("1010", me.evaluate("1010")); + Assert.assertEquals("1010.1", me.evaluate("1010.1")); + } finally { + //me.setDefaultNumeralBase(defaultNumeralBase); + } + + try { + me.setNumeralBase(NumeralBase.hex); + Assert.assertEquals("22F", me.evaluate("22F*exp(F)/exp(F)")); + Assert.assertEquals("E", me.evaluate("E")); + } finally { + me.setNumeralBase(NumeralBase.dec); + + } + } + + @Test + public void testFormat() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + try { + me.setUseGroupingSeparator(true); + Assert.assertEquals("123 456.7891011", Expression.valueOf("123456.7891011").numeric().toString()); + Assert.assertEquals("123 456.7891011", Expression.valueOf("123456.7891011").simplify().toString()); + Assert.assertEquals("123 456.78910111231", Expression.valueOf("123456.7891011123123123123123").simplify().toString()); + Assert.assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); + Assert.assertEquals("12 345", JsclInteger.valueOf(12345L).toString()); + + me.setScienceNotation(true); + Assert.assertEquals("0", Expression.valueOf("0.0").simplify().toString()); + Assert.assertEquals("1E0", Expression.valueOf("1.0").simplify().toString()); + Assert.assertEquals("100E0", Expression.valueOf("100.0").simplify().toString()); + + me.setRoundResult(true); + me.setPrecision(5); + Assert.assertEquals("0", Expression.valueOf("1222/(10^9)").numeric().toString()); + + me.setRoundResult(true); + me.setPrecision(10); + Assert.assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); + + me.setRoundResult(false); + Assert.assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); + + me.setScienceNotation(false); + Assert.assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); + + me.setScienceNotation(true); + Assert.assertEquals("333.33333E-3", Expression.valueOf("1/3").numeric().toString()); + + me.setRoundResult(true); + me.setPrecision(10); + Assert.assertEquals("333.33333E-3", Expression.valueOf("1/3").numeric().toString()); + + me.setScienceNotation(false); + me.setRoundResult(true); + me.setPrecision(10); + Assert.assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); + + } finally { + me.setUseGroupingSeparator(false); + me.setScienceNotation(false); + me.setRoundResult(false); + } + } +} diff --git a/jscl/src/test/java/jscl/math/JsclVectorTest.java b/jscl/src/test/java/jscl/math/JsclVectorTest.java new file mode 100644 index 00000000..b6f591ca --- /dev/null +++ b/jscl/src/test/java/jscl/math/JsclVectorTest.java @@ -0,0 +1,20 @@ +package jscl.math; + +import jscl.JsclMathEngine; +import jscl.MathEngine; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 12/26/11 + * Time: 9:52 AM + */ +public class JsclVectorTest { + + @Test + public void testVector() throws Exception { + MathEngine me = JsclMathEngine.getInstance(); + Assert.assertEquals("[1, 0, 0, 1]", me.evaluate("[1, 0, 0, 1]")); + } +} diff --git a/jscl/src/test/java/jscl/math/LiteralTest.java b/jscl/src/test/java/jscl/math/LiteralTest.java new file mode 100644 index 00000000..c75a9bfd --- /dev/null +++ b/jscl/src/test/java/jscl/math/LiteralTest.java @@ -0,0 +1,38 @@ +package jscl.math; + +import jscl.math.numeric.Real; +import org.junit.Test; + +/** + * User: serso + * Date: 12/23/11 + * Time: 5:28 PM + */ +public class LiteralTest { + @Test + public void testGcd() throws Exception { + + } + + @Test + public void testScm() throws Exception { + Expression e1 = Expression.valueOf("2+sin(2)"); + Expression e2 = Expression.valueOf("3+cos(2)"); + Literal l1 = Literal.valueOf(new DoubleVariable(new NumericWrapper(Real.valueOf(2d)))); + Literal l2 = Literal.valueOf(new DoubleVariable(new NumericWrapper(Real.valueOf(4d)))); + + System.out.println(e1); + System.out.println(e2); + + Literal result = Literal.newInstance(); + System.out.println(-1 + " -> " + result); + for (int i = 0; i < e1.size(); i++) { + result = result.scm(e1.literal(i)); + System.out.println(i + " -> " + result); + } + + System.out.println(e1.literalScm()); + System.out.println(e2.literalScm()); + + } +} diff --git a/jscl/src/test/java/jscl/math/NumeralBaseConversionTest.java b/jscl/src/test/java/jscl/math/NumeralBaseConversionTest.java new file mode 100644 index 00000000..f77a290a --- /dev/null +++ b/jscl/src/test/java/jscl/math/NumeralBaseConversionTest.java @@ -0,0 +1,134 @@ +package jscl.math; + +import au.com.bytecode.opencsv.CSVReader; +import jscl.JsclMathEngine; +import jscl.MathEngine; +import jscl.text.ParseException; +import jscl.util.ExpressionGeneratorWithInput; +import org.junit.Assert; +import org.junit.Test; +import org.solovyev.common.Converter; + +import javax.annotation.Nonnull; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +/** + * User: serso + * Date: 12/14/11 + * Time: 4:01 PM + */ +public class NumeralBaseConversionTest { + + public static void testExpression(@Nonnull String[] line, @Nonnull Converter<String, String> converter) throws ParseException { + final String dec = line[0].toUpperCase(); + final String hex = "0x:" + line[1].toUpperCase(); + final String bin = "0b:" + line[2].toUpperCase(); + + final String decResult = Expression.valueOf(converter.convert(dec)).numeric().toString(); + final String hexResult = Expression.valueOf(converter.convert(hex)).numeric().toString(); + final String binResult = Expression.valueOf(converter.convert(bin)).numeric().toString(); + + Assert.assertEquals(decResult, hexResult); + Assert.assertEquals(decResult, binResult); + } + + @Test + public void testConversion() throws Exception { + CSVReader reader = null; + try { + final MathEngine me = JsclMathEngine.getInstance(); + + reader = new CSVReader(new InputStreamReader(NumeralBaseConversionTest.class.getResourceAsStream("/jscl/math/nb_table.csv")), '\t'); + + // skip first line + reader.readNext(); + + String[] line = reader.readNext(); + for (; line != null; line = reader.readNext()) { + testExpression(line, new DummyExpression()); + testExpression(line, new Expression1()); + testExpression(line, new Expression2()); + testExpression(line, new Expression3()); + + final String dec = line[0].toUpperCase(); + final String hex = "0x:" + line[1].toUpperCase(); + final String bin = "0b:" + line[2].toUpperCase(); + + final List<String> input = new ArrayList<String>(); + input.add(dec); + input.add(hex); + input.add(bin); + + //System.out.println("Dec: " + dec); + //System.out.println("Hex: " + hex); + //System.out.println("Bin: " + bin); + + final ExpressionGeneratorWithInput eg = new ExpressionGeneratorWithInput(input, 20); + final List<String> expressions = eg.generate(); + + final String decExpression = expressions.get(0); + final String hexExpression = expressions.get(1); + final String binExpression = expressions.get(2); + + //System.out.println("Dec expression: " + decExpression); + //System.out.println("Hex expression: " + hexExpression); + //System.out.println("Bin expression: " + binExpression); + + final String decResult = Expression.valueOf(decExpression).numeric().toString(); + //System.out.println("Dec result: " + decResult); + + final String hexResult = Expression.valueOf(hexExpression).numeric().toString(); + //System.out.println("Hex result: " + hexResult); + + final String binResult = Expression.valueOf(binExpression).numeric().toString(); + //System.out.println("Bin result: " + binResult); + + Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult); + Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult); + + } + } finally { + if (reader != null) { + reader.close(); + } + } + } + + private static class DummyExpression implements Converter<String, String> { + + @Nonnull + @Override + public String convert(@Nonnull String s) { + return s; + } + } + + private static class Expression1 implements Converter<String, String> { + + @Nonnull + @Override + public String convert(@Nonnull String s) { + return s + "*" + s; + } + } + + private static class Expression2 implements Converter<String, String> { + + @Nonnull + @Override + public String convert(@Nonnull String s) { + return s + "*" + s + " * sin(" + s + ") - 0b:1101"; + } + } + + private static class Expression3 implements Converter<String, String> { + + @Nonnull + @Override + public String convert(@Nonnull String s) { + return s + "*" + s + " * sin(" + s + ") - 0b:1101 + √(" + s + ") + exp ( " + s + ")"; + } + } +} diff --git a/jscl/src/test/java/jscl/math/RandomExpressionTest.java b/jscl/src/test/java/jscl/math/RandomExpressionTest.java new file mode 100644 index 00000000..2bfe3322 --- /dev/null +++ b/jscl/src/test/java/jscl/math/RandomExpressionTest.java @@ -0,0 +1,29 @@ +package jscl.math; + +import jscl.JsclMathEngine; +import jscl.util.ExpressionGenerator; +import org.junit.Test; + +/** + * User: serso + * Date: 12/14/11 + * Time: 10:40 PM + */ +public class RandomExpressionTest { + + public static final int MAX = 1000; + + @Test + public void testRandomExpressions() throws Exception { + final ExpressionGenerator eg = new ExpressionGenerator(20); + int i = 0; + while (i < MAX) { + final String expression = eg.generate(); + final String result = JsclMathEngine.getInstance().evaluate(expression); + + //System.out.println(result + "-(" + expression + ")"); + + i++; + } + } +} diff --git a/jscl/src/test/java/jscl/math/TrigonometricTest.java b/jscl/src/test/java/jscl/math/TrigonometricTest.java new file mode 100644 index 00000000..4574e982 --- /dev/null +++ b/jscl/src/test/java/jscl/math/TrigonometricTest.java @@ -0,0 +1,118 @@ +package jscl.math; + +import au.com.bytecode.opencsv.CSVReader; +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.MathEngine; +import junit.framework.Assert; +import org.junit.Test; + +import java.io.InputStreamReader; + +/** + * User: serso + * Date: 11/22/11 + * Time: 12:49 PM + */ +public class TrigonometricTest { + + // todo serso: due to conversion errors values on the borders are calculated not precisely + /* + 0;0;1;0;Infinity + 90;1;0;1.633123935319537E16;0 + 180;0;-1;0;-8.165619676597685E15 + 270;-1;0;5.443746451065123E15;0 + 360;0;1;0;-4.0828098382988425E15 + */ + + @Test + public void testValues() throws Exception { + CSVReader reader = null; + try { + final MathEngine me = JsclMathEngine.getInstance(); + + reader = new CSVReader(new InputStreamReader(TrigonometricTest.class.getResourceAsStream("/jscl/math/trig_table.csv")), '\t'); + + // skip first line + reader.readNext(); + + String[] line = reader.readNext(); + for (; line != null; line = reader.readNext()) { + final Integer degrees = Integer.valueOf(line[0]); + + final Double sinValue = Double.valueOf(line[1]); + final Double cosValue = Double.valueOf(line[2]); + final Double tgValue = Double.valueOf(line[3]); + final Double ctgValue = Double.valueOf(line[4]); + + final Double radians = Double.valueOf(line[5]); + + final Double sinhValue = Double.valueOf(line[6]); + final Double coshValue = Double.valueOf(line[7]); + final Double tghValue = Double.valueOf(line[8]); + final Double cthgValue = Double.valueOf(line[9]); + + final Double asinValue = Double.valueOf(line[10]); + final Double acosValue = Double.valueOf(line[11]); + final Double atanValue = Double.valueOf(line[12]); + + + testValue(sinValue, Double.valueOf(me.evaluate("sin(" + degrees + "°)")), degrees); + testValue(cosValue, Double.valueOf(me.evaluate("cos(" + degrees + "°)")), degrees); + testValue(tgValue, Double.valueOf(me.evaluate("tan(" + degrees + "°)")), degrees); + testValue(ctgValue, Double.valueOf(me.evaluate("cot(" + degrees + "°)")), degrees); + + testValue(sinhValue, Double.valueOf(me.evaluate("sinh(" + degrees + "°)")), degrees); + testValue(coshValue, Double.valueOf(me.evaluate("cosh(" + degrees + "°)")), degrees); + testValue(tghValue, Double.valueOf(me.evaluate("tanh(" + degrees + "°)")), degrees); + testValue(cthgValue, Double.valueOf(me.evaluate("coth(" + degrees + "°)")), degrees); + + final AngleUnit angleUnits = me.getAngleUnits(); + try { + me.setAngleUnits(AngleUnit.rad); + + testValue(sinValue, Double.valueOf(me.evaluate("sin(" + radians + ")")), degrees); + testValue(cosValue, Double.valueOf(me.evaluate("cos(" + radians + ")")), degrees); + testValue(tgValue, Double.valueOf(me.evaluate("tan(" + radians + ")")), degrees); + testValue(ctgValue, Double.valueOf(me.evaluate("cot(" + radians + ")")), degrees); + + testValue(sinhValue, Double.valueOf(me.evaluate("sinh(" + radians + ")")), degrees); + testValue(coshValue, Double.valueOf(me.evaluate("cosh(" + radians + ")")), degrees); + testValue(tghValue, Double.valueOf(me.evaluate("tanh(" + radians + ")")), degrees); + testValue(cthgValue, Double.valueOf(me.evaluate("coth(" + radians + ")")), degrees); + } finally { + me.setAngleUnits(angleUnits); + } + + testValue(asinValue, Double.valueOf(me.evaluate("rad(asin(" + sinValue + "))")), degrees); + testValue(acosValue, Double.valueOf(me.evaluate("rad(acos(" + cosValue + "))")), degrees); + testValue(atanValue, Double.valueOf(me.evaluate("rad(atan(" + tgValue + "))")), degrees); + + // todo serso: check this + //testValue((double)degrees, Double.valueOf(me.evaluate("asin(sin(" + degrees + "°))")), degrees); + //testValue((double)degrees, Double.valueOf(me.evaluate("acos(cos(" + degrees + "°))")), degrees); + //testValue((double)degrees, Double.valueOf(me.evaluate("atan(tan(" + degrees + "°))")), degrees); + //testValue((double)degrees, Double.valueOf(me.evaluate("acot(cot(" + degrees + "°))")), degrees); + + testValue(sinValue, Double.valueOf(me.evaluate("sin(asin(sin(" + degrees + "°)))")), degrees); + testValue(cosValue, Double.valueOf(me.evaluate("cos(acos(cos(" + degrees + "°)))")), degrees); + testValue(tgValue, Double.valueOf(me.evaluate("tan(atan(tan(" + degrees + "°)))")), degrees); + testValue(ctgValue, Double.valueOf(me.evaluate("cot(acot(cot(" + degrees + "°)))")), degrees); + } + } finally { + if (reader != null) { + reader.close(); + } + } + } + + private void testValue(Double expected, Double actual, Integer degrees) { + if (expected.isInfinite() && actual.isInfinite()) { + // ok + } else if (expected.isNaN() && actual.isNaN()) { + // ok + } else { + Assert.assertTrue("Actual: " + actual + ", expected: " + expected + " for " + degrees + "°", Math.abs(expected - actual) < Math.pow(10, -10)); + } + } +} diff --git a/jscl/src/test/java/jscl/math/function/ConstantsRegistryTest.java b/jscl/src/test/java/jscl/math/function/ConstantsRegistryTest.java new file mode 100644 index 00000000..f5dfb3f5 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/ConstantsRegistryTest.java @@ -0,0 +1,32 @@ +package jscl.math.function; + +import org.solovyev.common.JBuilder; +import org.solovyev.common.math.AbstractMathRegistry; +import org.solovyev.common.math.AbstractMathRegistryTest; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 6/15/13 + * Time: 9:23 PM + */ +public class ConstantsRegistryTest extends AbstractMathRegistryTest<IConstant> { + + @Override + protected JBuilder<? extends IConstant> createBuilder(@Nonnull final String name) { + return new JBuilder<IConstant>() { + @Nonnull + @Override + public IConstant create() { + return new ExtendedConstant(new Constant(name), name, name); + } + }; + } + + @Nonnull + @Override + protected AbstractMathRegistry<IConstant> getRegistry() { + return new ConstantsRegistry(); + } +} diff --git a/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java b/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java new file mode 100644 index 00000000..ac357bcc --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java @@ -0,0 +1,171 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Expression; +import jscl.text.ParseException; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +/** + * User: serso + * Date: 11/15/11 + * Time: 5:35 PM + */ +public class CustomFunctionTest { + + @Test + public void testLog() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + Assert.assertEquals("∞", Expression.valueOf("1/0").numeric().toString()); + Assert.assertEquals("∞", Expression.valueOf("ln(10)/ln(1)").numeric().toString()); + + // logarithm + Function function = mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder(true, "log", Arrays.asList("a", "b"), "ln(b)/ln(a)")); + Assert.assertEquals("log(a, b)", function.toString()); + Assert.assertEquals("ln(b)/ln(a)", ((CustomFunction) mathEngine.getFunctionsRegistry().get("log")).getContent()); + Assert.assertEquals("∞", Expression.valueOf("log(1, 10)").numeric().toString()); + Assert.assertEquals("3.3219280948873626", Expression.valueOf("log(2, 10)").numeric().toString()); + Assert.assertEquals("1.4306765580733933", Expression.valueOf("log(5, 10)").numeric().toString()); + Assert.assertEquals("0.9602525677891275", Expression.valueOf("log(11, 10)").numeric().toString()); + Assert.assertEquals("1/b*1/ln(a)", Expression.valueOf("∂(log(a, b), b)").expand().toString()); + Assert.assertEquals("-1/a*(1/ln(a))^2*ln(b)", Expression.valueOf("∂(log(a, b), a)").expand().toString()); + + } + + @Test + public void testDerivative() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("t1", Arrays.asList("a"), "sin(a)")); + Assert.assertEquals("1", Expression.valueOf("t1(90)").numeric().toString()); + Assert.assertEquals("cos(t)", Expression.valueOf("∂(t1(t), t)").expand().toString()); + Assert.assertEquals("0", Expression.valueOf("∂(t1(t), t2)").expand().toString()); + Assert.assertEquals("cos(a)", Expression.valueOf("∂(t1(a), a)").expand().toString()); + Assert.assertEquals("1", Expression.valueOf("∂(t1(a), t1(a))").expand().toString()); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("t2", Arrays.asList("a", "b"), "b*sin(a)")); + Assert.assertEquals("y*cos(x)", Expression.valueOf("∂(t2(x, y), x)").expand().toString()); + Assert.assertEquals("sin(x)", Expression.valueOf("∂(t2(x, y), y)").expand().toString()); + } + + @Test + public void testAntiDerivative() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("t1", Arrays.asList("a"), "sin(a)")); + Assert.assertEquals("1", Expression.valueOf("t1(90)").numeric().toString()); + + + try { + mathEngine.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("-cos(t)", Expression.valueOf("∫(t1(t), t)").expand().toString()); + Assert.assertEquals("t2*sin(t)", Expression.valueOf("∫(t1(t), t2)").expand().toString()); + Assert.assertEquals("-cos(a)", Expression.valueOf("∫(t1(a), a)").expand().toString()); + Assert.assertEquals("1/2*sin(a)^2", Expression.valueOf("∫(t1(a), t1(a))").expand().toString()); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("t2", Arrays.asList("a", "b"), "b*sin(a)")); + Assert.assertEquals("-y*cos(x)", Expression.valueOf("∫(t2(x, y), x)").expand().toString()); + Assert.assertEquals("1/2*y^2*sin(x)", Expression.valueOf("∫(t2(x, y), y)").expand().toString()); + } finally { + mathEngine.setAngleUnits(AngleUnit.deg); + } + } + + + @Test + public void testFunction() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction", Arrays.asList("a", "b", "c", "d"), "b*cos(a)/c+d")); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction(2, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("7.749543120264322", Expression.valueOf("testFunction(2, 3, 4, 7)").numeric().toString()); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 4, 3!)").numeric().toString()); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString()); + Assert.assertEquals("testFunction(2, 3, 4, 3!)", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").simplify().toString()); + Assert.assertEquals("3*cos(2)/4+3!", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").expand().toString()); + Assert.assertEquals("3*(1/2*1/exp(2*i)+1/2*exp(2*i))/4+3!", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)").elementary().toString()); + Assert.assertEquals("sin(t)^2*testFunction(2, 3, 4, 3!)", Expression.valueOf("sin(t)*testFunction(2*1, 3, 2^2-1+e^0, 3!)*sin(t)").simplify().toString()); + Assert.assertEquals("testFunction(2, 3, 4, 3!)^2", Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)*testFunction(2, 3, 4, 3!)").simplify().toString()); + try { + Expression.valueOf("testFunction(2*1, 3, 2^2-1+e^0, 3!)*testFunction(2, 3, 4)"); + Assert.fail(); + } catch (ParseException e) { + // ok, not enough parameters + } + + mathEngine.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("a"), 1000d)); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction2", Arrays.asList("a", "b", "c", "d"), "b*cos(a)/c+d")); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("7.749543120264322", Expression.valueOf("testFunction2(2, 3, 4, 7)").numeric().toString()); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2*1, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("6.749543120264322", Expression.valueOf("testFunction2(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString()); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction3", Arrays.asList("a", "b", "c", "d"), "testFunction2(a, b, c, d) - testFunction(a, b, c, d)")); + Assert.assertEquals("0", Expression.valueOf("testFunction3(2, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("testFunction3(2, 3, 4, 7)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("testFunction3(2*1, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("0", Expression.valueOf("testFunction3(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString()); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction4", Arrays.asList("a", "b", "c", "d"), "testFunction2(a, b/2, c/3, d/4) - testFunction(a, b!, c, d)")); + Assert.assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("-5.624771560132161", Expression.valueOf("testFunction4(2, 3, 4, 7)").numeric().toString()); + Assert.assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2*1, 3, 4, 6)").numeric().toString()); + Assert.assertEquals("-4.874771560132161", Expression.valueOf("testFunction4(2*1, 3, 2^2-1+e^0, 3!)").numeric().toString()); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction5", Arrays.asList("a", "b"), "testFunction2(a, b/2, 2, 1) - testFunction(a, b!, 4!, 1)")); + Assert.assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); + Assert.assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); + Assert.assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2*1, 3)").numeric().toString()); + Assert.assertEquals("-111.02230246251565E-18", Expression.valueOf("testFunction5(2*1, 2^2-1+e^0)").numeric().toString()); + + try { + Expression.valueOf("testFunction5(2, 3.5)").numeric(); + Assert.fail(); + } catch (ArithmeticException e) { + + } + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction6", Arrays.asList("a", "b"), "testFunction(a, b!, 4!, Π)")); + Assert.assertEquals("180.24984770675476", Expression.valueOf("testFunction6(2, 3)").numeric().toString()); + + mathEngine.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("e"), 181d)); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction7", Arrays.asList("a", "b"), "testFunction(a, b!, 4!, e)")); + Assert.assertEquals("181.24984770675476", Expression.valueOf("testFunction7(2, 3)").numeric().toString()); + + mathEngine.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("e"), 181d)); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("testFunction8", Arrays.asList("a", "b"), "testFunction(sin(a), b!, 4!, e)")); + Assert.assertEquals("181.24999995362296", Expression.valueOf("testFunction8(2, 3)").numeric().toString()); + + } + + @Test + public void testFunction2() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("f", Arrays.asList("x", "y"), "z1/z2*√(x^2+y^2)")); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("f2", Arrays.asList("x", "y"), "√(x^2+y^2)")); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("f3", Arrays.asList("x", "y"), "x^2+y^2")); + + try { + Assert.assertEquals("1", Expression.valueOf("f(1, 1)").numeric().toString()); + Assert.fail(); + } catch (ArithmeticException e) { + //ok + } + + Assert.assertEquals("1.4142135623730951", Expression.valueOf("f2(1, 1)").numeric().toString()); + Assert.assertEquals("5", Expression.valueOf("f2(4, 3)").numeric().toString()); + + Assert.assertEquals("2*z1", Expression.valueOf("∂(f3(z1, z2), z1)").expand().toString()); + Assert.assertEquals("2*z2", Expression.valueOf("∂(f3(z1, z2), z2)").expand().toString()); + + // test symbols + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("f4", Arrays.asList("x", "y"), "2 000*x^2+y^2")); + mathEngine.getFunctionsRegistry().add(new CustomFunction.Builder("f5", Arrays.asList("x", "y"), "2'000* x ^2+y^2\r")); + + + } +} diff --git a/jscl/src/test/java/jscl/math/function/DegTest.java b/jscl/src/test/java/jscl/math/function/DegTest.java new file mode 100644 index 00000000..4544e1d6 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/DegTest.java @@ -0,0 +1,33 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import junit.framework.Assert; +import org.junit.Test; +import org.solovyev.common.math.Maths; + +/** + * User: serso + * Date: 11/12/11 + * Time: 4:17 PM + */ +public class DegTest { + + @Test + public void testDeg() throws Exception { + final JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + Assert.assertEquals("2", mathEngine.evaluate("deg(0.03490658503988659)")); + Assert.assertEquals("-2", mathEngine.evaluate("deg(-0.03490658503988659)")); + Assert.assertEquals("180", mathEngine.evaluate("deg(" + String.valueOf(Math.PI) + ")")); + + for (int i = 0; i < 1000; i++) { + double value = Math.random() * 100000; + assertEquals(value, Double.valueOf(mathEngine.evaluate("rad(deg(" + value + "))"))); + assertEquals(value, Double.valueOf(mathEngine.evaluate("deg(rad(" + value + "))"))); + } + } + + private void assertEquals(double expected, Double actual) { + Assert.assertTrue("Expected=" + expected + ", actual=" + actual, Maths.equals(expected, actual, 8)); + } +} diff --git a/jscl/src/test/java/jscl/math/function/DmsTest.java b/jscl/src/test/java/jscl/math/function/DmsTest.java new file mode 100644 index 00000000..2249e429 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/DmsTest.java @@ -0,0 +1,20 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/14/11 + * Time: 1:46 PM + */ +public class DmsTest { + @Test + public void testFunction() throws Exception { + final JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + Assert.assertEquals("43.1025", mathEngine.evaluate("dms(43,6,9)")); + Assert.assertEquals("102.765", mathEngine.evaluate("dms(102, 45, 54)")); + } +} diff --git a/jscl/src/test/java/jscl/math/function/FunctionTest.java b/jscl/src/test/java/jscl/math/function/FunctionTest.java new file mode 100644 index 00000000..458fcfe0 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/FunctionTest.java @@ -0,0 +1,25 @@ +package jscl.math.function; + +import org.junit.Test; + +/** + * User: serso + * Date: 10/29/11 + * Time: 5:20 PM + */ +public class FunctionTest { + + @Test + public void testSubstituteParameter() throws Exception { +/* Ln ln = new Ln(null); + Assert.assertEquals("ln(x)", ln.toString()); + Root eq = new Root(null, null); + Assert.assertEquals("eq(x, y)", eq.toString()); + Generic[] parameter = new Generic[40]; + for(int i = 0; i < 40; i++) { + parameter[i] = null; + } + eq.setParameters(parameter); + Assert.assertEquals("root(x, y, z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a, b, c, d, e, f, g, h, i, j, k)", eq.toString());*/ + } +} diff --git a/jscl/src/test/java/jscl/math/function/FunctionsRegistryTest.java b/jscl/src/test/java/jscl/math/function/FunctionsRegistryTest.java new file mode 100644 index 00000000..035f3668 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/FunctionsRegistryTest.java @@ -0,0 +1,23 @@ +package jscl.math.function; + +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/12/11 + * Time: 2:14 PM + */ +public class FunctionsRegistryTest { + + @Test + public void testOrder() throws Exception { + Function prev = null; + for (Function function : FunctionsRegistry.getInstance().getEntities()) { + if (prev != null) { + Assert.assertTrue(prev.getName() + "<" + function.getName(), prev.getName().length() >= function.getName().length()); + } + prev = function; + } + } +} diff --git a/jscl/src/test/java/jscl/math/function/LgTest.java b/jscl/src/test/java/jscl/math/function/LgTest.java new file mode 100644 index 00000000..3d648999 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/LgTest.java @@ -0,0 +1,20 @@ +package jscl.math.function; + +import jscl.math.Expression; +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + +/** + * User: serso + * Date: 6/15/13 + * Time: 12:52 AM + */ +public class LgTest { + + @Test + public void testSimplify() throws Exception { + assertEquals("lg(3)+lg(x/b)", Expression.valueOf("lg(3*x/b)").simplify().toString()); + assertEquals("-lg(7)+lg(15)", Expression.valueOf("lg(3*5/7)").simplify().toString()); + } +} diff --git a/jscl/src/test/java/jscl/math/function/LnTest.java b/jscl/src/test/java/jscl/math/function/LnTest.java new file mode 100644 index 00000000..074691d9 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/LnTest.java @@ -0,0 +1,39 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import jscl.MathEngine; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * User: serso + * Date: 1/9/12 + * Time: 6:49 PM + */ +public class LnTest { + + @Test + public void testConjugate() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + assertEquals("ln(5-i)", me.simplify("conjugate(ln(5+√(-1)))")); + assertEquals("lg(5-i)", me.simplify("conjugate(lg(5+√(-1)))")); + } + + @Test + public void testAntiDerivative() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + assertEquals("-x+x*ln(x)", me.simplify("∫(ln(x), x)")); + assertEquals("-(x-x*ln(x))/(ln(2)+ln(5))", me.simplify("∫(lg(x), x)")); + } + + @Test + public void testDerivative() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + assertEquals("1/x", me.simplify("∂(ln(x), x)")); + assertEquals("1/(x*ln(2)+x*ln(5))", me.simplify("∂(lg(x), x)")); + } +} diff --git a/jscl/src/test/java/jscl/math/function/PowTest.java b/jscl/src/test/java/jscl/math/function/PowTest.java new file mode 100644 index 00000000..587a3231 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/PowTest.java @@ -0,0 +1,29 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import jscl.math.Expression; +import jscl.math.JsclInteger; +import org.junit.Test; + +import static junit.framework.Assert.fail; + +/** + * User: serso + * Date: 6/15/13 + * Time: 10:13 PM + */ +public class PowTest { + + @Test + public void testPow() throws Exception { + JsclMathEngine me = JsclMathEngine.getInstance(); + + new Pow(Expression.valueOf("10"), new Inverse(JsclInteger.valueOf(10l)).expressionValue()).rootValue(); + try { + new Pow(Expression.valueOf("10"), new Inverse(JsclInteger.valueOf(10000000000l)).expressionValue()).rootValue(); + fail(); + } catch (NotRootException e) { + // ok + } + } +} diff --git a/jscl/src/test/java/jscl/math/function/RadTest.java b/jscl/src/test/java/jscl/math/function/RadTest.java new file mode 100644 index 00000000..cbafa4e4 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/RadTest.java @@ -0,0 +1,34 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/12/11 + * Time: 4:00 PM + */ +public class RadTest { + @Test + public void testRad() throws Exception { + final JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + Assert.assertEquals("0.03490658503988659", mathEngine.evaluate("rad(2)")); + Assert.assertEquals("0.03490658503988659", mathEngine.evaluate("rad(1+1)")); + Assert.assertEquals("-0.03490658503988659", mathEngine.evaluate("rad(-2)")); + Assert.assertEquals("-0.03490658503988659", mathEngine.evaluate("rad(-1-1)")); + Assert.assertEquals("π", mathEngine.evaluate("rad(180)")); + Assert.assertEquals(String.valueOf(-Math.PI), mathEngine.evaluate("rad(-180)")); + + // todo serso: think about zeroes + Assert.assertEquals("rad(-180, 0, 0)", mathEngine.simplify("rad(-180)")); + Assert.assertEquals("rad(2, 0, 0)", mathEngine.simplify("rad(1+1)")); + + Assert.assertEquals("rad(-180, 0, 0)", mathEngine.elementary("rad(-180)")); + Assert.assertEquals("rad(2, 0, 0)", mathEngine.elementary("rad(1+1)")); + + Assert.assertEquals(mathEngine.evaluate("rad(43.1025)"), mathEngine.evaluate("rad(43,6,9)")); + Assert.assertEquals(mathEngine.evaluate("rad(102.765)"), mathEngine.evaluate("rad(102, 45, 54)")); + } +} diff --git a/jscl/src/test/java/jscl/math/function/SgnTest.java b/jscl/src/test/java/jscl/math/function/SgnTest.java new file mode 100644 index 00000000..29463b4c --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/SgnTest.java @@ -0,0 +1,25 @@ +package jscl.math.function; + +import jscl.JsclMathEngine; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 2/10/12 + * Time: 9:35 PM + */ +public class SgnTest { + + @Test + public void testSgn() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + + Assert.assertEquals("1", me.evaluate("sgn(10)")); + Assert.assertEquals("1", me.evaluate("sgn(0.5)")); + Assert.assertEquals("0", me.evaluate("sgn(0)")); + Assert.assertEquals("0", me.evaluate("sgn(-0)")); + Assert.assertEquals("-1", me.evaluate("sgn(-1)")); + Assert.assertEquals("-1", me.evaluate("sgn(-10)")); + } +} diff --git a/jscl/src/test/java/jscl/math/function/SqrtTest.java b/jscl/src/test/java/jscl/math/function/SqrtTest.java new file mode 100644 index 00000000..ace8e26f --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/SqrtTest.java @@ -0,0 +1,31 @@ +package jscl.math.function; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 5/14/12 + * Time: 1:15 PM + */ +public class SqrtTest { + + @Test + public void testNumeric() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + final AngleUnit defaultAngleUnits = me.getAngleUnits(); + + Assert.assertEquals("0.9999060498015505+0.013707354604707477*i", me.evaluate("√(√(-1))")); + Assert.assertEquals("0.9984971498638638+0.05480366514878954*i", me.evaluate("√(√(-1))^4")); + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("0.7071067811865476+0.7071067811865475*i", me.evaluate("√(√(-1))")); + Assert.assertEquals("-1+277.55575615628914E-18*i", me.evaluate("√(√(-1))^4")); + } finally { + me.setAngleUnits(defaultAngleUnits); + } + } +} diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java new file mode 100644 index 00000000..a969856b --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java @@ -0,0 +1,27 @@ +package jscl.math.function.trigonometric; + +import jscl.JsclMathEngine; +import jscl.math.function.Constant; +import jscl.math.function.ExtendedConstant; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 6/17/13 + * Time: 10:36 PM + */ +public class CosTest { + + @Test + public void testIntegral() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("t"), 10d)); + Assert.assertEquals("-sin(t)", me.simplify("∂(cos(t),t,t,1)")); + Assert.assertEquals("∂(cos(t), t, t, 1°)", me.simplify("∂(cos(t),t,t,1°)")); + Assert.assertEquals("-0.17364817766693033", me.evaluate("∂(cos(t),t,t,1)")); + Assert.assertEquals("∂(cos(t), t, t, 1°)", me.evaluate("∂(cos(t),t,t,1°)")); + Assert.assertEquals("-0.17364817766693033", me.evaluate("∂(cos(t),t,t,2-1)")); + Assert.assertEquals("-0.17364817766693033", me.evaluate("∂(cos(t),t,t,2^5-31)")); + } +} diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java new file mode 100644 index 00000000..02c07ce2 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java @@ -0,0 +1,46 @@ +package jscl.math.function.trigonometric; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 1/7/12 + * Time: 3:51 PM + */ +public class SinTest { + + @Test + public void testIntegrate() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + + // todo serso: uncomment after variable modification issue fixed + /*Assert.assertEquals("-cos(x)", me.simplify("∫(sin(x), x)")); + Assert.assertEquals("-cos(x*π)/π", me.simplify("∫(sin(π*x), x)")); + + Assert.assertEquals("1.0", me.evaluate("cos(0)")); + Assert.assertEquals("0.8660254037844387", me.evaluate("cos(30)")); + Assert.assertEquals("0.1339745962155613", me.evaluate("∫ab(sin(x), x, 0, 30)"));*/ + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("0.5403023058681398", me.evaluate("cos(1)")); + Assert.assertEquals("0.3623577544766736", me.evaluate("cos(1.2)")); + Assert.assertEquals("0.17794455139146614", me.evaluate("∫ab(sin(x), x, 1, 1.2)")); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + + + //Assert.assertEquals("7.676178925", me.evaluate("∫ab(sin(x), x, 0, 30°)")); + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("0.1339745962155613", me.evaluate("∫ab(sin(x), x, 0, 30°)")); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + } +} diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java new file mode 100644 index 00000000..9c79b535 --- /dev/null +++ b/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java @@ -0,0 +1,58 @@ +package jscl.math.function.trigonometric; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * User: serso + * Date: 1/7/12 + * Time: 4:03 PM + */ +public class TanTest { + + @Test + public void testIntegrate() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + + // todo serso: uncomment after variable modification issue fixed +/* Assert.assertEquals("-2*ln(2)-ln(cos(x))", me.simplify("∫(tan(x), x)")); + Assert.assertEquals("-(2*ln(2)+ln(cos(x*π)))/π", me.simplify("∫(tan(π*x), x)")); + + Assert.assertEquals("-0.015308831465985804", me.evaluate("ln(cos(10))")); + Assert.assertEquals("-0.1438410362258904", me.evaluate("ln(cos(30))")); + Assert.assertEquals("0.12853220475990468", me.evaluate("∫ab(tan(x), x, 10, 30)"));*/ + + try { + me.setAngleUnits(AngleUnit.rad); + assertEquals("-2*ln(2)-ln(cos(x))", me.simplify("∫(tan(x), x)")); + assertEquals("-(2*ln(2)+ln(cos(x*π)))/π", me.simplify("∫(tan(π*x), x)")); + assertEquals("-0.015308831465985804", me.evaluate("ln(cos(10*π/180))")); + assertEquals("-0.1438410362258904", me.evaluate("ln(cos(30*π/180))")); + assertEquals("0.12853220475990468", me.evaluate("∫ab(tan(x), x, 10*π/180, 30*π/180)")); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + } + + @Test + public void testBoundaryConditions() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + assertEquals("-∞", me.evaluate("tan(-450)")); + assertEquals("0", me.evaluate("tan(-360)")); + assertEquals("-∞", me.evaluate("tan(-270)")); + assertEquals("0", me.evaluate("tan(-180)")); + assertEquals("-∞", me.evaluate("tan(-90)")); + assertEquals("0", me.evaluate("tan(0)")); + assertEquals("∞", me.evaluate("tan(180/2)")); + assertEquals("∞", me.evaluate("tan(45 + 45)")); + assertEquals("∞", me.evaluate("tan(30*3)")); + assertEquals("∞", me.evaluate("tan(90)")); + assertEquals("0", me.evaluate("tan(180)")); + assertEquals("∞", me.evaluate("tan(270)")); + assertEquals("0", me.evaluate("tan(360)")); + assertEquals("∞", me.evaluate("tan(450)")); + } +} diff --git a/jscl/src/test/java/jscl/math/numeric/ComplexTest.java b/jscl/src/test/java/jscl/math/numeric/ComplexTest.java new file mode 100644 index 00000000..828aa1a1 --- /dev/null +++ b/jscl/src/test/java/jscl/math/numeric/ComplexTest.java @@ -0,0 +1,37 @@ +package jscl.math.numeric; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.math.Expression; +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + +/** + * User: serso + * Date: 5/14/12 + * Time: 2:24 PM + */ +public class ComplexTest { + + @Test + public void testSmallImag() throws Exception { + assertEquals("1+100E-18*i", Complex.valueOf(1, 0.0000000000000001).toString()); + assertEquals("1-100E-18*i", Complex.valueOf(1, -0.0000000000000001).toString()); + } + + @Test + public void testTrig() throws Exception { + try { + JsclMathEngine.getInstance().setAngleUnits(AngleUnit.rad); + assertEquals("1.543080634815244", Expression.valueOf("cos(i)").numeric().toString()); + assertEquals("1.1752011936438014*i", Expression.valueOf("sin(i)").numeric().toString()); + assertEquals("11013.232874703395*i", Expression.valueOf("sin(10*i)").numeric().toString()); + assertEquals("11013.232920103324", Expression.valueOf("cos(10*i)").numeric().toString()); + assertEquals("0.46211715726000974*i", Expression.valueOf("tan(i/2)").numeric().toString()); + assertEquals("-2.163953413738653*i", Expression.valueOf("cot(i/2)").numeric().toString()); + } finally { + JsclMathEngine.getInstance().setAngleUnits(JsclMathEngine.DEFAULT_ANGLE_UNITS); + } + } +} diff --git a/jscl/src/test/java/jscl/math/numeric/MatrixTest.java b/jscl/src/test/java/jscl/math/numeric/MatrixTest.java new file mode 100644 index 00000000..4b15522d --- /dev/null +++ b/jscl/src/test/java/jscl/math/numeric/MatrixTest.java @@ -0,0 +1,16 @@ +package jscl.math.numeric; + +import org.junit.Test; + +/** + * User: serso + * Date: 1/15/12 + * Time: 4:08 PM + */ +public class MatrixTest { + + @Test + public void testMatrix() throws Exception { + //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/jscl/src/test/java/jscl/math/operator/DoubleFactorialTest.java b/jscl/src/test/java/jscl/math/operator/DoubleFactorialTest.java new file mode 100644 index 00000000..f0c4c8e1 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/DoubleFactorialTest.java @@ -0,0 +1,63 @@ +package jscl.math.operator; + +import jscl.JsclMathEngine; +import jscl.MathEngine; +import jscl.text.ParseException; +import jscl.text.msg.Messages; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 12/15/11 + * Time: 10:41 PM + */ +public class DoubleFactorialTest { + + @Test + public void testDoubleFactorial() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + Assert.assertEquals("1", me.evaluate("0!")); + Assert.assertEquals("1", me.evaluate("1!")); + Assert.assertEquals("2", me.evaluate("2!")); + Assert.assertEquals("6", me.evaluate("3!")); + Assert.assertEquals("24", me.evaluate("4!")); + + try { + me.evaluate("(-1)!!"); + Assert.fail(); + } catch (ArithmeticException e) { + // ok + } + + Assert.assertEquals("-1", me.evaluate("-1!!")); + Assert.assertEquals("1", me.evaluate("0!!")); + Assert.assertEquals("1", me.evaluate("1!!")); + Assert.assertEquals("2", me.evaluate("2!!")); + Assert.assertEquals("2", me.evaluate("(2!!)!")); + Assert.assertEquals("2", me.evaluate("(2!)!!")); + Assert.assertEquals("3", me.evaluate("3!!")); + Assert.assertEquals("48", me.evaluate("(3!)!!")); + Assert.assertEquals("6", me.evaluate("(3!!)!")); + Assert.assertEquals("8", me.evaluate("4!!")); + Assert.assertEquals("15", me.evaluate("5!!")); + Assert.assertEquals("48", me.evaluate("6!!")); + Assert.assertEquals("105", me.evaluate("7!!")); + Assert.assertEquals("384", me.evaluate("8!!")); + Assert.assertEquals("945", me.evaluate("9!!")); + + try { + me.evaluate("9!!!"); + Assert.fail(); + } catch (ParseException e) { + if (Messages.msg_18.equals(e.getMessageCode())) { + // ok + } else { + Assert.fail(); + } + } + + + } +} diff --git a/jscl/src/test/java/jscl/math/operator/GcdTest.java b/jscl/src/test/java/jscl/math/operator/GcdTest.java new file mode 100644 index 00000000..d525584a --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/GcdTest.java @@ -0,0 +1,26 @@ +package jscl.math.operator; + +import jscl.JsclMathEngine; +import org.junit.Test; + +/** + * User: serso + * Date: 12/23/11 + * Time: 4:52 PM + */ +public class GcdTest { + @Test + public void testNumeric() throws Exception { + JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + //mathEngine.getOperatorsRegistry().add(new Gcd()); + + + //Assert.assertEquals("1", Expression.valueOf("gcd(1, 1)").numeric().toString()); + //Assert.assertEquals("1", Expression.valueOf("gcd(2, 1)").numeric().toString()); + //Assert.assertEquals("2", Expression.valueOf("gcd(2, 4)").numeric().toString()); + //Assert.assertEquals("4", Expression.valueOf("gcd(4, 8)").numeric().toString()); + //Assert.assertEquals("4", Expression.valueOf("gcd(4.0, 8.0)").numeric().toString()); + //Assert.assertEquals("4", Expression.valueOf("gcd(8, 4)").numeric().toString()); + } +} diff --git a/jscl/src/test/java/jscl/math/operator/IndefiniteIntegralTest.java b/jscl/src/test/java/jscl/math/operator/IndefiniteIntegralTest.java new file mode 100644 index 00000000..e3eeb325 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/IndefiniteIntegralTest.java @@ -0,0 +1,41 @@ +package jscl.math.operator; + +import jscl.AngleUnit; +import jscl.JsclMathEngine; +import jscl.MathEngine; +import jscl.math.Expression; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 1/14/12 + * Time: 1:06 PM + */ +public class IndefiniteIntegralTest { + + @Test + public void testIntegral() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + try { + Assert.assertEquals("∫(sin(t!), t)", me.evaluate("∫(sin(t!), t)")); + Assert.fail(); + } catch (ArithmeticException e) { + // ok + } + + try { + me.setAngleUnits(AngleUnit.rad); + Assert.assertEquals("-cos(t)", Expression.valueOf("∫(sin(t), t)").expand().toString()); + Assert.assertEquals("∫(sin(t!), t)", Expression.valueOf("∫(sin(t!), t)").expand().toString()); + Assert.assertEquals("∫(sin(t!), t)", me.simplify("∫(sin(t!), t)")); + Assert.assertEquals("∫(sin(t°), t)", Expression.valueOf("∫(sin(t°), t)").expand().toString()); + Assert.assertEquals("∫(sin(t°), t)", me.simplify("∫(sin(t°), t)")); + } finally { + me.setAngleUnits(AngleUnit.deg); + } + + + } +} diff --git a/jscl/src/test/java/jscl/math/operator/MeanTest.java b/jscl/src/test/java/jscl/math/operator/MeanTest.java new file mode 100644 index 00000000..e3026b27 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/MeanTest.java @@ -0,0 +1,34 @@ +package jscl.math.operator; + +import org.junit.Test; + +/** + * User: serso + * Date: 12/26/11 + * Time: 11:15 AM + */ +public class MeanTest { + + @Test + public void testEvaluate() throws Exception { + /*MathEngine me = JsclMathEngine.instance; + try { + me.evaluate("mean()"); + Assert.fail(); + } catch (ParseException e) { + // ok + } + + Assert.assertEquals("0", me.evaluate("mean([0])")); + Assert.assertEquals("5.0", me.evaluate("mean([10, 0])")); + Assert.assertEquals("100+mean([10, 0]%)", me.evaluate("100 + mean([10, 0]%)")); + Assert.assertEquals("105.0", me.evaluate("100 + mean([10, 0])")); + Assert.assertEquals("105.0", me.evaluate("100 + mean([10, 0])%")); + Assert.assertEquals("10", me.evaluate("mean([10])")); + Assert.assertEquals("15.0", me.evaluate("mean([10, 20])")); + Assert.assertEquals("0.5602494390798607", me.evaluate("mean([sin(7), cos(3)])")); + Assert.assertEquals("0.5", me.evaluate("mean([1, 0])")); + Assert.assertEquals("0.8", me.evaluate("mean([1, 0, 1, 1, 1])")); + Assert.assertEquals("0.8", me.evaluate("mean([0.5+mean([1, 0]), 0, sin(90), 1, 1])"));*/ + } +} diff --git a/jscl/src/test/java/jscl/math/operator/PercentTest.java b/jscl/src/test/java/jscl/math/operator/PercentTest.java new file mode 100644 index 00000000..9fdccafb --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/PercentTest.java @@ -0,0 +1,82 @@ +package jscl.math.operator; + +import jscl.JsclMathEngine; +import jscl.text.ParseException; +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/14/11 + * Time: 2:10 PM + */ +public class PercentTest { + + @Test + public void testNumeric() throws Exception { + final JsclMathEngine mathEngine = JsclMathEngine.getInstance(); + + Assert.assertEquals("150", mathEngine.evaluate("100+50%")); + Assert.assertEquals("0", mathEngine.evaluate("100-100%")); + Assert.assertEquals("50", mathEngine.evaluate("100*50%")); + Assert.assertEquals("150", mathEngine.evaluate("100+100*50%")); + Assert.assertEquals("125", mathEngine.evaluate("100+100*50%*50%")); + Assert.assertEquals("125", mathEngine.evaluate("100+100*50%*(25+25)%")); + Assert.assertEquals("250", mathEngine.evaluate("100+100*50%*(25+25)%+100%")); + Assert.assertEquals("150", mathEngine.evaluate("100+(100*50%*(25+25)%+100%)")); + Assert.assertEquals("140", mathEngine.evaluate("100+(20+20)%")); + // todo serso: think about such behaviour + Assert.assertEquals("124", mathEngine.evaluate("100+(20%+20%)")); + + Assert.assertEquals("100+50%-50%", mathEngine.simplify("100+50%-50%")); + + Assert.assertEquals("100+(100*50%*(50)%+100%)", mathEngine.simplify("100+(100*50%*(25+25)%+100%)")); + + + Assert.assertEquals("450", mathEngine.evaluate("((100+100*50%)+50%)*200%")); + Assert.assertEquals("150", mathEngine.evaluate("((100+100*50%)*50%)+100%")); + Assert.assertEquals("150", mathEngine.evaluate("100*50%+100")); + Assert.assertEquals("75", mathEngine.evaluate("100+50%-50%")); + Assert.assertEquals("75", mathEngine.evaluate("100+50%+(-50%)")); + Assert.assertEquals("0", mathEngine.evaluate("0+(-50%)")); + Assert.assertEquals("0", mathEngine.evaluate("0+(50%)")); + Assert.assertEquals("0", mathEngine.evaluate("0+50%")); + Assert.assertEquals("-150", mathEngine.evaluate("-100+50%")); + Assert.assertEquals("-148.5", mathEngine.evaluate("1-100+50%")); + Assert.assertEquals("-49.5", mathEngine.evaluate("1-100-50%")); + Assert.assertEquals("-49.5", mathEngine.evaluate("(1-100)-50%")); + Assert.assertEquals("-49", mathEngine.evaluate("1-(100-50%)")); + Assert.assertEquals("50", mathEngine.evaluate("100-50%")); + Assert.assertEquals("2600", mathEngine.evaluate("100+50%^2")); + Assert.assertEquals("101.08138265680029", mathEngine.evaluate("100+50^2%")); + Assert.assertEquals("22500", mathEngine.evaluate("(100+50%)^2")); + Assert.assertEquals("225", mathEngine.evaluate("(100+50%)+50%")); + Assert.assertEquals("225", mathEngine.evaluate("(100+50%)+(abs(-50)+10-10)%")); + + Assert.assertEquals("0", mathEngine.evaluate("100-(10+2*40+10)%")); + Assert.assertEquals("3", mathEngine.evaluate("100-(10+2*40+10)%+3")); + + Assert.assertEquals("0", mathEngine.evaluate("100-(200/2)%")); + Assert.assertEquals("3", mathEngine.evaluate("100-(200/2)%+3")); + + Assert.assertEquals("99", mathEngine.evaluate("100-2*50%")); + Assert.assertEquals("102", mathEngine.evaluate("100-2*50%+3")); + + Assert.assertEquals("84", mathEngine.evaluate("20+2^3!")); + Assert.assertEquals("21.0471285480509", mathEngine.evaluate("20+10^2%")); + Assert.assertEquals("20.48", mathEngine.evaluate("20+4!*2%")); + + Assert.assertEquals("120", mathEngine.evaluate("100-20+50%")); + + try { + mathEngine.evaluate("+50%"); + Assert.fail(); + } catch (ParseException e) { + } + + Assert.assertEquals("0.5", mathEngine.evaluate("50%")); + Assert.assertEquals("-0.5", mathEngine.evaluate("-50%")); + Assert.assertEquals("225", mathEngine.evaluate("(100+50%)+50%")); + + } +} diff --git a/jscl/src/test/java/jscl/math/operator/RandTest.java b/jscl/src/test/java/jscl/math/operator/RandTest.java new file mode 100644 index 00000000..9a017a62 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/RandTest.java @@ -0,0 +1,26 @@ +package jscl.math.operator; + +import jscl.math.Expression; +import jscl.text.ParseException; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 12/26/11 + * Time: 9:56 AM + */ +public class RandTest { + + @Test + public void testRand() throws Exception { + /*testRandString("rand()-rand()"); + testRandString("rand()*rand()"); + testRandString("rand()^2"); + testRandString("rand()/rand()");*/ + } + + private void testRandString(final String expression) throws ParseException { + Assert.assertEquals(expression, Expression.valueOf(expression).toString()); + } +} diff --git a/jscl/src/test/java/jscl/math/operator/SumTest.java b/jscl/src/test/java/jscl/math/operator/SumTest.java new file mode 100644 index 00000000..540b61d0 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/SumTest.java @@ -0,0 +1,24 @@ +package jscl.math.operator; + +import jscl.JsclMathEngine; +import jscl.math.function.Constant; +import jscl.math.function.ExtendedConstant; +import org.junit.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 1/30/12 + * Time: 4:17 PM + */ +public class SumTest { + + @Test + public void testExp() throws Exception { + final JsclMathEngine me = JsclMathEngine.getInstance(); + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("x"), 2d)); + me.getConstantsRegistry().add(new ExtendedConstant.Builder(new Constant("i"), (String) null)); + Assert.assertEquals("51.735296462438285", me.evaluate("Σ((1+x/i)^i, i, 1, 10)")); + Assert.assertEquals("686.0048440525586", me.evaluate("Σ((1+x/i)^i, i, 1, 100)")); + } +} diff --git a/jscl/src/test/java/jscl/math/operator/stat/MinTest.java b/jscl/src/test/java/jscl/math/operator/stat/MinTest.java new file mode 100644 index 00000000..16f6a554 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/stat/MinTest.java @@ -0,0 +1,20 @@ +package jscl.math.operator.stat; + +import jscl.JsclMathEngine; +import jscl.MathEngine; +import org.junit.Test; + +/** + * User: serso + * Date: 1/15/12 + * Time: 5:03 PM + */ +public class MinTest { + + @Test + public void testFunction() throws Exception { + final MathEngine me = JsclMathEngine.getInstance(); + + + } +} diff --git a/jscl/src/test/java/jscl/math/operator/stat/StandardDeviationTest.java b/jscl/src/test/java/jscl/math/operator/stat/StandardDeviationTest.java new file mode 100644 index 00000000..eb9ba681 --- /dev/null +++ b/jscl/src/test/java/jscl/math/operator/stat/StandardDeviationTest.java @@ -0,0 +1,16 @@ +package jscl.math.operator.stat; + +import org.junit.Test; + +/** + * User: serso + * Date: 1/15/12 + * Time: 5:17 PM + */ +public class StandardDeviationTest { + + @Test + public void testFunction() throws Exception { + //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/jscl/src/test/java/jscl/text/ParserUtilsTest.java b/jscl/src/test/java/jscl/text/ParserUtilsTest.java new file mode 100644 index 00000000..3736a0c7 --- /dev/null +++ b/jscl/src/test/java/jscl/text/ParserUtilsTest.java @@ -0,0 +1,27 @@ +package jscl.text; + +import junit.framework.Assert; +import org.junit.Test; + +/** + * User: serso + * Date: 11/19/11 + * Time: 7:22 PM + */ +public class ParserUtilsTest { + @Test + public void testCopyOf() throws Exception { + final Integer[] array = new Integer[]{1, 2, 3, 7}; + final Integer[] copy = ParserUtils.copyOf(array); + + Assert.assertEquals(array.length, copy.length); + Assert.assertEquals(array[0], copy[0]); + Assert.assertEquals(array[1], copy[1]); + Assert.assertEquals(array[2], copy[2]); + Assert.assertEquals(array[3], copy[3]); + + copy[3] = 12; + Assert.assertFalse(array[3].equals(copy[3])); + + } +} diff --git a/jscl/src/test/java/jscl/text/PowerParserTest.java b/jscl/src/test/java/jscl/text/PowerParserTest.java new file mode 100644 index 00000000..aea21b2e --- /dev/null +++ b/jscl/src/test/java/jscl/text/PowerParserTest.java @@ -0,0 +1,27 @@ +package jscl.text; + +import jscl.JsclMathEngine; +import org.junit.Assert; + +/** + * User: serso + * Date: 10/27/11 + * Time: 3:45 PM + */ +public class PowerParserTest { + + @org.junit.Test + public void testParse() throws Exception { + PowerParser.parser.parse(Parser.Parameters.newInstance(" ^", new MutableInt(0), JsclMathEngine.getInstance()), null); + PowerParser.parser.parse(Parser.Parameters.newInstance(" **", new MutableInt(0), JsclMathEngine.getInstance()), null); + PowerParser.parser.parse(Parser.Parameters.newInstance(" **7", new MutableInt(0), JsclMathEngine.getInstance()), null); + PowerParser.parser.parse(Parser.Parameters.newInstance("^", new MutableInt(0), JsclMathEngine.getInstance()), null); + PowerParser.parser.parse(Parser.Parameters.newInstance("**", new MutableInt(0), JsclMathEngine.getInstance()), null); + try { + PowerParser.parser.parse(Parser.Parameters.newInstance("*", new MutableInt(0), JsclMathEngine.getInstance()), null); + Assert.fail(); + } catch (ParseException e) { + + } + } +} diff --git a/jscl/src/test/java/jscl/text/msg/JsclMessageTest.java b/jscl/src/test/java/jscl/text/msg/JsclMessageTest.java new file mode 100644 index 00000000..204ff028 --- /dev/null +++ b/jscl/src/test/java/jscl/text/msg/JsclMessageTest.java @@ -0,0 +1,87 @@ +package jscl.text.msg; + +import org.junit.Test; +import org.solovyev.common.msg.MessageType; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import static java.util.Locale.ENGLISH; +import static jscl.text.msg.Messages.msg_1; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.solovyev.common.msg.MessageType.error; + +/** + * User: serso + * Date: 11/30/11 + * Time: 9:53 PM + */ +public class JsclMessageTest { + + private static final Locale[] LOCALES = new Locale[]{ + Locale.ENGLISH, new Locale("ar"), new Locale("cs"), new Locale("de"), new Locale("es", "ES"), new Locale("fi"), new Locale("fr"), new Locale("it"), new Locale("ja"), new Locale("nl"), new Locale("pl"), new Locale("pt", "BR"), new Locale("pt", "PT"), + new Locale("ru"), new Locale("uk"), new Locale("vi"), new Locale("zh", "CN"), new Locale("zh", "TW") + }; + + @Test + public void testTranslation() throws Exception { + String localizedMessage = new JsclMessage(msg_1, error).getLocalizedMessage(ENGLISH); + assertTrue(localizedMessage.startsWith("Parsing error ")); + } + + @Test + public void testShouldContainPolishStrings() throws Exception { + String localizedMessage = new JsclMessage(msg_1, error).getLocalizedMessage(new Locale("pl", "PL")); + assertTrue(localizedMessage.startsWith("Wystąpił błąd ")); + } + + @Test + public void testAllMessages() throws Exception { + for (int i = 0; i < Messages.COUNT; i++) { + final String id = "msg_" + i; + final List<String> arguments = makeMessageArguments(i); + final JsclMessage message = new JsclMessage(id, MessageType.info, arguments); + for (Locale locale : LOCALES) { + final String text = message.getLocalizedMessage(locale); + assertFalse(text.isEmpty()); + if (arguments.size() == 1) { + assertTrue(text.contains("param0")); + } else if (arguments.size() == 2) { + assertTrue(text.contains("param1")); + assertTrue(text.contains("param2")); + } + } + + } + + } + + @Nonnull + private List<String> makeMessageArguments(int i) { + switch (i) { + case 0: + case 10: + case 19: + return Arrays.asList("param1", "param2"); + case 1: + case 2: + case 3: + case 4: + case 6: + case 8: + case 11: + case 12: + case 13: + case 14: + case 17: + case 20: + case 21: + return Arrays.asList("param0"); + } + return Collections.emptyList(); + } +} diff --git a/jscl/src/test/java/org/solovyev/common/math/AbstractMathRegistryTest.java b/jscl/src/test/java/org/solovyev/common/math/AbstractMathRegistryTest.java new file mode 100644 index 00000000..163fa70e --- /dev/null +++ b/jscl/src/test/java/org/solovyev/common/math/AbstractMathRegistryTest.java @@ -0,0 +1,34 @@ +package org.solovyev.common.math; + +import org.junit.Test; +import org.solovyev.common.JBuilder; + +import javax.annotation.Nonnull; + +import static org.junit.Assert.assertEquals; + +/** + * User: serso + * Date: 6/15/13 + * Time: 9:20 PM + */ +public abstract class AbstractMathRegistryTest<T extends MathEntity> { + + @Test + public void testAdd() throws Exception { + final AbstractMathRegistry<T> registry = getRegistry(); + + final int oldSize = registry.getEntities().size(); + + registry.add(createBuilder("test")); + registry.add(createBuilder("test")); + registry.add(createBuilder("test1")); + + assertEquals(2, registry.getEntities().size() - oldSize); + } + + protected abstract JBuilder<? extends T> createBuilder(@Nonnull String name); + + @Nonnull + protected abstract AbstractMathRegistry<T> getRegistry(); +} diff --git a/jscl/src/test/resources/jscl/math/nb_table.csv b/jscl/src/test/resources/jscl/math/nb_table.csv new file mode 100644 index 00000000..98a0ed23 --- /dev/null +++ b/jscl/src/test/resources/jscl/math/nb_table.csv @@ -0,0 +1,257 @@ +dec hex bin +0 0 0 +1 1 1 +2 2 10 +3 3 11 +4 4 100 +5 5 101 +6 6 110 +7 7 111 +8 8 1000 +9 9 1001 +10 a 1010 +11 b 1011 +12 c 1100 +13 d 1101 +14 e 1110 +15 f 1111 +16 10 10000 +17 11 10001 +18 12 10010 +19 13 10011 +20 14 10100 +21 15 10101 +22 16 10110 +23 17 10111 +24 18 11000 +25 19 11001 +26 1a 11010 +27 1b 11011 +28 1c 11100 +29 1d 11101 +30 1e 11110 +31 1f 11111 +32 20 100000 +33 21 100001 +34 22 100010 +35 23 100011 +36 24 100100 +37 25 100101 +38 26 100110 +39 27 100111 +40 28 101000 +41 29 101001 +42 2a 101010 +43 2b 101011 +44 2c 101100 +45 2d 101101 +46 2e 101110 +47 2f 101111 +48 30 110000 +49 31 110001 +50 32 110010 +51 33 110011 +52 34 110100 +53 35 110101 +54 36 110110 +55 37 110111 +56 38 111000 +57 39 111001 +58 3a 111010 +59 3b 111011 +60 3c 111100 +61 3d 111101 +62 3e 111110 +63 3f 111111 +64 40 1000000 +65 41 1000001 +66 42 1000010 +67 43 1000011 +68 44 1000100 +69 45 1000101 +70 46 1000110 +71 47 1000111 +72 48 1001000 +73 49 1001001 +74 4a 1001010 +75 4b 1001011 +76 4c 1001100 +77 4d 1001101 +78 4e 1001110 +79 4f 1001111 +80 50 1010000 +81 51 1010001 +82 52 1010010 +83 53 1010011 +84 54 1010100 +85 55 1010101 +86 56 1010110 +87 57 1010111 +88 58 1011000 +89 59 1011001 +90 5a 1011010 +91 5b 1011011 +92 5c 1011100 +93 5d 1011101 +94 5e 1011110 +95 5f 1011111 +96 60 1100000 +97 61 1100001 +98 62 1100010 +99 63 1100011 +100 64 1100100 +101 65 1100101 +102 66 1100110 +103 67 1100111 +104 68 1101000 +105 69 1101001 +106 6a 1101010 +107 6b 1101011 +108 6c 1101100 +109 6d 1101101 +110 6e 1101110 +111 6f 1101111 +112 70 1110000 +113 71 1110001 +114 72 1110010 +115 73 1110011 +116 74 1110100 +117 75 1110101 +118 76 1110110 +119 77 1110111 +120 78 1111000 +121 79 1111001 +122 7a 1111010 +123 7b 1111011 +124 7c 1111100 +125 7d 1111101 +126 7e 1111110 +127 7f 1111111 +128 80 10000000 +129 81 10000001 +130 82 10000010 +131 83 10000011 +132 84 10000100 +133 85 10000101 +134 86 10000110 +135 87 10000111 +136 88 10001000 +137 89 10001001 +138 8a 10001010 +139 8b 10001011 +140 8c 10001100 +141 8d 10001101 +142 8e 10001110 +143 8f 10001111 +144 90 10010000 +145 91 10010001 +146 92 10010010 +147 93 10010011 +148 94 10010100 +149 95 10010101 +150 96 10010110 +151 97 10010111 +152 98 10011000 +153 99 10011001 +154 9a 10011010 +155 9b 10011011 +156 9c 10011100 +157 9d 10011101 +158 9e 10011110 +159 9f 10011111 +160 a0 10100000 +161 a1 10100001 +162 a2 10100010 +163 a3 10100011 +164 a4 10100100 +165 a5 10100101 +166 a6 10100110 +167 a7 10100111 +168 a8 10101000 +169 a9 10101001 +170 aa 10101010 +171 ab 10101011 +172 ac 10101100 +173 ad 10101101 +174 ae 10101110 +175 af 10101111 +176 b0 10110000 +177 b1 10110001 +178 b2 10110010 +179 b3 10110011 +180 b4 10110100 +181 b5 10110101 +182 b6 10110110 +183 b7 10110111 +184 b8 10111000 +185 b9 10111001 +186 ba 10111010 +187 bb 10111011 +188 bc 10111100 +189 bd 10111101 +190 be 10111110 +191 bf 10111111 +192 c0 11000000 +193 c1 11000001 +194 c2 11000010 +195 c3 11000011 +196 c4 11000100 +197 c5 11000101 +198 c6 11000110 +199 c7 11000111 +200 c8 11001000 +201 c9 11001001 +202 ca 11001010 +203 cb 11001011 +204 cc 11001100 +205 cd 11001101 +206 ce 11001110 +207 cf 11001111 +208 d0 11010000 +209 d1 11010001 +210 d2 11010010 +211 d3 11010011 +212 d4 11010100 +213 d5 11010101 +214 d6 11010110 +215 d7 11010111 +216 d8 11011000 +217 d9 11011001 +218 da 11011010 +219 db 11011011 +220 dc 11011100 +221 dd 11011101 +222 de 11011110 +223 df 11011111 +224 e0 11100000 +225 e1 11100001 +226 e2 11100010 +227 e3 11100011 +228 e4 11100100 +229 e5 11100101 +230 e6 11100110 +231 e7 11100111 +232 e8 11101000 +233 e9 11101001 +234 ea 11101010 +235 eb 11101011 +236 ec 11101100 +237 ed 11101101 +238 ee 11101110 +239 ef 11101111 +240 f0 11110000 +241 f1 11110001 +242 f2 11110010 +243 f3 11110011 +244 f4 11110100 +245 f5 11110101 +246 f6 11110110 +247 f7 11110111 +248 f8 11111000 +249 f9 11111001 +250 fa 11111010 +251 fb 11111011 +252 fc 11111100 +253 fd 11111101 +254 fe 11111110 +255 ff 11111111 diff --git a/jscl/src/test/resources/jscl/math/trig_table.csv b/jscl/src/test/resources/jscl/math/trig_table.csv new file mode 100644 index 00000000..86340fb6 --- /dev/null +++ b/jscl/src/test/resources/jscl/math/trig_table.csv @@ -0,0 +1,357 @@ +"X, Angle in degrees" "sin(x)" "cos(x)" "tan(x)" "cot(x)" "Y, Angle in radians" "sinh(y)" "cosh(y)" "tanh(y)" "coth(y)" "asin(sin(x))" "acos(cos(x))" "atan(tan(x))" +1 0.017452406437284 0.99984769515639 0.017455064928218 57.289961630759 0.0174532925199433 0.0174541786295951 1.00015231257626 0.0174515205435415 57.3015971591129 0.0174532925199438 0.0174532925200115 0.0174532925199437 +2 0.034899496702501 0.9993908270191 0.034920769491748 28.636253282916 0.0349065850398866 0.0349136742410173 1.00060929670327 0.0348924144079494 28.6595243398282 0.0349065850398866 0.0349065850397648 0.0349065850398869 +3 0.052335956242944 0.99862953475457 0.052407779283041 19.081136687728 0.0523598775598299 0.0523838054357798 1.00137109158989 0.0523120807817702 19.1160432744339 0.0523598775598301 0.0523598775599049 0.0523598775598297 +4 0.069756473744125 0.99756405025982 0.06992681194351 14.300666256712 0.0698131700797732 0.0698698940552625 1.00243792929802 0.0696999704552189 14.3472083771181 0.0698131700797729 0.0698131700798344 0.0698131700797728 +5 0.087155742747658 0.99619469809175 0.087488663525924 11.430052302761 0.0872664625997165 0.0873772668018779 1.00381013481324 0.0870456112879702 11.4882299659167 0.0872664625997163 0.0872664625996654 0.0872664625997165 +6 0.10452846326765 0.99452189536827 0.10510423526568 9.5143644542226 0.10471975511966 0.104911256861719 1.00548812614387 0.104338633280596 9.58417767760783 0.104719755119656 0.104719755119692 0.104719755119663 +7 0.12186934340515 0.99254615164132 0.1227845609029 8.1443464279746 0.122173047639603 0.122477205529182 1.00747241444828 0.12156879312299 8.22579524161525 0.122173047639606 0.12217304763962 0.122173047639599 +8 0.13917310096007 0.99026806874157 0.14054083470239 7.1153697223842 0.139626340159546 0.140080463834058 1.00976360419059 0.138725998097688 7.20845417378665 0.139626340159551 0.139626340159548 0.139626340159545 +9 0.15643446504023 0.98768834059514 0.15838444032454 6.313751514675 0.15707963267949 0.157726394171594 1.01236239332483 0.155800329221619 6.41847167458514 0.157079632679489 0.157079632679475 0.157079632679493 +10 0.17364817766693 0.98480775301221 0.17632698070846 5.6712818196177 0.174532925199433 0.17542037193601 1.01526957350753 0.172782063516364 5.78763778860236 0.174532925199433 0.174532925199422 0.174532925199428 +11 0.19080899537654 0.98162718344766 0.19438030913772 5.1445540159703 0.191986217719376 0.193167787157981 1.01848603033891 0.189661695304454 5.27254593182221 0.191986217719371 0.191986217719397 0.191986217719378 +12 0.20791169081776 0.97814760073381 0.21255656167002 4.7046301094785 0.20943951023932 0.210974046146575 1.02201274363261 0.206429956437427 4.84425815544421 0.20943951023932 0.209439510239298 0.209439510239317 +13 0.22495105434386 0.97437006478524 0.23086819112556 4.3314758742842 0.226892802759263 0.228844573136153 1.02585078771421 0.223077835370251 4.4827402881163 0.226892802759258 0.226892802759242 0.22689280275926 +14 0.24192189559967 0.970295726276 0.24932800284318 4.0107809335358 0.244346095279206 0.246784811938725 1.03000133174847 0.23959659500614 4.17368201736912 0.244346095279208 0.244346095279191 0.244346095279205 +15 0.25881904510252 0.96592582628907 0.26794919243112 3.7320508075689 0.261799387799149 0.264800227602271 1.03446564009551 0.255977789245685 3.90658893862159 0.261799387799149 0.261799387799143 0.261799387799147 +16 0.275637355817 0.96126169593832 0.28674538575881 3.4874144438409 0.279252680319093 0.282896308075536 1.03924507269593 0.272213278184392 3.67359008594217 0.279252680319094 0.279252680319089 0.279252680319095 +17 0.29237170472274 0.95630475596304 0.30573068145866 3.2708526184841 0.296705972839036 0.301078565879793 1.04434108548512 0.288295241913169 3.46866633442805 0.296705972839039 0.296705972839021 0.296705972839036 +18 0.30901699437495 0.95105651629515 0.32491969623291 3.0776835371753 0.314159265358979 0.319352539788101 1.04975523083675 0.304216192886744 3.28713600190338 0.314159265358982 0.314159265358991 0.314159265358983 +19 0.32556815445716 0.94551857559932 0.34432761328967 2.9042108776758 0.331612557878923 0.337723796512546 1.05548915803567 0.319968986835517 3.12530289228956 0.331612557878926 0.331612557878913 0.331612557878927 +20 0.34202014332567 0.93969262078591 0.3639702342662 2.7474774194546 0.349065850398866 0.356197932400012 1.06154461378034 0.335546832206639 2.98020992605936 0.349065850398867 0.349065850398861 0.349065850398864 +21 0.3583679495453 0.9335804264972 0.38386403503542 2.6050890646938 0.366519142918809 0.374780575136959 1.06792344271487 0.350943298130241 2.84946316207721 0.366519142918809 0.366519142918814 0.366519142918813 +22 0.37460659341591 0.92718385456679 0.40402622583516 2.4750868534163 0.383972435438752 0.393477385463767 1.07462758799102 0.366152320916457 2.73110381356333 0.38397243543875 0.383972435438746 0.383972435438755 +23 0.39073112848927 0.92050485345244 0.4244748162096 2.3558523658238 0.401425727958696 0.412294058899132 1.08165909186006 0.381168209098245 2.62351365127162 0.401425727958692 0.401425727958697 0.401425727958692 +24 0.4067366430758 0.9135454576426 0.44522868530854 2.2460367739042 0.418879020478639 0.431236327475069 1.08902009629491 0.395985647043824 2.52534405594082 0.418879020478639 0.418879020478641 0.418879020478642 +25 0.4226182617407 0.90630778703665 0.466307658155 2.1445069205096 0.436332312998582 0.450309961483032 1.0967128436427 0.410599697170813 2.4354620982197 0.436332312998583 0.436332312998582 0.436332312998584 +26 0.43837114678908 0.89879404629917 0.48773258856586 2.0503038415793 0.453785605518526 0.469520771231691 1.10473967730774 0.425005800801795 2.35290906174328 0.453785605518529 0.453785605518519 0.453785605518525 +27 0.45399049973955 0.89100652418837 0.50952544949443 1.9626105055052 0.471238898038469 0.488874608816893 1.11310304246546 0.439199777707967 2.27686818335532 0.471238898038473 0.471238898038464 0.47123889803847 +28 0.46947156278589 0.88294759285893 0.53170943166148 1.8807264653463 0.488692190558412 0.508377369904367 1.12180548680726 0.453177824393821 2.20663930618763 0.488692190558411 0.488692190558406 0.488692190558413 +29 0.48480962024634 0.8746197071394 0.55430905145277 1.8040477552714 0.506145483078356 0.528034995525681 1.13084966131657 0.46693651118127 2.14161877697285 0.506145483078359 0.506145483078347 0.506145483078356 +30 0.5 0.86602540378444 0.57735026918963 1.7320508075689 0.523598775598299 0.54785347388804 1.14023832107643 0.480472778156452 2.08128336393364 0.523598775598299 0.523598775598296 0.523598775598302 +31 0.51503807491005 0.85716730070211 0.60086061902756 1.6642794823505 0.541052068118242 0.567838842198436 1.14997432610874 0.4937839300464 2.02517728737351 0.541052068118237 0.541052068118247 0.541052068118242 +32 0.5299192642332 0.84804809615643 0.62486935190933 1.6003345290411 0.558505360638185 0.58799718850274 1.16006064224554 0.506867630096088 1.97290168206328 0.55850536063818 0.558505360638178 0.558505360638187 +33 0.54463903501503 0.83867056794542 0.64940759319751 1.5398649638146 0.575958653158129 0.608334653540269 1.1705003420324 0.519721893018833 1.92410597558522 0.575958653158132 0.575958653158136 0.575958653158128 +34 0.55919290347075 0.82903757255504 0.67450851684243 1.4825609685127 0.593411945678072 0.628857432614412 1.18129660566447 0.532345077094915 1.87848078817061 0.593411945678076 0.593411945678075 0.593411945678074 +35 0.57357643635105 0.81915204428899 0.70020753820971 1.4281480067421 0.610865238198015 0.649571777479873 1.1924527219552 0.544735875494339 1.83575204972963 0.61086523819802 0.610865238198018 0.610865238198016 +36 0.58778525229247 0.80901699437495 0.72654252800536 1.3763819204712 0.628318530717959 0.670483998247118 1.20397208933822 0.556893306900211 1.79567609739506 0.628318530717955 0.628318530717954 0.628318530717958 +37 0.60181502315205 0.79863551004729 0.75355405010279 1.3270448216204 0.645771823237902 0.691600465304585 1.21585821690258 0.568816705509011 1.75803556807485 0.645771823237904 0.645771823237907 0.645771823237899 +38 0.61566147532566 0.78801075360672 0.78128562650672 1.2799416321931 0.663225115757845 0.712927611259275 1.2281147254617 0.580505710483406 1.72263593956254 0.663225115757847 0.663225115757848 0.663225115757847 +39 0.62932039104984 0.77714596145697 0.80978403319501 1.2348971565351 0.680678408277788 0.734471932896275 1.24074534865636 0.59196025493197 1.68930260379546 0.680678408277792 0.68067840827779 0.68067840827779 +40 0.64278760968654 0.76604444311898 0.83909963117728 1.1917535925942 0.698131700797732 0.756239993157849 1.25375393409209 0.603180554488537 1.657878379133 0.698131700797733 0.698131700797729 0.698131700797732 +41 0.65605902899051 0.75470958022277 0.86928673781623 1.150368407221 0.715584993317675 0.778238423142676 1.2671444445112 0.61416709556177 1.62822138669822 0.715584993317679 0.715584993317678 0.715584993317677 +42 0.66913060635886 0.74314482547739 0.90040404429784 1.1106125148292 0.733038285837618 0.800473924125845 1.28092095899998 0.624920623323064 1.60020323010372 0.733038285837621 0.733038285837625 0.733038285837618 +43 0.6819983600625 0.73135370161917 0.93251508613766 1.0723687100247 0.750491578357562 0.822953269600232 1.29508767423125 0.635442129498088 1.57370742917197 0.750491578357564 0.750491578357562 0.750491578357561 +44 0.694658370459 0.71933980033865 0.96568877480707 1.0355303137906 0.767944870877505 0.845683307339883 1.3096489057428 0.645732840024197 1.54862806723989 0.767944870877509 0.767944870877507 0.767944870877503 +45 0.70710678118655 0.70710678118655 1 1 0.785398163397448 0.868670961486009 1.32460908925201 0.655794202632672 1.52486861882206 0.785398163397452 0.785398163397445 0.785398163397448 +46 0.71933980033865 0.694658370459 1.0355303137906 0.96568877480707 0.802851455917392 0.891923234656263 1.33997278200704 0.66562787441124 1.50234093018493 0.80285145591739 0.802851455917388 0.802851455917406 +47 0.73135370161917 0.6819983600625 1.0723687100247 0.93251508613766 0.820304748437335 0.915447210077902 1.35574466417516 0.675235709398764 1.48096433005655 0.820304748437334 0.820304748437333 0.820304748437343 +48 0.74314482547739 0.66913060635886 1.1106125148292 0.90040404429784 0.837758040957278 0.93925005374553 1.37192954026837 0.684619746260292 1.46066485149232 0.837758040957272 0.837758040957276 0.837758040957282 +49 0.75470958022277 0.65605902899051 1.150368407221 0.86928673781623 0.855211333477221 0.963339016604027 1.38853234060702 0.693782196086903 1.44137454901587 0.855211333477218 0.855211333477218 0.855211333477218 +50 0.76604444311898 0.64278760968654 1.1917535925942 0.83909963117728 0.872664625997165 0.987721436757379 1.4055581228217 0.702725430361072 1.42303089769525 0.872664625997168 0.872664625997164 0.872664625997161 +51 0.77714596145697 0.62932039104984 1.2348971565351 0.80978403319501 0.890117918517108 1.01240474170404 1.42301207339391 0.711451969124507 1.40557626290721 0.890117918517107 0.890117918517105 0.890117918517127 +52 0.78801075360672 0.61566147532566 1.2799416321931 0.78128562650672 0.907571211037051 1.03739645059956 1.440899509236 0.719964469381772 1.38895743127254 0.907571211037048 0.907571211037049 0.907571211037059 +53 0.79863551004729 0.60181502315205 1.3270448216204 0.75355405010279 0.925024503556995 1.06270417654705 1.45922587931085 0.728265713769363 1.3731251946823 0.92502450355699 0.925024503556993 0.925024503556991 +54 0.80901699437495 0.58778525229247 1.3763819204712 0.72654252800536 0.942477796076938 1.08833562891639 1.47799676629174 0.736358599516427 1.35803398053164 0.942477796076942 0.942477796076942 0.942477796076947 +55 0.81915204428899 0.57357643635105 1.4281480067421 0.70020753820971 0.959931088596881 1.11429861569269 1.49721788826297 0.744246127719902 1.34364152227924 0.959931088596878 0.959931088596876 0.959931088596876 +56 0.82903757255504 0.55919290347075 1.4825609685127 0.67450851684243 0.977384381116825 1.14060104585473 1.51689510046176 0.751931392953616 1.32990856529073 0.977384381116821 0.977384381116821 0.977384381116812 +57 0.83867056794542 0.54463903501503 1.5398649638146 0.64940759319751 0.994837673636768 1.16725093178432 1.53703439706188 0.759417573227758 1.31679860363211 0.994837673636761 0.994837673636764 0.994837673636773 +58 0.84804809615643 0.5299192642332 1.6003345290411 0.62486935190933 1.01229096615671 1.19425639170703 1.55764191299961 0.766707920312187 1.30427764407706 1.01229096615672 1.01229096615672 1.01229096615673 +59 0.85716730070211 0.51503807491005 1.6642794823505 0.60086061902756 1.02974425867665 1.2216256521652 1.57872392584266 0.773805750434261 1.29231399409839 1.02974425867665 1.02974425867666 1.02974425867665 +60 0.86602540378444 0.5 1.7320508075689 0.57735026918963 1.0471975511966 1.24936705052398 1.60028685770239 0.780714435359268 1.28087807104504 1.0471975511966 1.0471975511966 1.0471975511966 +61 0.8746197071394 0.48480962024634 1.8040477552714 0.55430905145277 1.06465084371654 1.27748903751106 1.62233727719021 0.78743739385906 1.26994223007269 1.06465084371655 1.06465084371654 1.06465084371654 +62 0.88294759285893 0.46947156278589 1.8807264653463 0.53170943166148 1.08210413623648 1.30600017979103 1.64488190141852 0.793978083572297 1.25948060870996 1.08210413623649 1.08210413623649 1.08210413623648 +63 0.89100652418837 0.45399049973955 1.9626105055052 0.50952544949443 1.09955742875643 1.33490916257496 1.66792759804692 0.800339993257551 1.24946898621146 1.09955742875643 1.09955742875642 1.09955742875644 +64 0.89879404629917 0.43837114678908 2.0503038415793 0.48773258856586 1.11701072127637 1.36422479226612 1.69148138737425 0.806526635438686 1.23988465607968 1.11701072127638 1.11701072127637 1.11701072127637 +65 0.90630778703665 0.4226182617407 2.1445069205096 0.466307658155 1.13446401379631 1.39395599914269 1.71555044447719 0.812541539440125 1.23070631033712 1.13446401379631 1.13446401379631 1.13446401379632 +66 0.9135454576426 0.4067366430758 2.2460367739042 0.44522868530854 1.15191730631626 1.42411184007809 1.74014210139592 0.818388244808103 1.22191393430203 1.15191730631626 1.15191730631626 1.15191730631625 +67 0.92050485345244 0.39073112848927 2.3558523658238 0.4244748162096 1.1693705988362 1.45470150129997 1.76526384936768 0.824070295112569 1.21348871076999 1.1693705988362 1.1693705988362 1.16937059883621 +68 0.92718385456679 0.37460659341591 2.4750868534163 0.40402622583516 1.18682389135614 1.48573430118855 1.79092334110878 0.829591232123156 1.20541293263276 1.18682389135615 1.18682389135615 1.18682389135614 +69 0.9335804264972 0.3583679495453 2.6050890646938 0.38386403503542 1.20427718387609 1.51721969311522 1.8171283931458 0.834954590351548 1.19766992307805 1.20427718387608 1.20427718387609 1.20427718387609 +70 0.93969262078591 0.34202014332567 2.7474774194546 0.3639702342662 1.22173047639603 1.5491672683223 1.84388698819672 0.840163891951616 1.19024396261199 1.22173047639604 1.22173047639603 1.22173047639603 +71 0.94551857559932 0.32556815445716 2.9042108776758 0.34432761328967 1.23918376891597 1.58158675884476 1.87120727760264 0.845222641967846 1.18312022223139 1.23918376891598 1.23918376891597 1.23918376891597 +72 0.95105651629515 0.30901699437495 3.0776835371753 0.32491969623291 1.25663706143592 1.61448804047485 1.89909758381088 0.850134323921939 1.17628470214764 1.25663706143591 1.25663706143591 1.25663706143592 +73 0.95630475596304 0.29237170472274 3.2708526184841 0.30573068145866 1.27409035395586 1.6478811357705 1.92756640291023 0.854902395726829 1.16972417552978 1.27409035395588 1.27409035395586 1.27409035395586 +74 0.96126169593832 0.275637355817 3.4874144438409 0.28674538575881 1.2915436464758 1.68177621710845 1.95662240721904 0.859530285916931 1.16342613679193 1.29154364647581 1.2915436464758 1.2915436464758 +75 0.96592582628907 0.25881904510252 3.7320508075689 0.26794919243112 1.30899693899575 1.71618360978304 1.98627444792706 0.864021390183066 1.15737875400067 1.30899693899575 1.30899693899575 1.30899693899575 +76 0.970295726276 0.24192189559967 4.0107809335358 0.24932800284318 1.32645023151569 1.75111379515149 2.01653155779171 0.868379068200214 1.15157082502297 1.32645023151571 1.32645023151569 1.32645023151569 +77 0.97437006478524 0.22495105434387 4.3314758742842 0.23086819112556 1.34390352403563 1.78657741382686 2.0474029538897 0.872606640736101 1.14599173707461 1.34390352403566 1.34390352403563 1.34390352403564 +78 0.97814760073381 0.20791169081776 4.7046301094785 0.21255656167002 1.36135681655558 1.8225852689194 2.07889804042478 0.876707387028461 1.14063142936371 1.3613568165556 1.36135681655558 1.36135681655558 +79 0.98162718344766 0.19080899537654 5.1445540159703 0.19438030913772 1.37881010907552 1.85914832932744 2.11102641159248 0.880684542418856 1.13548035855544 1.3788101090755 1.37881010907553 1.37881010907552 +80 0.98480775301221 0.17364817766693 5.6712818196177 0.17632698070847 1.39626340159546 1.89627773307885 2.14379785450277 0.884541296230877 1.13052946681077 1.39626340159548 1.39626340159546 1.39626340159546 +81 0.98768834059514 0.15643446504023 6.313751514675 0.15838444032454 1.41371669411541 1.93398479072391 2.17722235216144 0.888280789880713 1.12577015217709 1.41371669411542 1.41371669411541 1.41371669411541 +82 0.99026806874157 0.13917310096007 7.1153697223842 0.14054083470239 1.43116998663535 1.9722809887808 2.2113100865112 0.891906115208149 1.12119424112999 1.43116998663535 1.43116998663535 1.43116998663535 +83 0.99254615164132 0.12186934340515 8.1443464279746 0.1227845609029 1.44862327915529 2.01117799323469 2.24607144153331 0.895420313016284 1.1167939630847 1.44862327915528 1.44862327915529 1.44862327915529 +84 0.99452189536827 0.10452846326765 9.5143644542226 0.10510423526568 1.46607657167524 2.05068765309151 2.28151700641086 0.898826371808433 1.11256192671339 1.4660765716752 1.46607657167524 1.46607657167524 +85 0.99619469809175 0.087155742747658 11.430052302761 0.087488663525924 1.48352986419518 2.0908220039874 2.31765757875444 0.902127226710969 1.10849109791959 1.48352986419523 1.48352986419518 1.48352986419518 +86 0.99756405025982 0.069756473744125 14.300666256712 0.06992681194351 1.50098315671512 2.13159327185514 2.35450416789143 0.905325758571107 1.10457477933503 1.50098315671506 1.50098315671512 1.50098315671512 +87 0.99862953475457 0.052335956242944 19.081136687728 0.052407779283041 1.51843644923507 2.17301387664841 2.39206799821965 0.908424793218975 1.10080659121657 1.51843644923499 1.51843644923507 1.51843644923507 +88 0.9993908270191 0.034899496702501 28.636253282916 0.034920769491748 1.53588974175501 2.21509643612527 2.43036051262665 0.911427100883592 1.09718045363205 1.53588974175513 1.53588974175501 1.53588974175501 +89 0.99984769515639 0.017452406437284 57.289961630759 0.017455064928218 1.55334303427495 2.25785376969181 2.46939337597547 0.914335395752775 1.09369056983373 1.55334303427489 1.55334303427495 1.55334303427495 +91 0.99984769515639 -0.017452406437283 -57.28996163076 -0.017455064928218 1.58824961931484 2.34544506845187 2.54972794021739 0.919880521939882 1.0870977003526 1.55334303427489 1.58824961931484 -1.55334303427495 +92 0.9993908270191 -0.034899496702501 -28.636253282916 -0.034920769491747 1.60570291183478 2.39030571615814 2.59105411303938 0.922522499290548 1.08398440229809 1.53588974175513 1.60570291183478 -1.53588974175501 +93 0.99862953475457 -0.052335956242944 -19.081136687728 -0.052407779283041 1.62315620435473 2.43589451110775 2.63316958611572 0.925080755888958 1.08098670698111 1.51843644923499 1.62315620435473 -1.51843644923507 +94 0.99756405025982 -0.069756473744125 -14.300666256712 -0.06992681194351 1.64060949687467 2.4822253407943 2.67608718887883 0.927557723496391 1.07810001972766 1.50098315671506 1.64060949687467 -1.50098315671512 +95 0.99619469809175 -0.087155742747658 -11.430052302761 -0.087488663525924 1.65806278939461 2.52931231875387 2.71981999510999 0.929955777699027 1.07531994959404 1.48352986419523 1.65806278939461 -1.48352986419518 +96 0.99452189536827 -0.10452846326765 -9.5143644542226 -0.10510423526568 1.67551608191456 2.57716978886429 2.76438132692196 0.932277238225263 1.07264229887631 1.4660765716752 1.67551608191455 -1.46607657167524 +97 0.99254615164132 -0.12186934340515 -8.1443464279746 -0.1227845609029 1.6929693744345 2.6258123297147 2.80978475881725 0.93452436933995 1.07006305325809 1.44862327915528 1.6929693744345 -1.44862327915529 +98 0.99026806874157 -0.13917310096007 -7.1153697223842 -0.14054083470239 1.71042266695444 2.67525475904651 2.85604412182323 0.936699380308836 1.06757837255139 1.43116998663535 1.71042266695445 -1.43116998663535 +99 0.98768834059514 -0.15643446504023 -6.313751514675 -0.15838444032454 1.72787595947439 2.72551213826731 2.9031735077054 0.938804425926818 1.0651845819887 1.41371669411542 1.72787595947439 -1.41371669411541 +100 0.98480775301221 -0.17364817766693 -5.6712818196177 -0.17632698070846 1.74532925199433 2.77659977703891 2.95118727326012 0.940841607103994 1.06287816402816 1.39626340159548 1.74532925199433 -1.39626340159546 +101 0.98162718344766 -0.19080899537654 -5.1445540159703 -0.19438030913772 1.76278254451427 2.82853323794105 3.00010004468806 0.942812971503807 1.06065575063629 1.3788101090755 1.76278254451427 -1.37881010907552 +102 0.97814760073381 -0.20791169081776 -4.7046301094785 -0.21255656167002 1.78023583703422 2.88132834121219 3.04992672204966 0.944720514227907 1.05851411601586 1.3613568165556 1.78023583703422 -1.36135681655558 +103 0.97437006478524 -0.22495105434386 -4.3314758742842 -0.23086819112556 1.79768912955416 2.93500116956871 3.10068248380413 0.946566178542686 1.05645016974891 1.34390352403566 1.79768912955415 -1.34390352403564 +104 0.970295726276 -0.24192189559967 -4.0107809335358 -0.24932800284318 1.8151424220741 2.98956807310414 3.15238279143311 0.948351856642717 1.05446095032715 1.32645023151571 1.81514242207411 -1.32645023151569 +105 0.96592582628907 -0.25881904510252 -3.7320508075689 -0.26794919243112 1.83259571459405 3.04504567426978 3.20504339415071 0.950079390446654 1.05254361904417 1.30899693899575 1.83259571459405 -1.30899693899575 +106 0.96126169593832 -0.275637355817 -3.4874144438409 -0.28674538575881 1.85004900711399 3.10145087293836 3.25868033370107 0.951750572421402 1.05069545422583 1.29154364647581 1.85004900711399 -1.2915436464758 +107 0.95630475596304 -0.29237170472274 -3.2708526184841 -0.30573068145866 1.86750229963393 3.15880085155212 3.31330994924507 0.953367146430669 1.04891384577696 1.27409035395588 1.86750229963394 -1.27409035395586 +108 0.95105651629515 -0.30901699437495 -3.0776835371753 -0.32491969623291 1.88495559215388 3.21711308035704 3.36894888233769 0.954930808604228 1.04719629002404 1.25663706143591 1.88495559215388 -1.25663706143592 +109 0.94551857559932 -0.32556815445716 -2.9042108776758 -0.34432761328966 1.90240888467382 3.27640532272471 3.42561408199739 0.95644320822453 1.04554038483511 1.23918376891598 1.90240888467382 -1.23918376891597 +110 0.93969262078591 -0.34202014332567 -2.7474774194546 -0.3639702342662 1.91986217719376 3.33669564056352 3.48332280986927 0.957905948627466 1.04394382499957 1.22173047639604 1.91986217719376 -1.22173047639603 +111 0.9335804264972 -0.3583679495453 -2.6050890646938 -0.38386403503542 1.93731546971371 3.39800239982072 3.54209264548336 0.959320588114378 1.04240439785159 1.20427718387608 1.93731546971371 -1.20427718387609 +112 0.92718385456679 -0.37460659341591 -2.4750868534163 -0.40402622583516 1.95476876223365 3.4603442760772 3.6019414916098 0.960688640872587 1.04091997912217 1.18682389135615 1.95476876223365 -1.18682389135614 +113 0.92050485345244 -0.39073112848927 -2.3558523658238 -0.4244748162096 1.97222205475359 3.52374026023653 3.66288757971246 0.96201157790192 1.03948852900599 1.1693705988362 1.97222205475359 -1.16937059883621 +114 0.9135454576426 -0.4067366430758 -2.2460367739042 -0.44522868530854 1.98967534727354 3.58820966431005 3.72494947550273 0.963290827944929 1.03810808842994 1.15191730631626 1.98967534727354 -1.15191730631625 +115 0.90630778703665 -0.4226182617407 -2.1445069205096 -0.466307658155 2.00712863979348 3.65377212729981 3.78814608459508 0.964527778418655 1.03677677551133 1.13446401379631 2.00712863979348 -1.13446401379632 +116 0.89879404629917 -0.43837114678908 -2.0503038415793 -0.48773258856586 2.02458193231342 3.7204476211811 3.85249665826618 0.965723776345983 1.03549278219462 1.11701072127638 2.02458193231342 -1.11701072127637 +117 0.89100652418837 -0.45399049973955 -1.9626105055052 -0.50952544949443 2.04203522483337 3.78825645698641 3.91802079931937 0.966880129284789 1.03425437105602 1.09955742875643 2.04203522483337 -1.09955742875644 +118 0.88294759285893 -0.46947156278589 -1.8807264653463 -0.53170943166148 2.05948851735331 3.85721929099268 3.9847384680561 0.967998106253225 1.03305987226632 1.08210413623649 2.05948851735331 -1.08210413623648 +119 0.8746197071394 -0.48480962024634 -1.8040477552714 -0.55430905145277 2.07694180987325 3.92735713101375 4.05266998835638 0.969078938649663 1.0319076807029 1.06465084371655 2.07694180987326 -1.06465084371654 +120 0.86602540378444 -0.5 -1.7320508075689 -0.57735026918963 2.0943951023932 3.99869134279982 4.12183605386995 0.970123821165931 1.03079625320216 1.0471975511966 2.0943951023932 -1.0471975511966 +121 0.85716730070211 -0.51503807491005 -1.6642794823505 -0.60086061902756 2.11184839491314 4.07124365654605 4.19225773432007 0.971133912692597 1.02972410594474 1.02974425867665 2.11184839491313 -1.02974425867665 +122 0.84804809615643 -0.5299192642332 -1.6003345290411 -0.62486935190933 2.12930168743308 4.14503617351207 4.26395648192188 0.972110337215213 1.02868981196587 1.01229096615672 2.12930168743308 -1.01229096615673 +123 0.83867056794542 -0.54463903501503 -1.5398649638146 -0.64940759319751 2.14675497995303 4.22009137275462 4.3369541379173 0.97305418470051 1.027691998784 0.994837673636761 2.14675497995303 -0.994837673636773 +124 0.82903757255504 -0.55919290347075 -1.4825609685127 -0.67450851684243 2.16420827247297 4.29643211797521 4.41127293922842 0.973966511971645 1.02672934614113 0.977384381116821 2.16420827247297 -0.977384381116812 +125 0.81915204428899 -0.57357643635105 -1.4281480067421 -0.70020753820971 2.18166156499291 4.374081664485 4.48693552523143 0.974848343571727 1.02580058384889 0.959931088596878 2.18166156499292 -0.959931088596876 +126 0.80901699437495 -0.58778525229247 -1.3763819204712 -0.72654252800536 2.19911485751286 4.45306366628894 4.56396494465314 0.975700672614911 1.02490448973451 0.942477796076942 2.19911485751285 -0.942477796076947 +127 0.79863551004729 -0.60181502315205 -1.3270448216204 -0.75355405010279 2.2165681500328 4.53340218329138 4.64238466259217 0.97652446162444 1.02403988768137 0.92502450355699 2.2165681500328 -0.925024503556991 +128 0.78801075360672 -0.61566147532566 -1.2799416321931 -0.78128562650672 2.23402144255274 4.61512168862529 4.72221856766707 0.977320643357116 1.02320564575919 0.907571211037048 2.23402144255274 -0.907571211037059 +129 0.77714596145697 -0.62932039104984 -1.2348971565351 -0.80978403319501 2.25147473507268 4.69824707610748 4.80349097929334 0.978090121613731 1.022400674439 0.890117918517107 2.25147473507269 -0.890117918517127 +130 0.76604444311898 -0.64278760968654 -1.1917535925942 -0.83909963117728 2.26892802759263 4.78280366782176 4.88622665509177 0.978833772035067 1.02162392488862 0.872664625997168 2.26892802759263 -0.872664625997161 +131 0.75470958022277 -0.65605902899051 -1.150368407221 -0.86928673781623 2.28638132011257 4.8688172218328 4.97045079843022 0.979552442883144 1.02087438734436 0.855211333477218 2.28638132011258 -0.855211333477218 +132 0.74314482547739 -0.66913060635886 -1.1106125148292 -0.90040404429784 2.30383461263251 4.95631394003259 5.05618906610121 0.980246955807444 1.02015108955507 0.837758040957272 2.30383461263252 -0.837758040957282 +133 0.73135370161917 -0.6819983600625 -1.0723687100247 -0.93251508613766 2.32128790515246 5.04532047612227 5.14346757613759 0.980918106595897 1.0194530952949 0.820304748437334 2.32128790515246 -0.820304748437343 +134 0.71933980033865 -0.694658370459 -1.0355303137906 -0.96568877480707 2.3387411976724 5.13586394373147 5.23231291576879 0.98156666591047 1.01877950294128 0.80285145591739 2.33874119767241 -0.802851455917406 +135 0.70710678118655 -0.70710678118655 -1 -1 2.35619449019234 5.2279719246778 5.32275214951996 0.982193380007239 1.01812944411479 0.785398163397452 2.35619449019235 -0.785398163397448 +136 0.694658370459 -0.71933980033865 -0.96568877480707 -1.0355303137906 2.37364778271229 5.32167247736903 5.41481282745646 0.982798971440868 1.01750208237796 0.767944870877509 2.37364778271229 -0.767944870877503 +137 0.6819983600625 -0.73135370161917 -0.93251508613766 -1.0723687100247 2.39110107523223 5.4169941453503 5.50852299357636 0.983384139753471 1.01689661198999 0.750491578357564 2.39110107523223 -0.750491578357561 +138 0.66913060635886 -0.74314482547739 -0.90040404429784 -1.1106125148292 2.40855436775217 5.51396596599926 5.60391119435329 0.983949562147832 1.0163122567148 0.733038285837621 2.40855436775217 -0.733038285837618 +139 0.65605902899051 -0.75470958022277 -0.86928673781623 -1.150368407221 2.42600766027212 5.61261747937156 5.70100648743247 0.984495894145049 1.01574826867959 0.715584993317679 2.42600766027211 -0.715584993317677 +140 0.64278760968654 -0.76604444311898 -0.83909963117728 -1.1917535925942 2.44346095279206 5.71297873719951 5.79983845048237 0.985023770226629 1.0152039272818 0.698131700797733 2.44346095279206 -0.698131700797732 +141 0.62932039104984 -0.77714596145697 -0.80978403319501 -1.2348971565351 2.460914245312 5.81508031204659 5.90043719020479 0.98553380446115 1.01467853814183 0.680678408277792 2.460914245312 -0.68067840827779 +142 0.61566147532566 -0.78801075360672 -0.78128562650672 -1.2799416321931 2.47836753783195 5.91895330662059 6.00283335150617 0.986026591115588 1.01417143209962 0.663225115757847 2.47836753783194 -0.663225115757847 +143 0.60181502315205 -0.79863551004729 -0.75355405010279 -1.3270448216204 2.49582083035189 6.02462936324835 6.10705812683277 0.986502705251444 1.01368196425282 0.645771823237904 2.49582083035189 -0.645771823237899 +144 0.58778525229247 -0.80901699437495 -0.72654252800536 -1.3763819204712 2.51327412287183 6.13214067351471 6.21314326567266 0.986962703305832 1.01320951303479 0.628318530717955 2.51327412287184 -0.628318530717958 +145 0.57357643635105 -0.81915204428899 -0.70020753820971 -1.4281480067421 2.53072741539178 6.24151998806898 6.32112108422743 0.987407123657689 1.01275347933045 0.61086523819802 2.53072741539177 -0.610865238198016 +146 0.55919290347075 -0.82903757255504 -0.67450851684243 -1.4825609685127 2.54818070791172 6.35280062660152 6.43102447525654 0.9878364871793 1.01231328562831 0.593411945678076 2.54818070791172 -0.593411945678074 +147 0.54463903501503 -0.83867056794542 -0.64940759319751 -1.5398649638146 2.56563400043166 6.46601648799383 6.54288691809724 0.988251297773343 1.01188837520692 0.575958653158132 2.56563400043166 -0.575958653158128 +148 0.5299192642332 -0.84804809615643 -0.62486935190933 -1.6003345290411 2.58308729295161 6.58120206064494 6.65674248886325 0.988652042895653 1.01147821135443 0.55850536063818 2.58308729295162 -0.558505360638187 +149 0.51503807491005 -0.85716730070211 -0.60086061902756 -1.6642794823505 2.60054058547155 6.6983924329775 6.77262587082516 0.989039194063939 1.01108227661942 0.541052068118237 2.60054058547155 -0.541052068118242 +150 0.5 -0.86602540378444 -0.57735026918963 -1.7320508075689 2.61799387799149 6.81762330412654 6.89057236497588 0.989413207352682 1.01070007209187 0.523598775598299 2.6179938779915 -0.523598775598302 +151 0.48480962024634 -0.8746197071394 -0.55430905145277 -1.8040477552714 2.63544717051144 6.93893099481438 7.01061790078419 0.989774523874452 1.01033111671285 0.506145483078359 2.63544717051145 -0.506145483078356 +152 0.46947156278589 -0.88294759285893 -0.53170943166148 -1.8807264653463 2.65290046303138 7.06235245841479 7.13279904713973 0.990123570247897 1.00997494661159 0.488692190558411 2.65290046303139 -0.488692190558413 +153 0.45399049973955 -0.89100652418837 -0.50952544949443 -1.9626105055052 2.67035375555132 7.18792529220995 7.25715302349285 0.990460759052647 1.00963111446886 0.471238898038473 2.67035375555133 -0.47123889803847 +154 0.43837114678908 -0.89879404629917 -0.48773258856586 -2.0503038415793 2.68780704807127 7.31568774884349 7.38371771119257 0.990786489271394 1.00929918890535 0.453785605518529 2.68780704807127 -0.453785605518525 +155 0.4226182617407 -0.90630778703665 -0.466307658155 -2.1445069205096 2.70526034059121 7.44567874797327 7.51253166502616 0.991101146719405 1.00897875389414 0.436332312998583 2.70526034059121 -0.436332312998584 +156 0.4067366430758 -0.9135454576426 -0.44522868530854 -2.2460367739042 2.72271363311115 7.5779378881272 7.64363412496398 0.991405104461736 1.00866940819609 0.418879020478639 2.72271363311115 -0.418879020478642 +157 0.39073112848927 -0.92050485345244 -0.4244748162096 -2.3558523658238 2.7401669256311 7.71250545876605 7.77706502811286 0.991698723218407 1.00837076481721 0.401425727958692 2.7401669256311 -0.401425727958692 +158 0.37460659341591 -0.92718385456679 -0.40402622583516 -2.4750868534163 2.75762021815104 7.84942245255652 7.91286502088204 0.991982351757791 1.00808245048715 0.38397243543875 2.75762021815105 -0.383972435438755 +159 0.3583679495453 -0.9335804264972 -0.38386403503542 -2.6050890646938 2.77507351067098 7.98873057785875 8.05107547136501 0.99225632727851 1.00780410515772 0.366519142918809 2.77507351067098 -0.366519142918813 +160 0.34202014332567 -0.93969262078591 -0.3639702342662 -2.7474774194546 2.79252680319093 8.13047227143164 8.19173848194134 0.992520975780078 1.00753538152082 0.349065850398867 2.79252680319093 -0.349065850398864 +161 0.32556815445716 -0.94551857559932 -0.34432761328967 -2.9042108776758 2.80998009571087 8.27469071136021 8.33489690210209 0.992776612422561 1.00727594454488 0.331612557878926 2.80998009571088 -0.331612557878927 +162 0.30901699437495 -0.95105651629515 -0.32491969623291 -3.0776835371753 2.82743338823081 8.42142983020873 8.48059434150281 0.993023541875534 1.0070254710289 0.314159265358982 2.8274333882308 -0.314159265358983 +163 0.29237170472274 -0.95630475596304 -0.30573068145866 -3.2708526184841 2.84488668075076 8.57073432840366 8.62887518324822 0.993262058656564 1.00678364917366 0.296705972839039 2.84488668075077 -0.296705972839036 +164 0.275637355817 -0.96126169593832 -0.28674538575881 -3.4874144438409 2.8623399732707 8.72264968785052 8.77978459741233 0.993492447459514 1.00655017816907 0.279252680319094 2.8623399732707 -0.279252680319095 +165 0.25881904510252 -0.96592582628907 -0.26794919243112 -3.7320508075689 2.87979326579064 8.87722218578886 8.93336855479847 0.993714983472898 1.00632476779724 0.261799387799149 2.87979326579065 -0.261799387799147 +166 0.24192189559967 -0.970295726276 -0.24932800284318 -4.0107809335358 2.89724655831059 9.03449890888945 9.08967384094306 0.993929932688554 1.00610713805049 0.244346095279208 2.8972465583106 -0.244346095279205 +167 0.22495105434387 -0.97437006478524 -0.23086819112556 -4.3314758742842 2.91469985083053 9.19452776759802 9.24874807036774 0.994137552200882 1.00589701876379 0.226892802759268 2.91469985083055 -0.22689280275926 +168 0.20791169081776 -0.97814760073381 -0.21255656167002 -4.7046301094785 2.93215314335047 9.35735751073009 9.41063970108392 0.994338090496899 1.00569414926091 0.20943951023932 2.93215314335049 -0.209439510239317 +169 0.19080899537654 -0.98162718344766 -0.19438030913772 -5.1445540159703 2.94960643587042 9.52303774032098 9.57539804935428 0.994531787737343 1.00549827801392 0.191986217719371 2.9496064358704 -0.191986217719378 +170 0.17364817766693 -0.98480775301221 -0.17632698070847 -5.6712818196177 2.96705972839036 9.6916189267359 9.74307330471579 0.994718876029087 1.00530916231528 0.174532925199433 2.96705972839037 -0.174532925199438 +171 0.15643446504023 -0.98768834059514 -0.15838444032454 -6.313751514675 2.9845130209103 9.86315242404448 9.9137165452687 0.994899579689077 1.00512656796228 0.157079632679489 2.98451302091032 -0.157079632679493 +172 0.13917310096007 -0.99026806874157 -0.14054083470239 -7.1153697223842 3.00196631343025 10.0376904856645 10.0873797532362 0.995074115500038 1.00495026895307 0.139626340159551 3.00196631343024 -0.139626340159545 +173 0.12186934340515 -0.99254615164132 -0.1227845609029 -8.1443464279746 3.01941960595019 10.2152862802796 10.2641158307995 0.995242692958183 1.00478004719399 0.122173047639606 3.01941960595017 -0.122173047639599 +174 0.10452846326765 -0.99452189536827 -0.10510423526568 -9.5143644542226 3.03687289847013 10.3959939080357 10.4439786162131 0.995405514513132 1.00461569221777 0.104719755119656 3.0368728984701 -0.104719755119663 +175 0.087155742747658 -0.99619469809175 -0.087488663525924 -11.430052302761 3.05432619099008 10.5798684170217 10.6270229002055 0.995562775800272 1.00445700091203 0.0872664625997163 3.05432619099013 -0.0872664625997165 +176 0.069756473744126 -0.99756405025982 -0.069926811943511 -14.300666256712 3.07177948351002 10.7669658200377 10.8133044426697 0.99571466586577 1.00430377725782 0.0698131700797739 3.07177948350996 -0.0698131700797738 +177 0.052335956242944 -0.99862953475457 -0.052407779283042 -19.081136687728 3.08923277602996 10.9573431116588 11.0028799896489 0.995861367384452 1.00415583207773 0.0523598775598301 3.08923277602989 -0.0523598775598307 +178 0.034899496702501 -0.9993908270191 -0.034920769491748 -28.636253282915 3.10668606854991 11.1510582855964 11.195807290623 0.996003056870752 1.00401298279325 0.0349065850398866 3.10668606855003 -0.0349065850398869 +179 0.017452406437283 -0.99984769515639 -0.017455064928218 -57.28996163076 3.12413936106985 11.3481703523649 11.3921451161006 0.996139904882926 1.00387505319097 0.0174532925199428 3.12413936106978 -0.0174532925199437 +181 -0.017452406437283 -0.99984769515639 0.017455064928217 57.28996163076 3.15904594610974 11.7528263986386 11.795292635477 0.99639973011686 1.00361327866148 -0.0174532925199428 3.12413936106978 0.0174532925199427 +182 -0.034899496702501 -0.9993908270191 0.034920769491748 28.636253282916 3.17649923862968 11.9604936465537 12.0022251382504 0.996523020421957 1.00348911114624 -0.0349065850398866 3.10668606855003 0.0349065850398869 +183 -0.052335956242944 -0.99862953475457 0.052407779283041 19.081136687728 3.19395253114962 12.1718043616699 12.2128138206871 0.99664209578404 1.00336921772637 -0.0523598775598301 3.08923277602989 0.0523598775598297 +184 -0.069756473744125 -0.99756405025982 0.06992681194351 14.300666256712 3.21140582366957 12.3868229145462 12.4271228333966 0.996757099821844 1.00325345079432 -0.0698131700797729 3.07177948350996 0.0698131700797728 +185 -0.087155742747658 -0.99619469809175 0.087488663525924 11.430052302761 3.22885911618951 12.605614805242 12.6452174602944 0.996868171292678 1.00314166787296 -0.0872664625997163 3.05432619099013 0.0872664625997165 +186 -0.10452846326765 -0.99452189536827 0.10510423526568 9.5143644542226 3.24631240870945 12.8282466832703 12.8671641384897 0.996975444254807 1.00303373143503 -0.104719755119656 3.0368728984701 0.104719755119663 +187 -0.12186934340515 -0.99254615164132 0.1227845609029 8.1443464279746 3.2637657012294 13.054786367901 13.0930304785231 0.997079048224565 1.00292950872916 -0.122173047639606 3.01941960595017 0.122173047639599 +188 -0.13917310096007 -0.99026806874157 0.14054083470239 7.1153697223842 3.28121899374934 13.2853028688201 13.3228852849628 0.997179108328346 1.00282887161202 -0.139626340159551 3.00196631343024 0.139626340159545 +189 -0.15643446504023 -0.98768834059514 0.15838444032454 6.313751514675 3.29867228626928 13.5198664071517 13.5567985773644 0.997275745449641 1.00273169638667 -0.157079632679489 2.98451302091032 0.157079632679493 +190 -0.17364817766693 -0.98480775301221 0.17632698070847 5.6712818196177 3.31612557878923 13.7585484368496 13.7948416116002 0.997369076371266 1.00263786364653 -0.174532925199433 2.96705972839037 0.174532925199438 +191 -0.19080899537654 -0.98162718344766 0.19438030913772 5.1445540159703 3.33357887130917 14.0014216664634 14.0370869015658 0.997459213912935 1.00254725812507 -0.191986217719371 2.9496064358704 0.191986217719378 +192 -0.20791169081776 -0.97814760073381 0.21255656167002 4.7046301094785 3.35103216382911 14.2485600812877 14.2836082412697 0.997546267064323 1.00245976855078 -0.20943951023932 2.93215314335049 0.209439510239317 +193 -0.22495105434386 -0.97437006478524 0.23086819112556 4.3314758742842 3.36848545634906 14.5000389658999 14.5344807273124 0.997630341113751 1.0023752875074 -0.226892802759258 2.91469985083055 0.22689280275926 +194 -0.24192189559967 -0.970295726276 0.24932800284318 4.0107809335358 3.385938748869 14.7559349270936 14.7897807817635 0.997711537772647 1.00229371129902 -0.244346095279208 2.8972465583106 0.244346095279205 +195 -0.25881904510252 -0.96592582628907 0.26794919243112 3.7320508075689 3.40339204138894 15.0163259172148 15.0495861754408 0.9977899552959 1.00221493982012 -0.261799387799149 2.87979326579065 0.261799387799147 +196 -0.275637355817 -0.96126169593832 0.28674538575881 3.4874144438409 3.42084533390889 15.2812912579088 15.313976051602 0.99786568859824 1.00213887643011 -0.279252680319094 2.8623399732707 0.279252680319095 +197 -0.29237170472274 -0.95630475596304 0.30573068145866 3.2708526184841 3.43829862642883 15.5509116642828 15.5830309500536 0.997938829366784 1.00206542783241 -0.296705972839039 2.84488668075077 0.296705972839036 +198 -0.30901699437495 -0.95105651629515 0.32491969623291 3.0776835371753 3.45575191894877 15.8252692694943 15.8568328316849 0.998009466169843 1.00199450395776 -0.314159265358982 2.8274333882308 0.314159265358983 +199 -0.32556815445716 -0.94551857559932 0.34432761328967 2.9042108776758 3.47320521146872 16.1044476497706 16.135465103436 0.998077684562137 1.00192601785171 -0.331612557878926 2.80998009571088 0.331612557878927 +200 -0.34202014332567 -0.93969262078591 0.3639702342662 2.7474774194546 3.49065850398866 16.3885318498683 16.419012643705 0.998143567186515 1.00185988556608 -0.349065850398867 2.79252680319093 0.349065850398864 +201 -0.3583679495453 -0.9335804264972 0.38386403503542 2.6050890646938 3.5081117965086 16.6776084089802 16.7075618282048 0.998207193872294 1.00179602605422 -0.366519142918809 2.77507351067098 0.366519142918813 +202 -0.37460659341591 -0.92718385456679 0.40402622583516 2.4750868534163 3.52556508902855 16.9717653870972 17.0012005562746 0.998268641730333 1.00173436107005 -0.38397243543875 2.75762021815105 0.383972435438755 +203 -0.39073112848927 -0.92050485345244 0.4244748162096 2.3558523658238 3.54301838154849 17.2710923918338 17.3000182776568 0.998327985244943 1.00167481507057 -0.401425727958692 2.7401669256311 0.401425727958692 +204 -0.4067366430758 -0.9135454576426 0.44522868530854 2.2460367739042 3.56047167406843 17.5756806057242 17.6041060197452 0.998385296362727 1.00161731512188 -0.418879020478639 2.72271363311115 0.418879020478642 +205 -0.4226182617407 -0.90630778703665 0.466307658155 2.1445069205096 3.57792496658838 17.8856228139997 17.9135564153148 0.998440644578469 1.0015617908085 -0.436332312998583 2.70526034059121 0.436332312998584 +206 -0.43837114678908 -0.89879404629917 0.48773258856586 2.0503038415793 3.59537825910832 18.2010134328527 18.2284637307394 0.998494097018144 1.0015081741458 -0.453785605518529 2.68780704807127 0.453785605518525 +207 -0.45399049973955 -0.89100652418837 0.50952544949443 1.9626105055052 3.61283155162826 18.5219485381985 18.5489238947081 0.998545718519159 1.00145639949566 -0.471238898038473 2.67035375555133 0.47123889803847 +208 -0.46947156278589 -0.88294759285893 0.53170943166148 1.8807264653463 3.63028484414821 18.8485258949427 18.8750345274472 0.998595571707909 1.00140640348494 -0.488692190558411 2.65290046303139 0.488692190558413 +209 -0.48480962024634 -0.8746197071394 0.55430905145277 1.8040477552714 3.64773813666815 19.1808449867622 19.2068949704579 0.99864371707474 1.00135812492691 -0.506145483078359 2.63544717051145 0.506145483078356 +210 -0.5 -0.86602540378444 0.57735026918963 1.7320508075689 3.66519142918809 19.5190070464112 19.5446063167783 0.998690213046393 1.00131150474541 -0.523598775598299 2.6179938779915 0.523598775598302 +211 -0.51503807491005 -0.85716730070211 0.60086061902756 1.6642794823505 3.68264472170804 19.8631150865585 19.8882714417787 0.998735116056024 1.00126648590166 -0.541052068118237 2.60054058547155 0.541052068118242 +212 -0.5299192642332 -0.84804809615643 0.62486935190933 1.6003345290411 3.70009801422798 20.2132739311685 20.2379950345002 0.998778480610871 1.00122301332362 -0.55850536063818 2.58308729295162 0.558505360638187 +213 -0.54463903501503 -0.83867056794542 0.64940759319751 1.5398649638146 3.71755130674792 20.5695902474326 20.5938836295458 0.998820359357652 1.00118103383786 -0.575958653158132 2.56563400043166 0.575958653158128 +214 -0.55919290347075 -0.82903757255504 0.67450851684243 1.4825609685127 3.73500459926786 20.9321725782629 20.9560456395328 0.998860803145759 1.00114049610382 -0.593411945678076 2.54818070791172 0.593411945678074 +215 -0.57357643635105 -0.81915204428899 0.70020753820971 1.4281480067421 3.75245789178781 21.3011313753573 21.3245913881188 0.998899861088331 1.00110135055027 -0.61086523819802 2.53072741539177 0.610865238198016 +216 -0.58778525229247 -0.80901699437495 0.72654252800536 1.3763819204712 3.76991118430775 21.6765790328456 21.6996331436087 0.99893758062127 1.00106354931413 -0.628318530717955 2.51327412287184 0.628318530717958 +217 -0.60181502315205 -0.79863551004729 0.75355405010279 1.3270448216204 3.7873644768277 22.0586299215277 22.0812851531544 0.998974007560268 1.00102704618135 -0.645771823237904 2.49582083035189 0.645771823237899 +218 -0.61566147532566 -0.78801075360672 0.78128562650672 1.2799416321931 3.80481776934764 22.447400423714 22.4696636775576 0.999009186155914 1.00099179652982 -0.663225115757847 2.47836753783194 0.663225115757847 +219 -0.62932039104984 -0.77714596145697 0.80978403319501 1.2348971565351 3.82227106186758 22.8430089686778 22.8648870266856 0.999043159146938 1.00095775727435 -0.680678408277792 2.460914245312 0.68067840827779 +220 -0.64278760968654 -0.76604444311898 0.83909963117728 1.1917535925942 3.83972435438752 23.2455760687325 23.2670755955111 0.999075967811667 1.00092488681352 -0.698131700797733 2.44346095279206 0.698131700797732 +221 -0.65605902899051 -0.75470958022277 0.86928673781623 1.150368407221 3.85717764690747 23.6552243559425 23.6763519007885 0.999107652017734 1.00089314497839 -0.715584993317679 2.42600766027211 0.715584993317677 +222 -0.66913060635886 -0.74314482547739 0.90040404429784 1.1106125148292 3.87463093942741 24.0720786194796 24.0928406183747 0.999138250270112 1.00086249298298 -0.733038285837621 2.40855436775217 0.733038285837618 +223 -0.6819983600625 -0.73135370161917 0.93251508613766 1.0723687100247 3.89208423194735 24.4962658436374 24.5166686212086 0.999167799757525 1.00083289337654 -0.750491578357564 2.39110107523223 0.750491578357561 +224 -0.694658370459 -0.71933980033865 0.96568877480707 1.0355303137906 3.9095375244673 24.9279152465139 24.9479650179605 0.999196336397291 1.00080430999738 -0.767944870877509 2.37364778271229 0.767944870877503 +225 -0.70710678118655 -0.70710678118655 1 1 3.92699081698724 25.3671583193742 25.3868611923608 0.999223894878641 1.00077670792836 -0.785398163397452 2.35619449019235 0.785398163397448 +226 -0.71933980033865 -0.694658370459 1.0355303137906 0.96568877480707 3.94444410950718 25.8141288667063 25.8334908432236 0.999250508704579 1.00075005345396 -0.80285145591739 2.33874119767241 0.802851455917406 +227 -0.73135370161917 -0.6819983600625 1.0723687100247 0.93251508613766 3.96189740202713 26.2689630469814 26.2879900251745 0.99927621023232 1.00072431401876 -0.820304748437334 2.32128790515246 0.820304748437343 +228 -0.74314482547739 -0.66913060635886 1.1106125148292 0.90040404429784 3.97935069454707 26.7317994141311 26.7504971900961 0.999301030712359 1.00069945818743 -0.837758040957272 2.30383461263252 0.837758040957282 +229 -0.75470958022277 -0.65605902899051 1.150368407221 0.86928673781623 3.99680398706701 27.2027789597543 27.221153229304 0.999325000326217 1.0006754556061 -0.855211333477218 2.28638132011258 0.855211333477218 +230 -0.76604444311898 -0.64278760968654 1.1917535925942 0.83909963117728 4.01425727958696 27.6820451560668 27.700101516466 0.999348148222906 1.00065227696499 -0.872664625997168 2.26892802759263 0.872664625997161 +231 -0.77714596145697 -0.62932039104984 1.2348971565351 0.80978403319501 4.0317105721069 28.1697439996069 28.187487951277 0.999370502554154 1.00062989396249 -0.890117918517107 2.25147473507269 0.890117918517127 +232 -0.78801075360672 -0.61566147532566 1.2799416321931 0.78128562650672 4.04916386462685 28.6660240557091 28.6834610039042 0.999392090508439 1.0006082792703 -0.907571211037048 2.23402144255274 0.907571211037059 +233 -0.79863551004729 -0.60181502315205 1.3270448216204 0.75355405010279 4.06661715714679 29.1710365037612 29.1881717602143 0.999412938343867 1.00058740649997 -0.92502450355699 2.2165681500328 0.925024503556991 +234 -0.80901699437495 -0.58778525229247 1.3763819204712 0.72654252800536 4.08407044966673 29.6849351832573 29.7017739677984 0.999433071419931 1.0005672501704 -0.942477796076942 2.19911485751285 0.942477796076947 +235 -0.81915204428899 -0.57357643635105 1.4281480067421 0.70020753820971 4.10152374218667 30.2078766406609 30.2244240828073 0.999452514228191 1.00054778567667 -0.959931088596878 2.18166156499292 0.959931088596876 +236 -0.82903757255504 -0.55919290347075 1.4825609685127 0.67450851684243 4.11897703470662 30.7400201770932 30.7562813176121 0.999471290421914 1.00052898925977 -0.977384381116821 2.16420827247297 0.977384381116812 +237 -0.83867056794542 -0.54463903501503 1.5398649638146 0.64940759319751 4.13643032722656 31.2815278968602 31.297507689304 0.999489422844706 1.0005108379775 -0.994837673636761 2.14675497995303 0.994837673636773 +238 -0.84804809615643 -0.52991926423321 1.6003345290411 0.62486935190933 4.1538836197465 31.8325647568337 31.848268069049 0.999506933558166 1.00049330967628 -1.01229096615672 2.12930168743309 1.01229096615673 +239 -0.85716730070211 -0.51503807491005 1.6642794823505 0.60086061902756 4.17133691226645 32.393298616701 32.4087302323119 0.999523843868605 1.00047638296406 -1.02974425867665 2.11184839491313 1.02974425867665 +240 -0.86602540378444 -0.5 1.7320508075689 0.57735026918963 4.18879020478639 32.9639002900999 32.9790649099645 0.999540174352852 1.00046003718404 -1.0471975511966 2.0943951023932 1.0471975511966 +241 -0.8746197071394 -0.48480962024634 1.8040477552714 0.55430905145277 4.20624349730633 33.5445435966521 33.559445840295 0.999555944883184 1.00044425238936 -1.06465084371655 2.07694180987326 1.06465084371654 +242 -0.88294759285893 -0.46947156278589 1.8807264653463 0.53170943166148 4.22369678982628 34.1354054149134 34.1500498219329 0.999571174651403 1.00042900931867 -1.08210413623649 2.05948851735331 1.08210413623648 +243 -0.89100652418837 -0.45399049973955 1.9626105055051 0.50952544949443 4.24115008234622 34.7366657362553 34.7510567677061 0.999585882192101 1.00041428937251 -1.09955742875643 2.04203522483337 1.09955742875642 +244 -0.89879404629917 -0.43837114678908 2.0503038415793 0.48773258856586 4.25860337486616 35.3485077196949 35.3626497594472 0.999600085405124 1.00040007459054 -1.11701072127638 2.02458193231342 1.11701072127637 +245 -0.90630778703665 -0.4226182617407 2.1445069205096 0.466307658155 4.27605666738611 35.9711177476897 35.9850151037645 0.999613801577276 1.00038634762957 -1.13446401379631 2.00712863979348 1.13446401379632 +246 -0.9135454576426 -0.4067366430758 2.2460367739042 0.44522868530854 4.29350995990605 36.6046854829145 36.6183423887959 0.99962704740328 1.00037309174225 -1.15191730631626 1.98967534727354 1.15191730631625 +247 -0.92050485345244 -0.39073112848927 2.3558523658238 0.4244748162096 4.31096325242599 37.2494039260371 37.2628245419623 0.999639839006029 1.00036029075665 -1.1693705988362 1.97222205475359 1.16937059883621 +248 -0.92718385456679 -0.37460659341591 2.4750868534163 0.40402622583516 4.32841654494594 37.9054694745118 37.9186578887379 0.999652191956139 1.00034792905639 -1.18682389135615 1.95476876223365 1.18682389135614 +249 -0.9335804264972 -0.3583679495453 2.6050890646938 0.38386403503542 4.34586983746588 38.5730819824062 38.5860422124559 0.999664121290845 1.00033599156157 -1.20427718387608 1.93731546971371 1.20427718387609 +250 -0.93969262078591 -0.34202014332567 2.7474774194546 0.3639702342662 4.36332312998582 39.2524448212824 39.2651808151678 0.999675641532244 1.00032446371031 -1.22173047639604 1.91986217719376 1.22173047639603 +251 -0.94551857559932 -0.32556815445716 2.9042108776758 0.34432761328967 4.38077642250577 39.9437649421488 39.9562805795739 0.999686766704919 1.00031333144092 -1.23918376891598 1.90240888467382 1.23918376891597 +252 -0.95105651629515 -0.30901699437495 3.0776835371753 0.32491969623291 4.39822971502571 40.6472529385026 40.6595520320454 0.999697510352964 1.00030258117471 -1.25663706143591 1.88495559215388 1.25663706143592 +253 -0.95630475596304 -0.29237170472274 3.2708526184841 0.30573068145866 4.41568300754565 41.363123110482 41.3752094067558 0.999707885556422 1.00029219979936 -1.27409035395588 1.86750229963394 1.27409035395586 +254 -0.96126169593832 -0.275637355817 3.4874144438409 0.28674538575881 4.4331363000656 42.0915935301475 42.103470710942 0.99971790494717 1.0002821746529 -1.29154364647581 1.85004900711399 1.2915436464758 +255 -0.96592582628907 -0.25881904510252 3.7320508075689 0.26794919243112 4.45058959258554 42.8328861079115 42.8445577913148 0.99972758072425 1.00027249350823 -1.30899693899575 1.83259571459405 1.30899693899575 +256 -0.970295726276 -0.24192189559967 4.0107809335358 0.24932800284318 4.46804288510548 43.5872266601387 43.5986964016392 0.999736924668691 1.00026314455815 -1.32645023151571 1.81514242207411 1.32645023151569 +257 -0.97437006478524 -0.22495105434387 4.3314758742842 0.23086819112556 4.48549617762543 44.3548449779348 44.3661162715042 0.999745948157815 1.00025411640093 -1.34390352403566 1.79768912955416 1.34390352403564 +258 -0.97814760073381 -0.20791169081776 4.7046301094784 0.21255656167002 4.50294947014537 45.1359748971471 45.1470511763049 0.999754662179053 1.00024539802636 -1.3613568165556 1.78023583703422 1.36135681655557 +259 -0.98162718344766 -0.19080899537654 5.1445540159703 0.19438030913772 4.52040276266531 45.9308543695963 45.9417390084557 0.999763077343297 1.00023697880235 -1.3788101090755 1.76278254451427 1.37881010907552 +260 -0.98480775301221 -0.17364817766693 5.6712818196177 0.17632698070846 4.53785605518526 46.7397255355628 46.7504218498586 0.999771203897791 1.00022884846184 -1.39626340159548 1.74532925199433 1.39626340159546 +261 -0.98768834059514 -0.15643446504023 6.313751514675 0.15838444032454 4.5553093477052 47.562834797549 47.5733460456476 0.999779051738582 1.00022099709034 -1.41371669411542 1.72787595947439 1.41371669411541 +262 -0.99026806874157 -0.13917310096007 7.1153697223842 0.14054083470239 4.57276264022514 48.4004328953393 48.4107622792313 0.999786630422541 1.00021341511375 -1.43116998663535 1.71042266695445 1.43116998663535 +263 -0.99254615164132 -0.12186934340515 8.1443464279746 0.12278456090291 4.59021593274509 49.2527749823821 49.2629256486576 0.999793949178986 1.00020609328671 -1.44862327915528 1.6929693744345 1.44862327915529 +264 -0.99452189536827 -0.10452846326765 9.5143644542225 0.10510423526568 4.60766922526503 50.1201207035156 50.1300957443228 0.999801016920891 1.00019902268125 -1.4660765716752 1.67551608191455 1.46607657167524 +265 -0.99619469809175 -0.087155742747658 11.430052302761 0.087488663525924 4.62512251778497 51.0027342740623 51.0125367280496 0.999807842255727 1.00019219467597 -1.48352986419523 1.65806278939461 1.48352986419518 +266 -0.99756405025982 -0.069756473744126 14.300666256712 0.069926811943511 4.64257581030492 51.9008845603159 51.9105174135573 0.99981443349592 1.0001856009454 -1.50098315671506 1.64060949687467 1.50098315671512 +267 -0.99862953475457 -0.052335956242943 19.081136687728 0.052407779283041 4.66002910282486 52.8148451614442 52.8243113483491 0.99982079866896 1.00017923344991 -1.51843644923499 1.62315620435473 1.51843644923507 +268 -0.9993908270191 -0.034899496702501 28.636253282916 0.034920769491748 4.6774823953448 53.7448944928348 53.7541968970418 0.999826945527158 1.00017308442588 -1.53588974175513 1.60570291183478 1.53588974175501 +269 -0.99984769515639 -0.017452406437283 57.289961630759 0.017455064928218 4.69493568786475 54.691315870907 54.7004573261625 0.999832881557078 1.00016714637616 -1.55334303427489 1.58824961931484 1.55334303427495 +271 -0.99984769515639 0.017452406437283 -57.289961630761 -0.017455064928217 4.72984227290463 56.6344330572848 56.643260920608 0.999844149803883 1.00015587448919 -1.55334303427489 1.55334303427495 -1.55334303427495 +272 -0.9993908270191 0.0348994967025 -28.636253282916 -0.034920769491747 4.74729556542458 57.6317207879597 57.6403959127741 0.999849495745526 1.00015052690941 -1.53588974175513 1.53588974175501 -1.53588974175501 +273 -0.99862953475457 0.052335956242943 -19.081136687728 -0.05240777928304 4.76474885794452 58.6465645903691 58.655089619336 0.999854658325097 1.00014536280218 -1.51843644923499 1.51843644923507 -1.51843644923507 +274 -0.99756405025982 0.069756473744125 -14.300666256712 -0.06992681194351 4.78220215046446 59.6792736114613 59.6876511415188 0.999859643830887 1.00014037587173 -1.50098315671506 1.50098315671512 -1.50098315671512 +275 -0.99619469809175 0.087155742747658 -11.430052302761 -0.087488663525924 4.79965544298441 60.7301624403791 60.7383950235338 0.999864458335597 1.00013556003844 -1.48352986419523 1.48352986419518 -1.48352986419518 +276 -0.99452189536827 0.10452846326765 -9.5143644542225 -0.10510423526568 4.81710873550435 61.7995512042926 61.8076413483962 0.999869107703721 1.00013090943131 -1.4660765716752 1.46607657167524 -1.46607657167524 +277 -0.99254615164132 0.12186934340515 -8.1443464279746 -0.1227845609029 4.83456202802429 62.8877656659169 62.8957158354309 0.999873597598685 1.0001264183809 -1.44862327915528 1.44862327915529 -1.44862327915529 +278 -0.99026806874157 0.13917310096007 -7.1153697223842 -0.14054083470239 4.85201532054424 63.9951373227483 64.0029499394943 0.999877933489732 1.00012208141232 -1.43116998663535 1.43116998663535 -1.43116998663535 +279 -0.98768834059514 0.15643446504023 -6.3137515146751 -0.15838444032454 4.86946861306418 65.1220035080468 65.1296809519443 0.99988212065858 1.0001178932386 -1.41371669411542 1.41371669411541 -1.41371669411541 +280 -0.98480775301221 0.17364817766693 -5.6712818196177 -0.17632698070846 4.88692190558412 66.2687074935959 66.2762521033874 0.999886164205848 1.00011384875422 -1.39626340159548 1.39626340159546 -1.39626340159546 +281 -0.98162718344766 0.19080899537654 -5.1445540159703 -0.19438030913772 4.90437519810407 67.435598594272 67.4430126682356 0.999890069057265 1.00010994302888 -1.3788101090755 1.37881010907553 -1.37881010907552 +282 -0.97814760073381 0.20791169081776 -4.7046301094785 -0.21255656167002 4.92182849062401 68.6230322744548 68.6303180711037 0.999893839969656 1.00010617130149 -1.3613568165556 1.36135681655558 -1.36135681655558 +283 -0.97437006478524 0.22495105434386 -4.3314758742842 -0.23086819112556 4.93928178314395 69.83137025631 69.8385299950812 0.999897481536743 1.00010252897437 -1.34390352403566 1.34390352403564 -1.34390352403564 +284 -0.970295726276 0.24192189559967 -4.0107809335358 -0.24932800284318 4.9567350756639 71.0609806299797 71.0680164919097 0.999900998194725 1.0000990116076 -1.32645023151571 1.32645023151569 -1.32645023151569 +285 -0.96592582628907 0.25881904510252 -3.7320508075689 -0.26794919243112 4.97418836818384 72.3122379657115 72.3191520941009 0.999904394227682 1.00009561491366 -1.30899693899575 1.30899693899575 -1.30899693899575 +286 -0.96126169593832 0.275637355817 -3.4874144438409 -0.28674538575881 4.99164166070378 73.5855234279623 73.5923179290284 0.99990767377279 1.00009233475213 -1.29154364647581 1.2915436464758 -1.2915436464758 +287 -0.95630475596304 0.29237170472274 -3.2708526184841 -0.30573068145866 5.00909495322373 74.88122489151 74.8879018350287 0.999910840825352 1.00008916712472 -1.27409035395588 1.27409035395586 -1.27409035395586 +288 -0.95105651629515 0.30901699437495 -3.0776835371753 -0.32491969623291 5.02654824574367 76.1997370596106 76.2062984795469 0.999913899243669 1.00008610817031 -1.25663706143591 1.25663706143591 -1.25663706143592 +289 -0.94551857559932 0.32556815445716 -2.9042108776758 -0.34432761328966 5.04400153826361 77.5414615842345 77.5479094793619 0.999916852753727 1.00008315416031 -1.23918376891598 1.23918376891597 -1.23918376891597 +290 -0.93969262078591 0.34202014332567 -2.7474774194546 -0.3639702342662 5.06145483078356 78.9068071884196 78.9131435229292 0.999919704953741 1.00008030149407 -1.22173047639604 1.22173047639603 -1.22173047639603 +291 -0.9335804264972 0.3583679495453 -2.6050890646938 -0.38386403503542 5.0789081233035 80.2961897907787 80.3024164948774 0.99992245931853 1.00007754669449 -1.20427718387608 1.20427718387609 -1.20427718387609 +292 -0.92718385456679 0.37460659341591 -2.4750868534163 -0.40402622583516 5.09636141582344 81.710032632199 81.7161516026974 0.999925119203751 1.0000748864038 -1.18682389135615 1.18682389135615 -1.18682389135614 +293 -0.92050485345244 0.39073112848927 -2.3558523658238 -0.4244748162096 5.11381470834339 83.1487664047718 83.1547795056622 0.99992768784998 1.00007231737944 -1.1693705988362 1.1693705988362 -1.16937059883621 +294 -0.9135454576426 0.4067366430758 -2.2460367739042 -0.44522868530854 5.13126800086333 84.6128293829918 84.6187384460161 0.999930168386662 1.00006983649013 -1.15191730631626 1.15191730631626 -1.15191730631625 +295 -0.90630778703665 0.4226182617407 -2.1445069205096 -0.466307658155 5.14872129338327 86.1026675572673 86.1084743824747 0.999932563835918 1.00006744071203 -1.13446401379631 1.13446401379631 -1.13446401379632 +296 -0.89879404629917 0.43837114678908 -2.0503038415793 -0.48773258856586 5.16617458590322 87.6187347697791 87.6244411260745 0.999934877116224 1.00006512712504 -1.11701072127638 1.11701072127637 -1.11701072127637 +297 -0.89100652418837 0.45399049973955 -1.9626105055052 -0.50952544949443 5.18362787842316 89.1614928527332 89.1671004784163 0.999937111045968 1.0000628929093 -1.09955742875643 1.09955742875642 -1.09955742875644 +298 -0.88294759285893 0.46947156278589 -1.8807264653463 -0.53170943166148 5.2010811709431 90.7314117690457 90.7369223723404 0.99993926834688 1.00006073534168 -1.08210413623649 1.08210413623649 -1.08210413623648 +299 -0.8746197071394 0.48480962024634 -1.8040477552714 -0.55430905145277 5.21853446346305 92.3289697555063 92.3343850150809 0.999941351647344 1.00005865179249 -1.06465084371655 1.06465084371654 -1.06465084371654 +300 -0.86602540378444 0.5 -1.7320508075689 -0.57735026918963 5.23598775598299 93.9546534684599 93.9599750339387 0.999943363485603 1.00005663972227 -1.0471975511966 1.0471975511966 -1.0471975511966 +301 -0.85716730070211 0.51503807491005 -1.6642794823505 -0.60086061902756 5.25344104850293 95.6089581320556 95.6141876245213 0.999945306312843 1.00005469667872 -1.02974425867665 1.02974425867666 -1.02974425867665 +302 -0.84804809615643 0.5299192642332 -1.6003345290411 -0.62486935190933 5.27089434102288 97.2923876891039 97.2975267015914 0.999947182496187 1.00005282029365 -1.01229096615672 1.01229096615672 -1.01229096615673 +303 -0.83867056794542 0.54463903501503 -1.5398649638146 -0.64940759319751 5.28834763354282 99.0054549545903 99.0105050525721 0.999948994321571 1.00005100828014 -0.994837673636761 0.994837673636764 -0.994837673636773 +304 -0.82903757255504 0.55919290347075 -1.4825609685127 -0.67450851684243 5.30580092606276 100.748681771892 100.753644493755 0.999950743996528 1.00004925842975 -0.977384381116821 0.977384381116821 -0.977384381116812 +305 -0.81915204428899 0.57357643635105 -1.4281480067421 -0.70020753820971 5.32325421858271 102.522599171744 102.527476029258 0.999952433652881 1.00004756860978 -0.959931088596878 0.959931088596876 -0.959931088596876 +306 -0.80901699437495 0.58778525229247 -1.3763819204712 -0.72654252800536 5.34070751110265 104.327747534004 104.332540012783 0.999954065349334 1.00004593676076 -0.942477796076942 0.942477796076942 -0.942477796076947 +307 -0.79863551004729 0.60181502315205 -1.3270448216204 -0.75355405010279 5.35816080362259 106.164676752269 106.169386312221 0.999955641073983 1.00004436089382 -0.92502450355699 0.925024503556993 -0.925024503556991 +308 -0.78801075360672 0.61566147532566 -1.2799416321931 -0.78128562650672 5.37561409614254 108.03394640138 108.038574477158 0.999957162746735 1.00004283908837 -0.907571211037048 0.907571211037049 -0.907571211037059 +309 -0.77714596145697 0.62932039104984 -1.2348971565351 -0.80978403319501 5.39306738866248 109.936125907891 109.940673909321 0.999958632221649 1.00004136948971 -0.890117918517107 0.890117918517105 -0.890117918517127 +310 -0.76604444311898 0.64278760968654 -1.1917535925942 -0.83909963117728 5.41052068118242 111.871794723523 111.876264036042 0.99996005128919 1.00003995030677 -0.872664625997168 0.872664625997164 -0.872664625997161 +311 -0.75470958022277 0.65605902899051 -1.150368407221 -0.86928673781623 5.42797397370237 113.841542501685 113.845934486757 0.999961421678414 1.00003857980993 -0.855211333477218 0.855211333477218 -0.855211333477218 +312 -0.74314482547739 0.66913060635886 -1.1106125148292 -0.90040404429784 5.44542726622231 115.845969277093 115.850285272628 0.99996274505907 1.00003725632891 -0.837758040957272 0.837758040957276 -0.837758040957282 +313 -0.73135370161917 0.6819983600625 -1.0723687100247 -0.93251508613766 5.46288055874225 117.885685648561 117.889926969319 0.99996402304364 1.00003597825075 -0.820304748437334 0.820304748437333 -0.820304748437343 +314 -0.71933980033865 0.694658370459 -1.0355303137906 -0.96568877480707 5.4803338512622 119.961312964998 119.965480902992 0.999965257189294 1.00003474401781 -0.80285145591739 0.802851455917388 -0.802851455917406 +315 -0.70710678118655 0.70710678118655 -1 -1 5.49778714378214 122.073483514693 122.077579339582 0.999966448999796 1.00003355212591 -0.785398163397452 0.785398163397445 -0.785398163397448 +316 -0.694658370459 0.71933980033865 -0.96568877480707 -1.0355303137906 5.51524043630208 124.222840717921 124.226865677397 0.999967599927328 1.00003240112247 -0.767944870877509 0.767944870877507 -0.767944870877503 +317 -0.6819983600625 0.73135370161917 -0.93251508613766 -1.0723687100247 5.53269372882203 126.410039322949 126.413994643115 0.999968711374265 1.00003128960474 -0.750491578357564 0.750491578357562 -0.750491578357561 +318 -0.66913060635886 0.74314482547739 -0.90040404429784 -1.1106125148292 5.55014702134197 128.635745605484 128.639632491231 0.99996978469488 1.00003021621811 -0.733038285837621 0.733038285837625 -0.733038285837618 +319 -0.65605902899051 0.75470958022277 -0.86928673781623 -1.150368407221 5.56760031386191 130.900637571644 130.904457207013 0.999970821196992 1.00002917965444 -0.715584993317679 0.715584993317678 -0.715584993317677 +320 -0.64278760968654 0.76604444311898 -0.83909963117728 -1.1917535925942 5.58505360638185 133.205405164487 133.209158713037 0.999971822143564 1.00002817865045 -0.698131700797733 0.698131700797729 -0.698131700797732 +321 -0.62932039104984 0.77714596145697 -0.80978403319501 -1.2348971565351 5.6025068989018 135.550750474194 135.55443907935 0.999972788754238 1.00002721198623 -0.680678408277792 0.68067840827779 -0.68067840827779 +322 -0.61566147532566 0.78801075360672 -0.78128562650672 -1.2799416321931 5.61996019142174 137.937387951938 137.941012737342 0.999973722206821 1.00002627848372 -0.663225115757847 0.663225115757848 -0.663225115757847 +323 -0.60181502315205 0.79863551004729 -0.75355405010279 -1.3270448216204 5.63741348394168 140.366044627524 140.369606697376 0.999974623638721 1.00002537700526 -0.645771823237904 0.645771823237907 -0.645771823237899 +324 -0.58778525229247 0.80901699437495 -0.72654252800536 -1.3763819204712 5.65486677646163 142.837460330862 142.840960770259 0.999975494148332 1.00002450645222 -0.628318530717955 0.628318530717954 -0.628318530717958 +325 -0.57357643635105 0.81915204428899 -0.70020753820971 -1.4281480067421 5.67232006898157 145.352387917338 145.355827792601 0.999976334796373 1.00002366576368 -0.61086523819802 0.610865238198018 -0.610865238198016 +326 -0.55919290347075 0.82903757255504 -0.67450851684243 -1.4825609685127 5.68977336150152 147.911593497152 147.914973856154 0.999977146607176 1.00002285391511 -0.593411945678076 0.593411945678075 -0.593411945678074 +327 -0.54463903501503 0.83867056794542 -0.64940759319751 -1.5398649638146 5.70722665402146 150.515856668693 150.519178541176 0.999977930569941 1.00002206991713 -0.575958653158132 0.575958653158136 -0.575958653158128 +328 -0.52991926423321 0.84804809615643 -0.62486935190933 -1.6003345290411 5.7246799465414 153.165970756027 153.169235153918 0.999978687639934 1.00002131281429 -0.558505360638191 0.558505360638178 -0.558505360638187 +329 -0.51503807491005 0.85716730070211 -0.60086061902756 -1.6642794823505 5.74213323906134 155.862743050563 155.865950968278 0.999979418739656 1.00002058168394 -0.541052068118237 0.541052068118247 -0.541052068118242 +330 -0.5 0.86602540378444 -0.57735026918963 -1.7320508075689 5.75958653158129 158.606995056971 158.610147471724 0.999980124759965 1.00001987563507 -0.523598775598299 0.523598775598296 -0.523598775598302 +331 -0.48480962024634 0.8746197071394 -0.55430905145277 -1.8040477552714 5.77703982410123 161.399562743438 161.402660615534 0.99998080656116 1.00001919380724 -0.506145483078359 0.506145483078347 -0.506145483078356 +332 -0.46947156278589 0.88294759285893 -0.53170943166148 -1.8807264653463 5.79449311662117 164.241296796322 164.244341069449 0.99998146497403 1.00001853536952 -0.488692190558411 0.488692190558406 -0.488692190558413 +333 -0.45399049973955 0.89100652418837 -0.50952544949443 -1.9626105055051 5.81194640914112 167.133062879291 167.136054480812 0.999982100800868 1.00001789951952 -0.471238898038473 0.471238898038464 -0.47123889803847 +334 -0.43837114678908 0.89879404629917 -0.48773258856586 -2.0503038415793 5.82939970166106 170.07574189703 170.078681738262 0.999982714816446 1.00001728548234 -0.453785605518529 0.453785605518519 -0.453785605518525 +335 -0.4226182617407 0.90630778703665 -0.466307658155 -2.1445069205096 5.846852994181 173.070230263582 173.073119240076 0.99998330776896 1.00001669250968 -0.436332312998583 0.436332312998582 -0.436332312998584 +336 -0.4067366430758 0.9135454576426 -0.44522868530854 -2.2460367739042 5.86430628670095 176.117440175425 176.120279167234 0.99998388038094 1.00001611987891 -0.418879020478639 0.418879020478641 -0.418879020478642 +337 -0.39073112848927 0.92050485345244 -0.4244748162096 -2.3558523658238 5.88175957922089 179.218299889341 179.221089761293 0.999984433350134 1.00001556689219 -0.401425727958692 0.401425727958697 -0.401425727958692 +338 -0.37460659341591 0.92718385456679 -0.40402622583516 -2.4750868534163 5.89921287174083 182.373754005193 182.376495607155 0.999984967350354 1.00001503287563 -0.38397243543875 0.383972435438746 -0.383972435438755 +339 -0.3583679495453 0.9335804264972 -0.38386403503542 -2.6050890646938 5.91666616426078 185.584763753674 185.587457920806 0.9999854830323 1.00001451717845 -0.366519142918809 0.366519142918814 -0.366519142918813 +340 -0.34202014332567 0.93969262078591 -0.3639702342662 -2.7474774194546 5.93411945678072 188.852307289118 188.854954842131 0.99998598102435 1.00001401917218 -0.349065850398867 0.349065850398861 -0.349065850398864 +341 -0.32556815445716 0.94551857559932 -0.34432761328967 -2.9042108776758 5.95157274930066 192.177379987472 192.179981732877 0.999986461933328 1.00001353824995 -0.331612557878926 0.331612557878913 -0.331612557878927 +342 -0.30901699437495 0.95105651629515 -0.32491969623291 -3.0776835371753 5.96902604182061 195.560994749514 195.563551479869 0.999986926345242 1.00001307382568 -0.314159265358982 0.314159265358991 -0.314159265358983 +343 -0.29237170472274 0.95630475596304 -0.30573068145866 -3.2708526184841 5.98647933434055 199.004182309407 199.006694803556 0.999987374826 1.0000126253334 -0.296705972839039 0.296705972839021 -0.296705972839036 +344 -0.275637355817 0.96126169593832 -0.28674538575881 -3.4874144438409 6.00393262686049 202.507991548687 202.510460571999 0.999987807922095 1.00001219222655 -0.279252680319094 0.279252680319089 -0.279252680319095 +345 -0.25881904510252 0.96592582628907 -0.26794919243112 -3.7320508075689 6.02138591938044 206.073489815777 206.075916120379 0.999988226161277 1.00001177397735 -0.261799387799149 0.261799387799143 -0.261799387799147 +346 -0.24192189559967 0.970295726276 -0.24932800284318 -4.0107809335358 6.03883921190038 209.701763251132 209.704147576136 0.999988630053189 1.00001137007609 -0.244346095279208 0.244346095279191 -0.244346095279205 +347 -0.22495105434387 0.97437006478524 -0.23086819112556 -4.3314758742841 6.05629250442032 213.393917118099 213.396260189831 0.999989020089996 1.00001098003056 -0.226892802759268 0.226892802759242 -0.22689280275926 +348 -0.20791169081776 0.97814760073381 -0.21255656167002 -4.7046301094784 6.07374579694027 217.151076139614 217.153378671832 0.999989396746977 1.00001060336545 -0.20943951023932 0.209439510239298 -0.209439510239317 +349 -0.19080899537654 0.98162718344766 -0.19438030913772 -5.1445540159703 6.09119908946021 220.974384840816 220.97664753493 0.999989760483109 1.00001023962174 -0.191986217719371 0.191986217719397 -0.191986217719378 +350 -0.17364817766693 0.98480775301221 -0.17632698070847 -5.6712818196177 6.10865238198015 224.865007897701 224.867231442985 0.999990111741626 1.00000988835615 -0.174532925199433 0.174532925199422 -0.174532925199438 +351 -0.15643446504023 0.98768834059514 -0.15838444032454 -6.313751514675 6.1261056745001 228.824130491912 228.826315565714 0.999990450950555 1.00000954914063 -0.157079632679489 0.157079632679475 -0.157079632679493 +352 -0.13917310096007 0.99026806874157 -0.14054083470239 -7.1153697223842 6.14355896702004 232.852958671773 232.855105939721 0.999990778523242 1.00000922156179 -0.139626340159551 0.139626340159548 -0.139626340159545 +353 -0.12186934340515 0.99254615164132 -0.12278456090291 -8.1443464279746 6.16101225953998 236.952719719683 236.954829835888 0.999991094858853 1.00000890522045 -0.122173047639606 0.12217304763962 -0.122173047639608 +354 -0.10452846326765 0.99452189536827 -0.10510423526568 -9.5143644542225 6.17846555205993 241.124662525975 241.126736133232 0.999991400342864 1.00000859973109 -0.104719755119656 0.104719755119692 -0.104719755119663 +355 -0.087155742747658 0.99619469809175 -0.087488663525924 -11.430052302761 6.19591884457987 245.370057969364 245.372095699346 0.999991695347524 1.00000830472144 -0.0872664625997163 0.0872664625996654 -0.0872664625997165 +356 -0.069756473744126 0.99756405025982 -0.069926811943511 -14.300666256712 6.21337213709981 249.690199304084 249.692201777535 0.999991980232315 1.000008019832 -0.0698131700797739 0.0698131700798344 -0.0698131700797738 +357 -0.052335956242943 0.99862953475457 -0.052407779283041 -19.081136687728 6.23082542961976 254.086402553848 254.088370380771 0.999992255344389 1.00000774471559 -0.0523598775598291 0.0523598775599049 -0.0523598775598297 +358 -0.034899496702501 0.9993908270191 -0.034920769491748 -28.636253282916 6.2482787221397 258.560006912742 258.561940692587 0.999992521018985 1.00000747903695 -0.0349065850398866 0.0349065850397648 -0.0349065850398869 +359 -0.017452406437284 0.99984769515639 -0.017455064928218 -57.289961630759 6.26573201465964 263.112375153174 263.11427547502 0.999992777579847 1.00000722247232 -0.0174532925199438 0.0174532925200115 -0.0174532925199437 diff --git a/settings.gradle b/settings.gradle index e7b4def4..1b96a949 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':jscl'