Skip to content

Commit 999c956

Browse files
committed
Possibility of checking regular constraints based on NFAs
1 parent 684bfb1 commit 999c956

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

src/main/java/org/xcsp/parser/XParser.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -719,8 +719,7 @@ private Object parseTuples(Element elt, TypePrimitive primitive, DomBasic[] doms
719719
return primitive.parseSeq(s, doms == null ? null : (Dom) doms[0]);
720720
}
721721
if (primitive == null) { // in that case, we keep String (although integers can also be present at some places
722-
// with hybrid
723-
// constraints)
722+
// with hybrid constraints)
724723
return Stream.of(s.split(DELIMITER_LISTS)).skip(1).map(tok -> tok.split("\\s*,\\s*")).filter(t -> parseSymbolicTuple(t, doms, ab))
725724
.toArray(String[][]::new);
726725
}
@@ -876,8 +875,12 @@ private void parseSmart(Element elt, Element[] sons) {
876875
private void parseRegular(Element elt, Element[] sons) {
877876
addLeaf(list, parseSequence(sons[0]));
878877
Transition[] trans = Stream.of(sons[1].getTextContent().trim().split(DELIMITER_LISTS)).skip(1).map(t -> {
878+
boolean general = t.contains("{");
879+
if (general)
880+
t = replaceInternCommas(t);
879881
String[] tr = t.split("\\s*,\\s*");
880-
Object value = Character.isDigit(tr[1].charAt(0)) || tr[1].charAt(0) == '+' || tr[1].charAt(0) == '-' ? safeLong(tr[1]) : tr[1];
882+
Object value = general ? Utilities.splitToInts(tr[1].substring(1, tr[1].length() - 1))
883+
: Character.isDigit(tr[1].charAt(0)) || tr[1].charAt(0) == '+' || tr[1].charAt(0) == '-' ? safeLong(tr[1]) : tr[1];
881884
return new Transition(tr[0], value, tr[2]);
882885
}).toArray(Transition[]::new);
883886
addLeaf(transitions, trans);

src/main/java/org/xcsp/parser/callbacks/SolutionChecker.java

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.ArrayList;
2929
import java.util.Arrays;
3030
import java.util.HashMap;
31+
import java.util.HashSet;
3132
import java.util.List;
3233
import java.util.Map;
3334
import java.util.Scanner;
@@ -425,32 +426,57 @@ public void buildCtrExtension(String id, XVarInteger[] list, AbstractTuple[] tup
425426
controlConstraint(found == positive);
426427
}
427428

428-
private String reachedState(String startState, XVarInteger[] list, Transition[] transitions) {
429-
Map<String, String> map = new HashMap<>();
430-
Stream.of(transitions).forEach(tr -> map.put(tr.start + ":" + tr.value, tr.end + ""));
431-
String current = startState;
432-
for (XVarInteger x : list) {
433-
String next = map.get(current + ":" + solution.intValueOf(x));
434-
if (next == null)
435-
return null;
436-
else
437-
current = next;
438-
}
439-
return current;
440-
}
429+
private void collectStates(String current, int i, XVarInteger[] list, Map<String, List<String>> map, Set<String> reached, Set<String> seen) {
430+
String node = current + " " + i; // it is important to record the level
431+
if (seen.contains(node))
432+
return; // because already explored
433+
seen.add(node);
434+
List<String> nexts = map.get(current + ":" + solution.intValueOf(list[i]));
435+
if (nexts != null)
436+
for (String next : nexts)
437+
if (i == list.length - 1)
438+
reached.add(next);
439+
else
440+
collectStates(next, i + 1, list, map, reached, seen);
441+
}
442+
443+
private Set<String> reachedStates(String startState, XVarInteger[] list, Transition[] transitions) {
444+
Set<String> seen = new HashSet<>(), reached = new HashSet<>();
445+
Map<String, List<String>> map = new HashMap<>();
446+
for (Transition tr : transitions)
447+
map.computeIfAbsent(tr.start + ":" + tr.value, r -> new ArrayList<String>()).add(tr.end);
448+
collectStates(startState, 0, list, map, reached, seen);
449+
return reached;
450+
}
451+
452+
// private List<String> reachedStates(String startState, XVarInteger[] list, Transition[] transitions) {
453+
// List<String> reached = new ArrayList<>();
454+
// Map<String, String> map = new HashMap<>();
455+
// Stream.of(transitions).forEach(tr -> map.put(tr.start + ":" + tr.value, tr.end + ""));
456+
// String current = startState;
457+
// for (XVarInteger x : list) {
458+
// String next = map.get(current + ":" + solution.intValueOf(x));
459+
// System.out.println("tra " + x + " " + solution.intValueOf(x) + " " + next);
460+
// if (next == null)
461+
// return null;
462+
// else
463+
// current = next;
464+
// }
465+
// reached.add(current);
466+
// return reached;
467+
// }
441468

442469
@Override
443470
public void buildCtrRegular(String id, XVarInteger[] list, Transition[] transitions, String startState, String[] finalStates) {
444-
String state = reachedState(startState, list, transitions);
445-
controlConstraint(state != null && Arrays.stream(finalStates).anyMatch(v -> v.equals(state)));
471+
Set<String> reached = reachedStates(startState, list, transitions);
472+
controlConstraint(reached.size() > 0 && Arrays.stream(finalStates).anyMatch(v -> reached.stream().anyMatch(state -> v.equals(state))));
446473
}
447474

448475
@Override
449476
public void buildCtrMDD(String id, XVarInteger[] list, Transition[] transitions) {
450-
String state = reachedState(transitions[0].start, list, transitions); // The first state of the first transition
451-
// MUST be the
452-
// starting state
453-
controlConstraint(state != null);
477+
Set<String> reached = reachedStates(transitions[0].start, list, transitions);
478+
// The first state of the first transition MUST be the starting state
479+
controlConstraint(reached.size() > 0);
454480
}
455481

456482
@Override

0 commit comments

Comments
 (0)