org.xcsp.modeler.entities.VarEntities Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xcsp3-tools Show documentation
Show all versions of xcsp3-tools Show documentation
Java Tools for parsing XCSP3 instances, compiling JvCSP3 models, and checking solutions. For more information about XCSP3, follow www.xcsp.org
The newest version!
package org.xcsp.modeler.entities;
import static java.util.stream.Collectors.joining;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.xcsp.common.IVar;
import org.xcsp.common.IVar.Var;
import org.xcsp.common.IVar.VarSymbolic;
import org.xcsp.common.Size;
import org.xcsp.common.Size.Size1D;
import org.xcsp.common.Size.Size2D;
import org.xcsp.common.Size.Size3D;
import org.xcsp.common.Size.Size4D;
import org.xcsp.common.Types.TypeClass;
import org.xcsp.common.Types.TypeVar;
import org.xcsp.common.Utilities;
import org.xcsp.common.enumerations.EnumerationCartesian;
import org.xcsp.modeler.implementation.ProblemIMP;
public final class VarEntities {
private ProblemIMP imp;
public VarEntities(ProblemIMP imp) {
this.imp = imp;
}
public List allEntities = new ArrayList<>();
public List varAlones = new ArrayList<>();
public List varArrays = new ArrayList<>();
public Map varToVarAlone = new LinkedHashMap<>();
public Map varToVarArray = new LinkedHashMap<>();
public Map buildTimes = new HashMap<>();
// public boolean isVarAlone(IVar x) { return varToVarArray.get(x) != null; }
public void newVarAloneEntity(String id, IVar var, String note, TypeClass... classes) {
VarAlone va = new VarAlone(id, var, note, classes);
allEntities.add(va);
varAlones.add(va);
varToVarAlone.put(var, va);
int limit = imp.stackLoops.size() > 0 ? imp.stackLoops.peek() : -1;
if (limit != -1)
buildTimes.put(va, limit);
}
public VarArray buildVarArray(String id, Size size, Object vars, String note, TypeClass... classes) {
if (size instanceof Size1D)
return new VarArray1D(id, (IVar[]) vars, note, classes);
if (size instanceof Size2D)
return new VarArray2D(id, (IVar[][]) vars, note, classes);
if (size instanceof Size3D)
return new VarArray3D(id, (IVar[][][]) vars, note, classes);
if (size instanceof Size4D)
return new VarArray4D(id, (IVar[][][][]) vars, note, classes);
return new VarArray5D(id, (IVar[][][][][]) vars, note, classes);
}
public void newVarArrayEntity(String id, Size size, Object vars, String note, TypeClass... classes) {
VarArray va = buildVarArray(id, size, vars, note, classes);
allEntities.add(va);
varArrays.add(va);
if (va.flatVars != null) // null can be the case if the array has no useful variables
Stream.of(va.flatVars).forEach(x -> varToVarArray.put(x, va));
int limit = imp.stackLoops.size() > 0 ? imp.stackLoops.peek() : -1;
if (limit != -1)
buildTimes.put(va, limit);
}
public abstract class VarEntity extends ModelingEntity {
protected VarEntity(String id, String note, TypeClass[] classes) {
super(id, note, classes);
}
public abstract TypeVar getType();
}
public final class VarAlone extends VarEntity {
public final IVar var;
protected VarAlone(String id, IVar var, String note, TypeClass... classes) {
super(id, note, classes);
this.var = var;
}
@Override
public TypeVar getType() {
return var instanceof Var ? TypeVar.integer : var instanceof VarSymbolic ? TypeVar.symbolic : null;
}
}
public abstract class VarArray extends VarEntity {
public final int[] sizes;
final int[] mins, maxs; // used for computing ranges of indexes at each dimension
public Object vars;
public final IVar[] flatVars;
public String getStringSize() {
StringBuilder sb = new StringBuilder();
for (int s : sizes)
sb.append("[" + s + "]");
return sb.toString();
// return Arrays.stream(sizes).mapToObj(s -> "[" + s + "]").reduce("", (s, t) -> s + t);
}
public String getEmptyStringSize() {
StringBuilder sb = new StringBuilder();
for (int s : sizes)
sb.append("[]");
return sb.toString();
}
@Override
public TypeVar getType() {
return flatVars[0] instanceof Var ? TypeVar.integer : flatVars[0] instanceof VarSymbolic ? TypeVar.symbolic : null;
}
protected VarArray(String id, int[] sizes, String note, TypeClass[] classes, Object vars) {
super(id, note, classes);
this.sizes = sizes;
this.mins = new int[sizes.length];
this.maxs = new int[sizes.length];
this.vars = vars;
this.flatVars = Utilities.collect(IVar.class, vars);
Utilities.control(Utilities.isRegular(vars), "Not regular arrays");
}
private int updateWith(int increment, int dimension, int i) {
mins[dimension] = Math.min(mins[dimension], i);
maxs[dimension] = Math.max(maxs[dimension], i);
return increment;
}
// protected int updateRangesOLD(Object array, IVar[] t, int dimIndex) {
// Object[] vars = (Object[]) array;
// if (dimIndex == sizes.length - 1) {
// int sum = 0;
// for (int i = 0; i < vars.length; i++)
// if (Utilities.indexOf(vars[i], t) != -1)
// sum += updateWith(1, dimIndex, i);
// return sum;
// // return IntStream.range(0, vars.length).filter(i -> Utilities.indexOf(vars[i], t) != -1).map(i -> updateWith(1,
// // dimensions[dimIndex], i)).sum();
// } else {
// int nFound = 0;
// for (int i = 0; i < vars.length; i++) {
// int nb = updateRangesOLD(vars[i], t, dimIndex + 1);
// if (nb > 0)
// nFound += updateWith(nb, dimIndex, i);
// }
// return nFound;
// }
// }
protected void updateRanges(IVar[] t) {
for (IVar x : t) {
int[] dims = Utilities.splitToInts(x.id().substring(x.id().indexOf('[')), "\\[|\\]");
for (int i = 0; i < dims.length; i++)
updateWith(0, i, dims[i]);
}
}
protected String compactFormOf(IVar[] t) {
assert IntStream.range(0, t.length).noneMatch(i -> IntStream.range(i + 1, t.length).anyMatch(j -> t[i] == t[j]));
if (flatVars != null && Utilities.indexOf(t[0], flatVars) == -1) // quick test: is the first variable in flatVars ?
return null;
Arrays.fill(mins, Integer.MAX_VALUE);
Arrays.fill(maxs, -1);
updateRanges(t);
// int nFound = updateRangesOLD(vars, t, 0);
// if (nFound != t.length) return null;
int size = 1;
for (int i = 0; i < mins.length; i++)
size *= (maxs[i] - mins[i] + 1);
// System.out.println("Size" + size + " t.length " + t.length);
if (size != t.length)
return null;
String s = id;
for (int i = 0; i < mins.length; i++)
s += "[" + (mins[i] == 0 && maxs[i] == sizes[i] - 1 ? "" : mins[i] == maxs[i] ? mins[i] + "" : mins[i] + ".." + maxs[i]) + "]";
return s;
}
}
class VarArray1D extends VarArray {
public VarArray1D(String id, IVar[] vars, String note, TypeClass... classes) {
super(id, new int[] { vars.length }, note, classes, vars);
}
}
class VarArray2D extends VarArray {
protected VarArray2D(String id, IVar[][] vars, String note, TypeClass... classes) {
super(id, new int[] { vars.length, vars[0].length }, note, classes, vars);
}
}
class VarArray3D extends VarArray {
protected VarArray3D(String id, IVar[][][] vars, String note, TypeClass... classes) {
super(id, new int[] { vars.length, vars[0].length, vars[0][0].length }, note, classes, vars);
}
}
class VarArray4D extends VarArray {
protected VarArray4D(String id, IVar[][][][] vars, String note, TypeClass... classes) {
super(id, new int[] { vars.length, vars[0].length, vars[0][0].length, vars[0][0][0].length }, note, classes, vars);
}
}
class VarArray5D extends VarArray {
protected VarArray5D(String id, IVar[][][][][] vars, String note, TypeClass... classes) {
super(id, new int[] { vars.length, vars[0].length, vars[0][0].length, vars[0][0][0].length, vars[0][0][0][0].length }, note, classes, vars);
}
}
private final class SequenceOfSuccessiveVariables {
private IVar firstVar; // the first variable of the sequence
private String prefix; // the prefix of the id of the variables (in case of an array)
private int[] starts; // the indexes of the first variable (in case of an array)
private int posMod = -1, stopMod;
SequenceOfSuccessiveVariables(IVar var) {
this.firstVar = var;
String id = var.id();
if (id.indexOf('[') != -1) {
this.prefix = id.substring(0, id.indexOf('['));
this.starts = Utilities.splitToInts(id.substring(id.indexOf('[')), "\\[|\\]");
}
}
int differJustAt(int[] t) {
int pos = -1;
for (int i = 0; i < starts.length; i++)
if (starts[i] != t[i])
if (pos == -1)
pos = i;
else
return -1; // at least two differences
return pos;
}
boolean canBeExtendedWith(String id) {
if (id.indexOf('[') == -1 || prefix == null || !prefix.equals(id.substring(0, id.indexOf('['))))
return false;
int[] t = Utilities.splitToInts(id.substring(id.indexOf('[')), "\\[|\\]");
int pos = differJustAt(t);
if (pos == -1)
return false;
if (posMod == -1) {
if (t[pos] != starts[pos] + 1)
return false;
posMod = pos;
stopMod = t[pos];
} else {
if (pos != posMod)
return false;
if (t[pos] != stopMod + 1)
return false;
stopMod = t[pos];
}
return true;
}
@Override
public String toString() {
if (prefix == null)
return firstVar.id();
String s = prefix;
for (int i = 0; i < starts.length; i++)
if (posMod != i)
s += "[" + starts[i] + "]";
else if (starts[posMod] == 0 && varToVarArray.get(firstVar) != null && stopMod == varToVarArray.get(firstVar).sizes[posMod] - 1)
s += "[]";
else // if (stopMod != starts[i] + 1 || starts.length > 1)
s += "[" + starts[i] + ".." + stopMod + "]";
// else if (stopMod == starts[i] + 1)
// else s = s + "[" + starts[i] + "] " + s + "[" + stopMod + "]";
return s;
}
}
private String expand(String compactForm) {
Utilities.control(compactForm.indexOf(' ') == -1, "The specified string must correspond to a single token; bad form : " + compactForm);
if (compactForm.endsWith(")"))
return compactForm; // this means that we have an expression (predicate) here
int pos = compactForm.indexOf("[");
if (pos == -1) { // we have just a single variable
VarAlone va = varAlones.stream().filter(a -> a.id.equals(compactForm)).findAny().orElse(null);
Utilities.control(va != null, "An object VarAlone should have been found");
return compactForm; // id of a single variable
}
// we have an array
String prefix = compactForm.substring(0, pos), suffix = compactForm.substring(pos);
VarArray va = varArrays.stream().filter(a -> a.id.equals(prefix)).findAny().orElse(null);
Utilities.control(va != null, "Pb with " + compactForm);
List list = new ArrayList<>();
while (suffix.length() > 0) {
pos = suffix.indexOf("]");
list.add(suffix.substring(1, pos));
suffix = suffix.substring(pos + 1);
}
String[] tokens = list.toArray(new String[0]);
Utilities.control(tokens.length == va.sizes.length, prefix + " ");
int[] mins = new int[tokens.length], maxs = new int[tokens.length], sizes = new int[tokens.length];
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].length() == 0) {
mins[i] = 0;
maxs[i] = va.sizes[i] - 1;
} else if (Utilities.isInteger(tokens[i]))
mins[i] = maxs[i] = Integer.parseInt(tokens[i]);
else {
StringTokenizer st = new StringTokenizer(tokens[i], "..");
mins[i] = Integer.parseInt(st.nextToken());
maxs[i] = Integer.parseInt(st.nextToken());
}
sizes[i] = maxs[i] - mins[i] + 1;
}
String s = "";
EnumerationCartesian ec = new EnumerationCartesian(sizes);
while (ec.hasNext()) {
int[] t = ec.next();
s += prefix + IntStream.range(0, t.length).mapToObj(i -> "[" + (mins[i] + t[i]) + "]").collect(joining()) + " ";
}
return s.trim();
// String s2 = ""; int[] t = new int[sizes.length]; boolean hasNext = true;
// while (hasNext) { String ss = prefix; for (int i = 0; i < t.length; i++) ss += "[" + (mins[i] + t[i]) + "]";
// s2 += ss + " "; hasNext = false;
// for (int i = t.length - 1; !hasNext && i >= 0; i--) if (t[i] + 1 < sizes[i]) { t[i]++; hasNext = true; } else t[i] = 0; }
// System.out.println("s2=" + s2);
// return s2.trim();
}
private StringBuilder handlePart(StringBuilder sb, List list, boolean preserveOrder) {
if (list.size() == 1)
return sb.append(" " + list.get(0).id());
if (list.size() == 2)
return sb.append(" " + list.get(0).id() + " " + list.get(1).id());
IVar[] t = list.stream().toArray(IVar[]::new);
String compactFromOneArray = varArrays.stream().map(va -> va.compactFormOf(t)).filter(s -> s != null).findFirst().orElse(null);
if (compactFromOneArray != null && (!preserveOrder || expand(compactFromOneArray).equals(Stream.of(t).map(x -> x.id()).collect(joining(" ")))))
return sb.append(" " + compactFromOneArray); // if perserveOrder=true, we know for sure that order is preserved because of the expand test
// if compression from a single array (as tried above) has not succeeded, then we execute the code below
if (!preserveOrder) {
// we search for compact forms of the form x[][i] for a given i ; this is possible because the order is not important here
// boolean[] bs = new boolean[t.length];
// for (VarArray va : varArrays) {
// if (va instanceof VarEntities.VarArray2D) {
// IVar[][] m = (IVar[][]) VarArray2D.class.cast(va).vars;
// for (int i = 0; i < m[0].length; i++) {
// int j = 0;
// while (j < m.length && Utilities.indexOf(m[j][i], t) != -1)
// j++;
// if (j == m.length) {
// for (j = 0; j < m.length; j++)
// bs[Utilities.indexOf(m[j][i], t)] = true;
// sb.append(" " + va.id + "[][" + i + "]");
// }
// }
// }
// }
// list = IntStream.range(0, t.length).filter(i -> !bs[i]).mapToObj(i -> t[i]).collect(toList());
}
if (list.size() > 0) {
SequenceOfSuccessiveVariables sequence = null;
for (IVar var : list)
if (sequence == null)
sequence = new SequenceOfSuccessiveVariables(var); // we start trying to find a sequence of successive variables
else {
if (sequence.canBeExtendedWith(var.id()) == false) {
sb.append(" " + sequence.toString()); // we add the curr sequence because it was no more possible to extend it
sequence = new SequenceOfSuccessiveVariables(var); // we restart trying to find a new sequence
}
}
sb.append(" " + sequence.toString());
}
return sb;
}
private String compact(IVar[] vars, boolean preserveOrder) {
Utilities.control(vars != null && vars.length > 0, "The array is empty");
if (vars.length == 1)
return vars[0].id();
if (vars.length == 2)
return vars[0].id() + " " + vars[1].id();
StringBuilder sb = new StringBuilder();
if (preserveOrder) {
ArrayList list = new ArrayList<>();
list.add(vars[0]);
String prefix = vars[0].idPrefix();
for (int i = 1; i <= vars.length; i++) {
if (i == vars.length || !prefix.equals(vars[i].idPrefix())) {
handlePart(sb, list, preserveOrder);
list.clear();
if (i < vars.length) {
list.add(vars[i]);
prefix = vars[i].idPrefix();
}
} else
list.add(vars[i]);
}
} else {
Map> byPrefixId = Stream.of(vars).collect(Collectors.groupingBy(x -> x.idPrefix()));
for (List list : byPrefixId.values())
handlePart(sb, list, preserveOrder);
}
return sb.toString().trim();
}
// private String compact(IVar[] vars, boolean preserveOrder) {
// if (vars.length == 2)
// return vars[0].id() + " " + vars[1].id();
//
// String compactFromOneArray = varArrays.stream().map(va -> va.compactFormOf(vars)).filter(s -> s != null).findFirst().orElse(null);
// if (compactFromOneArray != null && (!preserveOrder || expand(compactFromOneArray).equals(Stream.of(vars).map(x -> x.id()).collect(joining("
// ")))))
// return compactFromOneArray; // if preserveOrder is true, we know for sure that the order is preserved because we have just controlled it
// // if compression from a single array (as tried above) has not succeeded, then we execute the code below
// String s = "";
// List list = null; // contains variables remaining after trying compression on columns (when not preserving order)
// if (!preserveOrder) {
// // we search for compact forms of the form x[][i] for a given i ; this is possible because the order is not important here
// boolean[] bs = new boolean[vars.length];
// for (VarArray va : varArrays) {
// if (va instanceof VarEntities.VarArray2D) {
// IVar[][] m = (IVar[][]) VarArray2D.class.cast(va).vars;
// for (int i = 0; i < m[0].length; i++) {
// int j = 0;
// while (j < m.length && Utilities.indexOf(m[j][i], vars) != -1)
// j++;
// if (j == m.length) {
// for (j = 0; j < m.length; j++)
// bs[Utilities.indexOf(m[j][i], vars)] = true;
// s += " " + va.id + "[][" + i + "]";
// }
// }
// }
// }
// list = IntStream.range(0, vars.length).filter(i -> !bs[i]).mapToObj(i -> vars[i]).collect(toList());
// } else
// list = Arrays.asList(vars);
// if (list.size() > 0) {
// SequenceOfSuccessiveVariables sequence = null;
// for (IVar var : list)
// if (sequence == null)
// sequence = new SequenceOfSuccessiveVariables(var); // we start trying to find a sequence of successive variables
// else {
// if (sequence.canBeExtendedWith(var.id()) == false) {
// s += " " + sequence.toString(); // we add the current sequence because it was no more possible to extend it
// sequence = new SequenceOfSuccessiveVariables(var); // we restart trying to find a sequence of successive variables
// }
// }
// s += " " + sequence.toString();
// }
// return s.trim(); // note that the order is always preserved in that case
// }
public String compact(IVar[] vars) {
return compact(vars, false);
}
public String compactOrdered(IVar[] vars) {
return compact(vars, true);
}
public String[] compact(IVar[][] vars) {
return Stream.of(vars).map(t -> compact(t)).toArray(String[]::new);
}
public String[] compactOrdered(IVar[][] vars) {
return Stream.of(vars).map(t -> compactOrdered(t)).toArray(String[]::new);
}
public String compactMatrix(IVar[][] matrix) {
String s = compactOrdered(Utilities.collect(IVar.class, (Object) matrix));
if (s.indexOf(" ") == -1)
return s;
return Stream.of(matrix).map(t -> "(" + Stream.of(t).map(x -> x.toString()).collect(Collectors.joining(",")) + ")").collect(Collectors.joining(""));
}
public int nVarsIn(String s) {
return expand(s).split(" ").length;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy