Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

355
LINES

< > BotCompany Repo | #1025607 // PhilosophyBot1 backup before backtracking

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (6624L/43K).

1  
sclass PhilosophyBot1 {
2  
  srecord LogicRule(lhs, rhs) {}
3  
  srecord And(a, b) {}
4  
  srecord If(condition, thenBlock, elseBlock) {}
5  
  srecord For(var, condition, body) {}
6  
  srecord While(condition, body) {}
7  
8  
  // body takes variable mapping
9  
  // body can return
10  
  //   Bool => immediate result (ok or fail)
11  
  //   SS   => variable mapping
12  
  //   null => not applicable
13  
  srecord NativePredicate(S head, IF1<SS, O> body) {}
14  
  
15  
  srecord WithAlternative(IF0<O> alternative, O result) {}
16  
17  
  replace Proc with L. // procedures are a list of statements
18  
19  
  transient S program;
20  
  transient int maxRounds = 1000;
21  
  transient Set<S> facts = linkedCISet();
22  
  transient Set<S> originalFacts;
23  
  transient new LinkedHashSet<LogicRule> logicRules;
24  
  transient new AllOnAll<LogicRule, S> rulesOnFacts;
25  
  transient new L<Proc> proceduresToRun;
26  
 // parsed procedures
27  
  transient long proceduresExecuted;
28  
  transient new L<NativePredicate> nativePredicates;
29  
  transient bool debugNativeCalls = true, debugAllCmds = true;
30  
31  
  transient Set<S> vars = litciset("x", "y", "z");
32  
33  
  void addLogicRule(LogicRule rule) {
34  
    if (logicRules.add(rule)) {
35  
      print("Got logic rule", rule);
36  
      rulesOnFacts.newA(rule); // to combine it with the facts
37  
    }
38  
  }
39  
40  
  void addFact(S fact) {
41  
    fact = trim(fact);
42  
    if (empty(fact)) ret;
43  
    fact = tok_deRoundBracket(fact);
44  
    // Check if it's a procedure
45  
    LS tok = javaTokWithBrackets(fact);
46  
    if (countCodeTokens(tok) == 2 && eqic(getCodeToken(tok, 0), "proc")
47  
      && isCurlyBracketed(getCodeToken(tok, 1))) pcall {
48  
        // It's a procedure!
49  
        S proc = uncurly_keepSpaces(getCodeToken(tok, 1));
50  
        if (proceduresToRun.add(parseProcedure(proc))) {
51  
          print("Got procedure:");
52  
          print(indentx("> ", proc));
53  
        }
54  
      }
55  
    else // It's a fact, not a procedure
56  
      if (facts.add(fact)) {
57  
        print("Got fact: " + fact);
58  
        rulesOnFacts.newB(fact); // to combine it with the rules
59  
      }
60  
  }
61  
62  
  void runProcedure(S proc) pcall {
63  
    print("Running procedure.");
64  
    runParsedProcedure(parseProcedure(proc));
65  
  }
66  
67  
  void runParsedProcedure(Proc commands) {
68  
    ++proceduresExecuted;
69  
    L remainingCommands = cloneLinkedList(commands);
70  
    O cmd;
71  
    while not null (cmd = popFirst(remainingCommands)) {
72  
      if (cmd cast L) continue with runParsedProcedure(cmd);
73  
      if (debugAllCmds)
74  
        print("Running cmd: " + sfu(cmd));
75  
      if cmd is If(O condition, O thenBlock, O elseBlock) {
76  
        O blockToRun = checkCondition(condition) ? thenBlock : elseBlock;
77  
        runParsedProcedure(ll(blockToRun));
78  
      } else if cmd is For(O var, O condition, O body) {
79  
        // make a new logic rule and add it
80  
        // assume the variable is globally declared as a variable
81  
        addLogicRule(new LogicRule(condition, "proc {\n" + body + "\n}"));
82  
      } else if cmd is While(O condition, O body) {
83  
        bool b = checkCondition(condition);
84  
        if (!b) ret;
85  
        proceduresToRun.add(ll(body, cmd));
86  
      } else if (cmd cast S) {
87  
        O result = runNativePredicate(cmd);
88  
        if (result != null) {
89  
          if (result instanceof WithAlternative) {
90  
            print("Have alternative");
91  
            result = ((WithAlternative) result).result;
92  
          }
93  
          if (isFalse(result)) ret;
94  
          if (isTrueOpt(result)) continue;
95  
          SS mapping = cast result; // assume it's a variable mapping
96  
          // apply to all remaining commands and continue
97  
          L remainingCommands2 = mapToLinkedList(remainingCommands,
98  
            c -> replaceVars(c, mapValues optRound(mapping)));
99  
          print("Applying var mapping " + mapping + " to " + remainingCommands
100  
            + " => " + remainingCommands2);
101  
          remainingCommands = remainingCommands2;
102  
        } else
103  
          addFact(cmd);
104  
      } else if (cmd != null)
105  
        fail("Unimplemented command: " + cmd);
106  
    }
107  
  }
108  
109  
  // return var mapping (SS), Bool or null for no matching predicate
110  
  O runNativePredicate(S s) {
111  
    for (NativePredicate np : nativePredicates) {
112  
      SS map = zipIt(np.head, s);
113  
      if (map != null) {
114  
        O result = np.body.get(mapValues tok_deRoundBracket(map));
115  
        if (debugNativeCalls)
116  
          print("Native predicate result: " + np.head + " => " + result);
117  
        if (result instanceof Map && nempty(map)) {
118  
          result = mapKeys((SS) result, var -> lookupOrKeep(map, var));
119  
          if (debugNativeCalls)
120  
            print("Rewrote native predicate result: " + result);
121  
        }
122  
        try object result;
123  
      }
124  
    }
125  
    null;
126  
  }
127  
128  
  bool checkCondition(O o) {
129  
    if (o cast S) {
130  
      if (contains(facts, o)) true;
131  
      O result = runNativePredicate(o);
132  
      if (result cast Bool) ret result;
133  
      if (result instanceof Map) true; // TODO
134  
    }
135  
    print("Ignoring condition: " + o);
136  
    false;
137  
  }
138  
  
139  
  Proc parseProcedure(S proc) {
140  
    //printStruct(proc);
141  
    proc = withoutLinesEmptyAfterTrim(proc);
142  
    //printStruct(proc);
143  
    proc = autoUnindent(proc);
144  
    //printStruct(proc);
145  
    print(indentx("> ", proc));
146  
    
147  
    LS l = groupPythonStyleIndents(proc);
148  
    pnl("unpythonized ", l);
149  
150  
    new L out;
151  
    for i over l: {
152  
      S s = l.get(i);
153  
      LS tok = javaTokWithBrackets(s);
154  
      if (eqic(firstCodeToken(tok), "if")) {
155  
        assertEquals(s, ":", getCodeToken(tok, 2));
156  
        out.add(new If(deRoundBracket(getCodeToken(tok, 1)),
157  
          parseProcedure(joinSubList(tok, 3*2)), null));
158  
      } else if (eqic(firstCodeToken(tok), "while")) {
159  
        assertEquals(s, ":", getCodeToken(tok, 2));
160  
        out.add(new While(deRoundBracket(getCodeToken(tok, 1)),
161  
          parseProcedure(joinSubList(tok, 3*2))));
162  
      } else if (eqic(firstCodeToken(tok), "else")) {
163  
        O last = last(out);
164  
        if (!last instanceof If) fail("Else without if");
165  
        assertEquals(s, ":", getCodeToken(tok, 1));
166  
        ((If) last).elseBlock = joinSubList(tok, 2*2);
167  
      } else if (eqic(firstCodeToken(tok), "for")) {
168  
        assertEquals(s, ":", getCodeToken(tok, 2));
169  
        S cond = getCodeToken(tok, 1);
170  
        // cond looks like: "(y | x has a y)"
171  
        cond = deRoundBracket(cond);
172  
        LS tok2 = javaTok(cond);
173  
        assertEquals(cond, "|", getCodeToken(tok2, 1));
174  
        S var = assertIdentifier(cond, getCodeToken(tok2, 0));
175  
        S actualCondition = trimJoinSubList(tok2, 2*2+1);
176  
        out.add(new For(var, actualCondition, parseProcedure(joinSubList(tok, 3*2))));
177  
      } else
178  
        out.add(s);
179  
    }
180  
    pnl("Parsed procedure ", out);
181  
    ret out;
182  
  }
183  
184  
  O splitAtAmpersand2(S s) {
185  
    LS l = tok_splitAtAmpersand(s);
186  
    if (l(l) == 1) ret s;
187  
    ret new And(first(l), splitAtAmpersand2(join(" & ", dropFirst(l))));
188  
  }
189  
190  
  // "zip" a condition with a fact (match word-by-word)
191  
  SS zipIt(S cond, S fact) {
192  
    SS map = gazelle_zip(cond, fact);
193  
    if (map == null) null; // no match
194  
    print("gazelle zip => " + map);
195  
196  
    // are only variables changed?
197  
    if (!allKeysAreInSet(map, vars))
198  
      null; /*with print("Non-variable changes, exiting")*/;
199  
200  
    ret map;
201  
  }
202  
203  
  O replaceVars(O o, SS map) {
204  
    if (empty(map)) ret o;
205  
    // TODO: non-string cases
206  
    ret join(replaceCodeTokensUsingMap(javaTok((S) o), map));
207  
  }
208  
209  
  void applyLogicRuleToFact(LogicRule rule, S fact) {
210  
    O lhs = rule.lhs, rhs = rule.rhs;
211  
    O cond, remaining = null;
212  
    if lhs is And(O a, O b) {
213  
      cond = a;
214  
      remaining = b;
215  
    } else
216  
      cond = lhs;
217  
    
218  
    // now we match the condition with the fact
219  
    SS map = zipIt((S) cond, fact);
220  
    if (map == null) ret; // no match
221  
222  
    // Now we have a proper mapping with the keys being variables!
223  
    print("Match.");
224  
225  
    // drop round brackets
226  
    // XXX? map = mapValues tok_deRoundBracket(map);
227  
228  
    // Apply mapping to right hand side
229  
    S rhs_replaced = cast replaceVars(rhs, map);
230  
    print(+rhs_replaced);
231  
232  
    if (remaining == null) {
233  
      // Add as fact
234  
      addFact(rhs_replaced);
235  
    } else {
236  
      // Apply mapping to remaning condition
237  
      S remaining_replaced = cast replaceVars(remaining, map);
238  
      addLogicRule(new LogicRule(remaining_replaced, rhs_replaced));
239  
    }
240  
  }
241  
  
242  
  run {
243  
    parseProgram();
244  
    think();
245  
  }
246  
  
247  
  void parseProgram {
248  
    // split into paragraphs and unindent
249  
250  
    LS paragraphs = map autoUnindent(map rtrim(splitAtEmptyLines(program)));
251  
    print("Got " + n2(paragraphs, "parapraph"));
252  
253  
    // print the parapraphs
254  
    print(joinWithEmptyLines(map(s -> indentx("> ", s), paragraphs)));
255  
256  
    // throw away comment-only and quoted paragraphs (assume it's a title)
257  
    LS paragraphs2 = antiFilter(paragraphs, s -> 
258  
      isSingleLine(trim(s)) && isQuoted(trim(s)) || countJavaTokens(s) == 0
259  
      || endsWith(rtrim(s), "----"));
260  
    print("Got " + n2(paragraphs2, "filtered paragraph"));
261  
    print(joinWithEmptyLines(map(s -> indentx("> ", s), paragraphs2)));
262  
263  
    // find fact paragraphs
264  
    
265  
    print(map allLinesAreUnindented(paragraphs2));
266  
    Pair<LS> p1 = filterAntiFilter(s ->
267  
      !isSingleLine(trim(s)) && allLinesAreUnindented(s), paragraphs2);
268  
    LS multiFactParagraphs = p1.a, paragraphs3 = p1.b;
269  
270  
    for (S para : multiFactParagraphs)
271  
      for (S s : tlft(para))
272  
        addFact(s);
273  
274  
    // find logic rules
275  
276  
    new LS paragraphs4;
277  
    for (S para : paragraphs3) {
278  
      PairS p = splitAtDoubleArrow_pair(para);
279  
      if (p == null) continue with paragraphs4.add(para);
280  
      addLogicRule(new LogicRule(splitAtAmpersand2(p.a), splitAtAmpersand2(p.b)));
281  
    }
282  
283  
    pnlStruct("Unparsed - assuming facts", paragraphs4);
284  
285  
    // assume the unparsed stuff consists of facts
286  
    for (S para : paragraphs4)
287  
      addFact(para);
288  
    
289  
    originalFacts = cloneSet(facts);
290  
  }
291  
292  
  bool doSomeLogic() {
293  
    bool anyAction;
294  
    Pair<LogicRule, S> p;
295  
    while not null (p = rulesOnFacts.next()) {
296  
      set anyAction;
297  
      //print("Combination: " + p);
298  
      applyLogicRuleToFact(p.a, p.b);
299  
    }
300  
    ret anyAction;
301  
  }
302  
  
303  
  // indicator for end of thought process (when this stays stable)
304  
  long size() {
305  
    ret l(logicRules) + l(facts) + proceduresExecuted;
306  
  }
307  
308  
  void think {
309  
    int round = 0;
310  
 
311  
    while (round++ < maxRounds) {
312  
      long lastSize = size();
313  
      print("Logic round " + round + ", size: " + lastSize);
314  
      while (doSomeLogic() && round++ < maxRounds) {}
315  
316  
      for (Proc proc : getAndClearList(proceduresToRun))
317  
        runParsedProcedure(proc);
318  
        
319  
      if (size() == lastSize) {
320  
        print("No changes, exiting");
321  
        break;
322  
      }
323  
    }
324  
325  
    // We're done logicking, so print all the facts gathered
326  
327  
    LS factsToPrint = listMinusList(facts, originalFacts);
328  
    pnlWithHeading("Facts I deduced", factsToPrint);
329  
330  
    // Print the actual output
331  
332  
    new LS output;
333  
    for (S fact : factsToPrint) {
334  
      LS tok = javaTokWithBrackets(fact);
335  
      if (countCodeTokens(tok) == 2 && eqic(getCodeToken(tok, 0), "print"))
336  
        // For the user, we print without all the round brackets
337  
        output.add(tok_dropRoundBrackets(getCodeToken(tok, 1)));
338  
    }
339  
    
340  
    pnlWithHeading("Bot Output", output);
341  
  }
342  
343  
  void addNativePredicate(S head, IF0 body) {
344  
    nativePredicates.add(new NativePredicate(head, map -> body!));
345  
  }
346  
  
347  
  void addNativePredicate(S head, IF1<SS, O> body) {
348  
    nativePredicates.add(new NativePredicate(head, body));
349  
  }
350  
351  
  // for backtracking in native predicates
352  
  WithAlternative withAlternative(IF0<O> alternative, O result) {
353  
    ret new WithAlternative(alternative, result);
354  
  }
355  
}

Author comment

Began life as a copy of #1025597

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1025607
Snippet name: PhilosophyBot1 backup before backtracking
Eternal ID of this version: #1025607/1
Text MD5: e1670695d1a19d50a8b46ceaccaae02e
Transpilation MD5: 76eebc65135d53eba4a6a4a96f58c156
Author: stefan
Category:
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-10-08 12:40:27
Source code size: 11766 bytes / 355 lines
Pitched / IR pitched: No / No
Views / Downloads: 279 / 347
Referenced in: [show references]