new math rules
This commit is contained in:
parent
4b97d6e639
commit
3c81271338
@ -6,7 +6,7 @@
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-9.0.1">
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
|
@ -1,10 +1,10 @@
|
||||
package org.warp.picalculator;
|
||||
|
||||
import org.warp.picalculator.device.Keyboard;
|
||||
import org.warp.picalculator.device.Keyboard.Key;
|
||||
import org.warp.picalculator.gui.DisplayManager;
|
||||
import org.warp.picalculator.gui.screens.LoadingScreen;
|
||||
import org.warp.picalculator.gui.screens.Screen;
|
||||
import org.warp.picalculator.math.rules.RulesManager;
|
||||
|
||||
import com.pi4j.system.SystemInfo.BoardType;
|
||||
import com.pi4j.wiringpi.Gpio;
|
||||
@ -81,6 +81,7 @@ public class Main {
|
||||
|
||||
public void afterStart() {
|
||||
DisplayManager.INSTANCE.setBrightness(0.2f);
|
||||
RulesManager.initialize();
|
||||
}
|
||||
|
||||
public void beforeShutdown() {
|
||||
|
7
src/main/java/org/warp/picalculator/ScriptUtils.java
Normal file
7
src/main/java/org/warp/picalculator/ScriptUtils.java
Normal file
@ -0,0 +1,7 @@
|
||||
package org.warp.picalculator;
|
||||
|
||||
public class ScriptUtils {
|
||||
public static boolean instanceOf(Object a, Class<?> b) {
|
||||
return b.isInstance(a);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ public class StaticVars {
|
||||
public static boolean debugOn;
|
||||
public static int outputLevel = 5;
|
||||
public static final boolean debugWindow2x = true;
|
||||
public static final ClassLoader classLoader = StaticVars.class.getClassLoader();
|
||||
|
||||
private StaticVars() {
|
||||
|
||||
|
@ -59,9 +59,9 @@ public class Utils {
|
||||
private static String OS = System.getProperty("os.name").toLowerCase();
|
||||
public static String forceEngine;
|
||||
public static boolean msDosMode;
|
||||
|
||||
|
||||
public static final class AdvancedOutputStream extends StringWriter {
|
||||
|
||||
|
||||
public void println(String str) {
|
||||
println(0, str);
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package org.warp.picalculator.math;
|
||||
|
||||
import org.warp.picalculator.Error;
|
||||
import org.warp.picalculator.math.functions.Variable.VariableValue;
|
||||
import org.warp.picalculator.math.rules.Rule;
|
||||
import org.warp.picalculator.math.rules.RuleType;
|
||||
import org.warp.picalculator.math.rules.RulesManager;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
||||
@ -137,4 +140,8 @@ public class MathContext {
|
||||
// return mc;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ObjectArrayList<Rule> getAcceptableRules(RuleType currentAcceptedRules) {
|
||||
return RulesManager.rules[currentAcceptedRules.ordinal()];
|
||||
}
|
||||
}
|
||||
|
144
src/main/java/org/warp/picalculator/math/MathSolver.java
Normal file
144
src/main/java/org/warp/picalculator/math/MathSolver.java
Normal file
@ -0,0 +1,144 @@
|
||||
package org.warp.picalculator.math;
|
||||
|
||||
import org.warp.picalculator.math.rules.Rule;
|
||||
import org.warp.picalculator.math.rules.RuleType;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||
|
||||
public class MathSolver {
|
||||
|
||||
private final MathContext mathContext;
|
||||
private final Function initialFunction;
|
||||
private int stepState = 0;
|
||||
private int currentStepStateN = 0;
|
||||
private enum StepState {
|
||||
_1_CALCULATION,
|
||||
_2_REDUCTION,
|
||||
_3_CALCULATION,
|
||||
_4_EXPANSION
|
||||
}
|
||||
|
||||
public MathSolver(MathContext mathContext, Function initialFunction) {
|
||||
this.mathContext = mathContext;
|
||||
this.initialFunction = initialFunction;
|
||||
}
|
||||
|
||||
public ObjectArrayList<ObjectArrayList<Function>> solveAllSteps() {
|
||||
ObjectArrayList<ObjectArrayList<Function>> steps = new ObjectArrayList<>();
|
||||
ObjectArrayList<Function> lastFnc = null, currFnc = new ObjectArrayList<>();
|
||||
currFnc.add(initialFunction);
|
||||
do {
|
||||
lastFnc = currFnc;
|
||||
currFnc = new ObjectArrayList<>();
|
||||
for (Function fnc : lastFnc) {
|
||||
currFnc.addAll(solveStep(fnc));
|
||||
}
|
||||
steps.add(currFnc);
|
||||
} while(checkEquals(currFnc, lastFnc));
|
||||
return steps;
|
||||
}
|
||||
|
||||
private boolean checkEquals(ObjectArrayList<Function> a, ObjectArrayList<Function> b) {
|
||||
if (a == null && b == null) {
|
||||
return true;
|
||||
} else if (a != null && b != null) {
|
||||
if (a.isEmpty() == b.isEmpty()) {
|
||||
int size;
|
||||
if ((size = a.size()) == b.size()) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (a.get(i).equals(b.get(i)) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ObjectArrayList<Function> solveStep(Function fnc) {
|
||||
RuleType currentAcceptedRules;
|
||||
switch(StepState.values()[stepState]) {
|
||||
case _1_CALCULATION: {
|
||||
currentAcceptedRules = RuleType.CALCULATION;
|
||||
break;
|
||||
}
|
||||
case _2_REDUCTION: {
|
||||
currentAcceptedRules = RuleType.REDUCTION;
|
||||
break;
|
||||
}
|
||||
case _3_CALCULATION: {
|
||||
currentAcceptedRules = RuleType.CALCULATION;
|
||||
break;
|
||||
}
|
||||
case _4_EXPANSION: {
|
||||
currentAcceptedRules = RuleType.EXPANSION;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
System.err.println("Unknown Step State");
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
ObjectArrayList<Rule> rules = mathContext.getAcceptableRules(currentAcceptedRules);
|
||||
ObjectArrayList<Function> results = null;
|
||||
for (Rule rule : rules) {
|
||||
ObjectArrayList<Function> ruleResults = rule.execute(fnc);
|
||||
if (ruleResults != null && !ruleResults.isEmpty()) {
|
||||
results = ruleResults;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(StepState.values()[stepState]) {
|
||||
case _1_CALCULATION: {
|
||||
if (results == null) {
|
||||
stepState++;
|
||||
currentStepStateN = 0;
|
||||
} else {
|
||||
currentStepStateN++;
|
||||
return results;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case _2_REDUCTION: {
|
||||
if (results == null) {
|
||||
if (currentStepStateN == 0) {
|
||||
stepState += 2;
|
||||
} else {
|
||||
stepState++;
|
||||
}
|
||||
currentStepStateN = 0;
|
||||
} else {
|
||||
currentStepStateN++;
|
||||
return results;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case _3_CALCULATION: {
|
||||
if (results == null) {
|
||||
stepState++;
|
||||
currentStepStateN = 0;
|
||||
} else {
|
||||
currentStepStateN++;
|
||||
return results;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case _4_EXPANSION: {
|
||||
if (results == null) {
|
||||
stepState++;
|
||||
currentStepStateN = 0;
|
||||
} else {
|
||||
currentStepStateN++;
|
||||
return results;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
System.err.println("Unknown Step State");
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
33
src/main/java/org/warp/picalculator/math/rules/Rule.java
Normal file
33
src/main/java/org/warp/picalculator/math/rules/Rule.java
Normal file
@ -0,0 +1,33 @@
|
||||
package org.warp.picalculator.math.rules;
|
||||
|
||||
import org.warp.picalculator.math.Function;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
||||
/**
|
||||
* Rule interface
|
||||
* @author Andrea Cavalli
|
||||
*
|
||||
*/
|
||||
public interface Rule {
|
||||
/**
|
||||
* Get rule name
|
||||
* @return
|
||||
*/
|
||||
public default String getRuleName() {
|
||||
return "UnnamedRule1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule type
|
||||
* @return
|
||||
*/
|
||||
public RuleType getRuleType();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param func
|
||||
* @return <ul><li><code>null</code> if it's not executable on the function <b>func</b></li><li>An <code>ObjectArrayList<Function></code> if it did something</li></ul>
|
||||
*/
|
||||
public ObjectArrayList<Function> execute(Function func);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package org.warp.picalculator.math.rules;
|
||||
|
||||
public enum RuleType {
|
||||
EXPANSION,
|
||||
REDUCTION,
|
||||
CALCULATION
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package org.warp.picalculator.math.rules;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.warp.picalculator.StaticVars;
|
||||
import org.warp.picalculator.math.MathContext;
|
||||
import org.warp.picalculator.math.functions.Subtraction;
|
||||
import org.warp.picalculator.math.functions.Sum;
|
||||
import org.warp.picalculator.math.functions.SumSubtraction;
|
||||
import org.warp.picalculator.math.functions.Variable;
|
||||
import org.warp.picalculator.math.functions.Variable.V_TYPE;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
||||
public class RulesManager {
|
||||
|
||||
public static ObjectArrayList<Rule>[] rules;
|
||||
|
||||
private RulesManager() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void initialize() {
|
||||
rules = new ObjectArrayList[RuleType.values().length];
|
||||
for (RuleType val : RuleType.values()) {
|
||||
rules[val.ordinal()] = new ObjectArrayList<Rule>();
|
||||
}
|
||||
try {
|
||||
final Path rulesPath = Paths.get(StaticVars.classLoader.getResource("rules.csv").toURI());
|
||||
if (!Files.exists(rulesPath)) {
|
||||
throw new FileNotFoundException("rules.csv not found!");
|
||||
}
|
||||
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
List<String> ruleLines = Files.readAllLines(rulesPath);
|
||||
for (String rulesLine : ruleLines) {
|
||||
String[] ruleDetails = rulesLine.split(",", 1);
|
||||
String ruleName = ruleDetails[0];
|
||||
URL resourceURL = StaticVars.classLoader.getResource("rules" + File.separator + ruleName.replace("/", "_") + ".js");
|
||||
if (resourceURL == null) {
|
||||
throw new FileNotFoundException("rules/" + ruleName + ".js not found!");
|
||||
}
|
||||
Path rulePath = Paths.get(resourceURL.toURI());
|
||||
engine.eval(new FileReader(rulePath.toString()));
|
||||
}
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void addRule(Rule rule) {
|
||||
MathContext mc = new MathContext();
|
||||
System.out.println(rule.execute(new SumSubtraction(mc, null, new Sum(mc, new Variable(mc, 'x', V_TYPE.VARIABLE), new Variable(mc, 'y', V_TYPE.VARIABLE)))));
|
||||
System.out.println(rule.getRuleName());
|
||||
}
|
||||
}
|
3
src/main/resources/rules.csv
Normal file
3
src/main/resources/rules.csv
Normal file
@ -0,0 +1,3 @@
|
||||
ExpandRule1
|
||||
ExpandRule2
|
||||
ExpandRule5
|
|
128
src/main/resources/rules/ExpandRule1.js
Normal file
128
src/main/resources/rules/ExpandRule1.js
Normal file
@ -0,0 +1,128 @@
|
||||
// Imports
|
||||
var ObjectArrayList = Java.type("it.unimi.dsi.fastutil.objects.ObjectArrayList");
|
||||
var ScriptUtils = org.warp.picalculator.ScriptUtils;
|
||||
var Rule = org.warp.picalculator.math.rules.Rule;
|
||||
var RuleType = org.warp.picalculator.math.rules.RuleType;
|
||||
var RulesManager = org.warp.picalculator.math.rules.RulesManager;
|
||||
var Multiplication = org.warp.picalculator.math.functions.Multiplication;
|
||||
var Sum = org.warp.picalculator.math.functions.Sum;
|
||||
var Subtraction = org.warp.picalculator.math.functions.Subtraction;
|
||||
var SumSubtraction = org.warp.picalculator.math.functions.SumSubtraction;
|
||||
var Number = org.warp.picalculator.math.functions.Number;
|
||||
|
||||
/**
|
||||
* Expand rule
|
||||
* -(+a+b) = -a-b
|
||||
* -(+a-b) = -a+b
|
||||
*
|
||||
* @author Andrea Cavalli
|
||||
*
|
||||
*/
|
||||
var rule = {
|
||||
// Rule name
|
||||
getRuleName: function() {
|
||||
return "ExpandRule1";
|
||||
},
|
||||
// Rule type
|
||||
getRuleType: function() {
|
||||
return RuleType.EXPANSION;
|
||||
},
|
||||
/* Rule function
|
||||
Returns:
|
||||
- null if it's not executable on the function "f"
|
||||
- An ObjectArrayList<Function> if it did something
|
||||
*/
|
||||
execute: function(f) {
|
||||
var isExecutable;
|
||||
if (ScriptUtils.instanceOf(f, Multiplication.class)) {
|
||||
var fnc = f;
|
||||
if (fnc.getParameter1().equals(new Number(fnc.getMathContext(), -1))) {
|
||||
var 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 (ScriptUtils.instanceOf(f,Subtraction.class) || ScriptUtils.instanceOf(f,SumSubtraction.class)) {
|
||||
var fnc = f;
|
||||
var expr = fnc.getParameter2();
|
||||
if (ScriptUtils.instanceOf(expr,Sum.class)) {
|
||||
isExecutable = true;
|
||||
} else if (ScriptUtils.instanceOf(expr,Subtraction.class)) {
|
||||
isExecutable = true;
|
||||
} else if (ScriptUtils.instanceOf(expr,SumSubtraction.class)) {
|
||||
isExecutable = true;
|
||||
}
|
||||
}
|
||||
if (isExecutable) {
|
||||
var result = new ObjectArrayList();
|
||||
var root = f.getMathContext();
|
||||
|
||||
var expr = null;
|
||||
var fromSubtraction = 0;
|
||||
var subtraction = null;
|
||||
if (ScriptUtils.instanceOf(f,Multiplication.class)) {
|
||||
expr = f.getParameter2();
|
||||
} else if (f instanceof Subtraction || f instanceof SumSubtraction) {
|
||||
expr = f.getParameter2();
|
||||
if (f instanceof Subtraction) {
|
||||
fromSubtraction = 1;
|
||||
} else {
|
||||
fromSubtraction = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (f instanceof SumSubtraction) {
|
||||
|
||||
}
|
||||
|
||||
var fnc = expr;
|
||||
if (fnc instanceof Sum) {
|
||||
var a = fnc.getParameter1();
|
||||
var b = fnc.getParameter2();
|
||||
var fnc2 = new Subtraction(root, new Multiplication(root, new Number(root, -1), a), b);
|
||||
if (fromSubtraction > 0) {
|
||||
subtraction = new Subtraction(root, f.getParameter1(), fnc2);
|
||||
result.add(subtraction);
|
||||
} else {
|
||||
result.add(fnc2);
|
||||
}
|
||||
} else if (fnc instanceof Subtraction) {
|
||||
var a = fnc.getParameter1();
|
||||
var b = fnc.getParameter2();
|
||||
var fnc2 = new Sum(root, new Multiplication(root, new Number(root, -1), a), b);
|
||||
if (fromSubtraction > 0) {
|
||||
subtraction = new Subtraction(root, f.getParameter1(), fnc2);
|
||||
result.add(subtraction);
|
||||
} else {
|
||||
result.add(fnc2);
|
||||
}
|
||||
} else if (fnc instanceof SumSubtraction) {
|
||||
var a = fnc.getParameter1();
|
||||
var b = fnc.getParameter2();
|
||||
var fnc2 = new Sum(root, new Multiplication(root, new Number(root, -1), a), b);
|
||||
var fnc3 = new Subtraction(root, new Multiplication(root, new Number(root, -1), a), b);
|
||||
if (fromSubtraction > 0) {
|
||||
subtraction = new SumSubtraction(root, f.getParameter1(), fnc2);
|
||||
result.add(subtraction);
|
||||
subtraction = new SumSubtraction(root, f.getParameter1(), fnc3);
|
||||
result.add(subtraction);
|
||||
result.add(subtraction);
|
||||
} else {
|
||||
result.add(fnc2);
|
||||
result.add(fnc2);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Add this rule to the list of rules
|
||||
RulesManager.addRule(engine.getInterface(rule, Rule.class));
|
0
src/main/resources/rules/ExpandRule2.js
Normal file
0
src/main/resources/rules/ExpandRule2.js
Normal file
0
src/main/resources/rules/ExpandRule5.js
Normal file
0
src/main/resources/rules/ExpandRule5.js
Normal file
28
src/main/resources/rules/_EXAMPLE RULE.js
Normal file
28
src/main/resources/rules/_EXAMPLE RULE.js
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
// Imports
|
||||
var Rule = org.warp.picalculator.math.rules.Rule;
|
||||
var RuleType = org.warp.picalculator.math.rules.RuleType;
|
||||
var RulesManager = org.warp.picalculator.math.rules.RulesManager;
|
||||
|
||||
// Rule class
|
||||
var rule = {
|
||||
// Rule name
|
||||
getRuleName: function() {
|
||||
return "ExampleRule1";
|
||||
},
|
||||
// Rule type
|
||||
getRuleType: function() {
|
||||
return RuleType.CALCULATION;
|
||||
},
|
||||
/* Rule function
|
||||
Returns:
|
||||
- null if it's not executable on the function "func"
|
||||
- An ObjectArrayList<Function> if it did something
|
||||
*/
|
||||
execute: function(func) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Add this rule to the list of rules
|
||||
RulesManager.addRule(engine.getInterface(rule, Rule.class));
|
Loading…
Reference in New Issue
Block a user