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

196
LINES

< > BotCompany Repo | #1005173 // Rule Matching Test [dev.]

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Click here for Pure Java version (2068L/14K/46K).

!752

static L<S> data = toLinesFullTrim([[
  If A likes B then A will greet B.
  If X then Y.
  If U then V. && U. => V.
  John likes Paul.
]]);

static L<L<S>> log;

static S toCheck = "John will greet Paul.";

sclass Flow {
  new StringBuilder desc;
  new L<Flow> subs;
  
  Flow sub(S desc) {
    new Flow flow;
    flow.append(desc);
    subs.add(flow);
    ret flow;
  }
  
  void append(O o) {
    desc.append(o).append("\n");
  }
  
  void x(O o) { append(o); }
  
  public S toString() {
    ret str(desc) + indentx(allToStringWithLineBreaks(subs));
  }
}

p-typewriter {
  // Parse data
  log = map("tok", data);
  
  new TreeSet<S> newData;
  
  // Go through all rules
  new Flow flow;
  for (L<S> tok : log) {
    SS m = matchSingle("I => O", tok);
    if (m == null) continue;
    S i = m.get("I"), o = m.get("O");
    // Parse left-hand
    L<S> tokI = tok(i);
    L<L<S>> is = splitAtAmpersands(tokI);
    flow.x("Processing LHS: " + struct(is));
    // Apply rule to input
    for (SS m2 : gSatAnd(is, flow))
      newData.add(join(" ", replaceVars(tok(o), m2)));
  }
  
  print("Lines made (\*l(newData)*/):");
  psl(asList(newData));
  printWithAsciiHeading("FLOW", flow);
}

// null = no satisfaction
// otherwise return var map
static Iterable<SS> gSatAnd(L<L<S>> statements, Flow flow) {
  flow = flow.sub("gSatAnd" + struct(statements));
  assertTrue(l(statements) >= 1);
  
  if (l(statements) == 1)
    ret gSat(first(statements), flow);
  
  new L<SS> l;
  for (SS map : gSat(first(statements), flow)) {
    flow.x("First clause satisfied. " + struct(map));
    L<L<S>> s2 = mapReplaceVars(dropFirst(statements), map);
    flow.x("Now looking for: " + struct(s2));
    for (SS map2 : gSatAnd(s2, flow)) {
      flow.x("Sub gSatAnd returned: " + struct(map2));
      addIfNotEmpty(l, mergeMappings(map, map2));
    }
  }
  ret l;
}

static IterableIterator<SS> gSat(L<S> pat, Flow flow) {
  flow = flow.sub("gSat" + struct(pat));
  ret gMatch(pat, flow);
}

static IterableIterator<SS> gMatch(final L<S> pat, final Flow flow) {
  ret new IterableIterator<SS>() {
    int i = l(log);
    Iterator<SS> m;
    
    public bool hasNext() {
      if (m != null && m.hasNext()) true;
      m = null;
      while (--i >= 0) {
        L<SS> l = match(pat, get(log, i));
        if (nempty(l)) {
          flow.x("gMatch found: " + struct(l));
          m = l.iterator();
          true;
        }
      }
      false;
    }
    
    public SS next() { ret m.next(); }
  };
}

static L<L<S>> splitAtAmpersands(L<S> tok) {
  new L<L<S>> l;
  int iAmp;
  while ((iAmp = indexOfSubList(tok, ll("&", "&"))) >= 0) {
    //print("&& found at " + iAmp);
    l.add(subList(tok, 0, iAmp));
    tok = subList(tok, iAmp+2);
  }
  l.add(tok);
  ret l;
}

static SS matchSingle(S pat, L<S> input) {
  ret getSingletonOpt(match(tok(pat), input));
}

static SS matchSingle(S pat, S input) {
  ret getSingletonOpt(match(pat, input));
}

static L<S> tok(S s) {
  ret s == null ? null : codeTokens(nlTok(s));
}

static L<SS> match(S pat, S input) {
  ret match(tok(pat), tok(input));
}

static L<SS> match(L<S> pat, L<S> input) {
  Map<Int, S> vars = singleCharacterVars(pat);
  new L<SS> matches;
  matchImpl(pat, vars, 0, input, 0, new HashMap, matches);
  ret matches;
}

static void matchImpl(L<S> pat, Map<Int, S> vars,
  int iPat, L<S> input, int iInput, SS values,
  L<SS> matches) {
  if (iPat >= l(pat)) {
    if (iInput < l(input)) ret; // fail, too much input
    //print("Match! " + struct(values));
    matches.add(cloneMap(values));
    ret;
  }
  if (iInput >= l(input)) ret; // out of input
  S t = pat.get(iPat);
  S var = vars.get(iPat);
  if (var != null) {
    // it's a variable, try different lengths of input as match
    for (int jInput = iInput+1; jInput <= l(input); jInput++) {
      S value = join(" ", subList(input, iInput, jInput));
      S oldValue = values.get(var);
      if (oldValue != null && !eqic(value, oldValue)) ret; // fail, bad multi-assignment
      if (oldValue == null)
        values.put(var, value);
      // proceed
      matchImpl(pat, vars, iPat+1, input, jInput, values, matches);
      // delete assignment
      if (oldValue == null) values.remove(var); else values.put(var, oldValue);
    }
  } else {
    // it's a literal
    if (!eqic(t, input.get(iInput))) ret; // fail
    // match, proceed
    matchImpl(pat, vars, iPat+1, input, iInput+1, values, matches);
  }
}

static Map<Int, S> singleCharacterVars(L<S> tok) {
  new Map<Int, S> vars;
  for i over tok: {
    S t = tok.get(i);
    if (l(t) == 1 && isUpperCaseLetter(t.charAt(0)))
      vars.put(i, t);
  }
  ret vars;
}

static L<L<S>> mapReplaceVars(L<L<S>> patterns, final SS map) {
  ret map(func(L<S> pat) { replaceVars(pat, map) }, patterns);
}

static L<S> replaceVars(L<S> tok, final Map<S, S> map) {
  ret flattenList(map(tok, func(S t) { or((O) tok(map.get(t)), t) }));
}

Author comment

Began life as a copy of #1005169

download  show line numbers  debug dex  old transpilations   

Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1005173
Snippet name: Rule Matching Test [dev.]
Eternal ID of this version: #1005173/1
Text MD5: f9b0375363a7b51dfc00af59a4429c45
Transpilation MD5: 4c5d2caab5b5bb4337a2cc3d9c6b8742
Author: stefan
Category: javax / a.i.
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-11-20 17:23:37
Source code size: 5090 bytes / 196 lines
Pitched / IR pitched: No / No
Views / Downloads: 687 / 706
Referenced in: [show references]