From f6de8fd687e2ad4af901717bbdf220d8ed2b1d40 Mon Sep 17 00:00:00 2001 From: zeroflag Date: Sun, 8 Aug 2021 11:03:13 +0200 Subject: [PATCH] optimization --- src/main/java/com/vectron/fcl/Fcl.java | 2 +- src/main/java/com/vectron/fcl/Juggler.java | 82 ++++++++++++++----- .../com/vectron/fcl/interop/JvmInterOp.java | 4 +- .../com/vectron/fcl/interop/MethodSpec.java | 4 + src/main/java/com/vectron/fcl/types/Lst.java | 4 +- src/main/res/raw/misc.forth | 8 +- .../java/com/vectron/fcl/JugglerTest.java | 15 +++- 7 files changed, 91 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/vectron/fcl/Fcl.java b/src/main/java/com/vectron/fcl/Fcl.java index a9438da..f7afe4e 100644 --- a/src/main/java/com/vectron/fcl/Fcl.java +++ b/src/main/java/com/vectron/fcl/Fcl.java @@ -532,7 +532,7 @@ public class Fcl { addPrimitive(name, code, false); } - private void addPrimitive(String name, Runnable code, boolean immediate) { + public void addPrimitive(String name, Runnable code, boolean immediate) { Primitive word = new Primitive(name, code); word.immediate(immediate); dict.add(word); diff --git a/src/main/java/com/vectron/fcl/Juggler.java b/src/main/java/com/vectron/fcl/Juggler.java index 2670b5a..06f7d9b 100644 --- a/src/main/java/com/vectron/fcl/Juggler.java +++ b/src/main/java/com/vectron/fcl/Juggler.java @@ -1,19 +1,23 @@ package com.vectron.fcl; +import com.vectron.fcl.types.Lst; +import com.vectron.fcl.types.Nil; import com.vectron.fcl.types.Obj; +import com.vectron.fcl.types.Str; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.EmptyStackException; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.Stack; public class Juggler { private final List input; private final List output; - private final Stack stack; - private final Stack rstack; + private final LStack stack; + private final LStack rstack; private final Set uniqueOutput; private final List code; private final List availableWords; @@ -54,6 +58,21 @@ public class Juggler { } } + public static Obj solve(Lst input, Lst output, Lst excluded, int maxSteps) { + List words = solve(input.value(), output.value(), filter(excluded.value()), maxSteps); + if (words == null) return Nil.INSTANCE; + Lst result = new Lst(); + for (String each : words) + result.append(new Str(each)); + return result; + } + + private static Set filter(List excluded) { + Set result = new HashSet<>(); + for (Obj each : excluded) result.add(each.asStr().value()); + return result; + } + public static List solve(List input, List output, Set excluded, int maxSteps) { Juggler juggler = new Juggler(input, output, excluded, maxSteps); return juggler.solve(); @@ -64,8 +83,8 @@ public class Juggler { this.output = output; this.maxSteps = maxSteps; this.uniqueOutput = new HashSet<>(output); - this.stack = new Stack<>(); - this.rstack = new Stack<>(); + this.stack = new LStack(); + this.rstack = new LStack(); this.code = new ArrayList<>(); this.availableWords = populateWords(excluded); this.code.add(0); @@ -98,8 +117,7 @@ public class Juggler { while (code.get(i) > max) { code.set(i, 0); if (i > 0) { - i--; - code.set(i, code.get(i) +1); + code.set(--i, code.get(i) +1); } else { code.add(0, 0); } @@ -110,16 +128,16 @@ public class Juggler { stack.clear(); stack.addAll(input); rstack.clear(); - List> stackHistory = new ArrayList<>(); - List> rstackHistory = new ArrayList<>(); + List stackHistory = new ArrayList<>(); + List rstackHistory = new ArrayList<>(); for (int i = 0; i < code.size(); i++) { if (!nthWord(code.get(i)).eval(this) || nop() || cycle(stackHistory, rstackHistory)) { skip(i, code); return false; } - stackHistory.add(copy(stack)); - rstackHistory.add(copy(rstack)); + stackHistory.add(new LStack(stack)); + rstackHistory.add(new LStack(rstack)); } return rstack.isEmpty() && stack.equals(output); } @@ -135,7 +153,7 @@ public class Juggler { } } - private boolean cycle(List> stackHistory, List> rstackHistory) { + private boolean cycle(List stackHistory, List rstackHistory) { for (int i = 0; i < stackHistory.size(); i++) { if (stackHistory.get(i).equals(stack) && rstackHistory.get(i).equals(rstack)) return true; @@ -147,12 +165,6 @@ public class Juggler { return rstack.isEmpty() && stack.equals(input); } - private Stack copy(Stack stack) { - Stack result = new Stack<>(); - result.addAll(stack); - return result; - } - private List result(List code) { List result = new ArrayList<>(); for (Integer each : code) @@ -165,7 +177,7 @@ public class Juggler { } private boolean dup() { - if (stack.empty()) return false; + if (stack.size() == 0) return false; stack.push(pick(1)); return true; } @@ -185,7 +197,7 @@ public class Juggler { } private boolean drop() { - if (stack.empty()) return false; + if (stack.size() == 0) return false; stack.pop(); return !missing(); } @@ -313,10 +325,38 @@ public class Juggler { private boolean missing() { for (Obj each : uniqueOutput) { - if (!stack.contains(each) && !stack.contains(each)) + if (!stack.contains(each) && !rstack.contains(each)) return true; } return false; } + + public final class LStack extends ArrayList { + public LStack() { + super(10); + } + + public LStack(final Collection collection) { + super(collection); + } + + public void push(Obj item) { + add(item); + } + + public Obj pop() { + Obj top = peek(); + remove(size() - 1); + return top; + } + + public Obj peek() { + int size = size(); + if (size == 0) { + throw new EmptyStackException(); + } + return get(size - 1); + } + } } diff --git a/src/main/java/com/vectron/fcl/interop/JvmInterOp.java b/src/main/java/com/vectron/fcl/interop/JvmInterOp.java index 4eeb81c..0fbc3c5 100644 --- a/src/main/java/com/vectron/fcl/interop/JvmInterOp.java +++ b/src/main/java/com/vectron/fcl/interop/JvmInterOp.java @@ -28,7 +28,7 @@ public class JvmInterOp { Obj receiver = stack.pop(); MethodSpec spec = MethodSpec.parseDynamic( methodName, - receiver instanceof JvmObj ? ((JvmObj) receiver).value() : receiver); + receiver instanceof JvmObj ? receiver.value() : receiver); spec.invoke(stack); } @@ -37,7 +37,7 @@ public class JvmInterOp { Obj receiver = stack.pop(); MethodSpec spec = MethodSpec.parseDynamic( methodName, - receiver instanceof JvmObj ? ((JvmObj) receiver).value() : receiver); + receiver instanceof JvmObj ? receiver.value() : receiver); stack.push(spec.exists() ? Bool.TRUE : Bool.FALSE); } diff --git a/src/main/java/com/vectron/fcl/interop/MethodSpec.java b/src/main/java/com/vectron/fcl/interop/MethodSpec.java index 94abd98..b8a19c0 100644 --- a/src/main/java/com/vectron/fcl/interop/MethodSpec.java +++ b/src/main/java/com/vectron/fcl/interop/MethodSpec.java @@ -5,6 +5,7 @@ import com.vectron.fcl.exceptions.InterOpFailed; import com.vectron.fcl.types.Bool; import com.vectron.fcl.types.Dic; import com.vectron.fcl.types.JvmObj; +import com.vectron.fcl.types.Lst; import com.vectron.fcl.types.Nil; import com.vectron.fcl.types.Num; import com.vectron.fcl.types.Obj; @@ -115,6 +116,8 @@ class MethodSpec { params.add(value.doubleValue()); else if (clazz == String.class) params.add((String)value.value()); + else if (clazz == Lst.class) + params.add((Lst)value); else if (clazz == Dic.class) params.add((Dic)value); else if (clazz == Num.class) @@ -137,6 +140,7 @@ class MethodSpec { case 's': return String.class; case 'm': return Map.class; case 't': return List.class; + case 'T': return Lst.class; case 'N': return Num.class; case 'O': return Obj.class; case 'M': return Dic.class; diff --git a/src/main/java/com/vectron/fcl/types/Lst.java b/src/main/java/com/vectron/fcl/types/Lst.java index ede569b..c630fbc 100644 --- a/src/main/java/com/vectron/fcl/types/Lst.java +++ b/src/main/java/com/vectron/fcl/types/Lst.java @@ -42,12 +42,12 @@ public class Lst implements Obj, ArithmeticOperand { } @Override - public Object value() { + public List value() { return value; } @Override - public Object unwrap() { + public List unwrap() { List result = new ArrayList<>(); for (Obj each : value) result.add(each.unwrap()); diff --git a/src/main/res/raw/misc.forth b/src/main/res/raw/misc.forth index c5fcda6..faed26c 100644 --- a/src/main/res/raw/misc.forth +++ b/src/main/res/raw/misc.forth @@ -47,4 +47,10 @@ var: irr-guess 0 irr-guess ! loop nil ; -: irr* ( cashflow -- n ) list* irr ; \ No newline at end of file +: irr* ( cashflow -- n ) list* irr ; + +var: juggler.steps 5 juggler.steps ! +[ ] val: juggler.exclude + +: juggler.solve ( steps exclude-list output-list input-list -- list/nil ) :com.vectron.fcl.Juggler/solve/TTTi jvm-call-static ; +: wzd* ( stack1 stack2 -- list/nil ) list* exchange list* aux> juggler.steps @ juggler.exclude 2swap juggler.solve ; \ No newline at end of file diff --git a/src/test/java/com/vectron/fcl/JugglerTest.java b/src/test/java/com/vectron/fcl/JugglerTest.java index 50fd3cc..0378b59 100644 --- a/src/test/java/com/vectron/fcl/JugglerTest.java +++ b/src/test/java/com/vectron/fcl/JugglerTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertTrue; public class JugglerTest { private final Set excluded = new HashSet<>(); + private int maxSteps = 5; @Test public void testEmpty() { @@ -148,8 +149,12 @@ public class JugglerTest { @Test public void testComplex4() { + assertSolution(">r nip over r>", "0 1 2 3", "0 2 0 3"); + excluded.add("over"); assertSolution("swap 2over drop 2swap nip", "0 1 2 3", "0 2 0 3"); + excluded.remove("over"); excluded.add("2over"); + excluded.add("nip"); assertSolution("rot drop >r over r>", "0 1 2 3", "0 2 0 3"); } @@ -178,8 +183,16 @@ public class JugglerTest { assertSolution(null, "0 1 2 3 4 5", "0 0 2 1"); } + @Test + public void testNoSolution2() { + maxSteps = 6; + long started = System.currentTimeMillis(); + assertSolution(null, "0 1 2 3 4 5 6 7 8", "10"); + System.out.println(System.currentTimeMillis() - started); + } + private List solve(List input, List output) { - return Juggler.solve(input, output, excluded, 5); + return Juggler.solve(input, output, excluded, maxSteps); } private void assertSolution(String expected, String input, String output) {