diff --git a/src/main/java/org/warp/picalculator/math/functions/Multiplication.java b/src/main/java/org/warp/picalculator/math/functions/Multiplication.java index ab3cc05b..72b8825a 100755 --- a/src/main/java/org/warp/picalculator/math/functions/Multiplication.java +++ b/src/main/java/org/warp/picalculator/math/functions/Multiplication.java @@ -84,4 +84,22 @@ public class Multiplication extends FunctionOperator { return result; } } + + public boolean isNegative() { + return parameter1.equals(new Number(getMathContext(), -1)) || parameter2.equals(new Number(getMathContext(), -1)); + } + + public Function toPositive() { + if (parameter1.equals(new Number(getMathContext(), -1))) { + return parameter2; + } else if (parameter2.equals(new Number(getMathContext(), -1))) { + return parameter2; + } else { + return null; + } + } + + public static Multiplication newNegative(MathContext context, Function value2) { + return new Multiplication(context, new Number(context, -1), value2); + } } \ No newline at end of file diff --git a/src/main/java/org/warp/picalculator/math/functions/Undefined.java b/src/main/java/org/warp/picalculator/math/functions/Undefined.java index 3190bab3..286846f2 100755 --- a/src/main/java/org/warp/picalculator/math/functions/Undefined.java +++ b/src/main/java/org/warp/picalculator/math/functions/Undefined.java @@ -29,9 +29,6 @@ public class Undefined implements Function { @Override public boolean equals(Object o) { - if (o instanceof Undefined) { - return true; - } return false; } diff --git a/src/main/java/org/warp/picalculator/math/solver/MathSolver.java b/src/main/java/org/warp/picalculator/math/solver/MathSolver.java index 291653d7..6fe284b2 100644 --- a/src/main/java/org/warp/picalculator/math/solver/MathSolver.java +++ b/src/main/java/org/warp/picalculator/math/solver/MathSolver.java @@ -27,12 +27,13 @@ public class MathSolver { } private final StepState[] stepStates = StepState.values(); @SuppressWarnings("unchecked") - private final ObjectArrayList[] lastFunctions = new ObjectArrayList[stepStates.length]; + private final ObjectArrayList[][] lastFunctions = new ObjectArrayList[2][stepStates.length]; public MathSolver(Function initialFunction) { this.initialFunction = initialFunction; } + @SuppressWarnings("unchecked") public ObjectArrayList> solveAllSteps() throws InterruptedException, Error { ObjectArrayList> steps = new ObjectArrayList<>(); ObjectArrayList lastFnc = null, currFnc = new ObjectArrayList<>(); @@ -42,9 +43,11 @@ public class MathSolver { int initStepState = 0, endStepState = 0; AtomicInteger stepState = new AtomicInteger(0); do { + lastFunctions[1] = lastFunctions[0]; + lastFunctions[0] = new ObjectArrayList[stepStates.length]; final String stepName = "Step " + stepNumber; - for (int i = initStepState; i < endStepState; i++) { - lastFunctions[i] = currFnc; + for (int i = initStepState; i <= endStepState; i++) { + lastFunctions[0][i] = currFnc; } lastFnc = currFnc; initStepState = stepState.get(); @@ -63,11 +66,19 @@ public class MathSolver { Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", stepName, "Step result: " + stepResult); Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", stepName, "Step result details: Consecutive steps that did nothing: " + consecutiveNullSteps + ", this step did " + stepStateRepetitions + " simplifications."); Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", stepName, "Next step state: " + stepStates[endStepState]); - } while(consecutiveNullSteps < stepStates.length && !checkEquals(currFnc, lastFunctions[endStepState])); + if (StaticVars.debugOn) { + Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", stepName, currFnc + " is " + (checkEquals(currFnc, lastFunctions[0][endStepState]) ? "" : "not ") + "equals to [0]:" + lastFunctions[0][endStepState]); + } + if (StaticVars.debugOn) { + Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", stepName, currFnc + " is " + (checkEquals(currFnc, lastFunctions[1][endStepState]) ? "" : "not ") + "equals to [1]:" + lastFunctions[1][endStepState]); + } + } while(consecutiveNullSteps < stepStates.length && !checkEquals(currFnc, lastFunctions[0][endStepState]) && !checkEquals(currFnc, lastFunctions[1][endStepState])); if (consecutiveNullSteps >= stepStates.length) { Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", "Loop ended because " + consecutiveNullSteps + " >= " + stepStates.length); + } else if (checkEquals(currFnc, lastFunctions[0][endStepState])) { + Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", "Loop ended because " + currFnc + " is equals to [0]:" + lastFunctions[0][endStepState]); } else { - Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", "Loop ended because " + currFnc + " is equals to " + lastFunctions[endStepState]); + Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_VERBOSE, "Math Solver", "Loop ended because " + currFnc + " is equals to [1]:" + lastFunctions[1][endStepState]); } return steps; } diff --git a/src/main/resources/font_smal.rft b/src/main/resources/font_smal.rft index bd07662e..0f034b49 100644 Binary files a/src/main/resources/font_smal.rft and b/src/main/resources/font_smal.rft differ diff --git a/src/main/resources/rules.csv b/src/main/resources/rules.csv index 7ab759a4..b171febb 100644 --- a/src/main/resources/rules.csv +++ b/src/main/resources/rules.csv @@ -28,6 +28,11 @@ FractionsRule2 FractionsRule3 FractionsRule4 FractionsRule5 +FractionsRule6 +FractionsRule7 +FractionsRule8 +FractionsRule9 +FractionsRule10 FractionsRule11 FractionsRule12 FractionsRule14 diff --git a/src/main/resources/rules/ExpandRule2.java b/src/main/resources/rules/ExpandRule2.java index 762bfd33..1a9d782b 100644 --- a/src/main/resources/rules/ExpandRule2.java +++ b/src/main/resources/rules/ExpandRule2.java @@ -3,6 +3,8 @@ SETTINGS: (please don't move this part) PATH=ExpandRule2 */ +import org.warp.picalculator.Errors; +import org.warp.picalculator.Error; import org.warp.picalculator.math.Function; import org.warp.picalculator.math.FunctionOperator; import org.warp.picalculator.math.MathContext; @@ -18,7 +20,7 @@ import org.warp.picalculator.math.functions.Number; /** * Expand rule - * -(-a) = a + * a(b+c)=ab+ac * * @author Andrea Cavalli * @@ -42,90 +44,40 @@ public class ExpandRule2 implements Rule { - An ObjectArrayList if it did something */ @Override - public ObjectArrayList execute(Function f) { + public ObjectArrayList execute(Function f) throws Error { boolean isExecutable = false; if (f instanceof Multiplication) { - FunctionOperator fnc = (FunctionOperator) f; - if (fnc.getParameter1().equals(new Number(fnc.getMathContext(), -1))) { - Function expr = fnc.getParameter2(); - if (expr instanceof Sum) { - isExecutable = true; - } else if (expr instanceof Subtraction) { - isExecutable = true; - } else if (expr instanceof SumSubtraction) { - isExecutable = true; - } - } - } else if (f instanceof Subtraction || f instanceof SumSubtraction) { - FunctionOperator fnc = (FunctionOperator) f; - Function expr = fnc.getParameter2(); - if (expr instanceof Sum) { + final Multiplication fnc = (Multiplication) f; + if (fnc.getParameter1() instanceof Sum) { isExecutable = true; - } else if (expr instanceof Subtraction) { - isExecutable = true; - } else if (expr instanceof SumSubtraction) { + } else if (fnc.getParameter2() instanceof Sum) { isExecutable = true; + } else { + isExecutable = false; } } if (isExecutable) { ObjectArrayList result = new ObjectArrayList<>(); MathContext root = f.getMathContext(); - - Function expr = null; - int fromSubtraction = 0; - Function subtraction = null; - if (f instanceof Multiplication) { - expr = ((FunctionOperator) f).getParameter2(); - } else if (f instanceof Subtraction || f instanceof SumSubtraction) { - expr = ((FunctionOperator) f).getParameter2(); - if (f instanceof Subtraction) { - fromSubtraction = 1; - } else { - fromSubtraction = 2; - } + + final Multiplication fnc = (Multiplication) f; + final Sum sum; + final Function a; + if (fnc.getParameter1() instanceof Sum) { + sum = (Sum) fnc.getParameter1(); + a = fnc.getParameter2(); + } else if (fnc.getParameter2() instanceof Sum) { + sum = (Sum) fnc.getParameter2(); + a = fnc.getParameter1(); + } else { + throw new Error(Errors.UNBALANCED_STACK); } - if (f instanceof SumSubtraction) { - - } - - FunctionOperator fnc = (FunctionOperator) expr; - if (fnc instanceof Sum) { - Function a = fnc.getParameter1(); - Function b = fnc.getParameter2(); - Function fnc2 = new Subtraction(root, new Multiplication(root, new Number(root, -1), a), b); - if (fromSubtraction > 0) { - subtraction = new Subtraction(root, ((FunctionOperator)f).getParameter1(), fnc2); - result.add(subtraction); - } else { - result.add(fnc2); - } - } else if (fnc instanceof Subtraction) { - Function a = fnc.getParameter1(); - Function b = fnc.getParameter2(); - Function fnc2 = new Sum(root, new Multiplication(root, new Number(root, -1), a), b); - if (fromSubtraction > 0) { - subtraction = new Subtraction(root, ((FunctionOperator)f).getParameter1(), fnc2); - result.add(subtraction); - } else { - result.add(fnc2); - } - } else if (fnc instanceof SumSubtraction) { - Function a = fnc.getParameter1(); - Function b = fnc.getParameter2(); - Function fnc2 = new Sum(root, new Multiplication(root, new Number(root, -1), a), b); - Function fnc3 = new Subtraction(root, new Multiplication(root, new Number(root, -1), a), b); - if (fromSubtraction > 0) { - subtraction = new SumSubtraction(root, ((FunctionOperator)f).getParameter1(), fnc2); - result.add(subtraction); - subtraction = new SumSubtraction(root, ((FunctionOperator)f).getParameter1(), fnc3); - result.add(subtraction); - result.add(subtraction); - } else { - result.add(fnc2); - result.add(fnc2); - } - } + final Function b = sum.getParameter1(); + final Function c = sum.getParameter2(); + final Multiplication ab = new Multiplication(root, a, b); + final Multiplication ac = new Multiplication(root, a, c); + result.add(new Sum(root, ab, ac)); return result; } else { return null; diff --git a/src/main/resources/rules/FractionsRule10.java b/src/main/resources/rules/FractionsRule10.java new file mode 100644 index 00000000..f366a966 --- /dev/null +++ b/src/main/resources/rules/FractionsRule10.java @@ -0,0 +1,67 @@ +/* +SETTINGS: (please don't move this part) + PATH=FractionsRule10 +*/ + +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.FunctionOperator; +import org.warp.picalculator.math.FunctionDynamic; +import org.warp.picalculator.math.FunctionSingle; +import org.warp.picalculator.math.MathContext; +//Imports + +import java.math.BigDecimal; + +import org.warp.picalculator.Error; +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.MathContext; +import org.warp.picalculator.math.functions.Division; +import org.warp.picalculator.math.functions.Multiplication; +import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.rules.Rule; +import org.warp.picalculator.math.rules.RuleType; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +/** + * Number rule + * a/(-b) = -(a/b) + * + * @author Andrea Cavalli + * + */ +public class FractionsRule10 implements Rule { + // Rule name + @Override + public String getRuleName() { + return "FractionsRule10"; + } + + // Rule type + @Override + public RuleType getRuleType() { + return RuleType.EXPANSION; + } + + /* Rule function + Returns: + - null if it's not executable on the function "f" + - An ObjectArrayList if it did something + */ + + @Override + public ObjectArrayList execute(Function f) { + if (f instanceof Division) { + MathContext root = f.getMathContext(); + Division div = (Division) f; + if (div.getParameter2() instanceof Multiplication && ((Multiplication)div.getParameter2()).isNegative()) { + ObjectArrayList result = new ObjectArrayList<>(); + result.add(Multiplication.newNegative(root, new Division(root, div.getParameter1(), ((Multiplication)div.getParameter2()).toPositive()))); + return result; + } + } + + return null; + } +} diff --git a/src/main/resources/rules/FractionsRule12.java b/src/main/resources/rules/FractionsRule12.java index 96e70c5e..340021ba 100644 --- a/src/main/resources/rules/FractionsRule12.java +++ b/src/main/resources/rules/FractionsRule12.java @@ -72,7 +72,7 @@ public class FractionsRule12 implements Rule { a = fnc.getParameter2(); b = div2.getParameter1(); c = div2.getParameter2(); - result.add(new Division(fnc.getMathContext(), new Multiplication(fnc.getMathContext(), a, c), b)); + result.add(new Division(fnc.getMathContext(), b, new Multiplication(fnc.getMathContext(), c, a))); return result; } else { diff --git a/src/main/resources/rules/FractionsRule6.java b/src/main/resources/rules/FractionsRule6.java new file mode 100644 index 00000000..488ccada --- /dev/null +++ b/src/main/resources/rules/FractionsRule6.java @@ -0,0 +1,76 @@ +/* +SETTINGS: (please don't move this part) + PATH=FractionsRule6 +*/ + +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.FunctionOperator; +import org.warp.picalculator.math.FunctionDynamic; +import org.warp.picalculator.math.FunctionSingle; +import org.warp.picalculator.math.MathContext; +//Imports + + +import org.warp.picalculator.Error; +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.MathContext; +import org.warp.picalculator.math.functions.Division; +import org.warp.picalculator.math.functions.Multiplication; +import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.rules.Rule; +import org.warp.picalculator.math.rules.RuleType; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +/** + * Number rule + * a ^ -1 = 1/a + * + * @author Andrea Cavalli + * + */ +public class FractionsRule6 implements Rule { + // Rule name + @Override + public String getRuleName() { + return "FractionsRule6"; + } + + // Rule type + @Override + public RuleType getRuleType() { + return RuleType.EXPANSION; + } + + /* Rule function + Returns: + - null if it's not executable on the function "f" + - An ObjectArrayList if it did something + */ + + @Override + public ObjectArrayList execute(Function f) { + boolean isExecutable = false; + if (f instanceof Power) { + MathContext root = f.getMathContext(); + Power pow = (Power) f; + if (pow.getParameter2() instanceof Number) { + Function numb = pow.getParameter2(); + if (numb.equals(new Number(root, -1))) { + isExecutable = true; + } + } + } + + if (isExecutable) { + MathContext root = f.getMathContext(); + ObjectArrayList result = new ObjectArrayList<>(); + Function a = new Division(root, new Number(root, 1), ((Power) f).getParameter1()); + result.add(a); + return result; + } else { + return null; + } + } +} diff --git a/src/main/resources/rules/FractionsRule7.java b/src/main/resources/rules/FractionsRule7.java new file mode 100644 index 00000000..69d0bf8c --- /dev/null +++ b/src/main/resources/rules/FractionsRule7.java @@ -0,0 +1,77 @@ +/* +SETTINGS: (please don't move this part) + PATH=FractionsRule7 +*/ + +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.FunctionOperator; +import org.warp.picalculator.math.FunctionDynamic; +import org.warp.picalculator.math.FunctionSingle; +import org.warp.picalculator.math.MathContext; +//Imports + +import java.math.BigDecimal; + +import org.warp.picalculator.Error; +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.MathContext; +import org.warp.picalculator.math.functions.Division; +import org.warp.picalculator.math.functions.Multiplication; +import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.rules.Rule; +import org.warp.picalculator.math.rules.RuleType; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +/** + * Number rule + * a ^ -b = 1/(a^b) + * + * @author Andrea Cavalli + * + */ +public class FractionsRule7 implements Rule { + // Rule name + @Override + public String getRuleName() { + return "FractionsRule7"; + } + + // Rule type + @Override + public RuleType getRuleType() { + return RuleType.EXPANSION; + } + + /* Rule function + Returns: + - null if it's not executable on the function "f" + - An ObjectArrayList if it did something + */ + + @Override + public ObjectArrayList execute(Function f) { + boolean isExecutable = false; + if (f instanceof Power) { + MathContext root = f.getMathContext(); + Power pow = (Power) f; + if (pow.getParameter2() instanceof Number) { + Number numb = (Number) pow.getParameter2(); + if (numb.getTerm().compareTo(BigDecimal.ZERO) < 0) { + ObjectArrayList result = new ObjectArrayList<>(); + Function a = new Division(root, new Number(root, 1), new Power(root, ((Power) f).getParameter1(), ((Number)((Power)f).getParameter2()).multiply(new Number(root, -1)))); + result.add(a); + return result; + } + } else if (pow.getParameter2() instanceof Multiplication && ((Multiplication)pow.getParameter2()).getParameter1().equals(new Number(root, -1))) { + ObjectArrayList result = new ObjectArrayList<>(); + Function a = new Division(root, new Number(root, 1), new Power(root, ((Power) f).getParameter1(), ((Multiplication)((Power)f).getParameter2()).getParameter2())); + result.add(a); + return result; + } + } + + return null; + } +} diff --git a/src/main/resources/rules/FractionsRule8.java b/src/main/resources/rules/FractionsRule8.java new file mode 100644 index 00000000..932e2fa1 --- /dev/null +++ b/src/main/resources/rules/FractionsRule8.java @@ -0,0 +1,69 @@ +/* +SETTINGS: (please don't move this part) + PATH=FractionsRule8 +*/ + +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.FunctionOperator; +import org.warp.picalculator.math.FunctionDynamic; +import org.warp.picalculator.math.FunctionSingle; +import org.warp.picalculator.math.MathContext; +//Imports + +import java.math.BigDecimal; + +import org.warp.picalculator.Error; +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.MathContext; +import org.warp.picalculator.math.functions.Division; +import org.warp.picalculator.math.functions.Multiplication; +import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.rules.Rule; +import org.warp.picalculator.math.rules.RuleType; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +/** + * Number rule + * -a/-b = a/b + * + * @author Andrea Cavalli + * + */ +public class FractionsRule8 implements Rule { + // Rule name + @Override + public String getRuleName() { + return "FractionsRule8"; + } + + // Rule type + @Override + public RuleType getRuleType() { + return RuleType.CALCULATION; + } + + /* Rule function + Returns: + - null if it's not executable on the function "f" + - An ObjectArrayList if it did something + */ + + @Override + public ObjectArrayList execute(Function f) { + if (f instanceof Division) { + MathContext root = f.getMathContext(); + Division div = (Division) f; + if (div.getParameter1() instanceof Multiplication && ((Multiplication)div.getParameter1()).isNegative()) { + if (div.getParameter2() instanceof Multiplication && ((Multiplication)div.getParameter2()).isNegative()) { + ObjectArrayList result = new ObjectArrayList<>(); + result.add(new Division(root, ((Multiplication)div.getParameter1()).toPositive(), ((Multiplication)div.getParameter2()).toPositive())); + return result; + } + } + } + + return null; + } +} diff --git a/src/main/resources/rules/FractionsRule9.java b/src/main/resources/rules/FractionsRule9.java new file mode 100644 index 00000000..4bfe2ed5 --- /dev/null +++ b/src/main/resources/rules/FractionsRule9.java @@ -0,0 +1,67 @@ +/* +SETTINGS: (please don't move this part) + PATH=FractionsRule9 +*/ + +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.FunctionOperator; +import org.warp.picalculator.math.FunctionDynamic; +import org.warp.picalculator.math.FunctionSingle; +import org.warp.picalculator.math.MathContext; +//Imports + +import java.math.BigDecimal; + +import org.warp.picalculator.Error; +import org.warp.picalculator.math.Function; +import org.warp.picalculator.math.MathContext; +import org.warp.picalculator.math.functions.Division; +import org.warp.picalculator.math.functions.Multiplication; +import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.rules.Rule; +import org.warp.picalculator.math.rules.RuleType; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +/** + * Number rule + * (-a)/b = -(a/b) + * + * @author Andrea Cavalli + * + */ +public class FractionsRule9 implements Rule { + // Rule name + @Override + public String getRuleName() { + return "FractionsRule9"; + } + + // Rule type + @Override + public RuleType getRuleType() { + return RuleType.EXPANSION; + } + + /* Rule function + Returns: + - null if it's not executable on the function "f" + - An ObjectArrayList if it did something + */ + + @Override + public ObjectArrayList execute(Function f) { + if (f instanceof Division) { + MathContext root = f.getMathContext(); + Division div = (Division) f; + if (div.getParameter1() instanceof Multiplication && ((Multiplication)div.getParameter1()).isNegative()) { + ObjectArrayList result = new ObjectArrayList<>(); + result.add(Multiplication.newNegative(root, new Division(root, ((Multiplication)div.getParameter1()).toPositive(), div.getParameter2()))); + return result; + } + } + + return null; + } +} diff --git a/src/main/resources/rules/functions/DivisionRule.java b/src/main/resources/rules/functions/DivisionRule.java index 97c87056..421e8845 100644 --- a/src/main/resources/rules/functions/DivisionRule.java +++ b/src/main/resources/rules/functions/DivisionRule.java @@ -53,7 +53,7 @@ public class DivisionRule implements Rule { */ @Override public ObjectArrayList execute(Function f) throws Error { - if (f instanceof DivisionRule) { + if (f instanceof Division) { ObjectArrayList result = new ObjectArrayList<>(); Function variable1 = ((FunctionOperator) f).getParameter1(); Function variable2 = ((FunctionOperator) f).getParameter2(); diff --git a/src/main/resources/rules/functions/PowerRule.java b/src/main/resources/rules/functions/PowerRule.java index 11c3bf7f..04d1e1bd 100644 --- a/src/main/resources/rules/functions/PowerRule.java +++ b/src/main/resources/rules/functions/PowerRule.java @@ -56,7 +56,11 @@ public class PowerRule implements Rule { MathContext mathContext = f.getMathContext(); if (variable1 instanceof Number && variable2 instanceof Number) { //a^b = c - result.add(((Number)variable1).pow((Number)variable2)); + Number out = ((Number)variable1).pow((Number)variable2); + if (mathContext.exactMode && !out.isInteger()) { + return null; + } + result.add(out); return result; } }