new math rules

This commit is contained in:
Andrea Cavalli 2017-12-21 23:21:29 +01:00
parent 4b97d6e639
commit 3c81271338
15 changed files with 437 additions and 4 deletions

View File

@ -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"/>

View File

@ -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() {

View File

@ -0,0 +1,7 @@
package org.warp.picalculator;
public class ScriptUtils {
public static boolean instanceOf(Object a, Class<?> b) {
return b.isInstance(a);
}
}

View File

@ -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() {

View File

@ -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);
}

View File

@ -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()];
}
}

View 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;
}
}

View 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&lt;Function&gt;</code> if it did something</li></ul>
*/
public ObjectArrayList<Function> execute(Function func);
}

View File

@ -0,0 +1,7 @@
package org.warp.picalculator.math.rules;
public enum RuleType {
EXPANSION,
REDUCTION,
CALCULATION
}

View File

@ -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());
}
}

View File

@ -0,0 +1,3 @@
ExpandRule1
ExpandRule2
ExpandRule5
1 ExpandRule1
2 ExpandRule2
3 ExpandRule5

View 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));

View File

View File

View 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));