Reputation: 69
Why does the following effectivly unused line (in the method: getAllDefinedVars) have an impact on the end result:
List collect = allVars.stream().filter(v -> false).collect(Collectors.toList());
If I remove the whole method and the one line of code, which is calling this method (first line in generateOneSetOfBools), I get an other result in the end.
I would expect such a behavior if...
As far as I can see, none of this happens. Therefore a removal of this whole method should have no impact on the result.
To convince yourself you can run the main the first time with the method containing the stream and the second time without this method and then compare the output.
public class PairwiseMain {
private static PairwisePermutator pp = new PairwisePermutator();
public static void main(String[] args) {
for(int i = 0; i < 20; i++) {
pp.permutate(i);
System.out.println("----------------");
}
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class PairwisePermutator {
private int n;
public Stream<boolean[]> permutate(int n) {
this.n = n;
List<Var> vars = generateRequiredVars(n);
List<TupleSet> table = generateTable(vars);
generateCombinations(table, vars);
return null;
}
private void generateCombinations(List<TupleSet> table, List<Var> vars) {
TupleSet start = findStartTupleSet(table);
if(start == null) {
return;
}else {
Tuple t = start.tuples.get(0);
start.setVars(t);
generateOneSetOfBools(table, vars, new HashSet<>(Arrays.asList(start)));
}
System.out.println(Arrays.toString(vars.toArray()));
resetAllVars(vars);
generateCombinations(table, vars);
}
private void resetAllVars(List<Var> vars) {
vars.stream().forEach(v -> v.value = null);
}
private void generateOneSetOfBools(List<TupleSet> table, List<Var> allVars, Set<TupleSet> start) {
List<Var> alreadyDefinedVars = getAllDefinedVars(allVars); //REMOVAL OF THIS LINE SHOULD HAVE NO IMPACT
Map<TupleSet, Integer> relevant = findRelevantTuplesInOtherTupleSets(table, start);
boolean changes = false;
boolean existsMultipleOptions = false;
TupleSet minimalMultipleOptions = null;
int minimalMultipleOptionsNumber = Integer.MAX_VALUE;
for(Map.Entry<TupleSet, Integer> entry : relevant.entrySet()) {
if(entry.getValue() == -1) {
removeTuple(entry.getKey());
start.add(entry.getKey());
changes = true;
}else if(entry.getValue() == 1) {
changes = true;
removeTuple(entry.getKey(), table, allVars);
start.add(entry.getKey());
}else if(entry.getValue() >= 2) {
existsMultipleOptions = true;
if(entry.getValue() < minimalMultipleOptionsNumber) {
minimalMultipleOptionsNumber = entry.getValue();
minimalMultipleOptions = entry.getKey();
}
}
}
if(!changes && existsMultipleOptions) {
removeRandomTuple(minimalMultipleOptions, start);
}else if(!changes) {
setVars(table);
}
if(areAllVarsDefined(allVars)) {
removeMatchingTuples(table);
return;
}
generateOneSetOfBools(table, allVars, start);
}
private List<Var> getAllDefinedVars(List<Var> allVars) {
List<Var> collect = allVars.stream().filter(v -> false).collect(Collectors.toList());
return collect;
}
private void removeMatchingTuples(List<TupleSet> table) {
for(TupleSet ts : table) {
boolean v1 = ts.x.value;
boolean v2 = ts.y.value;
Tuple toRemove = null;
for(Tuple t : ts.tuples) {
if(t.a == v1 && t.b == v2) {
toRemove = t;
}
}
if(toRemove != null) {
ts.setVars(toRemove);
}
}
}
private boolean areAllVarsDefined(List<Var> allVars) {
return allVars.stream().filter(v -> v.value != null).count() == n;
}
private void removeRandomTuple(TupleSet minimalMultipleOptions, Set<TupleSet> start) {
Tuple toRemove = minimalMultipleOptions.tuples.get(0);
minimalMultipleOptions.setVars(toRemove);
start.add(minimalMultipleOptions);
}
private void setVars(List<TupleSet> table) {
boolean foundOne = false;
for(TupleSet ts : table) {
if(ts.x.value == null && ts.y.value == null) {
foundOne = setVars(ts);
}
}
if(!foundOne) {
for(TupleSet ts : table) {
if(ts.x.value == null || ts.y.value == null) {
if(ts.tuples.isEmpty()){
ts.x.value = true;
ts.y.value = false;
}else {
ts.setVars(ts.tuples.get(0));
}
}
}
}
}
private boolean setVars(TupleSet ts) {
boolean foundOne;
if(ts.tuples.isEmpty()){
ts.x.value = true;
ts.y.value = false;
foundOne = true;
}else {
ts.setVars(ts.tuples.get(0));
foundOne = true;
}
return foundOne;
}
private void removeTuple(TupleSet ts, List<TupleSet> table, List<Var> vars) {
Tuple toRemove = null;
if(ts.x.value != null) {
for(Tuple t : ts.tuples) {
if(t.a == ts.x.value) {
toRemove = t;
}
}
}else if(ts.y.value != null) {
for(Tuple t : ts.tuples) {
if(t.b == ts.y.value) {
toRemove = t;
}
}
}
if(toRemove != null)
ts.setVars(toRemove);
}
private void removeTuple(TupleSet ts) {
boolean v1 = ts.x.value;
boolean v2 = ts.y.value;
Tuple toRemove = null;
for(Tuple t : ts.tuples) {
if(t.a == v1 && t.b == v2) {
toRemove = t;
}
}
if(toRemove != null) {
ts.setVars(toRemove);
}
}
private Map<TupleSet, Integer> findRelevantTuplesInOtherTupleSets(List<TupleSet> table, Set<TupleSet> alreadyVisited) {
Map<TupleSet, Integer> freedomMap = new HashMap<>();
for(TupleSet ts : table) {
if(!alreadyVisited.contains(ts)) {
int degreeOfFreedom = calculateDegreeOfFreedom(ts);
freedomMap.put(ts, degreeOfFreedom); }
}
return freedomMap;
}
private int calculateDegreeOfFreedom(TupleSet ts) {
List<Var> alreadyDefinedVars = new ArrayList<>();
if(ts.x.value != null) {
alreadyDefinedVars.add(ts.x);
}
if(ts.y.value != null) {
alreadyDefinedVars.add(ts.y);
}
int degreeOfFreedom = 0;
if(areBothDefinied(alreadyDefinedVars)) {
degreeOfFreedom = -1;
}else if(isExactlyOneDefinied(alreadyDefinedVars)) {
Var defined = getDefinedVar(alreadyDefinedVars);
if(defined == ts.x) {
degreeOfFreedom = (int) ts.tuples.stream().filter(t -> t.a == ts.x.value).count();
}else if(defined == ts.y) {
degreeOfFreedom = (int) ts.tuples.stream().filter(t -> t.b == ts.y.value).count();
}
}else if(alreadyDefinedVars.isEmpty()) {
degreeOfFreedom = ts.tuples.size();
}
return degreeOfFreedom;
}
private Var getDefinedVar(List<Var> alreadyDefinedVars) {
return alreadyDefinedVars.get(0);
}
private boolean isExactlyOneDefinied(List<Var> alreadyDefinedVars) {
return alreadyDefinedVars.size() == 1;
}
private boolean areBothDefinied(List<Var> alreadyDefinedVars) {
return alreadyDefinedVars.size() == 2;
}
private TupleSet findStartTupleSet(List<TupleSet> table) {
TupleSet startingTupleSet = null;
for(TupleSet ts : table) {
if(!ts.tuples.isEmpty()) {
startingTupleSet = ts;
}
}
return startingTupleSet;
}
private List<Var> generateRequiredVars(int n) {
return IntStream.range(0, n).mapToObj(number -> new Var()).collect(Collectors.toList());
}
private List<TupleSet> generateTable(List<Var> vars) {
List<TupleSet> tupleSets = new ArrayList<>();
int kStart = 1;
for(int i = 0; i < vars.size(); i++) {
for(int k = kStart; k < vars.size(); k++) {
tupleSets.add(getInitSet(vars.get(i), vars.get(k)));
}
kStart++;
}
return tupleSets;
}
private TupleSet getInitSet(Var x, Var y){
return new TupleSet(x, y, (new ArrayList<>(Arrays.asList( new Tuple(true, true),
new Tuple(true, false),
new Tuple(false, true),
new Tuple(false, false)))));
}
private static class TupleSet{
Var x;
Var y;
ArrayList<Tuple> tuples;
TupleSet(Var x, Var y, ArrayList<Tuple> tuples){
this.x = x;
this.y = y;
this.tuples = tuples;
}
public void setVars(Tuple t) {
x.value = t.a;
y.value = t.b;
tuples.remove(t);
}
@Override
public String toString() {
return "["+x+","+y+"]"+tuples;
}
}
private static class Var{
public Boolean value;
@Override
public String toString() {
return value == null ? "null" : value.toString();
}
}
private static class Tuple{
public Boolean a;
public Boolean b;
public Tuple(Boolean a, Boolean b) {
this.a = a;
this.b = b;
}
@Override
public String toString() {
return "("+a+","+b+")";
}
}
}
An example of an impact would be running pp.permutate(5) with the following output:
With the stream: run the code as it was posted
[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[true, false, false, true, false]
[false, false, true, true, false]
[true, true, true, false, false]
Without the stream: only delete the first line in generateOneSetOfBool()
[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[false, true, true, true, false]
[true, false, true, true, false]
[true, true, false, false, false]
Both outputs differ, for example the last line
Upvotes: 0
Views: 320
Reputation: 3131
The difference in results you're getting has nothing to do with the line List collect = allVars.stream().filter(v -> false).collect(Collectors.toList());
. The problem is that your algorithm is non-deterministic. I've taken your code and run it multiple time for the same input:
for(int i = 0; i < 20; i++) {
pp.permutate(5);
System.out.println("----------------");
}
Doesn't matter if there was the line you're talking about or not - I was getting both outputs you're mentioning (only those two variations appear tho):
[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[true, false, false, true, false]
[false, false, true, true, false]
[true, true, true, false, false]
----------------
[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[false, true, true, true, false]
[true, false, true, true, false]
[true, true, false, false, false]
I didn't go line by line through your code so I'm not sure but I'd guess that some of your collections doesn't guarantee anything about the order of elements.
However, what's interesting is that when I run main
multiple time the order in which different versions of the output appear will always be the same (or at least in 5 times I tried). What is more, when that one line you mentioned is removed then that order changes - but stays the same between calls of main. When we add to that the fact that on different machine it behaves differently my conclusion would be that it might have something to with how the program is placed in memory.
Upvotes: 2