<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.jtlv.env.module;

import net.sf.javabdd.BDDDomain;
import net.sf.javabdd.BDDException;
import net.sf.javabdd.BDDVarSet;

/**
 * <p>
 * JTLVBDDField is an object representing a field variable in JTLV environment.
 * On one hand, this object encapsulate the BDD domain, which does not
 * necessarily have two boolean values. On the other hand, this object also
 * encapsulate both prime and unprime versions of the variables.
 * </p>
 * 
 * @version {@value edu.wis.jtlv.env.Env#version}
 * @author <NAME>.
 * 
 */
public class ModuleBDDField extends ModuleEntity {
	/**
	 * <p>
	 * The domain of this field.
	 * </p>
	 */
	protected BDDDomain main;

	/**
	 * <p>
	 * Identify whether this field is the prime or the unprime version of the
	 * field.
	 * </p>
	 */
	protected boolean is_prime;

	/**
	 * <p>
	 * The other version of this field. i.e., if this is the unprime version
	 * then this.pair is the prime one, and wise versa.
	 * </p>
	 */
	protected ModuleBDDField pair;
	
	private int traceId;

	/**
	 * <p>
	 * The main public constructor for JTLVBDDField. Given a name, a
	 * domain, and a corresponding domain, a new BDD field is created with a
	 * corresponding prime version of the field.
	 * </p>
	 * 
	 * @param unprime
	 *            The domain to which we are constructing a field.
	 * @param prime
	 *            The other corresponding domain.
	 * @param name
	 *            A name for this field.
	 * 
	 * @see edu.wis.jtlv.env.Env#newVar(String, String)
	 * @see edu.wis.jtlv.env.Env#newVar(String, String, int)
	 */
	public ModuleBDDField(BDDDomain unprime, BDDDomain prime,
			String name) {
		this.main = unprime;
		this.main.setName(name);
		this.name = name;
		this.is_prime = false;
		this.pair = new ModuleBDDField(prime, this, name + "'");
	}

	/**
	 * <p>
	 * The corresponding private constructor for creating the prime version of
	 * the field.
	 * </p>
	 * 
	 * @param prime
	 *            The domain to which we are constructing a field.
	 * @param main_pair
	 *            The other JTLVBDDField which has invoked this instance.
	 * @param name
	 *            A name for this field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#JTLVBDDField(BDDDomain,
	 *      BDDDomain, String, String)
	 */
	private ModuleBDDField(BDDDomain prime, ModuleBDDField main_pair,
			String name) {
		this.main = prime;
		this.main.setName(name);
		this.name = name;
		this.is_prime = true;
		this.pair = main_pair;
	}

	/**
	 * <p>
	 * Return the other version of the field, regardless of which instance this
	 * is.
	 * </p>
	 * 
	 * @return The other version of the field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#prime()
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#unprime()
	 */
	public ModuleBDDField other() {
		return this.pair;
	}

	/**
	 * <p>
	 * Get the prime version of this field.
	 * </p>
	 * 
	 * @return The prime version of this field.
	 * @throws BDDException
	 *             If this is a prime version of the field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#other()
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#unprime()
	 */
	public ModuleBDDField prime() throws BDDException {
		if (is_prime) {
			throw new BDDException("Cannot prime primed variables.");
		}
		return this.other();
	}

	/**
	 * <p>
	 * Get the unprime version of this field.
	 * </p>
	 * 
	 * @return The unprime version of this field.
	 * @throws BDDException
	 *             If this is an unprime version of the field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#other()
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#prime()
	 */
	public ModuleBDDField unprime() throws BDDException {
		if (!is_prime) {
			throw new BDDException("Cannot unprime unprimed variables.");
		}
		return this.other();
	}

	/**
	 * <p>
	 * Get the set of BDD variables which construct the domain for this field.
	 * </p>
	 * 
	 * @return The set of BDD variables.
	 */
	public BDDVarSet support() {
		// return this.getDomain().set();
		return this.getDomain().ithVar(0).support();
	}

	/**
	 * <p>
	 * Check whether this is a prime version of the field representation.
	 * </p>
	 * 
	 * @return true if this is the prime version of the field, false otherwise.
	 */
	public boolean isPrime() {
		return is_prime;
	}

	/**
	 * <p>
	 * Getter for the domain of this field.
	 * </p>
	 * 
	 * @return The domain of this field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#getOtherDomain()
	 */
	public BDDDomain getDomain() {
		return this.main;
	}

	/**
	 * <p>
	 * Getter for the domain of the other corresponding field.
	 * </p>
	 * 
	 * @return The domain of the other corresponding field.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#getDomain()
	 */
	public BDDDomain getOtherDomain() {
		return this.other().getDomain();
	}

	/**
	 * <p>
	 * Check whether this object's domain is comparable to the give object
	 * domain.
	 * </p>
	 * 
	 * @param other
	 *            The other object to compare this filed to.
	 * @return true if the given object's domain is comparable to this domain,
	 *         false otherwise.
	 * 
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#equals(Object)
	 * @see edu.wis.jtlv.env.module.ModuleBDDField#strongEquals(Object)
	 */
	public boolean comparable(ModuleBDDField other) {
		return this.getDomain().size().equals((other.getDomain().size()));
	}

	public int getTraceId() {
	  return traceId;
	}
  
	public void setTraceId(int traceId) {
    this.traceId = traceId;
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.model.Variable;
import tau.smlab.syntech.gameinput.spec.Operator;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.VariableReference;

public class ArrayFunctionsTranslator implements Translator {
	
	private static final Map<Operator, Operator> ARRAY_TO_UNIT_OPERATORS = Collections.unmodifiableMap(new HashMap<Operator, Operator>() {{
		put(Operator.SUM_OF, Operator.ADD);
		put(Operator.PROD_OF, Operator.MULTIPLY);
		put(Operator.AND_OF, Operator.AND);
		put(Operator.OR_OF, Operator.OR);
	}});
	
	
	@Override
	public void translate(GameInput input) {
		// guarantees
		for (Constraint c : input.getSys().getConstraints()) {
			c.setSpec(replaceArrayOperators(c.getSpec(), c.getTraceId()));
		}

		// assumptions
		for (Constraint c : input.getEnv().getConstraints()) {
			c.setSpec(replaceArrayOperators(c.getSpec(), c.getTraceId()));
		}

	}
		
	private Spec replaceArrayOperators(Spec spec, int traceId) {
		if (spec instanceof SpecExp) {
			SpecExp specExp = (SpecExp) spec; 
			
			Operator arrayOp = specExp.getOperator();
						
			if (ARRAY_TO_UNIT_OPERATORS.containsKey(arrayOp) && (specExp.getChildren()[0] instanceof VariableReference)) {
				
				VariableReference array = (VariableReference) specExp.getChildren()[0];
				
				Spec newSpec = new VariableReference(new Variable(array.getReferenceName() + "[0]", array.getVariable().getType()));
				
				for (int index = 1; index < array.getIndexDimensions().get(0); index++) { 
					
					VariableReference currentElement = new VariableReference(new Variable(array.getReferenceName()+ "["+ index +"]", array.getVariable().getType())); 
					
					newSpec = new SpecExp(ARRAY_TO_UNIT_OPERATORS.get(arrayOp), currentElement, newSpec);										 
				}
				
				return newSpec;
			} else {
				for (int i = 0; i < specExp.getChildren().length; i++) {
					specExp.getChildren()[i] = replaceArrayOperators(specExp.getChildren()[i], traceId);
				}	
			}
		}

		return spec;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.jtlv.Env;

public class GR1GameBuilder {

	public static GR1Game getDefault(GameModel model, int energyBound) {
		boolean hasADD = Env.getBDDPackageInfo().contains("CUDDADDFactory");
		if (hasADD) {
			return new GR1GameEnergyADD(model, energyBound);
		} else {
			// in this case BDDGenerator took care of reduction already; we use regular GR1
			return getDefault(model);
		}
	}

	public static GR1Game getDefault(GameModel model) {
		// are we using pure Java? (this check also works correctly if the user chose a
		// native CUDD but Java is as fallback)
		boolean hasJNI = !Env.getBDDPackageInfo().contains("JTLVJavaFactory");

		// use GR(1)* synthesis
		if (model.getSys().existReqNum() > 0) {
			if (hasJNI) {
				return new GR1StarGameImplC(model);
			} else {
				new GR1StarGameMemoryless(model);
			}
		}
		if (hasJNI) {
			return new GR1GameImplC(model);
		}

		return new GR1GameExperiments(model);
	}

	/**
	 * Enable/disable optimization (if true, not all winning states are calculated!) 
	 * 
	 * TODO the current way this works is very ugly refactor this and make it not
	 * static all over
	 * 
	 * @param b
	 */
	public static void stopWhenInitialsLost(boolean b) {
		GR1GameExperiments.STOP_WHEN_INITIALS_LOST = b;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.checks;

import java.util.ArrayList;
import java.util.List;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

/**
 * assuming the user has an unrealizable spec this check will determine whether it makes sense to add assumptions that
 * allow "good" executions: where the environment can satisfy all assumptions and where the system can satisfy all
 * guarantees
 * 
 * This gives no guarantee that a corresponding strategy exists.
 *
 */
public class CouldAsmHelp {

  /**
   * assuming the user has an unrealizable spec this check will determine whether it makes sense to add assumptions that
   * allow "good" executions: where the environment can satisfy all assumptions and where the system can satisfy all
   * guarantees
   * 
   * This gives no guarantee that a corresponding strategy exists.
   * 
   * @param m
   *          the game model with both players
   * @return true if there is a common way to satisfy asms and gars
   */
  public static boolean couldAsmHelp(GameModel m) {
    BDD ini = m.getSys().initial().and(m.getEnv().initial());
    BDD trans = m.getSys().trans().and(m.getEnv().trans());
    List<BDD> buchis = new ArrayList<BDD>();
    for (int i = 0; i < m.getSys().justiceNum(); i++) {
      buchis.add(m.getSys().justiceAt(i));
    }
    for (int i = 0; i < m.getEnv().justiceNum(); i++) {
      buchis.add(m.getEnv().justiceAt(i));
    }
    if (buchis.isEmpty()) {
      buchis.add(Env.TRUE());
    }
    boolean commonSat = commonGeneralizedBuchiRealizable(ini, trans, buchis);
    ini.free();
    trans.free();
    return commonSat;
  }

  /**
   * compute a cooperative solution to the generalized Buchi game
   * 
   * @param ini
   * @param trans
   * @param buchis
   * @return
   */
  private static boolean commonGeneralizedBuchiRealizable(BDD ini, BDD trans, List<BDD> buchis) {
    BDD Z = Env.TRUE();

    FixPoint zFix = new FixPoint(true);
    while (zFix.advance(Z)) {
      Z = Z.id();
      for (BDD buchi : buchis) {
        BDD start = buchi.id().andWith(Env.pred(trans, Z));
        BDD nextZ = Z.id().andWith(reachBwd(trans, start));
        Z.free();
        Z = nextZ;
        start.free();

        BDD iniWin = ini.and(Z);
        if (iniWin.isZero()) {
          iniWin.free();
          return false;
        }
        iniWin.free();
      }
    }
    return true;
  }

  /**
   * compute all backwards reachable states
   * 
   * @param trans
   * @param to
   * @return
   */
  public static BDD reachBwd(BDD trans, BDD to) {
    BDD attr = Env.FALSE(); // no states
    FixPoint f = new FixPoint(true);
    while (f.advance(attr)) {
      attr = to.id().orWith(Env.pred(trans, attr));
    }
    return attr;
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;

import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.model.TriggerConstraint;
import tau.smlab.syntech.gameinput.model.WeightDefinition;
import tau.smlab.syntech.gameinput.spec.Operator;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;
import tau.smlab.syntech.gameinput.spec.VariableReference;
import tau.smlab.syntech.gameinputtrans.TranslationException;

/**
 * should be run only after all past LTL, predicates, patterns, and defines have
 * been instantiated
 * 
 * will only translate primes in main specifications
 */
public class PrimesTranslator implements Translator {

	@Override
	public void translate(GameInput input) {
		for (Constraint c : input.getSys().getConstraints()) {
			c.setSpec(replacePrimes(c.getSpec(), c.getTraceId()));
		}
		for (TriggerConstraint c : input.getSys().getTriggers()) {
			c.setSpec(detectPrimes(c.getInitSpecRegExp(), c.getTraceId()));
			c.setSpec(detectPrimes(c.getEffectSpecRegExp(), c.getTraceId()));
		}
		for (Constraint c : input.getEnv().getConstraints()) {
			c.setSpec(replacePrimes(c.getSpec(), c.getTraceId()));
		}
		for (Constraint c : input.getAux().getConstraints()) {
			c.setSpec(replacePrimes(c.getSpec(), c.getTraceId()));
		}
		for (WeightDefinition wd : input.getWeightDefs()) {
			wd.getDefinition().setSpec(replacePrimes(wd.getDefinition().getSpec(), wd.getDefinition().getTraceId()));
		}
	}

	/**
	 * look for prime operators and replace them
	 * 
	 * @param spec
	 * @return
	 */
	private Spec replacePrimes(Spec spec, int traceId) {
		if (spec instanceof SpecExp) {
			SpecExp e = (SpecExp) spec;
			if (Operator.PRIME.equals(e.getOperator())) {
				Spec pSpec = primeVarAllReferences(e.getChildren()[0], traceId);
				return replacePrimes(pSpec, traceId);
			} else {
				for (int i = 0; i < e.getChildren().length; i++) {
					e.getChildren()[i] = replacePrimes(e.getChildren()[i], traceId);
				}
			}
		}
		return spec;
	}
	
	/**
	 * detect primes in triggers if there are any left after predicate translations
	 * @param spec
	 * @param traceId
	 * @return
	 */
	private Spec detectPrimes(Spec spec, int traceId) {
		if (spec instanceof SpecRegExp) {
			SpecRegExp e = (SpecRegExp) spec;
			
			detectPrimes(e.getPredicate(), traceId);
			detectPrimes(e.getLeft(), traceId);
			detectPrimes(e.getRight(), traceId);
			
		} else if (spec instanceof SpecExp) {
			SpecExp e = (SpecExp) spec;
			if (Operator.PRIME.equals(e.getOperator())) {
				throw new TranslationException("Regular expressions can't have primed ('next') variables", traceId);
			} else {
				for (int i = 0; i < e.getChildren().length; i++) {
					detectPrimes(e.getChildren()[i], traceId);
				}
			}
		}
		return spec;
	}

	/**
	 * replace reference names with primed versions
	 * 
	 * @param spec
	 */
	private Spec primeVarAllReferences(Spec spec, int traceId) {

		if (spec instanceof VariableReference) {
			String refName = ((VariableReference) spec).getReferenceName();
			if (refName.endsWith("'")) {
				throw new TranslationException("Cannot prime primed variable.", traceId);
			}
			return new VariableReference(((VariableReference) spec).getVariable(), refName + "'");
		} else if (spec instanceof SpecExp) {
			SpecExp e = (SpecExp) spec;
			for (int i = 0; i < e.getChildren().length; i++) {
				e.getChildren()[i] = primeVarAllReferences(e.getChildren()[i], traceId);
			}
		}
		return spec;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.sfa;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.sfa.SFA.Pair;

/**
 * @author <NAME>
 * @author <NAME>
 *
 */
public class PowerSetIterator {
	
	private PowerSetIterator() {};
	
	public static enum PowerSetIteratorType {
		DEFAULT, EFFICIENT;
	}

	/**
	 * Returns an iterator that iterates over the powerset of the given set of SFA transitions. Each element in
	 * the iteration is an (ordered) Pair object whose left component is a transitions' subset {@code t} and whose right component is a satisfiable BDD {@code b} that encodes
	 * the conjunction of all transitions' guards in {@code t}. Subsets {@code t} where {@code b} is unsatisfiable (i.e., where {@code b} is the FALSE BDD), do not occur in the iteration.
	 * 
	 * @param type
	 * @param transitionsSet
	 * @return
	 */
	public static <T extends SFAState> Iterator<Pair<Set<Map.Entry<T, BDD>>, BDD>>
	getIterator(PowerSetIteratorType type, Set<Map.Entry<T, BDD>> transitionsSet) {
		if(type.equals(PowerSetIteratorType.DEFAULT)) {
			return new DefaultPowerSetIterator<T>(transitionsSet);
		}
		if(type.equals(PowerSetIteratorType.EFFICIENT)) {
			return new EfficientPowerSetIterator<T>(transitionsSet);
		}
		return null;
	}

	/**
	 * A class for constructing a lazy powerset iterator over sets of SFA
	 * transitions. The iterator uses a binary counter to keep track of the subsets' enumeration.
	 * The iterator only generates transitions' subsets whose transition formulas'
	 * conjunction is satisfiable.
	 */
	private static class DefaultPowerSetIterator<T extends SFAState> implements Iterator<Pair<Set<Map.Entry<T, BDD>>, BDD>>{

		private List<Map.Entry<T, BDD>> transitionsSetList;

		private boolean[] nextSubsetBinaryList;
		private Set<Map.Entry<T, BDD>> nextSubset = new HashSet<>();
		private BDD nextSubsetBDD, nextNextSubsetBDD;

		private Set<Map.Entry<T, BDD>> nextNextSubset = new HashSet<>();

		DefaultPowerSetIterator(Set<Map.Entry<T, BDD>> transitionsSet) {
			this.transitionsSetList = new ArrayList<>(transitionsSet);
			this.nextSubsetBinaryList = new boolean[transitionsSet.size()];
			this.nextNextSubsetBDD = Env.TRUE();
		}

		@Override
		public boolean hasNext() {
			if (this.nextNextSubset == null) {
				return false;
			}
			return true;
		}

		@Override
		public Pair<Set<Map.Entry<T, BDD>>, BDD> next() {
			if (!this.hasNext()) {
				return null;
			}

			this.nextSubset.clear();
			this.nextSubset.addAll(this.nextNextSubset);
			this.nextSubsetBDD = this.nextNextSubsetBDD;

			do {
				for (int i = 0; i < this.nextSubsetBinaryList.length; ++i) {
					this.nextSubsetBinaryList[i] = !this.nextSubsetBinaryList[i];
					if (this.nextSubsetBinaryList[i]) {
						break;
					}
				}

				this.nextNextSubset.clear();
				if(this.nextNextSubsetBDD.isZero()) {
					this.nextNextSubsetBDD.free();
				}
				this.nextNextSubsetBDD = Env.TRUE();
				for (int i = 0; i < this.transitionsSetList.size(); ++i) {
					if (this.nextSubsetBinaryList[i]) {
						this.nextNextSubset.add(this.transitionsSetList.get(i));
						this.nextNextSubsetBDD.andWith(this.transitionsSetList.get(i).getValue().id());
						if(this.nextNextSubsetBDD.isZero()) {
							break;
						}
					}
				}
				if (this.nextNextSubset.isEmpty()) {
					this.nextNextSubset = null;
					this.nextNextSubsetBDD.free();
					break;
				}
			} while(this.nextNextSubsetBDD.isZero());

			return new Pair<Set<Map.Entry<T, BDD>>, BDD>(this.nextSubset, this.nextSubsetBDD);
		}
	}

	/**
	 * A class for constructing a lazy powerset iterator over sets of SFA
	 * transitions. The iterator only generates transitions' subsets whose transition formulas'
	 * conjunction is satisfiable. The iterator generates transitions' subsets with a non-decreasing cardinality. In addition, it applies pruning as an optimization. That is,
	 * it does not look at proper supersets of a set which has already been explored and the conjunction of its transitions' formulas is unsatisfiable.
	 *  
	 */
	private static class EfficientPowerSetIterator<T extends SFAState> implements Iterator<Pair<Set<Map.Entry<T, BDD>>, BDD>> {

		private List<Map.Entry<T, BDD>> transitionsSetList;
		private int nextTransitionsSetListIdx = 0;

		private Set<Map.Entry<T, BDD>> nextSubset = new HashSet<>(), nextNextSubset = new HashSet<>();

		private BDD nextSubsetBDD, nextNextSubsetBDD;

		private int currPrevSizeSubsetIdx = 0; //the current index of the subset (of size N) that we try to extend with an additional element
		private List<List<Integer>> prevSizeSubsetsIndices = new ArrayList<>(); //each list contains the transitions' indices in each subset of size N
		private List<List<Integer>> currSizeSubsetsIndices = new ArrayList<>(); //each list contains the transitions' indices in each subset of size N+1


		private List<BDD> prevSizeSubsetsBDDs = new ArrayList<>(); //each BDD is the conjunction of all transitions in the corresponding subset of size N
		private List<BDD> currSizeSubsetsBDDs = new ArrayList<>(); //each BDD is the conjunction of all transitions in the corresponding subset of size N+1

		EfficientPowerSetIterator(Set<Map.Entry<T, BDD>> transitionsSet) {
			this.transitionsSetList = new ArrayList<>(transitionsSet);

			this.prevSizeSubsetsIndices.add(new ArrayList<>());

			this.nextNextSubsetBDD = Env.TRUE();
			this.prevSizeSubsetsBDDs.add(Env.TRUE());

		}

		/*
		 * This method is basically a flat (iterative) version of a recursive method
		 * that generates lazily all SATISFIABLE transition subsets of growing size, and
		 * their formulas' BDD conjunction. Once there are no satisfiable subsets left,
		 * null is returned.
		 * 
		 */
		@Override
		public Pair<Set<Map.Entry<T, BDD>>, BDD> next() {
			if(!this.hasNext()) {
				return null;
			}

			this.nextSubset.clear();
			this.nextSubset.addAll(this.nextNextSubset);
			this.nextSubsetBDD = this.nextNextSubsetBDD;
			Pair<Set<Map.Entry<T, BDD>>, BDD> nextPair = new Pair<>(this.nextSubset, this.nextSubsetBDD);

			List<Integer> nextNextSubsetIndices, currPrevSizeSubsetIndices;


			while(true) {
				while (this.nextTransitionsSetListIdx < this.transitionsSetList.size()) {
					this.nextNextSubsetBDD = this.prevSizeSubsetsBDDs.get(this.currPrevSizeSubsetIdx)
							.and(this.transitionsSetList.get(this.nextTransitionsSetListIdx).getValue());

					if(this.nextNextSubsetBDD.isZero()) {
						this.nextNextSubsetBDD.free();
						this.nextTransitionsSetListIdx++;
					}
					else {
						//the BDD of the next next subset is not FALSE, so keep it to consider (in the future) proper supersets thereof
						this.currSizeSubsetsBDDs.add(this.nextNextSubsetBDD.id());

						//create the list of the transitions' indices which are in the next next transitions subset
						nextNextSubsetIndices = new ArrayList<>();
						nextNextSubsetIndices.addAll(this.prevSizeSubsetsIndices.get(this.currPrevSizeSubsetIdx));
						nextNextSubsetIndices.add(this.nextTransitionsSetListIdx);
						this.currSizeSubsetsIndices.add(nextNextSubsetIndices);

						//increment the index of the transition which should be added next to the transitions subset 
						this.nextTransitionsSetListIdx++;

						//compute the next next transitions subset (nextNextSubset) from its indices list (nextNextSubsetIndices)
						this.nextNextSubset.clear();
						for(int transIdx : nextNextSubsetIndices) {
							this.nextNextSubset.add(this.transitionsSetList.get(transIdx));
						}
						return nextPair;
					}
				}

				/*
				 * 
				 * At this point, we have created all possible (satisfiable) supersets (of size N+1) of the current transitions subset of size N
				 * (which in this.prevSizeSubsetsIndices[this.currPrevSizeSubsetIdx]). Thus, we proceed to this.currPrevSizeSubsetIdx+1.
				 * If that's impossible, i.e., (this.currPrevSizeSubsetIdx+1) == this.prevSizeSubsetsIndices.size(), we clear and insert to this.prevSizeSubsetsIndices the indices
				 * lists in this.currSizeSubsetsIndices.
				 * 
				 * */

				this.currPrevSizeSubsetIdx++;
				if(this.currPrevSizeSubsetIdx == this.prevSizeSubsetsIndices.size()) {
					Env.free(this.prevSizeSubsetsBDDs); //free all previously stored BDDs
					this.prevSizeSubsetsBDDs.clear(); //remove all previously stored BDD objects
					this.prevSizeSubsetsIndices.clear(); //remove all previously stored transitions subsets' indices lists 

					if(this.currSizeSubsetsIndices.isEmpty()) { //there are no transitions' indices lists whose supersets should be generated next -> we are done!
						this.setIsExhausted(); //mark that the iterator is exhausted
						break;
					}
					
					//we have that this.currSizeSubsetsIndices is not empty
					
					this.prevSizeSubsetsIndices.addAll(this.currSizeSubsetsIndices); //insert to this.prevSizeSubsetsIndices all the indices lists in this.currSizeSubsetsIndices
					this.prevSizeSubsetsBDDs.addAll(this.currSizeSubsetsBDDs); //insert to this.prevSizeSubsetsBDDs all the BDDs in this.currSizeSubsetsBDDs
					this.currPrevSizeSubsetIdx = 0; //reset the index of the subset that we try to extend with an additional element 

					//clear current subsets indices and BDDs
					this.currSizeSubsetsIndices.clear();
					this.currSizeSubsetsBDDs.clear();
				}

				//set this.nextTransitionsSetListIdx according to the current transitions' indices subset that we try to extend
				//the next value of this.nextTransitionsSetListIdx should be equal to [maximal (last) index element in this.prevSizeSubsetsIndices.get(this.currPrevSizeSubsetIdx)] + 1
				currPrevSizeSubsetIndices = this.prevSizeSubsetsIndices.get(this.currPrevSizeSubsetIdx);
				this.nextTransitionsSetListIdx = currPrevSizeSubsetIndices.get(currPrevSizeSubsetIndices.size()-1)+1;
			}
			return nextPair;
		}

		@Override
		public boolean hasNext() {
			if (this.nextNextSubset == null) {
				return false;
			}
			return true;
		}

		private void setIsExhausted() {
			this.nextNextSubset = null;
		}

	}





}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.checks;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.checks.ddmin.AbstractDdmin;
import tau.smlab.syntech.checks.ddmin.DdminUNSAT;
import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.SpecTraceable;
import tau.smlab.syntech.gameinput.spec.VariableReference;
import tau.smlab.syntech.gameinputtrans.translator.CounterTranslator;
import tau.smlab.syntech.gameinputtrans.translator.MonitorTranslator;
import tau.smlab.syntech.gameinputtrans.translator.PastLTLTranslator;
import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.games.controller.symbolic.SymbolicController;
import tau.smlab.syntech.jtlv.CoreUtil;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.env.module.ModuleBDDField;

/**
 * some non-trivial checks on the BDD level
 * 
 * @author ringert
 * 
 */
public class Checker {

  private PlayerModule sys;
  private PlayerModule env;
  private String[] monitorCheckMessages;
  private String[] counterCheckMessages;

  /**
   * Computes a subset of initial and safety system constraints that allow the environment to deadlock the system on its initial
   * move. <br>
   * 
   * @param m
   * @return null if no deadlock can occur
   */
  public List<BehaviorInfo> computeIniDeadlockCore(GameModel model, List<String> l) {
    env = model.getEnv();
    sys = model.getSys();

    BDD sysDead = sys.initial().id().impWith(env.controlStates(sys, Env.FALSE()));
    BDD envKillSys = env.initial().id().andWith(sysDead.forAll(sys.moduleUnprimeVars()));
    sysDead.free();

    if (envKillSys.isZero()) {
      return null;
    }
    envKillSys.free();

    return new AbstractDdmin<BehaviorInfo>() {

      @Override
      protected boolean check(List<BehaviorInfo> part) {
        BDD iniPart = Env.TRUE();
        part.stream().filter(p -> p.isInitial()).forEach(p -> iniPart.andWith(p.initial.id()));

        BDD transPart = Env.TRUE();
        part.stream().filter(p -> p.isSafety()).forEach(p -> transPart.andWith(p.safety.id()));

        PlayerModule partSys = new PlayerModule();
        partSys.conjunctTrans(transPart);
        // initial states where the environment can force system to deadlock
        BDD sysDead = iniPart.impWith(env.controlStates(partSys, Env.FALSE()));
        partSys.free();
        // initial environment assignment that can deadlock the system
        BDD envKillSys = env.initial().id().andWith(sysDead.forAll(sys.moduleUnprimeVars()));
        boolean win = !envKillSys.isZero();
        if (win) {
          BDD e = envKillSys.exist(sys.modulePrimeVars());
          BDD e1 = e.exist(sys.moduleUnprimeVars());
          e.free();
          if (e1.isOne()) {
            l.add("Any initial assignment.");
          } else {
            l.add(Env.toNiceSignleLineString(e1));
          }
          e1.free();
        }
        envKillSys.free();
        return win;
      }

    }.minimize(
        model.getSysBehaviorInfo().stream().filter(p -> p.isInitial() || p.isSafety()).collect(Collectors.toList()));
  }

  /**
   * Computes reachable states (most permissive environment and system) and checks if justices can be reached. <br>
   * This is a heuristics because it assumes environment and system to be only restricted by their safeties and not by
   * any strategy.
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeUnreachableJustice(GameModel model) {

    env = model.getEnv();
    sys = model.getSys();

    List<BehaviorInfo> unreachableJustice = new ArrayList<>();

    // compute reachable states, which are not immediate deadlocks for the system
    BDD reach = Env.allSucc(env.initial().and(sys.initial()), env.trans().and(sys.trans()));
    BDD dead = env.controlStates(sys, Env.FALSE());
    reach.andWith(dead.not());
    dead.free();

    for (BehaviorInfo bi : model.getSysBehaviorInfo()) {
      if (bi.isJustice()) {
        BDD tmp = bi.justice.and(reach);
        if (tmp.isZero()) {
          unreachableJustice.add(bi);
        }
        tmp.free();
      }
    }

    for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
      if (bi.isJustice()) {
        BDD tmp = bi.justice.and(reach);
        if (tmp.isZero()) {
          unreachableJustice.add(bi);
        }
        tmp.free();
      }
    }

    reach.free();
    return unreachableJustice;
  }

  /**
   * computes a minimal unsatisfiable subset of constraints INI or SAFETY
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeUnsatSafetyCore(GameModel model) {

    sys = model.getSys();

    DdminUNSAT cc = new DdminUNSAT();
    if (sys.initial().isZero()) {
      List<BehaviorInfo> inis = new ArrayList<>();
      for (BehaviorInfo bi : model.getSysBehaviorInfo()) {
        if (bi.isInitial()) {
          inis.add(bi);
        }
      }
      return cc.minimize(inis);
    } else if (sys.trans().isZero()) {
      List<BehaviorInfo> safeties = new ArrayList<>();
      for (BehaviorInfo bi : model.getSysBehaviorInfo()) {
        if (bi.isInitial() || bi.isSafety()) {
          safeties.add(bi);
        }
      }
      return cc.minimize(safeties);
    }

    env = model.getEnv();

    if (env.initial().isZero()) {
      List<BehaviorInfo> inis = new ArrayList<>();
      for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
        if (bi.isInitial()) {
          inis.add(bi);
        }
      }
      return cc.minimize(inis);
    } else if (env.trans().isZero()) {
      List<BehaviorInfo> safeties = new ArrayList<>();
      for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
        if (bi.isInitial() || bi.isSafety()) {
          safeties.add(bi);
        }
      }
      return cc.minimize(safeties);
    }

    return new ArrayList<>();
  }

  /**
   * checks constraints whether they are trivially TRUE or FALSE
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeTrivialSpecs(GameModel model) {

    List<BehaviorInfo> infos = new ArrayList<>();
    infos.addAll(model.getSysBehaviorInfo());
    infos.addAll(model.getEnvBehaviorInfo());
    infos.addAll(model.getAuxBehaviorInfo());

    List<BehaviorInfo> trivial = new ArrayList<>();
    for (BehaviorInfo bi : infos) {
      if (bi.getBdd().isZero() || bi.getBdd().isOne()) {
        trivial.add(bi);
      }
    }
    return trivial;
  }

  /**
   * Checks whether there are illegal assumptions: initial assumptions with system variables or any primes, or safety
   * assumptions with any system primes.
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeEnvBadPrimesSpecs(GameModel model) {
    List<BehaviorInfo> infos = new ArrayList<>();
    infos.addAll(computeBadIniPrimesSpecs(model));
    infos.addAll(computeEnvBadIniSysSpec(model));
    infos.addAll(computeEnvBadSafetyPrimesSpecs(model));
    return infos;
  }

  /**
   * Checks whether there are illegal assumptions: initial assumptions with system variables.
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeEnvBadIniSysSpec(GameModel model) {
    sys = model.getSys();
    env = model.getEnv();
    List<BehaviorInfo> infos = new ArrayList<>();
    BDDVarSet primes = Env.globalPrimeVars();

    // initial assumptions may not have system variables
    if (Env.hasVars(env.initial(), sys.moduleUnprimeVars())) {
      // check whether BehaviorInfo was created
      if (model.getEnvBehaviorInfo().isEmpty()) {
        infos.add(new BehaviorInfo(env.initial(), null, null, null, null, 0, false));
      } else {
        for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
          if (bi.isInitial() && Env.hasVars(bi.initial, sys.moduleUnprimeVars())) {
            infos.add(bi);
          }
        }
      }
    }

    primes.free();
    return infos;
  }

  /**
   * Checks whether there are illegal assumptions: initial assumptions with any primes.
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeBadIniPrimesSpecs(GameModel model) {
    sys = model.getSys();
    env = model.getEnv();
    List<BehaviorInfo> infos = new ArrayList<>();
    BDDVarSet primes = Env.globalPrimeVars();

    // initial assumptions may not have primed variables
    if (Env.hasVars(env.initial(), primes)) {
      // check whether BehaviorInfo was created
      if (model.getEnvBehaviorInfo().isEmpty()) {
        infos.add(new BehaviorInfo(env.initial(), null, null, null, null, 0, false));
      } else {
        for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
          if (bi.isInitial() && Env.hasVars(bi.initial, primes)) {
            infos.add(bi);
          }
        }
      }
    }

    primes.free();
    return infos;
  }

  /**
   * Checks whether there are illegal assumptions: safety assumptions with any system primes.
   * 
   * @param model
   * @return
   */
  public List<BehaviorInfo> computeEnvBadSafetyPrimesSpecs(GameModel model) {
    sys = model.getSys();
    env = model.getEnv();
    List<BehaviorInfo> infos = new ArrayList<>();

    // safety assumptions may not have primed system variables
    if (Env.hasVars(env.trans(), sys.modulePrimeVars())) {
      // check whether BehaviorInfo was created
      if (model.getEnvBehaviorInfo().isEmpty()) {
        infos.add(new BehaviorInfo(null, env.trans(), null, null, null, 0, false));
      } else {
        for (BehaviorInfo bi : model.getEnvBehaviorInfo()) {
          if (bi.isSafety() && Env.hasVars(bi.safety, sys.modulePrimeVars())) {
            infos.add(bi);
          }
        }
      }
    }
    return infos;
  }

  public List<BehaviorInfo> computeSysBadPrimesSpecs(GameModel model) {
    sys = model.getSys();
    env = model.getEnv();
    List<BehaviorInfo> infos = new ArrayList<>();
    BDDVarSet primes = Env.globalPrimeVars();

    if (Env.hasVars(sys.initial(), primes)) {
      // check whether BehaviorInfo was created
      if (model.getSysBehaviorInfo().isEmpty()) {
        infos.add(new BehaviorInfo(sys.initial(), null, null, null, null, 0, false));
      } else {
        for (BehaviorInfo bi : model.getSysBehaviorInfo()) {
          if (bi.isInitial() && Env.hasVars(bi.initial, primes)) {
            infos.add(bi);
          }
        }
      }
    }
    
    primes.free();
    return infos;
  }

  public Map<Integer, Set<BehaviorInfo>> computeTraceIdtoBIMap(GameModel gm) {
    Map<Integer, Set<BehaviorInfo>> traceIdToBehaviorInfo = new HashMap<>();
    Set<BehaviorInfo> biSet;
    for (BehaviorInfo bi : gm.getAuxBehaviorInfo()) {
      if (traceIdToBehaviorInfo.containsKey(bi.traceId)) {
        biSet = traceIdToBehaviorInfo.get(bi.traceId);
      } else {
        biSet = new HashSet<>();
        traceIdToBehaviorInfo.put(bi.traceId, biSet);
      }
      biSet.add(bi);
    }
    return traceIdToBehaviorInfo;
  }

  /**
   * Fills in for the specified monitor monName the following info:
   * (1) Behavior info of initial and safety constraints (in initialConstraints and safetyConstraints).
   * (2) Behavior info of PAST initial and safety constraints, i.e, which were created during the PAST translation,
   *     (in pastInitialConstraints and pastSafetyConstraints).
   * (3) A list of the PAST variable references (in monNameToVarRefs).
   */
  public void fillMonitorConstraints(GameModel gm,
      String monName,
      MonitorTranslator monTranslator,
      PastLTLTranslator pastTranslator,
      Map<Integer, Set<BehaviorInfo>> traceIdToBehaviorInfo,
      Map<String, Set<BehaviorInfo>> safetyConstraints,
      Map<String, Set<BehaviorInfo>> initialConstraints,
      Map<String, Set<BehaviorInfo>> pastSafetyConstraints,
      Map<String, Set<BehaviorInfo>> pastInitialConstraints,
      Map<String, Set<VariableReference>> monNameToVarRefs) {

    Set<BehaviorInfo> biSet;
    for (Integer traceId : monTranslator.getTraceIdsOfMonitor(monName)) {
      biSet = traceIdToBehaviorInfo.get(traceId);
      for (BehaviorInfo bi : biSet) {
        if (bi.isInitial()) {
          addConstraintToMonitor(initialConstraints, monName, bi);
        } else if (bi.isSafety()) {
          addConstraintToMonitor(safetyConstraints, monName, bi);
        }
      }
    }

    List<Constraint> monPastConstraints = new ArrayList<>();
    for (Constraint c : monTranslator.getMonitorConstraints(monName)) {
      monPastConstraints.addAll(
          getPastConstraints(monName, c.getSpec(), pastTranslator, monNameToVarRefs));
    }

    for (Constraint c : monPastConstraints) {
      biSet = traceIdToBehaviorInfo.get(c.getTraceId());
      for (BehaviorInfo bi : biSet) {
        if (bi.isInitial()) {
          if (!initialConstraints.get(monName).contains(bi)) {
            addConstraintToMonitor(pastInitialConstraints, monName, bi);
          }
        } else if (bi.isSafety()) {
          if (!safetyConstraints.get(monName).contains(bi)) {
            addConstraintToMonitor(pastSafetyConstraints, monName, bi);
          }
        }
      }
    }
  }

  private Set<Constraint> getPastConstraints(String monName, Set<Constraint> cons, PastLTLTranslator pastTranslator,
      Map<String, Set<VariableReference>> monNameToVarRefs) {
    Set<Constraint> all = new HashSet<>(cons);
    for (Constraint c : cons) {
      all.addAll(getPastConstraints(monName, c.getSpec(), pastTranslator, monNameToVarRefs));
    }
    return all;
  }

  private Set<Constraint> getPastConstraints(String monName, Spec spec,
      PastLTLTranslator pastTranslator,
      Map<String, Set<VariableReference>> monNameToVarRefs) {

    if (spec instanceof VariableReference) {
      VariableReference varRef = (VariableReference) spec;
      //we need to maintain a mapping of a monitor name to variables of a monitor
      if (pastTranslator.getConstraintsOfVarRef(varRef) != null) {
        Set<VariableReference> monVarRefs;
        if (monNameToVarRefs.containsKey(monName)) {
          monVarRefs = monNameToVarRefs.get(monName);
        } else {
          monVarRefs = new HashSet<>();
          monNameToVarRefs.put(monName, monVarRefs);
        }
        monVarRefs.add(varRef);
        return getPastConstraints(monName, new HashSet<Constraint>(pastTranslator.getConstraintsOfVarRef(varRef)),
            pastTranslator, monNameToVarRefs);
      }
    }

    if (spec instanceof SpecExp) {
      SpecExp se = (SpecExp) spec;
      Set<Constraint> childrenConstraints = new HashSet<>();
      for (int i = 0; i < se.getChildren().length; i++) {
        childrenConstraints.addAll(getPastConstraints(monName,
            se.getChildren()[i], pastTranslator, monNameToVarRefs));
      }
      return childrenConstraints;
    }

    return new HashSet<>();
  }

  /**
   * Returns the behavior info list of the specified monitor monName.
   * 
   * @param monName
   * @param safetyConstraints
   * @param initialConstraints
   * @return
   */
  private List<BehaviorInfo> getMonitorSpecList(String monName,
      Map<String, Set<BehaviorInfo>> safetyConstraints,
      Map<String, Set<BehaviorInfo>> initialConstraints) {

    List<BehaviorInfo> monitorSpecs = new ArrayList<>();

    if (safetyConstraints != null && safetyConstraints.containsKey(monName)) {
      monitorSpecs.addAll(safetyConstraints.get(monName));
    }
    if (initialConstraints != null && initialConstraints.containsKey(monName)) {
      monitorSpecs.addAll(initialConstraints.get(monName));
    }

    return monitorSpecs;

  }

  public List<BehaviorInfo> checkMonitorsForCompleteness(GameModel gm, MonitorTranslator monitorTranslator,
      PastLTLTranslator pastLTLTranslator) {

    List<BehaviorInfo> result;
    Map<Integer, Set<BehaviorInfo>> traceIdtoBI = computeTraceIdtoBIMap(gm); //Note that the same traceId may have multiple Behavior infos
    Map<String, Set<BehaviorInfo>> safetyConstraints = new HashMap<>();
    Map<String, Set<BehaviorInfo>> pastSafetyConstraints = new HashMap<>();
    Map<String, Set<BehaviorInfo>> pastInitialConstraints = new HashMap<>();
    Map<String, Set<BehaviorInfo>> initialConstraints = new HashMap<>();
    Map<String, Set<VariableReference>> monNameToVarRefs = new HashMap<>();

    for (String monName : monitorTranslator.getMonitorsNames()) {
      fillMonitorConstraints(gm, monName, monitorTranslator, pastLTLTranslator, traceIdtoBI,
          safetyConstraints, initialConstraints, pastSafetyConstraints, pastInitialConstraints, monNameToVarRefs);

      //check for completeness
      // build a symbolic controller from the monitor's definition

      SymbolicController symCtrl = new SymbolicController();
      symCtrl.initial().free();
      symCtrl.trans().free();
      symCtrl.setTrans(Env.TRUE());

      if (safetyConstraints.containsKey(monName)) {
        for (BehaviorInfo bi : safetyConstraints.get(monName)) {
          symCtrl.conjunctTransWith(bi.safety.id());
        }
      }

      if (pastSafetyConstraints.containsKey(monName)) {
        for (BehaviorInfo bi : pastSafetyConstraints.get(monName)) {
          symCtrl.conjunctTransWith(bi.safety.id());
        }
      }

      BDD initials = Env.TRUE();
      if (initialConstraints.containsKey(monName)) {
        for (BehaviorInfo bi : initialConstraints.get(monName)) {
          initials.andWith(bi.initial.id());
        }
      }
      if (pastInitialConstraints.containsKey(monName)) {
        for (BehaviorInfo bi : pastInitialConstraints.get(monName)) {
          initials.andWith(bi.initial.id());
        }
      }
      symCtrl.setInit(initials);

      result = performMonitorCompletenessCheck(gm, monName, monNameToVarRefs.get(monName), symCtrl, safetyConstraints,
          initialConstraints);
      if (!result.isEmpty()) {
        return result;
      }
    }
    // if we have reached here, the monitor has passed the check 
    return new ArrayList<>();
  }

  private void addConstraintToMonitor(Map<String, Set<BehaviorInfo>> constraints,
      String parentMonitor, BehaviorInfo bi) {
    Set<BehaviorInfo> constraintSet;
    if (constraints.containsKey(parentMonitor)) {
      constraintSet = constraints.get(parentMonitor);
    } else {
      constraintSet = new HashSet<>();
      constraints.put(parentMonitor, constraintSet);
    }
    constraintSet.add(bi);
  }

  private List<BehaviorInfo> performMonitorCompletenessCheck(GameModel m, String monitorName,
      Set<VariableReference> pastVarlist, SymbolicController ctrl,
      Map<String, Set<BehaviorInfo>> safetyConstraints,
      Map<String, Set<BehaviorInfo>> initialConstraints) {

    // handling domain information
    BDD doms = m.getSys().getDoms().and(m.getEnv().getDoms());
    BDD domsIni = doms.exist(Env.globalPrimeVars());
    ctrl.initial().andWith(domsIni.id());
    ctrl.conjunctTrans(doms);

    // 1) check that all initial assignments to all unprimed variables minus 
    // the monitor's (aux) variable(s) have a corresponding initial state in the monitor's controller
    ModuleBDDField monVar = Env.getVar(monitorName);

    //VarSets of unprimed and primed past aux variables. These may exists if there
    //are past expressions in the monitor definition.
    BDDVarSet monAuxSet = Env.getEmptySet(), primeMonAuxSet = Env.getEmptySet();
    if (pastVarlist != null) {
      ModuleBDDField monAuxVar;
      for (VariableReference varRef : pastVarlist) {
        monAuxVar = Env.getVar(varRef.getReferenceName());
        monAuxSet.unionWith(monAuxVar.getDomain().set());
        primeMonAuxSet.unionWith(monAuxVar.getOtherDomain().set());
      }
    }
    BDDVarSet unprimedMonSet = monVar.getDomain().set().unionWith(monAuxSet);
    BDDVarSet primedMonSet = monVar.getOtherDomain().set().unionWith(primeMonAuxSet);
    BDDVarSet unprimedGloalMinusMonSet = Env.globalUnprimeVars().minus(unprimedMonSet);
    BDDVarSet primedGloalMinusMonSet = Env.globalPrimeVars().minus(primedMonSet);

    BDD ctrlIni = ctrl.initial().exist(unprimedMonSet);
    BDD result = domsIni.imp(ctrlIni).forAll(unprimedGloalMinusMonSet);

    if (!result.isOne()) {
      result.free();
      unprimedGloalMinusMonSet.free();
      primedGloalMinusMonSet.free();
      primedMonSet.free();
      unprimedMonSet.free();
      String[] errorMsg = new String[2];
      errorMsg[0] = monitorName;
      BDDVarSet nonAuxVars = Env.union(m.getSys().getNonAuxFields()).union(Env.union(m.getEnv().getNonAuxFields()));
      errorMsg[1] = CoreUtil.satOne(domsIni.and(ctrlIni.not()), nonAuxVars).toStringWithDomains(Env.stringer);
      ctrlIni.free();
      this.setMonitorCheckMessages(errorMsg);
      nonAuxVars.free();
      return getMonitorSpecList(monitorName, null, initialConstraints);
    }
    result.free();

    // 2) check that for all reachable states in the monitor controller it is enabled
    // for all next assignments to all to all primed variables minus 
    // the monitor's (aux) variable 
    BDD reachable = Env.allSucc(ctrl.initial().id(), ctrl.trans());

    BDD ctrlTrans = ctrl.trans().exist(primedMonSet);
    result = reachable.and(doms).imp(ctrlTrans).forAll(Env.globalUnprimeVars().union(Env.globalPrimeVars()));
    if (!result.isOne()) {
      String[] errorMsg = new String[2];
      BDDVarSet nonAuxVars = Env.union(m.getSys().getNonAuxFields()).union(Env.union(m.getEnv().getNonAuxFields()));
      errorMsg[0] = monitorName;
      errorMsg[1] = CoreUtil.satOne(reachable.and(doms).and(ctrlTrans.not()), nonAuxVars)
          .toStringWithDomains(Env.stringer);
      this.setMonitorCheckMessages(errorMsg);
      ctrlTrans.free();
      nonAuxVars.free();
    }

    Map<String, Set<BehaviorInfo>> safetiesToMark = (result.isOne() ? null : safetyConstraints);
    result.free();
    reachable.free();
    unprimedGloalMinusMonSet.free();
    primedGloalMinusMonSet.free();
    primedMonSet.free();
    unprimedMonSet.free();

    return getMonitorSpecList(monitorName, safetiesToMark, null);
  }

  public void setMonitorCheckMessages(String[] messages) {
    this.monitorCheckMessages = messages;
  }

  public String[] getMonitorCheckMessages() {
    return this.monitorCheckMessages;
  }

  //////////////////////////
  // --- Counters checks ---
  //////////////////////////

  public List<BehaviorInfo> checkCountersConsistency(GameModel gm, CounterTranslator counterTranslator) {
    Map<Integer, Set<BehaviorInfo>> traceIdtoBI = computeTraceIdtoBIMap(gm);

    for (String counterName : counterTranslator.getCountersNames()) {
      List<SpecTraceable> inconstentPredicates = getInconstentCounterPredicates(gm, counterName, counterTranslator, traceIdtoBI);
      if (inconstentPredicates.size() > 0) {
        List<BehaviorInfo> result = new ArrayList<BehaviorInfo>();
        for (SpecTraceable pred : inconstentPredicates) {
          Set<BehaviorInfo> behaviorInfos = traceIdtoBI.get(pred.getTraceId());
          result.addAll(behaviorInfos);
        }
        return result;
      }

    }

    return new ArrayList<BehaviorInfo>();
  }

  private List<SpecTraceable> getInconstentCounterPredicates(GameModel gm, String counterName,
      CounterTranslator counterTranslator, Map<Integer, Set<BehaviorInfo>> traceIdtoBI) {
    List<SpecTraceable> predicates = counterTranslator.getCounterPredicates(counterName);

    PlayerModule env = gm.getEnv();
    PlayerModule sys = gm.getSys();
    BDD reachableStates = Env.allSucc(env.initial().and(sys.initial()), env.trans().and(sys.trans()));

    List<BDD> predicatesBdds = new ArrayList<BDD>();
    for (SpecTraceable pred : predicates) {
    	for (BehaviorInfo bi : traceIdtoBI.get(pred.getTraceId())) {
    		predicatesBdds.add(bi.getBdd().id());
    	}
    }

    try {
      for (int i = 0; i < predicates.size(); i++) {
        for (int j = i + 1; j < predicates.size(); j++) {
          SpecTraceable p1 = predicates.get(i);
          SpecTraceable p2 = predicates.get(j);

          BDD p1ReachableStates = predicatesBdds.get(i);
          BDD p2ReachableStates = predicatesBdds.get(j);

          BDD reachableAndP1 = p1ReachableStates.and(reachableStates).exist(Env.globalPrimeVars());
          BDD reachableAndP2 = p2ReachableStates.and(reachableStates).exist(Env.globalPrimeVars());
          BDD intersection = reachableAndP1.and(reachableAndP2);
          reachableAndP1.free();
          reachableAndP2.free();

          if (!intersection.isZero()) {
            BDDVarSet nonAuxVars = Env.union(sys.getNonAuxFields()).union(Env.union(env.getNonAuxFields()));

            String[] errorMsg = new String[2];
            errorMsg[0] = counterName;
            errorMsg[1] = CoreUtil.satOne(intersection, nonAuxVars).toStringWithDomains(Env.stringer);
            this.setCounterCheckMessages(errorMsg);

            List<SpecTraceable> intersectingPredicates = new ArrayList<SpecTraceable>();
            intersectingPredicates.add(p1);
            intersectingPredicates.add(p2);
            return intersectingPredicates;
          }
          intersection.free();
        }
      }

      return new ArrayList<SpecTraceable>();
    } finally {
      for (BDD bdd : predicatesBdds) {
        bdd.free();
      }
      reachableStates.free();
    }
  }

  public void setCounterCheckMessages(String[] messages) {
    this.counterCheckMessages = messages;
  }

  public String[] getCounterCheckMessages() {
    return this.counterCheckMessages;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.symbolic;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

/**
 * characterization of a set of possible controllers
 * 
 * default: initial = FALSE and trans = FALSE
 * 
 * @author ringert
 * 
 */
public class SymbolicController {

	private BDD initial = Env.FALSE();
	private BDD trans = Env.FALSE();

	public SymbolicController() {
	}

	/**
	 * creates a new controller from given BDDs (consumed)
	 * 
	 * @param ini   (consumed)
	 * @param trans (consumed)
	 */
	public SymbolicController(BDD ini, BDD trans) {
		this.initial = ini;
		this.trans = trans;
	}

	/**
	 * 
	 * @return direct reference to BDD that describes inital states
	 */
	public BDD initial() {
		return initial;
	}

	/**
	 * sets the inital states
	 * 
	 * @param init is used (don't modify or free)
	 */
	public void setInit(BDD init) {
		this.initial = init;
	}

	/**
	 * 
	 * @return direct reference to BDD that describes transitions
	 */
	public BDD trans() {
		return trans;
	}

	/**
	 * sets the transitions
	 * 
	 * @param trans is used (don't modify or free)
	 */
	public void setTrans(BDD trans) {
		this.trans = trans;
	}

	/**
	 * adds moreTrans as a disjunction to current transitions
	 * 
	 * @param moreTrans (BDD not freed)
	 */
	public void disjunctTrans(BDD moreTrans) {
		trans.orWith(moreTrans.id());
	}

	public void disjunctTransWith(BDD moreTrans) {
		trans.orWith(moreTrans);
	}

	/**
	 * restricts trans of controller to trans2
	 * 
	 * @param moreTrans (BDD not freed)
	 */
	public void conjunctTrans(BDD trans2) {
		trans.andWith(trans2.id());
	}

	public void conjunctTransWith(BDD trans2) {
		trans.andWith(trans2);
	}

	/**
	 * <p>
	 * This procedure return all states which the controller can reach in a single
	 * step from given a set of state.
	 * </p>
	 * 
	 * @param from The set of state to start from.
	 * @return The set of states which the controller can reach in a single step
	 *         from the given states.
	 */
	public BDD succ(BDD from) {
		return Env.succ(from, trans);
	}
	
	public BDD pred(BDD to) {
		return Env.pred(trans, to);
	}

	@Override
	public String toString() {
		String ret = "Initial states:\n";
		ret += Env.toNiceString(initial);
		ret += "\n\nTransitions:\n";
		ret += Env.toNiceString(trans);
		return ret;
	}

	public void free() {
		initial.free();
		trans.free();
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.modelchecker;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;;

/**
 * An exception dedicated for counter examples.
 */
public class CounterExampleException extends ModelCheckException {
	private static final long serialVersionUID = 1L;
	private BDD[] path;

	public CounterExampleException(String desc, BDD[] path) {
		super(desc);
		this.path = path;
	}

	public BDD[] getPath() {
		return this.path;
	}

	public String toString() {
		String res = super.toString() + "\n";
		if ((path == null) || (path.length == 0))
			return res + "No Counter Example Exists.";
		res += " Counter Example\n";
		res += "=================\n";
		// the last is not printed. It is only to point to the cycle.
		BDD last = path[path.length - 1];
		int loop_index = -1;
		boolean loop_exists = false;
		for (int i = 0; i < path.length - 1; i++) {
			boolean loop_here = path[i].biimp(last).isOne();
			if ((loop_here) && (loop_index == -1)) {
				loop_index = i + 1;
				res += "[[" + (i + 1) + "]]";
				loop_exists = true;
			} else {
				res += "  " + (i + 1) + "  ";
			}
			res += " \t: " + Env.toNiceSignleLineString(path[i]) + "\n";
		}
		if (loop_exists)
			res += "Loop back to state " + loop_index;
		else
			res += "  " + path.length + "   \t: "
					+ Env.toNiceSignleLineString(path[path.length - 1]) + "\n";

		return res;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

// BDDBitVector.java, created Jul 14, 2003 9:50:57 PM by jwhaley
// Copyright (C) 2003 <NAME>
// Licensed under the terms of the GNU LGPL; see COPYING for details.
// Note: re-written to support vectors operations of different lengths and of a negative sign in Oct - Nov, 2016.
package net.sf.javabdd;
import java.math.BigInteger;

/**
 * <p>Bit vector implementation for BDDs.</p>
 * 
 * @author <NAME>
 * @version $Id: BDDBitVector.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
 */

public abstract class BDDBitVector {

	protected BDD[] bitvec;

	protected BDD sign;


	/**
	 * Creates a new BDDBitVector instance of the specified length. The new vector is not initialized. However, the sign BDD is 
	 * initialized to zero, i.e., a positive sign.
	 * @param bitnum the length (number of bits) of the new BDDBitVector.
	 */
	protected BDDBitVector(int bitnum) {
		bitvec = new BDD[bitnum];
		sign = this.getFactory().zero();
	}

	/**
	 * Creates a new BDDBitVector instance initialized with the specified value. 
	 * The vector's length is sufficient for the bit representation of the specified value
	 * and equals to {@code floor(log_2(val))+1}. If {@code val} holds a value out of the range of {@code long} type, the 
	 * new vector would have the value of 0. 
	 * 
	 * @param val the value which the new BDDBitVector holds.
	 */
	protected BDDBitVector(BigInteger val) {
		long lVal;
		int bitnum = 0;

		try {
			lVal = val.longValueExact();
		}
		catch (ArithmeticException ae) {
			lVal = 0;
		}
		long sVal = lVal;
		if(lVal < 0) {
			sVal = -lVal;
		}

		do {
			bitnum++;
			sVal >>= 1;
		}
		while(sVal != 0);

		bitvec = new BDD[bitnum];
		sign = this.getFactory().zero();

		initialize(lVal);
	}

	protected void initialize(boolean isTrue) {
		BDDFactory bdd = getFactory();
		for (int n = 0; n < bitvec.length; n++)
			if (isTrue)
				bitvec[n] = bdd.one();
			else
				bitvec[n] = bdd.zero();
	}

	protected void initialize(int val) {
		BDDFactory bdd = getFactory();
		if(val < 0) { 
			sign.free(); 
			sign = bdd.one();
		}
		for (int n = 0; n < bitvec.length; n++) {
			if ((val & 0x1) != 0)
				bitvec[n] = bdd.one();
			else
				bitvec[n] = bdd.zero();
			val >>= 1;
		}
	}

	protected void initialize(long val) {
		BDDFactory bdd = getFactory();
		if(val < 0) { 
			sign.free(); 
			sign = bdd.one();
		}
		for (int n = 0; n < bitvec.length; n++) {
			if ((val & 0x1) != 0)
				bitvec[n] = bdd.one();
			else
				bitvec[n] = bdd.zero();
			val >>= 1;
		}

	}

	protected void initialize(BigInteger val) {
		BDDFactory bdd = getFactory();
		if(val.intValue() < 0) { 
			sign.free(); 
			sign = bdd.one();
		}
		for (int n = 0; n < bitvec.length; n++) {
			if (val.testBit(0))
				bitvec[n] = bdd.one();
			else
				bitvec[n] = bdd.zero();
			val = val.shiftRight(1);
		}
	}

	protected void initialize(int offset, int step) {
		BDDFactory bdd = getFactory();
		for (int n = 0 ; n < bitvec.length ; n++)
			bitvec[n] = bdd.ithVar(offset+n*step);
	}

	protected void initialize(BDDDomain d) {
		initialize(d.vars());
	}

	protected void initialize(int[] var) {
		BDDFactory bdd = getFactory();
		for (int n=0 ; n < bitvec.length ; n++)
			bitvec[n] = bdd.ithVar(var[n]);
	}

	public abstract BDDFactory getFactory();
	/**
	 * Returns a copy of this BDDBitVector.
	 * @return copy of this BDDBitVector.
	 */
	public BDDBitVector copy() {
		BDDFactory bdd = getFactory();
		BDDBitVector dst = bdd.createBitVector(bitvec.length);
		dst.sign = sign.id();

		for (int n = 0; n < bitvec.length; n++)
			dst.bitvec[n] = bitvec[n].id();

		return dst;
	}

	public void replaceWith(BDDBitVector that) {
		//if (bitvec.length != that.bitvec.length)
		//	throw new BDDException();
		this.free();
		this.bitvec = that.bitvec;
		this.sign = that.sign;
		that.bitvec = null;
		that.sign = null;
	}

	/**
	 * Returns true if this BDDBitVector is a constant bit vector, i.e., every BDD bit is a constant boolean function (TRUE or FALSE BDD).
	 * @return true if this BDDBitVector is a constant bit vector.
	 */
	public boolean isConst() {
		for (int n = 0; n < bitvec.length; n++) {
			BDD b = bitvec[n];
			if (!b.isOne() && !b.isZero()) return false;
		}
		return true;
	}

	/**
	 * Returns the decimal value this BDDBitVector encodes if this BDDBitVector is a constant bit vector, and otherwise 0.
	 * @return The decimal value this BDDBitVector encodes.
	 */
	public long val() {
		int n;
		long val = 0L;
		if(this.sign.isOne()) { /*negative value*/
			val = -1L;
		}
		for (n = bitvec.length - 1; n >= 0; n--)
			if (bitvec[n].isOne())
				val = (val << 1) | 1L;
			else if (bitvec[n].isZero())
				val = val << 1;
			else /*non constant BDD Bit Vector*/
				return 0;

		return val;
	}

	/**
	 * Frees this BDDBitVector.
	 */
	public void free() {
		for (int n = 0; n < bitvec.length; n++) {
			bitvec[n].free();
		}
		bitvec = null;
		this.sign.free();
	}

	/**
	 * Returns true if this BDDBitVector encodes only negative values.
	 * @return true if this BDDBitVector encodes only negative values.
	 */
	public boolean isNegative() {
		return this.sign.isOne();
	}


	private static BDDBitVector removeTwosComplements(BDDBitVector vector) {

		BDDFactory bdd = vector.getFactory();

		BDDBitVector compVector = bdd.createBitVector(vector.size());

		/*first, create a two's complement representation of vector*/
		/*invert all bits*/
		for (int i = 0 ; i < vector.size() ; i++) {
			compVector.bitvec[i] = vector.bitvec[i].not();
		}

		compVector.sign = vector.sign.not();

		/*increment by one*/
		BDDBitVector oneVector = bdd.createBitVector(1);
		oneVector.initialize(1);
		BDDBitVector incCompVector = compVector.add(oneVector);

		oneVector.free();
		compVector.free();

		/*if the sign bit is 1 (negative) cancel two's complement form (i.e., use positive form); 
		 * else (sign bit is 0), use positive form as always.*/
		BDDBitVector iteCompVector = bdd.createBitVector(vector.size());

		/*make all representations in a positive form*/
		for (int i = 0 ; i < vector.size() ; i++) {
			iteCompVector.bitvec[i] = vector.sign.ite(incCompVector.bitvec[i], vector.bitvec[i]);
		}

		iteCompVector.sign = bdd.zero(); /*now all representations are positive*/

		incCompVector.free();

		return iteCompVector;
	}


	private static BDDBitVector restoreTwosComplements(BDD resSign, BDDBitVector posVector) {

		BDDFactory bdd = resSign.getFactory();

		BDDBitVector compVector = bdd.createBitVector(posVector.size());

		/*first, create a two's complement representation of posVector*/
		/*invert all bits*/
		for (int i = 0 ; i < posVector.size() ; i++) {
			compVector.bitvec[i] = posVector.bitvec[i].not();
		}

		compVector.sign = bdd.one();

		/*increment by one*/
		BDDBitVector oneVector = bdd.createBitVector(1);
		oneVector.initialize(1);
		BDDBitVector incCompVector = compVector.add(oneVector);

		oneVector.free();
		compVector.free();

		BDD notZeroRes = bdd.zero();

		for(int i = 0 ; i < posVector.size(); i++) {
			notZeroRes.orWith(posVector.bitvec[i].id());
		}

		BDD negAndNotZeroRes = resSign.and(notZeroRes); /*a boolean function that is true iff the number is negative and not zero (thus 
		surely negative : this fix was added to handle cases of a negative number multiplied by zero)*/

		/*if the sign bit is 1 (negative) add\restore two's complement form (i.e., use negative form); 
		 * else (sign bit is 0 -> positive or zero), use positive form as always.*/
		BDDBitVector iteCompVector = bdd.createBitVector(posVector.size());

		for (int i = 0 ; i < posVector.size() ; i++) {
			iteCompVector.bitvec[i] = negAndNotZeroRes.ite(incCompVector.bitvec[i], posVector.bitvec[i]);
		}

		iteCompVector.sign = negAndNotZeroRes; /*now all representations are positive*/

		incCompVector.free();

		return iteCompVector;
	}

	/**
	 * Performs bitwise multiplication of this and that BDDBitVectors. Both vectors can be of different lengths and of different signs (positive\negative). 
	 * @param that
	 * @return
	 */
	public BDDBitVector mult(BDDBitVector that) {

		BDDFactory bdd = this.getFactory();

		int longArgLen = java.lang.Math.max(this.size(), that.size());
		BDDBitVector shorterVector = (this.size() != longArgLen) ? this : that;
		BDDBitVector longerVector = (this.size() == longArgLen) ? this : that;

		BDDBitVector res = bdd.createBitVector(shorterVector.size() + longerVector.size());
		res.initialize(0);

		BDDBitVector posShorterVector = shorterVector;
		if(!shorterVector.sign.isZero()) {
			posShorterVector =  removeTwosComplements(shorterVector);
		}

		BDDBitVector posLongerVector;
		if(!longerVector.sign.isZero()) {
			posLongerVector =  removeTwosComplements(longerVector);
		}
		else {
			posLongerVector = longerVector.copy();

		}

		BDDBitVector resIfShorterIsOne;
		int n = 0;
		for (; n < posShorterVector.size() ; n++) {
			resIfShorterIsOne = res.add(posLongerVector);

			for(int i = 0 ; i < res.size() ; i++) {
				res.bitvec[i] = posShorterVector.bitvec[n].ite(resIfShorterIsOne.bitvec[i], res.bitvec[i]);
			}

			resIfShorterIsOne.free();

			BDDBitVector tmp1 = posLongerVector.shlWithExtraBits(1, bdd.zero()); 
			posLongerVector.free();
			posLongerVector = tmp1;
		}

		res.sign.free();
		res.sign = shorterVector.sign.xor(longerVector.sign);

		if(shorterVector.sign.isZero() && longerVector.sign.isZero()) {
			return res;
		}

		return restoreTwosComplements(res.sign, res);

	}


	/**
	 *  Performs bitwise addition of this and that BDDBitVectors. Both vectors can be of different lengths and of different signs (positive\negative). 
	 * @param that
	 * @return
	 */
	public BDDBitVector add(BDDBitVector that) {

		BDDFactory bdd = this.getFactory();

		int longArgLen = java.lang.Math.max(this.size(), that.size());
		BDDBitVector shorterVector = (this.size() != longArgLen) ? this : that;
		BDDBitVector longerVector = (this.size() == longArgLen) ? this : that;

		BDD c = bdd.zero(); /*set initial carry to zero*/
		BDDBitVector res = bdd.createBitVector(longArgLen+1);
		res.sign.free();

		int n = 0;
		for (; n < shorterVector.size(); n++) {


			/* bitvec[n] = l[n] ^ r[n] ^ c; */
			res.bitvec[n] = bitvec[n].xor(that.bitvec[n]);
			res.bitvec[n].xorWith(c.id());

			/* c = (l[n] & r[n]) | (c & (l[n] | r[n])); */
			BDD tmp1 = bitvec[n].or(that.bitvec[n]);
			tmp1.andWith(c);
			BDD tmp2 = bitvec[n].and(that.bitvec[n]);
			tmp2.orWith(tmp1);
			c = tmp2;
		}

		for (; n < longArgLen; n++) {
			/* bitvec[n] = longVector[n] ^ shortVectorSignExtension ^ c; */
			res.bitvec[n] = longerVector.bitvec[n].xor(shorterVector.sign);
			res.bitvec[n].xorWith(c.id());

			/* c = (longVector[n] & shortVectorSignExtension) | (c & (longVector[n] | shortVectorSignExtension)); */
			BDD tmp1 = longerVector.bitvec[n].or(shorterVector.sign);
			tmp1.andWith(c);
			BDD tmp2 = longerVector.bitvec[n].and(shorterVector.sign);
			tmp2.orWith(tmp1);
			c = tmp2;			
		}

		/*calculate the MSB*/
		res.bitvec[n] = longerVector.sign.xor(shorterVector.sign);
		res.bitvec[n].xorWith(c.id());

		/* c = (longerVector.sign & shorterVector.sign) | (c & (longerVector.sign | shorterVector.sign)); */
		BDD tmp1 = longerVector.sign.or(shorterVector.sign);
		tmp1.andWith(c);
		BDD tmp2 = longerVector.sign.and(shorterVector.sign);
		tmp2.orWith(tmp1);
		c = tmp2;

		/*calculate the sign extension*/
		res.sign =  longerVector.sign.xor(shorterVector.sign);
		res.sign.xorWith(c);

		return res;
	}

	/**
	 *  Performs bitwise subtraction of this and that BDDBitVectors. Both vectors can be of different lengths and of different signs (positive\negative). 
	 * @param that
	 * @return
	 */
	public BDDBitVector sub(BDDBitVector that) {

		BDDFactory bdd = getFactory();

		int longArgLen = java.lang.Math.max(this.size(), that.size());
		BDDBitVector shorterVector = (this.size() != longArgLen) ? this : that;
		BDDBitVector longerVector = (this.size() == longArgLen) ? this : that;

		BDD c = bdd.zero();
		BDDBitVector res = bdd.createBitVector(longerVector.size() + 1);
		res.sign.free();

		int n;
		BDD tmp1, tmp2;
		for (n = 0; n < shorterVector.size(); n++) {
			/* bitvec[n] = l[n] ^ r[n] ^ c; */
			res.bitvec[n] = bitvec[n].xor(that.bitvec[n]);
			res.bitvec[n].xorWith(c.id());

			/* c = (l[n] & r[n] & c) | (!l[n] & (r[n] | c)); */
			tmp1 = that.bitvec[n].or(c);
			tmp2 = this.bitvec[n].apply(tmp1, BDDFactory.less);
			tmp1.free();
			tmp1 = this.bitvec[n].and(that.bitvec[n]);
			tmp1.andWith(c);
			tmp1.orWith(tmp2);

			c = tmp1;
		}

		BDD l, r;
		for (; n < longerVector.size(); n++) {
			/* bitvec[n] = r.sign ^ l[n] ^ c; */
			res.bitvec[n] = longerVector.bitvec[n].xor(c);
			res.bitvec[n].xorWith(shorterVector.sign.id());

			if(longerVector == that) {
				l = this.sign;
				r = that.bitvec[n];
			}
			else {
				l = this.bitvec[n];
				r = that.sign;
			}
			tmp1 = r.or(c);
			tmp2 = l.apply(tmp1, BDDFactory.less);
			tmp1.free();
			tmp1 = l.and(r);
			tmp1.andWith(c);
			tmp1.orWith(tmp2);
			c = tmp1;
		}

		res.bitvec[n] = c.xor(this.sign);
		res.bitvec[n].xorWith(that.sign.id());

		/* c = (l.sign & r.sign & c) | (!l.sign & (r.sign | c)); */
		tmp1 = that.sign.or(c);
		tmp2 = this.sign.apply(tmp1, BDDFactory.less);
		tmp1.free();
		tmp1 = this.sign.and(that.sign);
		tmp1.andWith(c);
		tmp1.orWith(tmp2);
		c = tmp1;

		res.sign = c.xor(this.sign);
		res.sign.xorWith(that.sign.id());

		return res;
	}

	/**
	 * Returns a BDD that encodes less than equal (lte) boolean function of this BDDBitVector and the specified BDDBitVector, i.e, this <= r.
	 * @param r
	 * @return
	 */
	public BDD lte(BDDBitVector r)
	{
		BDDFactory bdd = getFactory();

		BDDBitVector cmpResTmp = this.sub(r);

		BDDBitVector oneVec = bdd.createBitVector(BigInteger.valueOf(1)); 
		BDDBitVector cmpRes = cmpResTmp.sub(oneVec);

		cmpResTmp.free();
		oneVec.free();

		BDD res = cmpRes.sign.id();
		cmpRes.free();
		return res;
	}

	/**
	 * Returns a BDD that encodes less than (lt) boolean function of this BDDBitVector and the specified BDDBitVector, i.e, this < r.
	 * @param r
	 * @return
	 */
	public BDD lt(BDDBitVector r)
	{

		BDDBitVector cmpRes = this.sub(r);

		BDD res = cmpRes.sign.id();
		cmpRes.free();
		return res;
	}

	/**
	 * Returns a BDD that encodes equals (eq) boolean function of this BDDBitVector and the specified BDDBitVector, i.e, this = r.
	 * @param r
	 * @return
	 */
	public BDD eq(BDDBitVector r)
	{

		BDDBitVector cmpRes = this.sub(r);

		BDD res = cmpRes.sign.id();

		for(int i = 0 ; i < cmpRes.size() ; i ++) {
			res.orWith(cmpRes.bitvec[i].id());
		}

		BDD resTmp = res.not();

		res.free();
		cmpRes.free();

		res = resTmp;

		return res;
	}

	/**
	 * Left shift. The vector's length grows.
	 * @param pos
	 * @param c
	 * @return
	 */
	public BDDBitVector shlWithExtraBits(int pos, BDD c) {

		if (pos < 0) {
			throw new BDDException();
		}

		BDDFactory bdd = getFactory();
		BDDBitVector res = bdd.createBitVector(bitvec.length + pos);

		int n;
		for (n = 0; n < pos; n++) {
			res.bitvec[n] = c.id();
		}

		for (n = pos; n < bitvec.length + pos; n++) {
			res.bitvec[n] = bitvec[n - pos].id();
		}

		res.sign = this.sign.id();

		return res;
	}

	/**
	 * Conditional shift left. If the condition if true, then the value will be the left shifted, and otherwise
	 * the same value as no left shift has been performed. The vector's length grows.
	 * @param pos
	 * @param c
	 * @param cond
	 * @return
	 */
	public BDDBitVector condShlWithExtraBits(int pos, BDD c, BDD cond) {

		if (pos < 0) {
			throw new BDDException();
		}

		BDDFactory bdd = getFactory();
		BDDBitVector res = bdd.createBitVector(bitvec.length + pos);

		int n;
		for (n = 0; n < pos; n++) {
			res.bitvec[n] = cond.ite(c, this.bitvec[n]);
		}

		for (n = pos; n < bitvec.length + pos; n++) {
			if(n < bitvec.length) {
				res.bitvec[n] = cond.ite(bitvec[n - pos], this.bitvec[n]);
			}
			else {
				res.bitvec[n] = cond.ite(bitvec[n - pos], this.sign);
			}
		}

		res.sign = this.sign.id();

		return res;
	}

	/**
	 * Right shift. The vector's length becomes shorter.
	 * @param pos
	 * @return
	 */
	public BDDBitVector shrWithLessBits(int pos) {
		if (pos < 0) {
			throw new BDDException();
		}

		int maxnum = Math.max(0, bitvec.length - pos);

		BDDFactory bdd = getFactory();
		BDDBitVector res = bdd.createBitVector(maxnum);

		for (int n = 0 ; n < maxnum ; n++) {
			res.bitvec[n] = bitvec[n + pos].id();
		}

		res.sign = this.sign.id();

		return res;
	}

	public int size() {
		return bitvec.length;
	}

	public BDD getBit(int n) {
		return bitvec[n];
	}

	/**
	 * Left shift. The vector's length remains the same.
	 * @param pos
	 * @param c
	 * @return
	 */
	public BDDBitVector shl(int pos, BDD c) {
		if (pos < 0)
			throw new BDDException();

		int minnum = Math.min(bitvec.length, pos);

		BDDFactory bdd = getFactory();
		BDDBitVector res = bdd.createBitVector(bitvec.length);

		int n;
		for (n = 0; n < minnum; n++)
			res.bitvec[n] = c.id();

		for (n = minnum; n < bitvec.length; n++)
			res.bitvec[n] = bitvec[n - pos].id();

		res.sign = this.sign.id();

		return res;
	}
	/**
	 * Right shift. The vector's length remains the same.
	 * @param pos
	 * @param c
	 * @return
	 */
	public BDDBitVector shr(int pos, BDD c) {	
		if (pos < 0)
			throw new BDDException();

		int maxnum = Math.max(0, bitvec.length - pos);

		BDDFactory bdd = getFactory();
		BDDBitVector res = bdd.createBitVector(bitvec.length);

		int n;
		for (n = maxnum ; n < bitvec.length ; n++)
			res.bitvec[n] = c.id();

		for (n = 0 ; n < maxnum ; n++)
			res.bitvec[n] = bitvec[n+pos].id();

		res.sign = this.sign.id();

		return res;
	}


	private static boolean powerOfTwo(long c) {
		boolean haveSeenOne = false;
		while(c != 0) {
			if((c & 1L) != 0) {
				if(haveSeenOne) {
					return false;
				}
				haveSeenOne = true;
			}
			c >>= 1;
		}
		return haveSeenOne;
	}
	/**
	 * Computes {@code this modulo c}
	 * @param c the modulo value
	 * @return
	 */
	public BDDBitVector mod (long c) {
		if(c <= 0L) {
			throw new BDDException("modulo divisor must be positive");
		}
		BDDFactory bdd = this.getFactory();
		BDDBitVector cBitVec = bdd.createBitVector(BigInteger.valueOf(c));
		BDDBitVector result =  mod(cBitVec, false, true);
		cBitVec.free();
		return result;
	}
	
	public BDDBitVector mod (BDDBitVector divisor) {
		return mod (divisor, true, false);
	}
	
	/**
	 * Computes {@code this modulo divisor}. The divisor must have positive values only. If non positive value 
	 * is found a {@link#BDDException} is thrown. However, {@code this} can be of any integer value.
	 * @param divisor
	 * @param checkZeroDivisor Whether to check if the divisor can get the value of zero.
	 * @param constDivisor Whether the divisor is a constant.
	 * @return The modulo result.
	 */
	public BDDBitVector mod (BDDBitVector divisor, boolean checkZeroDivisor, boolean constDivisor) {
		if(!divisor.sign.isZero()) { /*check if the divisor can get negative values*/
			throw new BDDException("modulo divisor must be positive");
		}
		BDDFactory bdd = getFactory();

		BDDBitVector result;
		if(this.sign.isZero()) { /*the dividend only has non-negative values*/
			if(constDivisor && powerOfTwo(divisor.val())) { 
				/*check if the divisor is a constant of a power of 2. 
				If so, optimize the computation*/

				int bitnum = 0;
				long tmpC = divisor.val()-1;
				
				while(tmpC != 0 && bitnum < this.bitvec.length) {
					bitnum++;
					tmpC >>= 1;	
				}
				
				result = bdd.createBitVector(bitnum);

				for(int i = 0; i < result.bitvec.length; i++) {
					result.bitvec[i] = this.bitvec[i].id();
				}
			}
			else {
				/*perform modulo division, and return the remainder which is also the modulo*/
				result = this.divmod(divisor, checkZeroDivisor, false, constDivisor);
			}
		}
		else { /*the dividend has negative value(s)*/

			/*Compute the remainder (this is the modulo only if this >= 0): 
			 * this % c = this - (this / c) * c;
			 * 
			 * */

			BDDBitVector posThis = removeTwosComplements(this); 			

			BDDBitVector posDivRes = posThis.divmod(divisor, checkZeroDivisor, true, constDivisor);

			BDDBitVector divRes = restoreTwosComplements(this.sign, posDivRes);

			posDivRes.free();
			posThis.free();

			BDDBitVector resTmp1 = divRes.mult(divisor);
			BDDBitVector remainder = this.sub(resTmp1);

			resTmp1.free();
			divRes.free();

			if(!remainder.sign.isZero()) { /*We have negative remainder(s)*/

				/*Compute modulo in case of a negative remainder (possible only if this < 0): remainder + c */

				BDDBitVector resIfRNeg = remainder.add(divisor); 

				result = bdd.createBitVector(remainder.bitvec.length);

				for(int i = 0 ; i < result.bitvec.length ; i ++) {
					result.bitvec[i] = remainder.sign.ite(resIfRNeg.bitvec[i], remainder.bitvec[i]);
				}
				remainder.free();
				resIfRNeg.free();

			}
			else {
				result = remainder;
			}
		}

		return result;
	}
	
	private BDD isNonZeroBdd(BDDBitVector vector) {
		BDDFactory bdd = getFactory();
		BDD res = bdd.zero();
		for(int i = 0 ; i < vector.bitvec.length ; i ++) {
			res.orWith(vector.bitvec[i].id());
		}
		return res;
	}
	
	/**
	 *  Performs bitwise (modulo 2) long division of this BDDBitVector (the dividend) and divisor (the divisor). 
	 *  Both vectors can be different lengths. However, both vectors must encode <i>positive</i> numbers only.
	 * 
	 * @param divisor The divisor.
	 * @param retRes If true, returns the quotient; otherwise, returns the remainder.
	 * @param checkZeroDivisor Whether to check if the divisor can have a value of 0.
	 * @param constDivisor Whether the divisor is a constant.
	 * @return The result or the remainder of the division, depending on the value of {@code retRes}.
	 */
	public BDDBitVector divmod(BDDBitVector divisor, boolean checkZeroDivisor, boolean retRes, boolean constDivisor) {
		if (!divisor.sign.isZero()) { /*check if the divisor can get negative values*/
			throw new BDDException("divisor must be positive");
		}

		BDDFactory bdd = getFactory();

		if(checkZeroDivisor) { 	/*check the divisor cannot have a value of 0 */
			
			BDD zeroCheck = isNonZeroBdd(divisor);
			
			if(!zeroCheck.isOne()) {
				throw new BDDException("Divisor cannot have a value of 0");
			}
			zeroCheck.free();

		}

		/*set the result (quotient) to be 0 in the same length (number of bits) of the dividend*/
		BDDBitVector quotient = bdd.buildVector(bitvec.length, false);

		/*set the initial remainder to be the dividend*/
		BDDBitVector remainder = this.copy();

		BDDBitVector product = divisor.copy(), productTmp, termTmp;
		BDD prodLteDiv = product.lt(this);//product.lte(this);

		BDDBitVector oneConstVector = bdd.constantVector(BigInteger.valueOf(1L));
		BDDBitVector term = oneConstVector;

		/* the divisor multiplied by 2, resulting in product = divisor * 2^i, such that product * 2 > dividend
		 * 
		 * */

		/* term = 2^i, such that divisor * 2^(i+1) > divided
		 * 
		 * */

		while(!prodLteDiv.isZero()) {
			/*shift left only products such that product < dividend*/
			if(constDivisor) {
				productTmp = product.shlWithExtraBits(1, bdd.zero());
			}
			else {
				productTmp = product.condShlWithExtraBits(1, bdd.zero(), prodLteDiv);
			}

			product.free();
			product = productTmp;

			/*shift left only terms such that term < dividend*/
			if(constDivisor) {
				termTmp = term.shlWithExtraBits(1, bdd.zero());
			}
			else {
				termTmp = term.condShlWithExtraBits(1, bdd.zero(), prodLteDiv);				
			}

			term.free();
			term = termTmp;

			prodLteDiv.free();
			prodLteDiv = product.lt(this);
		}


		BDD prodLteRemainder = product.lte(remainder);
		BDD termIsNonZero = isNonZeroBdd(term); /*get the bdd that evaluates to true when the term vector
		gets a non zero value*/
		
		prodLteRemainder.andWith(termIsNonZero.id());
		
		BDDBitVector quotientIfPLteR, remainderIfPLteR, quotientTmp, remainderTmp;//,productTmp, termTmp;
		
		
		
		while(!termIsNonZero.isZero()) { /*term >= 1*/

			if(!prodLteRemainder.isZero()) { /*product <= remainder*/

				quotientIfPLteR = quotient.add(term);
				quotientTmp = bdd.createBitVector(quotientIfPLteR.bitvec.length);

				/*quotientIfPLteR.bitvec.length > quotient.bitvec.length*/

				for(int i = 0 ; i < quotientTmp.bitvec.length ; i++) {
					if(i < quotient.bitvec.length) {
						quotientTmp.bitvec[i] = prodLteRemainder.ite(quotientIfPLteR.bitvec[i], quotient.bitvec[i]);
					} 
					else {
						quotientTmp.bitvec[i] = prodLteRemainder.ite(quotientIfPLteR.bitvec[i], quotient.sign);
					}
				}


				remainderIfPLteR = remainder.sub(product);
				remainderTmp = bdd.createBitVector(remainderIfPLteR.bitvec.length);

				/*remainderIfPLteR.bitvec.length > remainder.bitvec.length*/
				for(int i = 0 ; i < remainderTmp.bitvec.length ; i++) {
					if(i < remainder.bitvec.length) {
						remainderTmp.bitvec[i] = prodLteRemainder.ite(remainderIfPLteR.bitvec[i], remainder.bitvec[i]);
					} 
					else {
						remainderTmp.bitvec[i] = prodLteRemainder.ite(remainderIfPLteR.bitvec[i], remainder.sign);
					}
				}

				quotientIfPLteR.free();
				quotient.free();
				remainderIfPLteR.free();
				remainder.free();

				quotient = quotientTmp;
				remainder = remainderTmp;

			}

			/*divide (right shift) product and term by 2*/
			productTmp = product.shrWithLessBits(1);
			product.free();
			product = productTmp;

			termTmp = term.shrWithLessBits(1);
			term.free();
			term = termTmp;

			prodLteRemainder.free();
			prodLteRemainder = product.lte(remainder);
			termIsNonZero.free();
			termIsNonZero = isNonZeroBdd(term);
			prodLteRemainder.andWith(termIsNonZero.id());
		}

		return (retRes ? quotient : remainder);
	}

	///////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////// commented out methods of the original implementation /////////
	///////////////////////////////////////////////////////////////////////////////////////////

	/*BDD lte(BDDBitVector r) // less than equal 
	{
		if (this.bitvec.length != r.bitvec.length)
			throw new BDDException();

		BDDFactory bdd = getFactory();
		BDD p = bdd.one();
		for (int n = 0 ; n < bitvec.length ; n++) {
			 p = (!l[n] & r[n]) |
	 *     bdd_apply(l[n], r[n], bddop_biimp) & p; 

			BDD tmp1 = bitvec[n].apply(r.bitvec[n], BDDFactory.less);
			BDD tmp2 = bitvec[n].apply(r.bitvec[n], BDDFactory.biimp);
			tmp2.andWith(p);
			tmp1.orWith(tmp2);
			p = tmp1;
		}
		return p;
	}*/

	/*	public BDDBitVector map2(BDDBitVector that, BDDFactory.BDDOp op) {
	if (bitvec.length != that.bitvec.length)
		throw new BDDException();

	BDDFactory bdd = getFactory();
	BDDBitVector res = bdd.createBitVector(bitvec.length);
	for (int n=0 ; n < bitvec.length ; n++)
		res.bitvec[n] = bitvec[n].apply(that.bitvec[n], op);

	return res;
	}
	 */



	/*	public BDDBitVector add(BDDBitVector that) {

	if (bitvec.length != that.bitvec.length)
		throw new BDDException();

	BDDFactory bdd = getFactory();

	BDD c = bdd.zero();
	BDDBitVector res = bdd.createBitVector(bitvec.length);

	for (int n = 0; n < res.bitvec.length; n++) {
		 bitvec[n] = l[n] ^ r[n] ^ c; 
		res.bitvec[n] = bitvec[n].xor(that.bitvec[n]);
		res.bitvec[n].xorWith(c.id());

		 c = (l[n] & r[n]) | (c & (l[n] | r[n])); 
		BDD tmp1 = bitvec[n].or(that.bitvec[n]);
		tmp1.andWith(c);
		BDD tmp2 = bitvec[n].and(that.bitvec[n]);
		tmp2.orWith(tmp1);
		c = tmp2;
	}
	c.free();

	return res;
}
	 */


	/*	public BDDBitVector sub(BDDBitVector that) {

	if (bitvec.length != that.bitvec.length)
		throw new BDDException();

	BDDFactory bdd = getFactory();

	BDD c = bdd.zero();
	BDDBitVector res = bdd.createBitVector(bitvec.length);

	for (int n = 0; n < res.bitvec.length; n++) {
		 bitvec[n] = l[n] ^ r[n] ^ c; 
		res.bitvec[n] = bitvec[n].xor(that.bitvec[n]);
		res.bitvec[n].xorWith(c.id());

		 c = (l[n] & r[n] & c) | (!l[n] & (r[n] | c)); 
		BDD tmp1 = that.bitvec[n].or(c);
		BDD tmp2 = this.bitvec[n].apply(tmp1, BDDFactory.less);
		tmp1.free();
		tmp1 = this.bitvec[n].and(that.bitvec[n]);
		tmp1.andWith(c);
		tmp1.orWith(tmp2);

		c = tmp1;
	}
	c.free();

	return res;
}
	 */


	/*	public BDDBitVector coerce(int bitnum) {
	BDDFactory bdd = getFactory();
	BDDBitVector dst = bdd.createBitVector(bitnum);
	int minnum = Math.min(bitnum, bitvec.length);
	int n;
	for (n = 0; n < minnum; n++)
		dst.bitvec[n] = bitvec[n].id();
	for (; n < minnum; n++)
		dst.bitvec[n] = bdd.zero();
	return dst;
}
	 */

	/*
		static void div_rec(BDDBitVector divisor,
		BDDBitVector remainder,
		BDDBitVector result,
		int step) {
	BDD isSmaller = divisor.lte(remainder);
	BDDBitVector newResult = result.shl(1, isSmaller);
	BDDFactory bdd = divisor.getFactory();
	BDDBitVector zero = bdd.buildVector(divisor.bitvec.length, false);
	BDDBitVector sub = bdd.buildVector(divisor.bitvec.length, false);

	for (int n = 0; n < divisor.bitvec.length; n++)
		sub.bitvec[n] = isSmaller.ite(divisor.bitvec[n], zero.bitvec[n]);

	BDDBitVector tmp = remainder.sub(sub);
	BDDBitVector newRemainder =
			tmp.shl(1, result.bitvec[divisor.bitvec.length - 1]);

	if (step > 1)
		div_rec(divisor, newRemainder, newResult, step - 1);

	tmp.free();
	sub.free();
	zero.free();
	isSmaller.free();

	result.replaceWith(newResult);
	remainder.replaceWith(newRemainder);
	}

	 */

	/*
	public void replaceWith(BDDBitVector that) {
	if (bitvec.length != that.bitvec.length)
		throw new BDDException();
	free();
	this.bitvec = that.bitvec;
	that.bitvec = null;
	}
	 */

	/*		public BDDBitVector divmod(long c, boolean which) {
			if (c <= 0L)
				throw new BDDException();
			BDDFactory bdd = getFactory();
			BDDBitVector divisor = bdd.constantVector(bitvec.length, c);
			BDDBitVector tmp = bdd.buildVector(bitvec.length, false);
			BDDBitVector tmpremainder = tmp.shl(1, bitvec[bitvec.length-1]);
			BDDBitVector result = this.shl(1, bdd.zero());

			BDDBitVector remainder;

			div_rec(divisor, tmpremainder, result, divisor.bitvec.length);
			remainder = tmpremainder.shr(1, bdd.zero());

			tmp.free();
			tmpremainder.free();
			divisor.free();

			if (which) {
				remainder.free();
				return result;
			} else {
				result.free();
				return remainder;
			}
		}*/
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.jobs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDFactory;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.bddgenerator.BDDGenerator;
import tau.smlab.syntech.bddgenerator.BDDGenerator.TraceInfo;
import tau.smlab.syntech.bddgenerator.BDDTranslationException;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinputtrans.translator.Translator;
import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.PlayerModule.TransFuncType;
import tau.smlab.syntech.jtlv.BDDPackage;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.env.module.ModuleBDDField;
import tau.smlab.syntech.spectragameinput.translator.Tracer;
import tau.smlab.syntech.ui.logger.SpectraLogger;
import tau.smlab.syntech.ui.preferences.PreferencePage;

public abstract class SyntechJob extends Job {

	protected IFile specFile;
	protected MessageConsole console;
	protected GameModel model;
	protected GameInput gi;
	protected TraceInfo trace = TraceInfo.NONE;
	protected static IFile previousFileWithMarkers;
	protected String consoleOutput = "";
	protected long computationTime;
	protected long bddTranslationTime;
	protected boolean isUserCancelledJob = false;
	protected boolean isRealizable;
	protected boolean isWellSeparated;
	protected int coreSize;
	protected String issuesKind;
	protected int numIssues;
	protected List<Translator> translators;
	private static List<Integer> traceIDListInCore = new ArrayList<Integer>();

	/**
	 * set info what elements of spec to trace (creates relevant BehaviorInfo).<br>
	 * Note: the more you trace the longer everything takes due to BDD creation.
	 * 
	 * @param trace
	 */
	public void setTrace(TraceInfo trace) {
		this.trace = trace;
	}

	public SyntechJob() {
		super("SYNTECH");
	}

	/**
	 * Implementation of default run method to start a thread that actually will do
	 * the work.
	 */
	@SuppressWarnings("deprecation")
	@Override
	protected IStatus run(IProgressMonitor monitor) {

		long jobTime = System.currentTimeMillis();

		BDDPackage.setCurrPackage(PreferencePage.getBDDPackageSelection(), PreferencePage.getBDDPackageVersionSelection());
		if (PreferencePage.isReorderEnabled()) {
			Env.enableReorder();
			Env.TRUE().getFactory().autoReorder(BDDFactory.REORDER_SIFT);
		} else {
			Env.disableReorder();
		}
		
		Thread t = new Thread(() -> translateAnddoWork());
		t.start();
		while (t.isAlive()) {
			if (monitor.isCanceled()) {
				t.stop();
				printToConsole("User cancelled job.");
				Env.resetEnv();
				isUserCancelledJob = true;
				return Status.CANCEL_STATUS;
			}
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		computationTime = System.currentTimeMillis() - jobTime;
		printToConsole("Computation time: " + computationTime + "ms");
		SpectraLogger.logOperationDone(specFile, this.getName(), computationTime, isRealizable);

		return Status.OK_STATUS;
	}
	
	/**
	 * determinize b
	 * 
	 * @param b
	 * @param vars
	 * @return
	 */
	protected BDD det(BDD b, BDDVarSet vars) {
		// set new varorder where vars are at the end
		Env.disableReorder();
		int[] oldOrder = b.getFactory().getVarOrder();
		List<Integer> newOrder = Arrays.stream(oldOrder).boxed().collect(Collectors.toList());
		List<Integer> varsL = Arrays.stream(vars.toArray()).boxed().collect(Collectors.toList());
		newOrder.removeAll(varsL);
		newOrder.addAll(varsL);
		b.getFactory().setVarOrder(newOrder.stream().mapToInt(i->i).toArray());

		BDD det = b.id();
		for (int var : vars.toArray()) {
			BDD tmp = det;
			det = det(tmp, var);
			tmp.free();
		}
		//b.getFactory().setVarOrder(oldOrder);
		return det;
	}
	
	/**
	 * determinizes b to a fresh BDD
	 * @param b
	 * @param var
	 * @return
	 */
	private BDD det(BDD b, int var) {

		if (b.isZero()) {
			return b.id();
		}

		if (b.isOne()) {
			return b.getFactory().nithVar(var).id();
		}

		// var appears so make decision one option
		// this can only work because of varorder
		if (b.var() == var) {
			BDD blow = b.low();
			if (!blow.isZero()) {
				// take low branch regardless of high branch        
				BDD res = b.getFactory().ithVar(var);
				res = res.ite(Env.FALSE(), blow);
				blow.free();
				return res;
			} else {
				// there is only one choice for b so it is fine
				return b.id();
			}
		}


		// var did not appear
		if (passedVar(b, var)) {
			BDD res = b.getFactory().ithVar(var);
			res = res.ite(Env.FALSE(), b);
			return res;
		} else {
			// determinize children
			BDD res = b.getFactory().ithVar(b.var());
			BDD bhi = b.high();
			BDD high = det(bhi, var);
			bhi.free();
			BDD blo = b.low();
			BDD low = det(blo, var);
			blo.free();
			res = res.ite(high, low);
			high.free();
			low.free();
			return res;
		}
	}
	
	/**
	 * did var only appear above b?
	 * 
	 * @param b
	 * @param var
	 * @return
	 */
	private boolean passedVar(BDD b, int var) {
		int lvlB = b.getFactory().var2Level(b.var());
		int lvlVar = b.getFactory().var2Level(var);
		return lvlB > lvlVar;
	}
	

	/**
	 * first translate GameInput into GameModel (this can already be expensive due
	 * to BDD creation)
	 */
	private void translateAnddoWork() {
		long start = System.currentTimeMillis();
		try {
			this.model = BDDGenerator.generateGameModel(gi, trace, PreferencePage.isGroupVarSelection(),
					PreferencePage.getTransFuncSelection(false));
			bddTranslationTime = System.currentTimeMillis() - start;
			printToConsole("BDD translation: " + bddTranslationTime + "ms (" + Env.getBDDPackageInfo() + ")");
			int sysNonAux = getVarNum(model.getSys().getNonAuxFields());
			int sysAux = getVarNum(model.getSys().getAuxFields());
			printToConsole("Statespace env: " + getVarNum(model.getEnv().getAllFields()) + ", sys: " + sysNonAux
					+ ", aux: " + sysAux);
			doWork();
		} catch (BDDTranslationException e) {
			if (e.getTraceId() >= 0) {
				createMarker(e.getTraceId(), e.getMessage(), MarkerKind.CUSTOM_TEXT_ERROR);
			}
			printToConsole(e.getMessage());
		} catch (Exception e) {
			printToConsole(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * compute number of variables of player
	 * 
	 * @param p
	 * @return
	 */
	private int getVarNum(List<ModuleBDDField> fs) {
		int varNum = 0;
		for (ModuleBDDField f : fs) {
			varNum += f.support().size();
		}
		return varNum;
	}

	/**
	 * do the actual work specific to the Job
	 */
	protected abstract void doWork();

	public void setSpecFile(IFile f) {
		specFile = f;
	}

	public void setConsole(MessageConsole console) {
		this.console = console;
	}

	/**
	 * print a string to the console of the plug-in
	 * 
	 * @param s
	 */
	public void printToConsole(String s) {
		consoleOutput += s + System.lineSeparator();
		MessageConsoleStream mcs = console.newMessageStream();
		mcs.println(s);
		try {
			mcs.flush();
			mcs.close();
		} catch (IOException e) {
		}
	}

	public void setGameInput(GameInput i) {
		this.gi = i;
	}

	/**
	 * deletes all markers of all SYNTECH MarkerKind(s)
	 */
	public void clearMarkers(IFile specIfile) {
		traceIDListInCore.clear();

		for (MarkerKind k : MarkerKind.values()) {
			try {
				specIfile.deleteMarkers(k.getMarkerID(), true, IResource.DEPTH_ZERO);
			} catch (CoreException e) {
			}
		}
	}

	public void clearMarkers() {
		clearMarkers(specFile);
	}

	/**
	 * creates markers in the current file for a list of BehaviorInfos
	 * 
	 * @param infos
	 * @param kind
	 */
	public void createMarker(List<BehaviorInfo> infos, MarkerKind kind) {
		if (infos != null && infos.size() > 0) {
			if (previousFileWithMarkers != null) {
				clearMarkers(previousFileWithMarkers);

			}
			previousFileWithMarkers = specFile;
		}
		for (BehaviorInfo info : infos) {
			createMarker(info.traceId, kind.getMessage(), kind);
		}
	}

	/**
	 * create a marker for an element with the given traceId
	 * 
	 * @param traceId
	 * @param message
	 * @param kind
	 */
	public void createMarker(int traceId, String message, MarkerKind kind) {
		EObject o = Tracer.getTarget(traceId);
		traceIDListInCore.add(traceId);
		if (o != null) {
			INode node = NodeModelUtils.getNode(o);
			try {
				IMarker marker = specFile.createMarker(kind.getMarkerID());
				marker.setAttribute(IMarker.MESSAGE, message);
				marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
				marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
				marker.setAttribute(IMarker.LOCATION, node.getStartLine());
				marker.setAttribute(IMarker.CHAR_START, node.getOffset());
				marker.setAttribute(IMarker.CHAR_END, node.getEndOffset());
			} catch (CoreException e) {
			}
		}
	}

	public String getConsoleOutput() {
		return this.consoleOutput;
	}

	public long getComputationTime() {
		return this.computationTime;
	}

	public long getBddTranslationTime() {
		return this.bddTranslationTime;
	}

	public boolean isUserCancelledJob() {
		return this.isUserCancelledJob;
	}

	public boolean isRealizable() {
		return this.isRealizable;
	}

	public boolean isWellSeparated() {
		return this.isWellSeparated;
	}

	public int getCoreSize() {
		return this.coreSize;
	}

	public String getIssuesKind() {
		return issuesKind;
	}

	public int getNumIssues() {
		return numIssues;
	}

	public static List<Integer> getTraceIDListInCore() {
		// find active ifile
		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
		IEditorPart activeEditor = page.getActiveEditor();
		IFile ifile;
		if (activeEditor != null) {
			IEditorInput input = activeEditor.getEditorInput();
			if (input != null && input instanceof FileEditorInput) {
				ifile = ((FileEditorInput) input).getFile();

				if (ifile == null || !("spectra".equals(ifile.getFileExtension()))
						|| (ifile != previousFileWithMarkers)) {
					// return empty list. (We don't want to clear traceIDListInCore in case the user
					// will open the previousFileWithMarkers again).
					return new ArrayList<Integer>();
				}
			}
		}

		return traceIDListInCore;
	}

	public void setTranslators(List<Translator> transList) {
		this.translators = transList;
	}

	@SuppressWarnings("unchecked")
	public <T extends Translator> T getTranslator(Class<T> translatorClass) {
		for (Translator t : translators) {
			if (t.getClass().equals(translatorClass)) {
				return (T) t;
			}
		}
		return null;
	}

	public boolean needsBound() {
		return false;
	}

	/**
	 * If decomposed transitions are used, frees and resets to TRUE (restricted by
	 * variable domain constraint) the single transition relations of both players
	 */
	public void resetSingleTrans() {
		TransFuncType transFuncType = PreferencePage.getTransFuncSelection(false);
		if (transFuncType != TransFuncType.SINGLE_FUNC) {
			this.model.resetSingleTransFunc();
		}
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel;

import java.util.List;

import net.sf.javabdd.BDD;

public class BehaviorInfo {

	public BehaviorInfo() {
	}

	public BehaviorInfo(BDD initial, BDD safety, BDD justice, List<BDD> existentialFAssrts, SFAModuleConstraint existentialRegExp, int traceId, boolean aux) {
		this.initial = initial;
		this.safety = safety;
		this.justice = justice;
		this.existentialFAssrts = existentialFAssrts;
		this.existentialRegExp = existentialRegExp;
		this.traceId = traceId;
		this.aux = aux;
	}
	
	
	public SFAModuleConstraint existentialRegExp;
	public BDD initial;
	public BDD safety;
	public BDD justice;
	public List<BDD> existentialFAssrts;
	public int traceId;
	public boolean aux;
	
	public int getTraceId() {
		return traceId;
	}

	public boolean isJustice() {
		return justice != null;
	}

	public boolean isExistential() {
		return this.existentialFAssrts != null || this.existentialRegExp != null;
	}

	public boolean isSafety() {
		return safety != null;
	}

	public boolean isInitial() {
		return initial != null;
	}

	@Override
	public String toString() {
		String s = isInitial() ? "ini" : "err";
		s = isJustice() ? "justice" : s;
		s = isSafety() ? "safety" : s;
		s = isExistential() ? "existential" : s;
		return "TraceId (" + s + ") = " + traceId;
	}

	public void free() {
		if (isInitial()) {
			initial.free();
		}
		if (isSafety()) {
			safety.free();
		}
		if (isJustice()) {
			justice.free();
		}
		if(isExistential()) {
			if(this.existentialFAssrts != null) {
				for(BDD exBdd : this.existentialFAssrts) {
					if(!exBdd.isFree()) {
						exBdd.free();
					}
				}
			}
			else { //this.existentialRegExp != null
				this.existentialRegExp.free();
			}
		}
	}

	public BDD getBdd() {
		if (isInitial()) {
			return initial;
		}
		if (isSafety()) {
			return safety;
		}
		if (isJustice()) {
			return justice;
		}
		return null;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.jits;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

public class ExistentialJitController extends AbstractJitController {
	
	@Override
	public void free() {
		jitController.free();
		Env.free(fulfill);
		Env.free(towards);
		safeZone.free();
	}

	private BDD[][] fulfill;
	private BDD[][] towards;
	private BDD safeZone;
	
	private BDD[][] envViolationX;
	private BDD[] envViolationY;
	private int envViolationRank;
	
	private boolean envViolationPhase = false;
	private boolean exphase = false;
	
	private int exn;
	private int exjx = 0;
	private int towardsRank;
	private int fulfillRank;

	public ExistentialJitController(JitController jitController) {
		super(jitController);
	}
	
	private void loadFulfill(BDD fulfill, int[] fulfill_ranks, int exn) {

		BDD[][] F = new BDD[exn][];
		
		for (int exj = 0; exj < exn; exj++) {
			F[exj] = new BDD[fulfill_ranks[exj]];
			for (int r = 0; r < fulfill_ranks[exj]; r++) {
				
				BDD temp = Env.getVar("util_exJn").getDomain().ithVar(exj);
				temp.andWith(Env.getVar("util_Fn").getDomain().ithVar(r));
				
				BDD fulfillBDD = fulfill.restrict(temp);
				F[exj][r] = Env.prime(fulfillBDD);
				fulfillBDD.free();
				temp.free();
			}
		}
		
		this.fulfill = F;
	}
	
	private void loadTowards(BDD towards, int[] towards_ranks, int exn) {

		BDD[][] T = new BDD[exn][];
		
		for (int exj = 0; exj < exn; exj++) {
			T[exj] = new BDD[towards_ranks[exj]];
			for (int r = 0; r < towards_ranks[exj]; r++) {
				
				BDD temp = Env.getVar("util_exJn").getDomain().ithVar(exj);
				temp.andWith(Env.getVar("util_Tn").getDomain().ithVar(r));
				
				BDD towardsBDD = towards.restrict(temp);
				T[exj][r] = Env.prime(towardsBDD);
				towardsBDD.free();
				temp.free();
			}
		}
		
		this.towards = T;
		
		safeZone = Env.TRUE();
		for (int exj = 0; exj < exn; exj++) {
			safeZone.andWith(this.towards[exj][towardsRank(exj) - 1].id());
		}
	}
	
	private void loadEnvViolation(BDD envViolation, int m, int rank) {

		BDD[][] EV = new BDD[m][];
		BDD[] EVR = new BDD[rank];
		
		for (int i = 0; i < m; i++) {
			EV[i] = new BDD[rank];
			for (int r = 0; r < rank; r++) {
				
				BDD temp = Env.getVar("util_vIn").getDomain().ithVar(i);
				temp.andWith(Env.getVar("util_vRn").getDomain().ithVar(r));
				
				BDD envViolationBDD = envViolation.restrict(temp);
				EV[i][r] = Env.prime(envViolationBDD);
				envViolationBDD.free();
				temp.free();
			}
		}
		
		for (int r = 0; r < rank; r++) {
			EVR[r] = Env.FALSE();
			for (int i = 0; i < m; i++) {
				EVR[r].orWith(EV[i][r].id());
			}
		}
		
		this.envViolationX = EV;
		this.envViolationY = EVR;
		this.envViolationRank = rank - 1;
	}

	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
		jitController.load(folder, name, sysVars, envVars);
		
		try {
			
			String prefix;
			if (name == null) {
				prefix = folder + File.separator;
			} else {
				prefix = folder + File.separator + name + ".";
			}
			
			BufferedReader sizesReader = new BufferedReader(new FileReader(prefix + "existential_sizes"));
			
			exn = Integer.parseInt(sizesReader.readLine());
			int[] fulfill_ranks = new int[exn];
			int[] towards_ranks = new int[exn];
			int env_violation_rank;
			for (int f = 0; f < exn; f++) {
				fulfill_ranks[f] = Integer.parseInt(sizesReader.readLine());
			}
			for (int t = 0; t < exn; t++) {
				towards_ranks[t] = Integer.parseInt(sizesReader.readLine());
			}
			env_violation_rank = Integer.parseInt(sizesReader.readLine());
			sizesReader.close();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Read Existential Sizes");

			
			// Extract fulfill BDD
			
			BDD fulfill = Env.loadBDD(prefix + "fulfill.bdd");
			loadFulfill(fulfill, fulfill_ranks, exn);	
			fulfill.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Load Fulfill BDD");
			
			
			// Extract towards BDD
			
			BDD towards = Env.loadBDD(prefix + "towards.bdd");
			loadTowards(towards, towards_ranks, exn);
			towards.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Load Towards BDD");
			
			
			// Extract environment violation BDD

			BDD envViolation = Env.loadBDD(prefix + "envviolation.bdd");
			loadEnvViolation(envViolation, jitController.getJusticeAsm().size(), env_violation_rank);
			envViolation.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Load Env Violation BDD");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		Env.deleteVar("util_exJn");
		Env.deleteVar("util_Fn");
		Env.deleteVar("util_Tn");
		Env.deleteVar("util_vIn");
		Env.deleteVar("util_vRn");
	}
	
	private int fulfillRank(int exj) {
		return fulfill[exj].length;
	}
	
	private int towardsRank(int exj) {
		return towards[exj].length;
	}
	
	private BDD nextStatesEnvViolation(BDD currStatePrimed, BDD currAndTrans) {
		
		BDD temp;
		BDD nextStates = Env.FALSE();
		
		// Find lowest rank
		BDD candidate = Env.FALSE();
		if (envViolationRank > 0) {
			candidate = currAndTrans.and(envViolationY[envViolationRank-1]);
		}
		
		if (candidate.isZero()) {
			
			for (int i = 0; i < getJusticeAsm().size(); i++) {
				temp = envViolationX[i][envViolationRank].and(currStatePrimed);
				
				if (!temp.isZero()) {
					temp.free();
					nextStates = currAndTrans.and(envViolationX[i][envViolationRank]);
					break;
				}
				
				temp.free();
			}
			
		} else {
			
			// It is guaranteed to stop on some k because Y[jx][rank] = Z
			for (int r = 0; r < envViolationY.length; r++) {
				temp = currAndTrans.and(envViolationY[r]);
				
				if (!temp.isZero()) {
					nextStates = temp;
					envViolationRank = r;
					break;
				}
				
				temp.free();
			}
		}
		
		candidate.free();
		
		return nextStates;
	}
	
	@Override
	public BDD next(BDD currentState, BDD inputs) {
		
		BDD nextStates = Env.FALSE();
		
		// Phase 2
		if (exphase) {
			
			System.out.println(String.format("phase 2 - exjx %d, towards %d, fulfill %d", exjx, towardsRank, fulfillRank));
			
			BDD currAndTrans = getJitContext().getTrans().id();
			currAndTrans.andWith(currentState.id());
			currAndTrans.andWith(Env.prime(inputs));
			
			if (towardsRank == 0 && fulfillRank == 0) {
				
				exjx = (exjx + 1) % exn;
				
				exphase = false;
				nextStates = prepareReturnToPhaseOne(currAndTrans);
			
			} else if (towardsRank == 0 && fulfillRank > 0) {
				nextStates = currAndTrans.and(fulfill[exjx][fulfillRank - 1]);
				fulfillRank--;
				
				// Asssume nextStates is FALSE here, move to the next existential guarantee
				if (nextStates.isZero()) {
					
					System.out.println(String.format("phase 2 - could not satisfy existential gar %s, move to next", exjx));

					exjx = (exjx + 1) % exn;
					
					exphase = false;
					nextStates = prepareReturnToPhaseOne(currAndTrans);
				
				}
				
			} else {
				nextStates = getLowestTowards(currAndTrans);
			}
			
			currAndTrans.free();
		    BDD primedNextStates = nextStates.exist(Env.globalUnprimeVars());
		    nextStates.free();
		    nextStates = Env.unprime(primedNextStates);
		    primedNextStates.free();
		    
		    return nextStates;
		
		} else { // Phase 1
			
			// Check if there is at least one ex. gar. that cannot be reached from current state. This means that it will never be reached and
			// the system cannot satisfy its guarantee GEF(regex). The only way to win that is left for the system is to force environment
			// to violate assumptions
			BDD currStatePrimed = Env.prime(currentState);
			if (getEnvViolationPhase(currStatePrimed)) {
				
				System.out.println("phase 1 - in env violation phase");
				BDD currAndTrans = getJitContext().getTrans().id();
				currAndTrans.andWith(currentState.id());
				currAndTrans.andWith(Env.prime(inputs));
				nextStates = nextStatesEnvViolation(currStatePrimed, currAndTrans);
				
				currStatePrimed.free();
				currAndTrans.free();
			    BDD primedNextStates = nextStates.exist(Env.globalUnprimeVars());
			    nextStates.free();
			    nextStates = Env.unprime(primedNextStates);
			    primedNextStates.free();
			    return nextStates;
			}
			
			currStatePrimed.free();
			
			int oldJx = jitController.getJitState().getJx();
			BDD nextStatesOriginal = jitController.next(currentState, inputs);
			int newJx = jitController.getJitState().getJx();
			
			System.out.println(String.format("phase 1 - old jx %d, new jx %d", oldJx, newJx));
			
			// Justice guarantees cycle is satisfied
			if (newJx < oldJx) {
				
				// Maybe switching phase, recalculating next states
				
				BDD currAndTrans = getJitContext().getTrans().id();
				currAndTrans.andWith(currentState.id());
				currAndTrans.andWith(Env.prime(inputs));
			
				exphase = true;
				fulfillRank = fulfillRank(exjx) - 1;
				nextStates = getLowestTowards(currAndTrans);

				
				currAndTrans.free();
			    BDD primedNextStates = nextStates.exist(Env.globalUnprimeVars());
			    nextStates.free();
			    nextStates = Env.unprime(primedNextStates);
			    primedNextStates.free();
			    return nextStates;
				
			} else {
				return nextStatesOriginal;
			}
		}
	}
	
	private boolean getEnvViolationPhase(BDD currentState) {
		if (envViolationPhase) return true;
		BDD temp = currentState.and(safeZone);
		if (temp.isZero()) { // Not in safe zone
			envViolationPhase = true;
		}
		temp.free();
		return envViolationPhase;
	}
	
	private BDD prepareReturnToPhaseOne(BDD currAndTrans) {
		
		BDD temp;
		BDD next = Env.FALSE();
		for (int r = 0; r < jitController.getJitContext().rank(0); r++) {
			temp = currAndTrans.and(jitController.getJitContext().Y(0, r));
			
			if (!temp.isZero()) {
				next = temp;
				jitController.getJitState().setRank(r);
				break;
			}
			
			temp.free();
		}
		
		return next;
	}
	
	private BDD getLowestTowards(BDD currAndTrans) {
		
		BDD temp;
		BDD lowest = Env.FALSE();
		for (int r = 0; r < towardsRank(exjx); r++) {
			temp = currAndTrans.and(towards[exjx][r]);
			
			if (!temp.isZero()) {
				lowest = temp;
				towardsRank = r;
				break;
			}
			
			temp.free();
		}
		
		return lowest;
	}
	
	@Override
	public void saveState() {
		this.controller.saveState();
	}

	@Override
	public void loadState() {
		this.controller.loadState();
	}

	@Override
	public BDD succ(BDD from) {
		return jitController.succ(from);
	}

	@Override
	public BDD pred(BDD to) {
		return jitController.pred(to);
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.extension.console;

import org.eclipse.core.resources.IFile;
import org.eclipse.debug.ui.console.FileLink;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.IPatternMatchListenerDelegate;
import org.eclipse.ui.console.PatternMatchEvent;
import org.eclipse.ui.console.TextConsole;
import org.eclipse.ui.part.FileEditorInput;

public class ExplanationConsolePatternMatchListener implements IPatternMatchListenerDelegate
{
	private TextConsole console;
	IWorkbenchPage activePage;
	
	public ExplanationConsolePatternMatchListener() {}

	@Override
	public void connect(TextConsole console)
	{
		this.console = console;
		 activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
		
	}

	@Override
	public void disconnect()
	{
		console = null;
	}

	@Override
	public void matchFound(PatternMatchEvent event)
	{
		IEditorPart editor = activePage.getActiveEditor();
		if (editor != null) {
			IFile spec = ((FileEditorInput)editor.getEditorInput()).getFile();
			
			try {
				String file_reference_text = console.getDocument().get(event.getOffset(), event.getLength());
				// We add 2 because the match is "line: number" and we want to skip the ':' and the space
				int line_number_index = file_reference_text.lastIndexOf(":") + 2;
				int line_number = Integer.parseInt(file_reference_text.substring(line_number_index));
	
				FileLink f_l = new FileLink(spec, null, -1, -1, line_number);	
				
				console.addHyperlink(f_l, event.getOffset(), event.getLength());
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
		}
	}
}<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller;

import java.util.Map;

import net.sf.javabdd.BDD;

public abstract class AbstractController implements Controller {
	
	protected Controller controller;
	
	public AbstractController(Controller controller) {
		super();
		this.controller = controller;
	}
	
	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
		controller.load(folder, name, sysVars, envVars);
	}
	
	@Override
	public BDD next(BDD currentState, BDD inputs) {
		return controller.next(currentState, inputs);
	}
	
	@Override
	public void free() {
		controller.free();
	}
	
	@Override
	public BDD transitions() {
		return controller.transitions();
	}
	
	@Override
	public BDD initial() {
		return controller.initial();
	}
	
	@Override
	public void init(BDD currentState) {
		controller.init(currentState);
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.jobs;

import tau.smlab.syntech.bddgenerator.energy.BDDEnergyReduction;
import tau.smlab.syntech.games.gr1.GR1Game;
import tau.smlab.syntech.games.gr1.GR1GameEnergyADD;
import tau.smlab.syntech.games.gr1.GR1GameExperiments;
import tau.smlab.syntech.games.gr1.GR1GameImplC;
import tau.smlab.syntech.games.gr1.GR1GameMemoryless;
import tau.smlab.syntech.games.gr1.GR1SeparatedGame;
import tau.smlab.syntech.games.gr1.GR1SeparatedGameImplC;
import tau.smlab.syntech.games.gr1.GR1StarGameMemoryless;
import tau.smlab.syntech.jtlv.BDDPackage;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.ui.preferences.PreferenceConstants;
import tau.smlab.syntech.ui.preferences.PreferencePage;
public class CheckRealizabilityJob extends SyntechJob {

	@Override
	protected void doWork() {
		GR1Game gr1;

		// check for existential guarantees
		if(model.getSys().existReqNum() > 0) {
			printToConsole("GR1StarGameMemoryless");
			gr1 = new GR1StarGameMemoryless(model);
		}
		// check for weights or special reordering
		else if (model.getWeights() != null && PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD_ADD)) {
			printToConsole("GR1GameEnergyADD (without optimizations)");
			gr1 = new GR1GameEnergyADD(model, gi.getEnergyBound());
		/*} else if (PreferencePage.isSpecialReorderStrategy()) {
			gr1 = new GR1GameReachable(model);
			Env.TRUE().getFactory().autoReorder(BDDFactory.REORDER_NONE);
			Env.TRUE().getFactory().reorder(BDDFactory.REORDER_SIFTITE);*/
		} else {
			PreferencePage.setOptSelection();
			
			if (PreferencePage.getSynthesisMethod().equals(PreferenceConstants.SYNTHESIS_METHOD_PITERMAN) ||
					PreferencePage.getSynthesisMethod().equals(PreferenceConstants.SYNTHESIS_METHOD_PITERMAN_REDUCTION)) {
				if (PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD)) {
					printToConsole("GR1SeparatedGameImplC with memory");
					gr1 = new GR1SeparatedGameImplC(model);
				}  else {
					printToConsole("GR1SeparatedGame");
					gr1 = new GR1SeparatedGame(model);
				}
			} else if (PreferencePage.hasSymmetryDetection()) {
				printToConsole("GR1Game");
				gr1 = new GR1Game(model);
			} else if (PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD)) {
				printToConsole("GR1GameImplC with memory");
				gr1 = new GR1GameImplC(model);
			} else if (PreferencePage.hasOptSelection()) {
				printToConsole("GR1GameExperiments (with optimizations)");
				gr1 = new GR1GameExperiments(model);
			} else {
				printToConsole("GR1GameMemoryless");
				gr1 = new GR1GameMemoryless(model);
			}
		}
		
		
		this.isRealizable = false;
		String message = "Specification is unrealizable.";
		if (gr1.checkRealizability()) {	
			this.isRealizable = true;
			message = "Specification is realizable.";
			if (model.getWeights() != null) {
				message += " System wins with minimal initial credit ";
				if(PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD_ADD)) {
					message += ((GR1GameEnergyADD)gr1).getMinWinInitCred();
				}
				else {
					message += BDDEnergyReduction.getMinWinCred(model, gr1.sysWinningStates()).toStringWithDomains(Env.stringer);
				}
			}
		}
		printToConsole(message);
		Env.resetEnv();
	}
	

	@Override
	public boolean needsBound() {
		return true;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel.util;

import java.util.ArrayList;
import java.util.List;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.ModuleException;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.gamemodel.PlayerModule.TransFuncType;
import tau.smlab.syntech.jtlv.env.module.ModuleBDDField;

public class GameBuilderUtil {

	/**
	 * Use this method to build the system PlayerModule of the given GameModel. 
	 * Aux behaviors are automatically used.
	 * 
	 * @param m		game model
	 * @param part  the behaviors
	 */
  public static void buildSys(GameModel m, List<BehaviorInfo> part) {
	List<BehaviorInfo> bvs = new ArrayList<BehaviorInfo>(part);
	bvs.addAll(m.getAuxBehaviorInfo());
	m.getSysBehaviorInfo().clear();
	m.getSysBehaviorInfo().addAll(part);
    try {
  	  build(m.getSys(), bvs);		
    } catch (ModuleException e) {
  	  e.printStackTrace();
    }	  
  }

  	/**
  	 * Use this method to build the environment PlayerModule of the given GameModel. 
  	 * 
  	 * @param m		game model
  	 * @param part	the behaviors
  	 */
  public static void buildEnv(GameModel m, List<BehaviorInfo> part) {
	List<BehaviorInfo> bvs = new ArrayList<BehaviorInfo>(part);
	m.getEnvBehaviorInfo().clear();
	m.getEnvBehaviorInfo().addAll(part);
    try {
  	  build(m.getEnv(), bvs);		
    } catch (ModuleException e) {
  	  e.printStackTrace();
    }
  }
  
  /**
   * Build the PlayerModule using the given behaviors. Take into consideration the type of safety the module uses
   * 
   * @param module 
   * @param beavs
   * @throws ModuleException
   */
	private static void build(PlayerModule module, List<BehaviorInfo> beavs) throws ModuleException {

		module.reset();

		for (BehaviorInfo b : beavs) {
			if (b.isInitial()) {
				module.conjunctInitial(b.initial.id());
			}
			if (b.isSafety()) {
				switch (module.getTransFuncType()) {
				case SINGLE_FUNC:
					module.conjunctTrans(b.safety.id());
					break;
				case DECOMPOSED_FUNC:
					module.addToTransList(b.safety.id());
					break;
				case PARTIAL_DECOMPOSED_FUNC:
					module.addToTransList(b.safety.id());
					break;
				default:
					System.err.println("unknown type " + module.getTransFuncType());
					break;
				}
			}
			if (b.isJustice()) {
				module.addJustice(b.justice.id(), b.traceId);
			}
		}

		if (module.getTransFuncType() == TransFuncType.DECOMPOSED_FUNC) {
			module.calcTransQuantList();
		} else if (module.getTransFuncType() == TransFuncType.PARTIAL_DECOMPOSED_FUNC) {
			module.createPartialTransQuantList();
		}
	}
  
  public static void buildQuantifiedSys(GameModel m, List<ModuleBDDField> vars) {
    PlayerModule module = m.getSys();
	  
    module.reset();
	
	List<BehaviorInfo> part = new ArrayList<BehaviorInfo>();
	part.addAll(m.getSysBehaviorInfo());
	part.addAll(m.getAuxBehaviorInfo());
	  
	// quantify over core behavior and add
	for (BehaviorInfo b : part) {
	  if (b.isJustice()) {
		BDD q = b.justice.id();
		q = quanAll(q, vars);
		module.addJustice(q, b.traceId);
	  }
	  if (b.isSafety()) {
		BDD q = b.safety.id();
		q = quanAll(q, vars);		
		switch (module.getTransFuncType()) {
		case SINGLE_FUNC:
			module.conjunctTrans(q.id());
			break;
		case DECOMPOSED_FUNC:
			module.addToTransList(q.id());
			break;
		case PARTIAL_DECOMPOSED_FUNC:
			module.addToTransList(q.id());
			break;
		default:
			System.err.println("unknown type " + module.getTransFuncType());
			break;
		}
	  }
	  if (b.isInitial()) {
		BDD q = b.initial.id();
		q = quanAll(q, vars);
		module.conjunctInitial(q.id());	 
	  }
	}
	
	if (module.getTransFuncType() == TransFuncType.DECOMPOSED_FUNC) {
		module.calcTransQuantList();
	} else if (module.getTransFuncType() == TransFuncType.PARTIAL_DECOMPOSED_FUNC) {
		module.createPartialTransQuantList();
	}
  }
  
	/**
	 * quantify over a set of variables
	 * 
	 * @param bdd the BDD
	 * @param vars the vars for existetial quantification
	 * @return
	 */
  private static BDD quanAll(BDD bdd, List<ModuleBDDField> vars) {
	for (ModuleBDDField v:vars) {
	  bdd = bdd.exist(v.support());
	}
	return bdd;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.symbolic;

import java.util.Map;

import net.sf.javabdd.ADD;
import net.sf.javabdd.BDD;
import net.sf.javabdd.BDD.BDDIterator;
import net.sf.javabdd.BDDFactory;
import tau.smlab.syntech.gameinput.spec.Operator;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecBDD;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.ModuleVariableException;
import tau.smlab.syntech.modelchecker.CounterExampleException;
import tau.smlab.syntech.modelchecker.LTLModelChecker;
import tau.smlab.syntech.modelchecker.ModelCheckException;

public class SymbolicControllerChecker {

  public static boolean checkCompletenessForEnvIterate(SymbolicController ctrl, GameModel model) {

    PlayerModule env = model.getEnv();
    PlayerModule sys = model.getSys();

    // 1) check that all inital assignments to environment variables have a
    // corresponding inital state in the controller
    BDD result = env.initial().id().impWith(ctrl.initial().exist(sys.moduleUnprimeVars()))
        .forAll(env.moduleUnprimeVars());

    if (!result.isOne()) {
      result.free();
      return false;
    }
    result.free();

    // 2) check that for all reachable states in the controller it is enabled
    // for all next assignments to environment variables
    BDD reachable = Env.allSucc(ctrl.initial().id(), ctrl.trans().id());

    for (BDDIterator sit = reachable.iterator(Env.globalUnprimeVars()); sit.hasNext();) {
      BDD s = sit.nextBDD();
      BDD ctrlSucc = s.and(ctrl.trans());
      BDD envSucc = s.and(env.trans());
      BDD envChoices = envSucc.exist(sys.modulePrimeVars());
      envSucc.free();
      BDD ctrlEnvChoices = ctrlSucc.exist(sys.modulePrimeVars());
      ctrlSucc.free();
      BDD envNotCovered = envChoices.andWith(ctrlEnvChoices.not());
      if (!envNotCovered.isZero()) {
        System.out.println("State " + Env.toNiceSignleLineString(s));
        System.out.println(
            "Successors in Controller: " + Env.toNiceSignleLineString(ctrlEnvChoices.exist(Env.globalUnprimeVars())));
        System.out.println("EnvSuccessors not in Controller: "
            + Env.toNiceSignleLineString(envNotCovered.exist(Env.globalUnprimeVars())));
        s.free();
        envNotCovered.free();
        ctrlEnvChoices.free();
        return false;
      }
      s.free();
      envNotCovered.free();
      ctrlEnvChoices.free();
    }

    return true;
  }

  /**
   * Check whether from every state of the controller the environment can make all
   * choices
   * 
   * @param ctrl
   * @param model
   * @return
   */
  public static boolean checkCompletenessForEnv(SymbolicController ctrl, GameModel model) {

    PlayerModule env = model.getEnv();
    PlayerModule sys = model.getSys();

    // 1) check that all inital assignments to environment variables have a
    // corresponding inital state in the controller
    BDD result = env.initial().id().impWith(ctrl.initial().exist(sys.moduleUnprimeVars()))
        .forAll(env.moduleUnprimeVars());

    if (!result.isOne()) {
      System.out.println("initial states are not complete");
      result.free();
      return false;
    }
    result.free();

    // 2) check that for all reachable states in the controller it is enabled
    // for all next assignments to environment variables
    BDD reachable = Env.allSucc(ctrl.initial().id(), ctrl.trans().id());

    return reachable.andWith(env.trans().id()).impWith(ctrl.trans().exist(sys.modulePrimeVars()))
        .forAll(env.modulePrimeVars()).isOne();
  }

  /**
   * Check whether every reachable state (by controller and system) has an
   * environment successor or is a deadlock state for the system
   * 
   * @param ctrl
   * @param model
   * @return true if env has successors for all valid system choices
   */
  public static boolean checkCompletenessForSys(SymbolicController ctrl, GameModel model) {

    PlayerModule env = model.getEnv();
    PlayerModule sys = model.getSys();

    // 1) check that there is at least one valid initial env choice
    BDD result = ctrl.initial().exist(env.moduleUnprimeVars());

    if (result.isZero()) {
      System.out.println("no inital env choice");
      return false;
    }
    result.free();

    // 2) check that for all reachable states in the controller it is enabled
    BDD reachable = Env.allSucc(ctrl.initial().and(sys.initial()), sys.trans().and(ctrl.trans()));

    // remove states where env has a successor
    reachable.andWith(ctrl.trans().exist(env.modulePrimeVars().union(sys.modulePrimeVars())).not());
    // remove dead states
    reachable.andWith(env.controlStates(sys, Env.FALSE()).not());
    return reachable.isZero();
  }

  public static boolean checkStrategyIsWinningForSys(SymbolicController ctrl, ADD weightedArena, double worstInitEng) {

    ADD sourceStates = (ADD) ctrl.initial().id();
    ADD strategyTrans = (ADD) ctrl.trans().and(Env.allSucc(sourceStates.id(), ctrl.trans().id()));

    /* map every reachable state to -INF and every unreachable state to +INF */
    ADD strategyTransTmp = strategyTrans.not();
    strategyTrans.free();
    strategyTrans = strategyTransTmp;

    strategyTrans.applyWith(Env.CONST(2.0), BDDFactory.times);
    strategyTrans.applyWith(Env.TRUE(), BDDFactory.minus);
    strategyTrans.applyWith(Env.PLUS_INF(), BDDFactory.times);

    /*
     * restrict the arena to have only transitions from states that are reachable
     * from the initial states if sys plays by the strategy. Every outgoing legal
     * transition from a reachable source state, would have a finite or +INF weight;
     * Otherwise, the transition would have a +INF weight.
     */
    ADD strategyArena = weightedArena.apply(strategyTrans, BDDFactory.max);

    strategyTrans.free();

    /*
     * If there is a transition with -INF weight that is reachable from the initial
     * states when the system plays according to ctrl strategy, then it is loosing
     */
    ADD minimumCheck = strategyArena.findMin();
    if (minimumCheck.equals(Env.MINUS_INF())) {
      System.out.println(
          "The strategy is loosing for the system because there is a -INF transition reachable from an initial state");
      minimumCheck.free();
      return false;
    }
    minimumCheck.free();

    System.out.println(
        "Weights of reachable transitions from all initial states, if the system plays according to the constructed strategy:");
    strategyArena.printTerminalValues();

    System.out.println(
        "Checking that the system can play according to this strategy, without going into a negative cycle...");

    /*
     * Check that there is no negative cycle reachable from every initial state if
     * the system plays according to ctrl strategy
     */
    if (thereIsNegativeCycle(sourceStates, strategyArena, worstInitEng)) {
      System.out.println(
          "Error: there is a reachable negative cycle if the system plays according to this controller, i.e. it is loosing for the system!!");
      return false;
    }

    System.out.println("We don't have any negative cycles, so this controller is winning for the system!");

    return true;
  }

  /**
   * An implementation of symbolic Bellman Ford algorithm for calculating the
   * shortest paths weights from all given source states.
   * 
   * @param sourceStates
   * @param arena        the weighted arena
   * @return true if there is a negative cycle reachable from one of the source
   *         states; false, otherwise.
   */
  public static boolean thereIsNegativeCycle(ADD sourceStates, ADD arena, double worstInitEng) {

    /*
     * We add a new sink state, that has 0 weighted transitions to all initial
     * states. Therefore, at we initialize the shortest path estimate of each
     * initial state to 0; All other states are initialized to +INF.
     */
    ADD curDistEstimates = sourceStates.ite(Env.FALSE(), Env.PLUS_INF());

    ADD prevDistEstimates = null;
    ADD distSum, relaxPrimed, relaxUnprimed, worstInitEngCheck;

    /* V is the size of the state space */
    long V = 1;
    V <<= (2 * Env.globalPrimeVars().size());

    System.out.println("V = " + V);
    worstInitEng = (-1) * worstInitEng;
    for (long i = 0; i < V && (prevDistEstimates == null || !curDistEstimates.equals(prevDistEstimates)); i++) {
      if (i == V - 1) { // V's (last) iteration iff there is a negative cycle in the arena!
        return true;
      }
      /*
       * for efficiency of computation: if there is a negative cycle, we will end up
       * with worst required energy that is higher than the declared one; If so, we
       * should stop now (before reaching the V's iteration).
       */
      worstInitEngCheck = curDistEstimates.findMin();
      if (worstInitEngCheck
          .getConstantValue() < worstInitEng) { /*
                                                 * the strategy seems to be wrong, or there might be a negative cycle
                                                 */
        System.out.println(
            "the strategy requires energy from the initial states which is higher than the declared worst needed energy level!");
        System.out.println("The worst energy level that was found: " + (-1) * worstInitEngCheck.getConstantValue()
            + ", but the declared energy is " + (-1) * worstInitEng);
        return true;
      }
      worstInitEngCheck.free();
      // curDistEstimates.printTerminalValues();
      if (prevDistEstimates != null) {
        prevDistEstimates.free();
      }
      prevDistEstimates = curDistEstimates;

      /*
       * for all states v, d(v) is the shortest path estimate from one of the initial
       * states, i.e. it is the most energy consuming path to state v from one of the
       * initial states.
       */

      /*
       * Relax operation: for every target state v, do: d*(v) = min(d(u) + w(u,v)) for
       * all predecessors of v
       */
      distSum = arena.apply(prevDistEstimates, BDDFactory.plus);
      relaxPrimed = distSum.abstractMin(Env.globalUnprimeVars());
      relaxUnprimed = (ADD) Env.unprime(relaxPrimed);

      /*
       * for every target state v, do: d(v) = min(d(v), d*(v)); this is the last step
       * of the relax operation for each edge in the graph.
       */
      curDistEstimates = relaxUnprimed.apply(prevDistEstimates, BDDFactory.min);

      distSum.free();
      relaxPrimed.free();
      relaxUnprimed.free();
    }
    return false;

  }

  public static int checkMaxAccumulatedWeightUpToLimit(SymbolicController ctrl, Map<Integer, BDD> weights, int limit) {
    // TODO implement fixed point algorithm over reachable states but divided by
    // accumulated weights

    // compute a downwards closed set to guarantee fixpoint (to make it
    // downwardclosed keep only the state with the highest accumulated value)

    return -1;
  }

  public static boolean checkCompletenessForEnvUpTo(SymbolicController ctrl, GameModel model, BDD upTo) {

    PlayerModule env = model.getEnv();
    PlayerModule sys = model.getSys();

    // 1) check that all inital assignments to environment variables have a
    // corresponding inital state in the controller
    BDD result = env.initial().id().andWith(upTo.not()).impWith(ctrl.initial().exist(sys.moduleUnprimeVars()))
        .forAll(env.moduleUnprimeVars());

    if (!result.isOne()) {
      result.free();
      return false;
    }
    result.free();

    // 2) check that for all reachable states in the controller it is enabled
    // for all next assignments to environment variables
    BDD reachable = Env.allSucc(ctrl.initial().id(), ctrl.trans().id()).andWith(upTo.not());

    return reachable.andWith(env.trans().id()).impWith(ctrl.trans().exist(sys.modulePrimeVars()))
        .forAll(env.modulePrimeVars()).isOne();
  }

  /**
   * Model-checks controller against GR(1) specification (strict realizability
   * semantics)
   * 
   * @param ctrl
   * @param m
   * @return false in case of any exceptions (including counter-examples)
   */
  public static boolean checkGR1Spec(SymbolicController ctrl, GameModel m) {
    try {
      checkGR1SpecWC(ctrl, m);
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  /**
   * Model-checks controller against GR(1) specification (strict realizability
   * semantics)
   * 
   * @param ctrl
   * @param m
   * @throws ModelCheckException
   * @throws CounterExampleException (is a ModelCheckException) in case GR(1) spec
   *                                 is violated by controller
   * @throws ModuleVariableException
   */
  public static void checkGR1SpecWC(SymbolicController ctrl, GameModel m)
      throws ModelCheckException, CounterExampleException, ModuleVariableException {
    PlayerModule sys = m.getSys();
    if (sys.justiceNum() == 0) {
      sys.addJustice(Env.TRUE());
    }
    PlayerModule env = m.getEnv();
    if (env.justiceNum() == 0) {
      env.addJustice(Env.TRUE());
    }

    LTLModelChecker c = null;

    PlayerModule mod = new PlayerModule();
    mod.setName("symbolicGraph");
    mod.resetInitial();
    mod.conjunctInitial(ctrl.initial().id());
    mod.resetTrans();
    mod.conjunctTrans(ctrl.trans().id());
    c = new LTLModelChecker(mod);

    Spec sysJ = allJustice(sys);
    Spec envJ = allJustice(env);

    Spec rhoS = new SpecBDD(sys.trans());
    Spec rhoE = new SpecBDD(env.trans());

    Spec thetaS = new SpecBDD(sys.initial());
    Spec thetaE = new SpecBDD(env.initial());

    Spec implI = new SpecExp(Operator.IMPLIES, thetaE, thetaS);

    Spec HrhoE = null;
    // workaround of HISTORICALLY limitation in case of primes in rhoE
    if (Env.containPrimeVars(env.trans())) {
      HrhoE = new SpecExp(Operator.HISTORICALLY, new SpecExp(Operator.PRIME, new SpecExp(Operator.PREV, rhoE)));
    } else {
      HrhoE = new SpecExp(Operator.HISTORICALLY, rhoE);
    }
    Spec implS = new SpecExp(Operator.IMPLIES, thetaE,
        new SpecExp(Operator.GLOBALLY, new SpecExp(Operator.IMPLIES, HrhoE, rhoS)));
    Spec implJ = new SpecExp(Operator.IMPLIES,
        new SpecExp(Operator.AND, thetaE, new SpecExp(Operator.AND, new SpecExp(Operator.GLOBALLY, rhoE), envJ)), sysJ);

    Spec strongRealizability = new SpecExp(Operator.AND, new SpecExp(Operator.AND, implS, implJ), implI);

    // c.modelCheckStandardOutput(strongRealizability);
    c.modelCheck(strongRealizability);
  }

  /**
   * produces a conjunction of all justices as /\_{i} GF(J_i)
   * 
   * @param m
   * @return
   */
  private static Spec allJustice(PlayerModule m) {
    Spec allSysJ = new SpecExp(Operator.GLOBALLY, new SpecExp(Operator.FINALLY, new SpecBDD(m.justiceAt(0))));
    for (int i = 1; i < m.justiceNum(); i++) {
      Spec spec = new SpecExp(Operator.GLOBALLY, new SpecExp(Operator.FINALLY, new SpecBDD(m.justiceAt(i))));
      allSysJ = new SpecExp(Operator.AND, allSysJ, spec);
    }

    return allSysJ;
  }

  public static boolean checkRabinSpec(SymbolicController ctrl, GameModel m) {
    boolean res = false;

    PlayerModule sys = m.getSys();
    PlayerModule env = m.getEnv();

    LTLModelChecker c = null;
    try {
      PlayerModule mod = new PlayerModule();
      mod.setName("symbolicGraph");
      mod.resetInitial();
      mod.conjunctInitial(ctrl.initial().id());
      mod.resetTrans();
      mod.conjunctTrans(ctrl.trans().id());
      c = new LTLModelChecker(mod);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }

    Spec sysJ = allJustice(sys);
    Spec envJ = allJustice(env);

    Spec rhoS = new SpecBDD(sys.trans());
    Spec rhoE = new SpecBDD(env.trans());

    Spec thetaS = new SpecBDD(sys.initial());
    Spec thetaE = new SpecBDD(env.initial());

    Spec implI = new SpecExp(Operator.IMPLIES, thetaE, thetaS);

    Spec HrhoE = null;
    // workaround of HISTORICALLY limitation in case of primes in rhoE
    if (Env.containPrimeVars(env.trans())) {
      HrhoE = new SpecExp(Operator.HISTORICALLY, new SpecExp(Operator.PRIME, new SpecExp(Operator.PREV, rhoE)));
    } else {
      HrhoE = new SpecExp(Operator.HISTORICALLY, rhoE);
    }
    Spec implS = new SpecExp(Operator.AND, thetaE,
        new SpecExp(Operator.GLOBALLY, new SpecExp(Operator.IMPLIES, HrhoE, rhoS)));
    Spec implJ = new SpecExp(Operator.IMPLIES,
        new SpecExp(Operator.AND, thetaE, new SpecExp(Operator.AND, new SpecExp(Operator.GLOBALLY, rhoE), envJ)), sysJ);

    Spec strongRealizability = new SpecExp(Operator.AND, new SpecExp(Operator.AND, implS, implJ), implI);

    Spec rabin = new SpecExp(Operator.NOT, strongRealizability);

    res = c.modelCheckWithNoCounterExample(rabin);

    return res;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.sfa;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.sfa.PowerSetIterator.PowerSetIteratorType;

/**
 * 
 * An Epsilon-SFA that has exactly One Final state, which has no outgoing transitions.
 * 
 * @author <NAME>
 *
 */
public class OFEpsSFA extends EpsSFA {
	
	private EpsSFAState finalState; //The unique, only final state of this automaton
	
	protected OFEpsSFA() {
		this(null, null, PowerSetIteratorType.EFFICIENT);
	}

	protected OFEpsSFA(SFAState ini) {
		this(ini, null, PowerSetIteratorType.EFFICIENT);
	}
	
	protected OFEpsSFA(SFAState ini, SFAState finalState) {
		this(ini, finalState, PowerSetIteratorType.EFFICIENT);
	}

	protected OFEpsSFA(PowerSetIteratorType psIterType) {
		this(null, null, psIterType);
	}

	protected OFEpsSFA(SFAState ini, PowerSetIteratorType psIterType) {
		this(ini, null, psIterType);
	}
	
	protected OFEpsSFA(SFAState ini, SFAState finalState, PowerSetIteratorType psIterType) {
		super(ini, psIterType);
		if(finalState != null) {
			this.setFinalState(finalState);
		}
	}
	
	@Override
	public EpsSFAState getFinalState() {
		return this.finalState;
	}
	
	@Override
	public void setFinalState(SFAState finalState) {
		if(!(finalState instanceof EpsSFAState)) {
			throw new SFAException("The specified state has an invalid type. The final state must be an instance of EpsSFAState.");
		}
		if(!finalState.isAccepting()) {
			finalState.flipAcceptance();
		}
		this.finalState = (EpsSFAState) finalState;
	}
	
	@Override
	public OFEpsSFA copy() {
		OFEpsSFA copy = new OFEpsSFA();
		Map<EpsSFAState, EpsSFAState> copyStateMappingMap = new HashMap<>();

		copy.setIni(this.getIni().cloneWithoutSucc());
		copyStateMappingMap.put(this.getIni(), copy.getIni());
		
		Queue<EpsSFAState> worklist = new LinkedList<>();
		worklist.add(this.getIni());
		
		while (!worklist.isEmpty()) {
			EpsSFAState s = worklist.remove();
			
			if(s == this.finalState) {
				//the only accepting state is reachable from the initial state
				copy.finalState = copyStateMappingMap.get(s);
			}
			
			//non-epsilon transitions/successors
			for (Map.Entry<EpsSFAState, BDD> transition : s.getSucc().entrySet()) {
				if (!copyStateMappingMap.containsKey(transition.getKey())) {
					worklist.add(transition.getKey());
					copyStateMappingMap.put(transition.getKey(), transition.getKey().cloneWithoutSucc());
				}

				copyStateMappingMap.get(s).addTrans(transition.getValue().id(),
						copyStateMappingMap.get(transition.getKey()));
			}

			//handle epsilon transitions, if such transitions exist
			if(s.hasEpsSuccessors()) {
				for(EpsSFAState epsSucc : s.getEpsSucc()) {
					if (!copyStateMappingMap.containsKey(epsSucc)) {
						worklist.add(epsSucc);
						copyStateMappingMap.put(epsSucc, epsSucc.cloneWithoutSucc());
					}
					copyStateMappingMap.get(s).addEpsTrans(copyStateMappingMap.get(epsSucc));
				}
			}
		}
		
		if(!copyStateMappingMap.containsKey(this.finalState)) {
			//the final state is not reachable from the initial state
			copy.finalState = this.finalState.cloneWithoutSucc();
		}
		return copy;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.simple;

import java.util.Stack;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDD.BDDIterator;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.AbstractGamesException;
import tau.smlab.syntech.games.GameMemory;
import tau.smlab.syntech.games.controller.enumerate.ConcreteControllerConstruction;
import tau.smlab.syntech.games.controller.enumerate.EnumStateI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyImpl;
import tau.smlab.syntech.jtlv.CoreUtil;

public class SafetyGameConceteControllerConstruction extends ConcreteControllerConstruction {

  private GameMemory mem;

  public SafetyGameConceteControllerConstruction(GameMemory mem, GameModel m) {
    super(mem, m);
    this.mem = mem;
  }

  @Override
  public EnumStrategyI calculateConcreteController() throws AbstractGamesException {
    Stack<EnumStateI> st_stack = new Stack<EnumStateI>();

    BDDVarSet envUnprimedVars = env.moduleUnprimeVars();
    BDDVarSet sysUnprimedVars = sys.moduleUnprimeVars();

    EnumStrategyImpl aut = new EnumStrategyImpl();

    for (BDDIterator it = env.initial().iterator(envUnprimedVars); it.hasNext();) {
      BDD envIni = it.nextBDD();
      BDD iniWin = envIni.andWith(getWinningInitialStates());
      BDD oneIni = CoreUtil.satOne(iniWin, envUnprimedVars.union(sysUnprimedVars));
      st_stack.push(aut.getState(oneIni, null));
    }

    System.out.println("Initial states of environment: " + st_stack.size());

    // iterating over the stacks.
    while (!st_stack.isEmpty()) {
      // making a new entry.
      EnumStateI new_state = st_stack.pop();
      BDD p_st = new_state.getData();

      BDD good_suc = env.succ(p_st).andWith(mem.getWin().id());
      BDD one_cand = CoreUtil.satOne(good_suc, envUnprimedVars.union(sysUnprimedVars));
      good_suc.free();
      // add succ
      EnumStateI succ = aut.addSuccessorState(new_state, one_cand, null);
      if (succ != null) {
        // if a new state was created.
        st_stack.push(succ);
      }
    }

    return aut;
  }

  private BDD getWinningInitialStates() {
    return mem.getWin().and(sys.initial());
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

import java.util.List;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

/**
 * 
 * Realizability checking for GR(1)* specifications as presented in FM'19.
 * 
 * 
 * @author <NAME>
 * @author <NAME>
 * 
 */
public class GR1GameExistentialFM19Memoryless extends GR1Game {

	public GR1GameExistentialFM19Memoryless(GameModel model) {
		super(model);
	}

	@Override
	public boolean checkRealizability() {
		BDD z = Env.TRUE(), nextZ, V;
		FixPoint iterZ;

		V = (model.getSys().existReqNum() > 0) ? computeJusticeAssumptionViolation() : Env.FALSE();

		for (iterZ = new FixPoint(true); iterZ.advance(z);) {
			nextZ = Env.TRUE();
			for (int k = 0; k < model.getSys().existReqNum(); k++) {
				nextZ.andWith(computeExistentialBdd(z, model.getSys().existReqAt(k).getExistFinallyAssrts()));
			}

			nextZ.andWith(computeJusticeIteration(z));
			nextZ.orWith(V.id());

			z = nextZ;
		}
		mem.setWin(z);
		mem.setComplete(true);
		iterZ.free();
		return sysWinAllInitial(z);
	}

	/**
	 * GR(1) part: justice assumptions and justice guarantees
	 * 
	 * @param z
	 * @return
	 */
	private BDD computeJusticeIteration(BDD z) {
		BDD x, y, zApprox = z.id();
		FixPoint iterY, iterX;
		for (int j = 0; j < sys.justiceNum(); j++) {
			BDD yieldZandJj = sys.justiceAt(j).id().andWith(env.yieldStates(sys, zApprox));
			y = Env.FALSE();
			for (iterY = new FixPoint(true); iterY.advance(y);) {
				BDD start = yieldZandJj.id().orWith(env.yieldStates(sys, y));
				y = Env.FALSE();
				for (int i = 0; i < env.justiceNum(); i++) {
					BDD negp = env.justiceAt(i).not();
					x = zApprox.id();
					for (iterX = new FixPoint(true); iterX.advance(x);) {
						BDD sysCtrl = env.yieldStates(sys, x);
						BDD sysCtrlAndNotJustice = sysCtrl.and(negp);
						sysCtrl.free();
						x = sysCtrlAndNotJustice.or(start);
						sysCtrlAndNotJustice.free();
					}
					y.orWith(x);
					iterX.free();
					negp.free();
				}
				start.free();
			}
			zApprox.free();
			zApprox = y;
			iterY.free();
			yieldZandJj.free();
		}
		return zApprox;
	}

	/**
	 * Existential guarantees
	 * 
	 * @param z
	 * @param assertions
	 * @return
	 */
	private BDD computeExistentialBdd(BDD z, List<BDD> assertions) {
		BDD currAssrt, nextTarget = z.id(), y, oldNextTarget;
		if(assertions != null) { 
			FixPoint iterY;
			for (int i = assertions.size() - 1; i >= 0; i--) {
				currAssrt = assertions.get(i);
				y = Env.FALSE();
				for (iterY = new FixPoint(true); iterY.advance(y);) {
					y = currAssrt.and(nextTarget).orWith(z.id().andWith(env.pred(sys, y)));
				}
				oldNextTarget = nextTarget;
				nextTarget = y;
				oldNextTarget.free();
				iterY.free();
			}
		}
		return nextTarget;
	}

	/**
	 * Justice assumptions violation
	 * 
	 * @return
	 */
	private BDD computeJusticeAssumptionViolation() {
		BDD x, y, cPreY, sysCtrl, sysCtrlAndNotJustice, negJe;
		FixPoint iterY, iterX;
		y = Env.FALSE();
		for (iterY = new FixPoint(true); iterY.advance(y);) {
			cPreY = env.yieldStates(sys, y);
			y = Env.FALSE();
			for (int i = 0; i < env.justiceNum(); i++) {
				negJe = env.justiceAt(i).not();
				x = Env.TRUE();
				for (iterX = new FixPoint(true); iterX.advance(x);) {
					sysCtrl = env.yieldStates(sys, x);
					sysCtrlAndNotJustice = sysCtrl.and(negJe);
					sysCtrl.free();
					x = sysCtrlAndNotJustice.or(cPreY);
					sysCtrlAndNotJustice.free();
				}
				y.orWith(x);
				iterX.free();
				negJe.free();
			}
			cPreY.free();
		}
		iterY.free();
		return y;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games;

import java.util.Vector;

import net.sf.javabdd.BDD;

public abstract class GameIncrementalMemory {
    
    public boolean NEW_INI_ADDED = false;
    public boolean NEW_SAFETY_ADDED = false;
    public boolean NEW_JUSTICE_ADDED = false;
    public boolean PREV_INI_REMOVED = false;
    public boolean PREV_SAFETY_REMOVED = false;
    public boolean PREV_JUSTICE_REMOVED = false;
    
    public int leastRemovedJusticeIdx = 0;
    
    public BDD startZ = null;
        
    abstract public void addToStartZ(BDD z, int idx);
        
    public int getIncTypeBitmap()
    {
      int typeBitmap = 0;
//      NOTE: the bitmap needs to correspond to the enum values in the C code.
//      typedef enum INC_TYPE {
//        INC_TYPE_NO_INC = 0,
//        INC_TYPE_NEW_INI_ADDED = 1,
//        INC_TYPE_NEW_SAFETY_ADDED =2,
//        INC_TYPE_NEW_JUSTICE_ADDED = 4,
//        INC_TYPE_PREV_INI_REMOVED = 8,
//        INC_TYPE_PREV_SAFETY_REMOVED = 16,
//        INC_TYPE_PREV_JUSTICE_REMOVED = 32
//      } inc_type;
      if (NEW_INI_ADDED) typeBitmap |= 1;
      if (NEW_SAFETY_ADDED) typeBitmap |= 2;
      if (NEW_JUSTICE_ADDED) typeBitmap |= 4;
      if (PREV_INI_REMOVED) typeBitmap |= 8;
      if (PREV_SAFETY_REMOVED) typeBitmap |= 16;
      if (PREV_JUSTICE_REMOVED) typeBitmap |= 32;
      
      return typeBitmap;
    }
    
    abstract public void setPrevFirstZIterMem(BDD[] prevFirstZIterMem);
    abstract public void setPrevZMemory(BDD[] prevMem);
    abstract public void setPrevXMem(BDD[][][] xMem);
    abstract public void setPrevMem(Vector<BDD> zMem, Vector<Vector<Vector<BDD>>> xMem);
    
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;

import java.util.ArrayList;
import java.util.List;

import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.Counter;
import tau.smlab.syntech.gameinput.model.DefineArray;
import tau.smlab.syntech.gameinput.model.ExistentialConstraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.model.Pattern;
import tau.smlab.syntech.gameinput.model.Predicate;
import tau.smlab.syntech.gameinput.model.RegexpTestModel;
import tau.smlab.syntech.gameinput.model.TriggerConstraint;
import tau.smlab.syntech.gameinput.model.WeightDefinition;
import tau.smlab.syntech.gameinput.spec.DefineReference;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.SpecHelper;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;
import tau.smlab.syntech.gameinputtrans.TranslationException;

/**
 * iterate over all specs (in guarantees, assumptions, auxiliary constraints,
 * weight definition, patterns?, predicates)
 * 
 * if spec contains a DefineReference replace it by the spec of the define
 * 
 * finally delete the list of defines
 * 
 * Depends on : VarIndexesTranslator, QuantifierTranslator
 *
 */

public class DefinesTranslator implements Translator {

	@Override
	public void translate(GameInput input) {

		if (noWorkToDo(input)) {
			return;
		}
		// guarantees
		for (Constraint c : input.getSys().getConstraints()) {
			c.setSpec(replaceDefines(c.getSpec(), c.getTraceId()));
		}

		// sys existential constraints
		for (ExistentialConstraint exC : input.getSys().getExistentialConstraints()) {
			if(exC.isRegExp()) {
				SpecRegExp regExp = exC.getRegExp();
				for(SpecRegExp predRegExp : regExp.getPredicateSubExps()) {
					predRegExp.setPredicate(replaceDefines(predRegExp.getPredicate(), 0));
				}
			}
			else {
				for(int i = 0; i < exC.getSize() ; i++) {
					exC.replaceSpec(i, replaceDefines(exC.getSpec(i), exC.getTraceId()));
				}
			}
		}
		
		// regexp tests
		for (RegexpTestModel reT : input.getRegtestExpressions()) {
			SpecRegExp regExp = reT.getRegExp();
			for(SpecRegExp predRegExp : regExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceDefines(predRegExp.getPredicate(), 0));
			}
		}
		
		// sys triggers
		replaceDefinesInTriggers(input.getSys().getTriggers());

		// assumptions
		for (Constraint c : input.getEnv().getConstraints()) {
			c.setSpec(replaceDefines(c.getSpec(), c.getTraceId()));
		}
		
		// env triggers
		replaceDefinesInTriggers(input.getEnv().getTriggers());

		// auxiliary constraints
		for (Constraint c : input.getAux().getConstraints()) {
			c.setSpec(replaceDefines(c.getSpec(), c.getTraceId()));
		}

		// weight definition
		for (WeightDefinition wd : input.getWeightDefs()) {
			Constraint c = wd.getDefinition();
			c.setSpec(replaceDefines(c.getSpec(), c.getTraceId()));
		}

		// patterns
		for (Pattern patt : input.getPatterns()) {
			for (Constraint c : patt.getExpressions()) {
				c.setSpec(replaceDefines(c.getSpec(), c.getTraceId()));
			}
		}

		// predicates
		for (Predicate pred : input.getPredicates()) {
			pred.setSpec(replaceDefines(pred.getExpression(), pred.getTraceId()));

		}
		
		for (Counter counter : input.getCounters()) {
			if (counter.getDecPred() != null) {
				counter.getDecPred().setContent(replaceDefines(counter.getDecPred().getContent(), counter.getTraceId()));
			}
			if (counter.getIncPred() != null) {
				counter.getIncPred().setContent(replaceDefines(counter.getIncPred().getContent(), counter.getTraceId()));
			}
			if (counter.getIniPred() != null) {
				counter.getIniPred().setContent(replaceDefines(counter.getIniPred().getContent(), counter.getTraceId()));
			}
			if (counter.getResetPred() != null) {
				counter.getResetPred().setContent(replaceDefines(counter.getResetPred().getContent(), counter.getTraceId()));
			}
		}

		// clear the list of the defines
		input.getDefines().clear();
	}

	private void replaceDefinesInTriggers(List<TriggerConstraint> moduleTriggers) {
		SpecRegExp initSpecRegExp, effectSpecRegExp;
		for(TriggerConstraint trigger : moduleTriggers) {
			initSpecRegExp = trigger.getInitSpecRegExp();
			for(SpecRegExp predRegExp : initSpecRegExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceDefines(predRegExp.getPredicate(), 0));
			}
			effectSpecRegExp = trigger.getEffectSpecRegExp();
			for(SpecRegExp predRegExp : effectSpecRegExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceDefines(predRegExp.getPredicate(), 0));
			}
		}
	}

	private boolean noWorkToDo(GameInput input) {
		return input.getDefines() == null || input.getDefines().isEmpty();
	}

	private Spec replaceDefines(Spec spec, int traceId) {
		if (spec instanceof DefineReference) {
			DefineReference dr = (DefineReference) spec;
			// important: spec = dr.getDefine().getExpression() isn't enough! there might be nested defines. 
			try {
				
				DefineReference newdr = dr.clone();

				if (newdr.getIndexSpecs() != null) {
					List<Spec> indexSpecs = new ArrayList<>();
					for (Spec indexSpec : newdr.getIndexSpecs()) {
						indexSpecs.add(replaceDefines(indexSpec, traceId));	
					}
					newdr.setIndexSpecs(indexSpecs);
				}
				
				// Single define
				if (newdr.getDefine().getExpression() != null) {
					newdr.getDefine().setExpression(replaceDefines(newdr.getDefine().getExpression(), traceId));
					return newdr.getDefine().getExpression();
				}
				
				// Multiple define
				newdr.getDefine().setDefineArray(replaceDefinesInDefineArrays(newdr.getDefine().getDefineArray(), traceId));
				
				if (newdr.getIndexVars().isEmpty()) {
					return extractSpecFromDefine(newdr.getIndexSpecs(), 0, newdr.getDefine().getDefineArray());
				}
				
				return newdr;
				
			} catch (Exception e) {
				throw new TranslationException(e.getMessage(), traceId);
			}
			
		} else if (spec instanceof SpecExp) {
			
			try {
				SpecExp se = ((SpecExp) spec).clone();
				for (int i = 0; i < se.getChildren().length; i++) {
					se.getChildren()[i] = replaceDefines(se.getChildren()[i], traceId);
				}
				
				return se;
			} catch (Exception e) {
				throw new TranslationException(e.getMessage(), traceId);
			}
		}
		return spec;
	}
	
	private Spec extractSpecFromDefine(List<Spec> indexSpec, int index, DefineArray defArray) throws Exception {
		
		Integer indexValue = SpecHelper.calculateSpec(indexSpec.get(index));
		
		if (index == indexSpec.size() - 1) {
			
			if (defArray.getExpressions() == null || defArray.getExpressions().size() == 0) {
				throw new Exception("Invalid access to a define array, too few []");
			}
			
			if (defArray.getExpressions().size() <= indexValue) {
				throw new Exception("Invalid access to a define array, out of bounds");
			}
			
			return defArray.getExpressions().get(indexValue);
		} else {
			
			if (defArray.getDefineArray() == null || defArray.getDefineArray().size() == 0) {
				throw new Exception("Invalid access to a define array, too many []");
			}
			
			if (defArray.getDefineArray().size() <= indexValue) {
				throw new Exception("Invalid access to a define array, out of bounds");
			}
			
			return extractSpecFromDefine(indexSpec, index + 1, defArray.getDefineArray().get(indexValue));
		}
	}
	
	private DefineArray replaceDefinesInDefineArrays(DefineArray defArray, int traceId) {

		List<Spec> newSpec = null;
		if (defArray.getExpressions() != null) {
			newSpec = new ArrayList<>();
			for (Spec exp : defArray.getExpressions()) {
				newSpec.add(replaceDefines(exp, traceId));
			}
		}
		
		List<DefineArray> newDefArray = null;
		if (defArray.getDefineArray() != null) {
			newDefArray = new ArrayList<>();
			for (DefineArray innerArray : defArray.getDefineArray()) {
				newDefArray.add(replaceDefinesInDefineArrays(innerArray, traceId));
			}
		}
		
		return new DefineArray(newSpec, newDefArray);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.symbolic;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;

import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.controller.jits.SymbolicControllerExistentialJitInfo;
import tau.smlab.syntech.games.controller.jits.SymbolicControllerJitInfo;
import tau.smlab.syntech.games.util.SaveLoadWithDomains;
import tau.smlab.syntech.jtlv.Env;

public class SymbolicControllerReaderWriter {
	
	protected final static String CONTROLLER_INIT = "controller.init.bdd";
	protected final static String CONTROLLER_TRANS = "controller.trans.bdd";
	protected final static String VARS = "vars.doms";
	
	protected final static String SIZES = "sizes";
	protected final static String EXT_SIZES = "existential_sizes";
	protected final static String FIXPOINTS = "fixpoints.bdd";
	protected final static String TRANS = "trans.bdd";
	protected final static String JUSTICE = "justice.bdd";
	
	protected final static String FULFILL = "fulfill.bdd";
	protected final static String TOWARDS = "towards.bdd";
	protected final static String ENV_VIOLATION = "envviolation.bdd";

	/**
	 * loads a symbolic controller from a file path
	 * 
	 * Also loads and creates all BDD variables needed for it!
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public static SymbolicController readSymbolicController(ObjectInputStream ois, BufferedReader initReader,
			BufferedReader transReader) throws IOException {

		// TODO: not implemented yet
		return null;
	}
	
	public static void writeSymbolicController(SymbolicController ctrl, GameModel model, String path, boolean reorderBeforeSave) throws IOException {
		writeSymbolicController(ctrl, model, path, null, reorderBeforeSave);
	}

	/**
	 * stores a symbolic controller to a file path
	 * 
	 * @param ctrl
	 * @param model
	 * @param path  needs to be a folder name (folder will be created if not exists)
	 * @param name  name of the controller
	 */
	public static void writeSymbolicController(SymbolicController ctrl, GameModel model, String path, String name, boolean reorderBeforeSave) throws IOException {

		// write the actual symbolic controller BDDs and doms

		Env.disableReorder();

		File folder = new File(path);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		
		String prefix;
		if (name == null) {
			prefix = path + File.separator;
		} else {
			prefix = path + File.separator + name + ".";
		}
		
		SaveLoadWithDomains.saveStructureAndDomains(prefix + VARS, model);

		Env.saveBDD(prefix + CONTROLLER_INIT, ctrl.initial(), reorderBeforeSave);
		Env.saveBDD(prefix + CONTROLLER_TRANS, ctrl.trans(), reorderBeforeSave);
	}
	
	public static void writeJitSymbolicController(SymbolicControllerJitInfo jitInfo, GameModel model, String path, boolean reorderBeforeSave) throws IOException {
		writeJitSymbolicController(jitInfo, model, path, null, reorderBeforeSave);
	}
	
	/**
	 * stores a symbolic controller just in time info to a file path
	 * 
	 * @param jitInfo
	 * @param model
	 * @param path
	 * @param name of the controller
	 * @param reorderBeforeSave
	 * @throws IOException
	 */
	public static void writeJitSymbolicController(SymbolicControllerJitInfo jitInfo, GameModel model, String path, String name, boolean reorderBeforeSave) throws IOException {
		
		File folder = new File(path);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		
		String prefix;
		if (name == null) {
			prefix = path + File.separator;
		} else {
			prefix = path + File.separator + name + ".";
		}
        
        FileWriter sizesWriter = new FileWriter(prefix + SIZES);
        sizesWriter.write(model.getSys().justiceNum() + System.lineSeparator() + model.getEnv().justiceNum() + System.lineSeparator());
        
        
        for (int j = 0; j < model.getSys().justiceNum(); j++) {
        	sizesWriter.write((jitInfo.ranks(j) - 1) + System.lineSeparator());
        }
        
        sizesWriter.close();
        
        SaveLoadWithDomains.saveStructureAndDomains(prefix + VARS, model);
        
        Env.saveBDD(prefix + FIXPOINTS, jitInfo.fixpoints(), reorderBeforeSave);
        Env.saveBDD(prefix + TRANS, jitInfo.safeties(), reorderBeforeSave);
        Env.saveBDD(prefix + JUSTICE, jitInfo.justices(), reorderBeforeSave);
        
        if (model.getSys().hasExistReqs()) {
        	
        	SymbolicControllerExistentialJitInfo extJitInfo = (SymbolicControllerExistentialJitInfo) jitInfo;
        	
            sizesWriter = new FileWriter(prefix + EXT_SIZES);
            
            sizesWriter.write(model.getSys().existReqNum() + System.lineSeparator());
            
            for (int exj = 0; exj < model.getSys().existReqNum(); exj++) {
            	sizesWriter.write((extJitInfo.fulfillRanks(exj) - 1) + System.lineSeparator());
            }
            for (int exj = 0; exj < model.getSys().existReqNum(); exj++) {
            	sizesWriter.write((extJitInfo.towardsRanks(exj) - 1) + System.lineSeparator());
            }
            
            sizesWriter.write(extJitInfo.envViolationRank() + System.lineSeparator());
            
            sizesWriter.close();
            
            Env.saveBDD(prefix + FULFILL, extJitInfo.fulfill(), reorderBeforeSave);
            Env.saveBDD(prefix + TOWARDS, extJitInfo.towards(), reorderBeforeSave);
            Env.saveBDD(prefix + ENV_VIOLATION, extJitInfo.envViolation(), reorderBeforeSave);
        }

	}
	
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.Counter;
import tau.smlab.syntech.gameinput.model.Define;
import tau.smlab.syntech.gameinput.model.DefineArray;
import tau.smlab.syntech.gameinput.model.ExistentialConstraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.model.Monitor;
import tau.smlab.syntech.gameinput.model.RegexpTestModel;
import tau.smlab.syntech.gameinput.model.TriggerConstraint;
import tau.smlab.syntech.gameinput.model.Variable;
import tau.smlab.syntech.gameinput.model.WeightDefinition;
import tau.smlab.syntech.gameinput.spec.MonitorReference;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;
import tau.smlab.syntech.gameinput.spec.VariableReference;

/**
 * This translator removes monitors from GameInput in two steps:
 * <ul>
 * <li>Translates monitors to auxiliary variables and adds auxiliary
 * constraints.</li>
 * <li>Replaces references to monitors by references to the auxiliary
 * variables.</li>
 * </ul>
 * 
 * The replacement must happen in all places where monitors could be referenced,
 * i.e., this code needs to know about other structures in the GameInput.
 *
 */
public class MonitorTranslator implements Translator {

	protected Map<String, List<Constraint>> monitorConstraints = new HashMap<>();;
	protected Map<String, Set<Integer>> traceIdsByMonitor = new HashMap<>();
	protected List<String> monitorNameList = new ArrayList<>();

	@Override
	public void translate(GameInput input) {

		if (noWorkToDo(input)) {
			return;
		}
		// translate monitors
		Map<String, Variable> monVars = translateMonitors(input);

		// replace the monitor references in
		// guarantees
		for (Constraint c : input.getSys().getConstraints()) {
			c.setSpec(replaceMonRefs(monVars, c.getSpec()));
		}

		// sys existential constraints
		for (ExistentialConstraint exC : input.getSys().getExistentialConstraints()) {
			if (exC.isRegExp()) {
				SpecRegExp regExp = exC.getRegExp();
				for (SpecRegExp predRegExp : regExp.getPredicateSubExps()) {
					predRegExp.setPredicate(replaceMonRefs(monVars, predRegExp.getPredicate()));
				}
			} else {
				for (int i = 0; i < exC.getSize(); i++) {
					exC.replaceSpec(i, replaceMonRefs(monVars, exC.getSpec(i)));
				}
			}
		}

		// regexp test
		for (RegexpTestModel reT : input.getRegtestExpressions()) {
			SpecRegExp regExp = reT.getRegExp();
			for (SpecRegExp predRegExp : regExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceMonRefs(monVars, predRegExp.getPredicate()));
			}
		}

		// sys triggers
		replaceMonRefsInTriggers(monVars, input.getSys().getTriggers());

		// assumptions
		for (Constraint c : input.getEnv().getConstraints()) {
			c.setSpec(replaceMonRefs(monVars, c.getSpec()));
		}

		// env triggers
		replaceMonRefsInTriggers(monVars, input.getEnv().getTriggers());

		// auxiliary constraints
		for (Constraint c : input.getAux().getConstraints()) {
			c.setSpec(replaceMonRefs(monVars, c.getSpec()));
		}

		// defines
		for (Define d : input.getDefines()) {
			if (d.getExpression() != null) {
				d.setExpression(replaceMonRefs(monVars, d.getExpression()));
			} else {
				d.setDefineArray(replaceMonitorInDefineArrays(monVars, d.getDefineArray()));
			}
		}

		// weight definition
		for (WeightDefinition wd : input.getWeightDefs()) {
			Constraint c = wd.getDefinition();
			c.setSpec(replaceMonRefs(monVars, c.getSpec()));
		}

		// counters
    for (Counter counter : input.getCounters()) {
      if (counter.getDecPred() != null) {
        counter.getDecPred().setContent(replaceMonRefs(monVars, counter.getDecPred().getContent()));
      }
      if (counter.getIncPred() != null) {
        counter.getIncPred().setContent(replaceMonRefs(monVars, counter.getIncPred().getContent()));
      }
      if (counter.getIniPred() != null) {
        counter.getIniPred().setContent(replaceMonRefs(monVars, counter.getIniPred().getContent()));
      }
      if (counter.getResetPred() != null) {
        counter.getResetPred().setContent(replaceMonRefs(monVars, counter.getResetPred().getContent()));
      }
    }
    
		input.getMonitors().clear();
	}

	/**
	 * replace the monitor references by references to the new variables
	 * 
	 * @param monVars
	 * @param spec
	 * @return
	 */
	private Spec replaceMonRefs(Map<String, Variable> monVars, Spec spec) {
		if (spec instanceof MonitorReference) {
			// replace monitor reference by aux var
			String name = ((MonitorReference) spec).getMonitor().getName();
			return new VariableReference(monVars.get(name));
		} else if (spec instanceof SpecExp) {
			// replace references in all children
			SpecExp se = (SpecExp) spec;
			for (int i = 0; i < se.getChildren().length; i++) {
				se.getChildren()[i] = replaceMonRefs(monVars, se.getChildren()[i]);
			}
		}
		// nothing to do
		return spec;
	}

	/**
	 * Translate all monitors by creating auxiliary variables and creating auxiliary
	 * constraints.
	 * 
	 * @param input
	 * @return
	 */
	private Map<String, Variable> translateMonitors(GameInput input) {

		Map<String, Variable> monVars = new HashMap<>();
		Set<Integer> traceIdsSet;
		List<Constraint> monConstList;

		for (Monitor mon : input.getMonitors()) {

			// maintain a list of all monitor names
			monitorNameList.add(mon.getName());

			// create auxiliary variable for monitor
			Variable v = new Variable(mon.getName(), mon.getType());
			input.getAux().addVar(v);
			monVars.put(mon.getName(), v);

			// maintain a traceIds set of the monitor's constraints
			traceIdsSet = new HashSet<>();
			traceIdsByMonitor.put(mon.getName(), traceIdsSet);

			// maintain a list of the monitor's constraints
			monConstList = new ArrayList<>();
			monitorConstraints.put(mon.getName(), monConstList);

			for (Constraint c : mon.getExpressions()) {
				// add monitoring constraints to AUX player
				input.getAux().addConstraint(c);

				// add the current constraint c and its traceId
				traceIdsSet.add(c.getTraceId());
				monConstList.add(c);
			}
		}
		return monVars;
	}

	public List<Constraint> getMonitorConstraints(String MonName) {
		return monitorConstraints.get(MonName);
	}

	public Set<Integer> getTraceIdsOfMonitor(String monName) {
		return traceIdsByMonitor.get(monName);
	}

	public List<String> getMonitorsNames() {
		return monitorNameList;
	}

	private DefineArray replaceMonitorInDefineArrays(Map<String, Variable> monVars, DefineArray defArray) {

		List<Spec> newSpec = null;
		if (defArray.getExpressions() != null) {
			newSpec = new ArrayList<>();
			for (Spec exp : defArray.getExpressions()) {
				newSpec.add(replaceMonRefs(monVars, exp));
			}
		}

		List<DefineArray> newDefArray = null;
		if (defArray.getDefineArray() != null) {
			newDefArray = new ArrayList<>();
			for (DefineArray innerArray : defArray.getDefineArray()) {
				newDefArray.add(replaceMonitorInDefineArrays(monVars, innerArray));
			}
		}

		return new DefineArray(newSpec, newDefArray);
	}

	private boolean noWorkToDo(GameInput input) {
		return input.getMonitors() == null || input.getMonitors().isEmpty();
	}

	private void replaceMonRefsInTriggers(Map<String, Variable> monVars, List<TriggerConstraint> moduleTriggers) {
		SpecRegExp initSpecRegExp, effectSpecRegExp;
		for (TriggerConstraint trigger : moduleTriggers) {
			initSpecRegExp = trigger.getInitSpecRegExp();
			for (SpecRegExp predRegExp : initSpecRegExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceMonRefs(monVars, predRegExp.getPredicate()));
			}
			effectSpecRegExp = trigger.getEffectSpecRegExp();
			for (SpecRegExp predRegExp : effectSpecRegExp.getPredicateSubExps()) {
				predRegExp.setPredicate(replaceMonRefs(monVars, predRegExp.getPredicate()));
			}
		}
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.enumerate;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Vector;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.games.AbstractGamesException;
import tau.smlab.syntech.jtlv.Env;

public class EnumStrategyImpl implements EnumStrategyI {

  // ////////////////////////////////////////////////////////////////////////
  // the instance implementation of the result.

  private Vector<EnumStateI> aut;
  private Map<AbstractRankInfo, BDD> statesOfRank;
  private Map<AbstractRankInfo, Map<BDD, EnumStateI>> allStatesOfRank;

  private long wakeup_time = -1;
  // updating the construction time every time something is changed
  // (getState, when new state needs to be created, and addNextState).
  private long construction_time = -1;
  
  private int numTransitions;
  private int lenLongestShortestPath;
  private int maxNumOutEdgesPerState;
  private int maxNumInEdgesPerState;
  private boolean calcLenLongestShortestPath;

  public EnumStrategyImpl() {
	  this(false);
  }
  
  public EnumStrategyImpl(boolean calcStats) {
    aut = new Vector<EnumStateI>();
    statesOfRank = new HashMap<AbstractRankInfo, BDD>();
    allStatesOfRank = new HashMap<>();
    wakeup_time = System.currentTimeMillis();
    numTransitions = 0;
    maxNumOutEdgesPerState = 0;
    maxNumInEdgesPerState = 0;
    calcLenLongestShortestPath = calcStats;
  }

  /**
   * looks up a state or adds it to the automaton
   * 
   * if the state is not already in the automaton it is created as an initial state
   */
  @Override
  public EnumStateI getState(BDD state, AbstractRankInfo rank) {
    EnumStateI s = lookUpState(state, rank);
    if (s != null)
      return s;
    // else need to create state
    EnumStateI res = new EnumStateImpl(this, aut.size(), true, state, rank);
    aut.add(res);
    addState(res);
    construction_time = System.currentTimeMillis() - wakeup_time;
    return res;
  }

  @Override
  public EnumStateI getState(int id) throws ArrayIndexOutOfBoundsException {
    return aut.get(id);
  }

  // when doing together we could save an exhaustive search here.
  // returns the newly created state id or -1 if no state was created
  @Override
  public EnumStateI addSuccessorState(EnumStateI from, BDD state,
      AbstractRankInfo rank) throws AbstractGamesException {
	from.incNumOutEdges();  
	this.maxNumOutEdgesPerState = Math.max(from.getNumOutEdges(), this.maxNumOutEdgesPerState);  
	  
    EnumStateI succ = lookUpState(state, rank);
    if (succ != null) {
      succ.incNumInEdges();
      this.maxNumInEdgesPerState = Math.max(succ.getNumInEdges(), this.maxNumInEdgesPerState);
      if (this.calcLenLongestShortestPath) {
    	  boolean updated = succ.updateDistFromIni(from.getDistFromIni());
    	  if (updated) {
    		  // this calculation can be expensive, which is why we only perform it when the user
    		  // explicitly states he requires it via calcLenLongestSimplePath flag
    		  LinkedList<EnumStateI> workList = new LinkedList<EnumStateI>();
    		  workList.add(succ);
    		  while (!workList.isEmpty()) {
    			  EnumStateI currSucc = workList.pop();
    			  Vector<EnumStateI> succs = currSucc.getSuccessors();
    			  for (EnumStateI elem: succs) {
    				  updated = elem.updateDistFromIni(currSucc.getDistFromIni());
    				  if (updated) {
    					  workList.add(elem);
    				  }
    			  }
    		  }
    	  }
      }
      this.lenLongestShortestPath = Math.max(succ.getDistFromIni(), this.lenLongestShortestPath);
      from.addSuccessor(succ);
      construction_time = System.currentTimeMillis() - wakeup_time;
      numTransitions++;
      return null;
    }
    // else succ not existent
    EnumStateI to = new EnumStateImpl(this, aut.size(), false, state, rank);
    aut.add(to);
    addState(to);
    to.incNumInEdges();
    this.maxNumInEdgesPerState = Math.max(to.getNumInEdges(), this.maxNumInEdgesPerState);
    if (this.calcLenLongestShortestPath) {
    	to.updateDistFromIni(from.getDistFromIni());
    	this.lenLongestShortestPath = Math.max(to.getDistFromIni(), this.lenLongestShortestPath);
    }
    
    from.addSuccessor(to);
    construction_time = System.currentTimeMillis() - wakeup_time;
    numTransitions++;
    return to;
  }

  /**
   * lookup a state we already created
   * 
   * @param state
   * @param rank
   * @return null if state is not found
   */
  private EnumStateI lookUpState(BDD state, AbstractRankInfo rank) {
    Map<BDD, EnumStateI> m = allStatesOfRank.get(rank);
    if (m != null) {
      EnumStateI s = m.get(state);
      return s;
    }
    return null;
  }

  /**
   * adds a state to statesOfRank and allStatesOfRank
   * 
   * @param s
   */
  private void addState(EnumStateI s) {
    AbstractRankInfo rank = s.get_rank_info();
    BDD sor = statesOfRank.get(rank);
    if (sor == null) {
      sor = Env.FALSE();
      statesOfRank.put(rank, sor);
    }
    sor.orWith(s.getData().id());

    Map<BDD, EnumStateI> m = allStatesOfRank.get(rank);
    if (m == null) {
      m = new HashMap<>();
      allStatesOfRank.put(rank, m);
    }
    m.put(s.getData(), s);
  }

  /**
   * for states with ReactiveRankInfo retrive all of given rank
   * 
   * @param sys_just
   * @return
   */
  public BDD getStatesOfRank(AbstractRankInfo rank) {
    if (statesOfRank.containsKey(rank)) {
      return statesOfRank.get(rank);
    }
    return Env.FALSE();
  }

  @Override
  public int numOfStates() {
    return this.aut.size();
  }

  @Override
  public long getConstructionTime() {
    return this.construction_time;
  }

  @Override
  public Vector<? extends StateI> getInitialStates() {
    Vector<StateI> ret = new Vector<StateI>();
    for (StateI st : enumController())
      if (st.isInitial())
        ret.add(st);
    return ret;
  }

  @Override
  public Vector<? extends StateI> getNextState(StateI st) {
    if (st instanceof EnumStateI)
      return ((EnumStateI) st).getSuccessors();
    return new Vector<StateI>();
  }

  @Override
  public Vector<? extends EnumStateI> enumController() {
    return aut;
  }

  @Override
  public Vector<? extends EnumStateI> enumController(StateI st) {
    return aut;
  }
  
  @Override
  public int numOfTransitions() {
	  return this.numTransitions;
  }
  
  @Override
  public int lenLongestShortestPath() {
	  return this.lenLongestShortestPath;
  }
  
  @Override
  public int maxNumOutEdgesPerState() {
	  return this.maxNumOutEdgesPerState;
  }
  
  @Override
  public int maxNumInEdgesPerState() {
	  return this.maxNumInEdgesPerState;
  }

  @Override
  public boolean isCalcStats() {
    return this.calcLenLongestShortestPath;
  }


}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.model;

import java.io.Serializable;
import java.util.List;

public class Monitor implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 6681607472181997841L;
	
	private int traceId;
	private String name;
	private TypeDef type;
	private List<Constraint> expressions;

	/**
	 * 
	 * @param name
	 * @param expressions
	 * @param traceId
	 */
	public Monitor(String name, TypeDef type, List<Constraint> expressions, int traceId)
	{
		this.name = name;
		this.expressions = expressions;
		this.traceId = traceId;
		this.type = type;
	}

	public int getTraceId() {
		return traceId;
	}

	public String getName() {
		return name;
	}

	public TypeDef getType() {
		return type;
	}

	public List<Constraint> getExpressions() {
		return expressions;
	}

	public void addExpressions(List<Constraint> exps) {
		this.expressions.addAll(exps);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.rabin;

import java.util.Vector;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.games.GameMemory;
import tau.smlab.syntech.jtlv.Env;

/**
 * winning staes of game memory are winning for the environment!
 *
 */
public class RabinMemory extends GameMemory {

	private Vector<BDD> zMem;
	private Vector<Vector<Vector<BDD>>> xMem;

	public RabinMemory() {
		zMem = new Vector<BDD>();
		xMem = new Vector<Vector<Vector<BDD>>>();
	}

	public RabinMemory(Vector<BDD> zMem, Vector<Vector<Vector<BDD>>> xMem) {
		this.zMem = zMem;
		this.xMem = xMem;
	}

	public int sizeZ() {
		return zMem.size();
	}

	public int sizeX(int cz, int k) {
		return xMem.get(cz).get(k).size();
	}

	public boolean addZ(BDD z) {
		return zMem.add(z);
	}

	public BDD getZ(int zi) {
		return zMem.get(zi);
	}

	public BDD getX(int layer, int justice, int xi) {
		return xMem.get(layer).get(justice).get(xi);
	}

	public void addXLayer(int width) {
		Vector<Vector<BDD>> layer = new Vector<Vector<BDD>>();
		for (int i = 0; i < width; i++)
			layer.add(new Vector<BDD>());
		xMem.add(layer);
	}

	/**
	 * deletes all vectors in the MOST RECENT x layer and frees their BDDs
	 */
	public void clearXLayer() {
		if (xMem != null && xMem.size() > 0) {
			Vector<Vector<BDD>> layer = xMem.lastElement();
			for (int i = 0; i < layer.size(); i++) {
				Env.free(layer.get(i));
				layer.get(i).clear();
			}
		}
	}

	public boolean addX(int justice, BDD x) {
		return xMem.lastElement().get(justice).add(x);
	}

	public int getZRank(BDD s) {
		for (int i = 0; i < zMem.size(); i++)
			if (!(zMem.get(i).and(s).isZero()))
				return i;
		throw new NullPointerException("the following state is not in the"
				+ " Z memory (is it winning for the environment?)\n" + Env.toNiceSignleLineString(s));
	}

	public int getXRank(int zRank, int k, BDD s) {
		// int zRank = getZRank(s);
		Vector<BDD> relevantMem = xMem.get(zRank).get(k);
		for (int i = 0; i < relevantMem.size(); i++)
			if (!(relevantMem.get(i).and(s).isZero()))
				return i;
		throw new NullPointerException("the following state is not in the" + " the X memory (something is wrong... )\n"
				+ Env.toNiceSignleLineString(s));
	}

	/**
	 * frees all BDDs in the x and z memory
	 */
	@Override
	public void free() {
		super.free();
		Env.free(xMem);
		Env.free(zMem);
	}

	public Vector<BDD> getZMem() {
		return zMem;
	}

	public Vector<Vector<Vector<BDD>>> getXMem() {
		return xMem;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

import java.util.Map;
import java.util.Map.Entry;

import net.sf.javabdd.ADD;
import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDFactory;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.jtlv.Env;

public abstract class AbstractADDAlgorithm {

	protected PlayerModule env;
	protected PlayerModule sys;
	protected Map<Integer, BDD> weights;

	public AbstractADDAlgorithm(PlayerModule env, PlayerModule sys, Map<Integer, BDD> weights) {
		this.env = env;
		this.sys = sys;
		this.weights = weights;
	}

	/**
	 * weighted arena
	 */
	private ADD arena;

	/**
	 * the winning region, consists of all states that are winning for the system
	 */
	private ADD winningRegion;

	/**
	 * the required energy level from states in the winning region
	 * 
	 */
	private ADD winningRegionEng;

	/**
	 * maximal initial energy (a bound for the algorithm)
	 */
	private double maxEng;

	public double getMaxEng() {
		return maxEng;
	}

	public void setMaxEng(double maxEng) {
		this.maxEng = maxEng;
	}

	public ADD getWeightedArena() {
		return this.arena;
	}

	public ADD getWinningRegion() {
		return this.winningRegion;
	}

	/**
	 * check that new energy values are the same as old energy values
	 * 
	 * @return
	 */
	protected boolean reachedFixPoint(ADD previous, ADD current) {
		if (current != null && previous != null) {
			return current.equals(previous);
		}
		return false;
	}

	protected void printInitialEnergy() {
		double[] initEngVals, engVals;
		ADD initStatesEng, nonInitStatesEng;
		ADD states = this.winningRegionEng;
		String printStr = "Winning region required energy levels";
		if (states != null) {
			initStatesEng = (ADD) (env.initial().and(sys.initial())).ite(states, Env.PLUS_INF());
			nonInitStatesEng = (ADD) (env.initial().and(sys.initial())).ite(Env.PLUS_INF(), states);
			engVals = nonInitStatesEng.getTerminalValues();
			initEngVals = initStatesEng.getTerminalValues();
			System.out.println("Initial states required energy levels:");
			for (int i = 0; i < initEngVals.length; i++) {
				if (initEngVals[i] != Env.PLUS_INF().getConstantValue()) {
					System.out.print(initEngVals[i] + ", ");
				}
			}
			System.out.println(System.lineSeparator());
			System.out.println(printStr);
			for (int i = 0; i < engVals.length; i++) {
				if (engVals[i] != Env.PLUS_INF().getConstantValue()) {
					System.out.print(engVals[i] + ", ");
				}
			}
			System.out.println(System.lineSeparator());
			initStatesEng.free();
		}
	}

	/**
	 * create arena with:
	 * <ul>
	 * <li>system deadlocks: -INF</li>
	 * <li>environment deadlocks: +INF</li>
	 * <li>all other transitions: weight as defined</li>
	 * <ul>
	 * 
	 * @return
	 */
	private ADD computeWeightedArena() {

		ADD deadlocks = (ADD) env.trans().ite(Env.MINUS_INF(), Env.PLUS_INF());

		ADD weightedArena = (ADD) Env.FALSE();
		for (Entry<Integer, BDD> w : weights.entrySet()) {
			ADD tmp = (ADD) w.getValue().ite(Env.CONST(w.getKey()), weightedArena);
			weightedArena.free();
			weightedArena = tmp;
		}

		BDD both = env.trans().and(sys.trans());
		arena = (ADD) both.ite(weightedArena, deadlocks);
		weightedArena.free();

		return arena;
	}

	public ADD computeWinningRegion() {

		this.arena = computeWeightedArena();

		winningRegionEng = computeWinningRegionEng();
		winningRegion = (ADD) toStates(winningRegionEng);

		return winningRegion;
	}

	protected BDD toStates(ADD s) {
		return s.toZeroOneSLTThreshold(Env.PLUS_INF().getConstantValue());
	}

	abstract protected ADD computeWinningRegionEng();

	/**
	 * computes the states from which the system can force to current on the given
	 * arena respecting the bound maxEng
	 * 
	 * @param current
	 * @param arena
	 * @return
	 */
	protected ADD cPre(ADD current) {
		ADD pCurrent = (ADD) Env.prime(current);

		ADD accEngByTarget = pCurrent.engSubtract(arena, maxEng);
		ADD accEngSysMin = accEngByTarget.abstractMin(sys.modulePrimeVars());
		ADD pre = accEngSysMin.abstractMax(env.modulePrimeVars());

		pCurrent.free();
		accEngByTarget.free();
		accEngSysMin.free();
		return pre;
	}

	public void free() {
		arena.free();
		winningRegion.free();
		winningRegionEng.free();
	}

	/**
	 * returns an ADD where states in BDD have value 0 and all others infinity
	 * 
	 * @param states
	 * @return
	 */
	protected ADD getADDForGoodStates(BDD states) {
		BDD neg = states.not();
		ADD res = ((ADD) neg).apply(Env.PLUS_INF(), BDDFactory.times);
		neg.free();
		return res;
	}

	/**
	 * intersection of sets of states represented by the ADD (implemented via
	 * maximum)
	 * 
	 * @param a1
	 * @param a2
	 * @return
	 */
	protected ADD inter(ADD a1, ADD a2) {
		return a1.apply(a2, BDDFactory.max);
	}

	/**
	 * intersection of sets of states represented by the ADD (implemented via
	 * maximum)
	 * 
	 * @param a1
	 * @param a2
	 * @return
	 */
	protected ADD interWith(ADD a1, ADD a2) {
		return a1.applyWith(a2, BDDFactory.max);
	}

	/**
	 * union of sets of states represented by the ADD (implemented via minimum)
	 * 
	 * @param a1
	 * @param a2
	 * @return
	 */
	protected ADD union(ADD a1, ADD a2) {
		return a1.apply(a2, BDDFactory.min);
	}

	/**
	 * union of sets of states represented by the ADD (implemented via minimum)
	 * 
	 * @param a1
	 * @param a2
	 * @return
	 */
	protected ADD unionWith(ADD a1, ADD a2) {
		return a1.applyWith(a2, BDDFactory.min);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.GameIncrementalMemory;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

public class GR1GameIncremental extends GR1GameImplC {

	protected BDD[] firstZIterMem;

	protected GR1GameIncrementalMemory incMem;

	// protected BDD startZ = null;
	// protected BDD[] prevZMem;
	// protected BDD[] prevFirstZIterMem;
	// protected BDD[][][] prevXMem;
	//
	// public boolean NEW_INI_ADDED = false;
	// public boolean NEW_SAFETY_ADDED = false;
	// public boolean NEW_JUSTICE_ADDED = false;
	// public boolean PREV_INI_REMOVED = false;
	// public boolean PREV_SAFETY_REMOVED = false;
	// public boolean PREV_JUSTICE_REMOVED = false;
	//
	// public int leastRemovedJusticeIdx = 0;

	public GR1GameIncremental(GameModel model) {
		super(model);
		incMem = new GR1GameIncrementalMemory();
	}

	// public void setStartZ(BDD startZ)
	// {
	// this.startZ = startZ;
	// }
	//
	// public void setPrevZMemory(BDD[] prevMem)
	// {
	// this.prevZMem = prevMem;
	// }
	//
	// public void setPrevFirstZIterMem(BDD[] prevFirstZIterMem)
	// {
	// this.prevFirstZIterMem = prevFirstZIterMem;
	// }
	//
	// public void setPrevXMem(BDD[][][] xMem)
	// {
	// this.prevXMem = xMem;
	// }

	public GameIncrementalMemory GetGameIncrementalMemory() {
		return incMem;
	}

	public BDD[] getZMemoryCopy() {
		return incMem.getZMemoryCopy(mem.z_mem, sys.justiceNum());
	}

	// public BDD[] getZMemoryCopy(BDD[] z_mem)
	// {
	// BDD[] z_mem_copy = new BDD[sys.justiceNum()];
	// for (int j = 0; j < z_mem.length; j++)
	// {
	// z_mem_copy[j] = z_mem[j].id();
	// }
	//
	// return z_mem_copy;
	// }

	public BDD[][][] getXMemoryCopy() {
		return incMem.getXMemoryCopy(mem.x_mem, 0, sys.justiceNum(), env.justiceNum());
	}

	// public BDD[][][] getXMemoryCopy(BDD[][][] x_mem, int x_currSize)
	// {
	// BDD[][][] x_mem_copy = new BDD[sys.justiceNum()][env.justiceNum()][];
	//
	// for (int j = 0; j < x_mem.length; j++)
	// {
	// for (int i = 0; i < x_mem[0].length; i++)
	// {
	// int cySize = x_mem[j][i].length;
	// if (x_currSize > cySize) cySize = x_currSize;
	// x_mem_copy[j][i] = new BDD[cySize];
	// for (int k = 0; k < x_mem[j][i].length; k++)
	// {
	// x_mem_copy[j][i][k] = x_mem[j][i][k].id();
	// }
	// }
	// }
	//
	// return x_mem_copy;
	// }

	public BDD[][] getPartialXMemoryCopy() {
		BDD[][] x_mem = new BDD[sys.justiceNum()][env.justiceNum()];
		for (int j = 0; j < sys.justiceNum(); j++) {
			for (int i = 0; i < env.justiceNum(); i++) {
				int lastXIdx = mem.x_mem[j][i].length - 1;
				x_mem[j][i] = mem.x_mem[j][i][lastXIdx].id();
			}
		}

		return x_mem;
	}

	public BDD[] getFirstZIterMem() {
		BDD[] z_mem_copy = new BDD[sys.justiceNum()];
		for (int j = 0; j < firstZIterMem.length; j++) {
			z_mem_copy[j] = firstZIterMem[j].id();
		}

		return z_mem_copy;
	}

	// public void addToStartZ(BDD z, int idx)
	// {
	// System.out.println("Add to startZ: startZ.isOne = " + startZ.isOne() +
	// ", segMem.zMem["+idx+"].isOne = " + z);
	// BDD tmp = startZ;
	// startZ = tmp.and(z);
	// tmp.free();
	// }

	@Override
	public boolean checkRealizability() {

		mem.x_mem = new BDD[sys.justiceNum()][env.justiceNum()][50];
		mem.y_mem = new BDD[sys.justiceNum()][50];
		mem.z_mem = new BDD[sys.justiceNum()];
		firstZIterMem = new BDD[sys.justiceNum()];

		int zIterCount = 0;
		@SuppressWarnings("unused")
		int yIterCount = 0;
		@SuppressWarnings("unused")
		int xIterCount = 0;

		if ((incMem.PREV_INI_REMOVED && !incMem.PREV_SAFETY_REMOVED && !incMem.PREV_JUSTICE_REMOVED)
				|| (incMem.NEW_INI_ADDED && !incMem.NEW_SAFETY_ADDED && !incMem.NEW_JUSTICE_ADDED)) {
			System.out.println("Only ini states changed: PREV_INI_REMOVED=" + incMem.PREV_INI_REMOVED
					+ ", NEW_INI_ADDED=" + incMem.NEW_INI_ADDED);
			BDD z = incMem.prevZMem[sys.justiceNum() - 1].id();
			mem.x_mem = incMem.getXMemoryCopy(incMem.prevXMem, 0, sys.justiceNum(), env.justiceNum());
			mem.z_mem = incMem.getZMemoryCopy(incMem.prevZMem, sys.justiceNum());
			firstZIterMem = incMem.getZMemoryCopy(incMem.prevFirstZIterMem, sys.justiceNum());

			mem.setWin(z);
			mem.setComplete(true);
			return sysWinAllInitial(z);
		}

		// if (!PREV_SAFETY_REMOVED && PREV_JUSTICE_REMOVED && leastRemovedJusticeIdx >
		// 0)
		// {
		// System.out.println("previous justice was removed, leastRemovedJusticeIdx = "
		// + leastRemovedJusticeIdx);
		//// mem.x_mem = new
		// BDD[sys.justiceNum()][env.justiceNum()][previousMem.x_mem.length];
		//// mem.y_mem = new BDD[sys.justiceNum()][previousMem.y_mem.length];
		//// mem.z_mem = new BDD[sys.justiceNum()];
		// for (int j = 0; j < leastRemovedJusticeIdx; j++)
		// {
		// mem.z_mem[j] = prevFirstZIterMem[j].id(); //previousMem.z_mem[j].id();
		// if (previousMem.y_mem[j].length / 50 > 1) {
		// mem.y_mem = mem.extend_size(mem.y_mem, previousMem.y_mem[j].length);
		// }
		// for (int k = 0; k < previousMem.y_mem[j].length; k++) {
		// mem.y_mem[j][k] = previousMem.y_mem[j][k].id();
		// }
		// for (int i = 0; i < env.justiceNum(); i++) {
		// if (previousMem.x_mem[j][i].length / 50 > 1) {
		// mem.x_mem = mem.extend_size(mem.x_mem, previousMem.x_mem[j][i].length);
		// }
		// for (int k = 0; k < previousMem.x_mem[j][i].length; k++) {
		// mem.x_mem[j][i][k] = previousMem.x_mem[j][i][k].id();
		// }
		// }
		// }
		// }

		// NOTE: The justices were removed only from the end of the list
		// if (!PREV_SAFETY_REMOVED && leastRemovedJusticeIdx == sys.justiceNum() &&
		// leastRemovedJusticeIdx != 0)
		// {
		// System.out.println("leastRemovedJusticeIdx = sys.justiceNum() = " +
		// leastRemovedJusticeIdx);
		// mem.setWin(mem.z_mem[sys.justiceNum() - 1]);
		// mem.setComplete(previousMem.isComplete());
		// mem.x_mem = mem.extend_size(mem.x_mem, 0);
		// mem.y_mem = mem.extend_size(mem.y_mem, 0);
		// //TODO: need to recompute or maybe not?
		// return sysWinAllInitial(mem.z_mem[sys.justiceNum() - 1]);
		// }

		BDD x = null, y, z;
		FixPoint iterZ, iterY, iterX;
		int cy = 0;

		boolean firstZItr = true;

		z = Env.TRUE();
		int jStartIdx = 0;

		// if (!PREV_SAFETY_REMOVED && PREV_JUSTICE_REMOVED && leastRemovedJusticeIdx >
		// 0)
		// {
		// System.out.println("previous justice was removed, leastRemovedJusticeIdx = "
		// + leastRemovedJusticeIdx);
		// for (int j = 0; j < leastRemovedJusticeIdx; j++)
		// {
		// mem.z_mem[j] = prevFirstZIterMem[j].id();
		// firstZIterMem[j] = prevFirstZIterMem[j].id();
		// }
		//
		// z = prevFirstZIterMem[leastRemovedJusticeIdx-1];
		// jStartIdx = leastRemovedJusticeIdx;
		// }

		if (incMem.NEW_JUSTICE_ADDED && !incMem.NEW_SAFETY_ADDED && sys.justiceNum() != 1) {
			System.out.println("New justice(s) was added, to an existing list of justices, "
					+ "current sys.justiceNum() = " + sys.justiceNum());
			jStartIdx = incMem.prevZMem.length;
			mem.z_mem = incMem.getZMemoryCopy(incMem.prevZMem, sys.justiceNum());
			// mem.x_mem = getXMemoryCopy(prevXMem, 50);
			for (int j = 0; j < incMem.prevXMem.length; j++) {
				for (int i = 0; i < incMem.prevXMem[j].length; i++) {
					for (int k = 0; k < incMem.prevXMem[j][i].length; k++) {
						mem.x_mem[j][i][k] = incMem.prevXMem[j][i][k].id();
					}
				}
			}

			firstZIterMem = incMem.getZMemoryCopy(incMem.prevFirstZIterMem, sys.justiceNum());
			z = incMem.prevZMem[incMem.prevZMem.length - 1];
			System.out.println(
					"New justice was added, starting from jStartIdx=" + jStartIdx + " and z.isOne=" + z.isOne());
		} else if (incMem.NEW_JUSTICE_ADDED || incMem.NEW_SAFETY_ADDED) {
			System.out.println("use startZ");
			z = incMem.startZ;
		}

		System.out.println("is starting Z from One = " + z.isOne());

		for (iterZ = new FixPoint(false); iterZ.advance(z);) {
			zIterCount++;

			System.out.println("sys.justiceNum() = " + sys.justiceNum());

			if (firstZItr && !incMem.PREV_SAFETY_REMOVED && incMem.PREV_JUSTICE_REMOVED
					&& incMem.leastRemovedJusticeIdx > 0) {
				System.out.println(
						"previous justice was removed, leastRemovedJusticeIdx = " + incMem.leastRemovedJusticeIdx);
				for (int k = 0; k < incMem.leastRemovedJusticeIdx; k++) {
					mem.z_mem[k] = incMem.prevFirstZIterMem[k].id();
					firstZIterMem[k] = incMem.prevFirstZIterMem[k].id();
				}
				if (z != null)
					z.free();
				z = incMem.prevFirstZIterMem[incMem.leastRemovedJusticeIdx - 1];
				jStartIdx = incMem.leastRemovedJusticeIdx;
				System.out.println("starting first z iteration from jStartIdx = " + jStartIdx);
			}

			for (int j = jStartIdx; j < sys.justiceNum(); j++) {
				System.out.println("j = " + j);
				cy = 0;
				y = Env.FALSE();

				if (incMem.PREV_SAFETY_REMOVED && !incMem.PREV_JUSTICE_REMOVED) {
					System.out.println("use prevZMem[" + j + "] for current Y");
					y = incMem.prevZMem[j].id();
					if (y.isZero()) {
						System.out.println("Y = FALSE");
					}
				}

				BDD yieldToJ = sys.justiceAt(j).id().andWith(env.yieldStates(sys, z));

				for (iterY = new FixPoint(false); iterY.advance(y);) {
					yIterCount++;
					BDD start = yieldToJ.id().orWith(env.yieldStates(sys, y));

					y = Env.FALSE();

					for (int i = 0; i < env.justiceNum(); i++) {
						BDD negp = env.justiceAt(i).not();
						if (x != null) {
							x.free();
						}

						if (incMem.NEW_SAFETY_ADDED && j < incMem.prevXMem.length /* prevPartialXMem.length */) {
							System.out.println("use prevXMem[" + j + "][" + i + "][" + cy + "] for current X");
							int k = cy;
							if (incMem.prevXMem[j][i].length <= cy) {
								System.out.println("\tprevXMem[j][i].length = " + incMem.prevXMem[j][i].length + " <= "
										+ cy + " = cy");
								k = incMem.prevXMem[j][i].length - 1;
							}

							x = incMem.prevXMem[j][i][k].and(z.id());

							// NOTE: log for checks
							// System.out.println("\tx.isOne = " + x.isOne());
							// System.out.println("\tz.isOne = " + z.isOne());
							// System.out.println("\tprevXMem.isOne = " + prevXMem[j][i][k].isOne());
							// System.out.println("\tx in z = " + z.and(x).equals(x));
							// System.out.println("\tz in x = " + z.and(x).equals(z));
							// System.out.println("\tz equals x = " + z.equals(x));

							// if (prevPartialXMem[j][i] == null) {
							// System.out.println("\tis null, can't use it");
							// x = z.id();
							// } else {
							// x = prevPartialXMem[j][i].and(z.id());
							// System.out.println("\tx.isOne = " + x.isOne());
							// System.out.println("\tz.isOne = " + z.isOne());
							// System.out.println("\tprevPartialXMem[j][i].isOne = " +
							// prevPartialXMem[j][i].isOne());
							// if (z.equals(prevPartialXMem[j][i]))
							// {
							// System.out.println("\tequals current z");
							// }
							// if (z.equals(x))
							// {
							// System.out.println("\tx equals current z - prevPartialXMem did not minimized
							// the possible states");
							// }
							// }
						} else {
							x = z.id();
						}
						for (iterX = new FixPoint(false); iterX.advance(x);) {
							xIterCount++;
							BDD sysCtrl = env.yieldStates(sys, x);
							BDD sysCtrlAndNotJustice = sysCtrl.and(negp);
							sysCtrl.free();
							x = sysCtrlAndNotJustice.or(start);
							sysCtrlAndNotJustice.free();
						}

						// NOTE: log for checks
						// if (NEW_SAFETY_ADDED && j < prevXMem.length ) {
						// int k = cy;
						// if (prevXMem[j][i].length <= cy) k = prevXMem[j][i].length - 1;
						//
						// System.out.println("\tx new fixed point: x.isOne = " + x.isOne());
						// System.out.println("\tx new fixed point: x in prev x = " +
						// x.and(prevXMem[j][i][k]).equals(x));
						// System.out.println("\tx new fixed point: x in prev x.and(z) = "
						// + x.and((prevXMem[j][i][k].and(z.id()))).equals(x));
						// }

						// System.out.println("x iters # " + xIterCount);
						xIterCount = 0;

						mem.x_mem[j][i][cy] = x.id();
						BDD oy = y;
						y = y.or(x);
						oy.free();
					}
					start.free();
					mem.y_mem[j][cy] = y.id();
					cy++;
					if (cy % 50 == 0) {
						mem.x_mem = mem.extend_size(mem.x_mem, cy);
						mem.y_mem = mem.extend_size(mem.y_mem, cy);
					}
				}

				for (int i = 0; i < env.justiceNum(); i++) {
					for (int k = cy; k < mem.x_mem[j][i].length; k++) {
						mem.x_mem[j][i][k] = null;
					}
				}
				for (int k = cy; k < mem.y_mem[j].length; k++) {
					mem.y_mem[j][k] = null;
				}

				// System.out.println("y iters # " + yIterCount);
				yIterCount = 0;

				z = y.id();
				if (DETECT_FIX_POINT_EARLY && !firstZItr) {
					// check if we will reach a fix-point after the end of this iteration
					if (mem.z_mem[j].equals(z)) {
						z.free();
						z = mem.z_mem[sys.justiceNum() - 1].id();
						break;
					}
				}

				mem.z_mem[j] = z.id();
				if (firstZItr) {
					firstZIterMem[j] = z.id();
				}

				yieldToJ.free();
			}

			jStartIdx = 0;
			if (firstZItr) {
				firstZItr = false;
			}
		}

		System.out.println("z iters # " + zIterCount);

		mem.x_mem = mem.extend_size(mem.x_mem, 0);
		mem.y_mem = mem.extend_size(mem.y_mem, 0);

		mem.setWin(z);
		mem.setComplete(true);
		return sysWinAllInitial(z);
	}

	@Override
	public void free() {
		Env.free(firstZIterMem);
		mem.free();
	}

	public boolean sysWinAllInitial() {
		return this.sysWinAllInitial(mem.getWin());
	}

	public BDD sysWinningStates() {
		return mem.getWin();
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel.util;

import java.util.ArrayList;
import java.util.List;

import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;

/**
 * This is an abstract base class for building games based on lists of traces
 * 
 * @author shalom
 *
 */
public abstract class TraceInfoBuilder {

	protected GameModel gm = null;
	protected List<BehaviorInfo> env = null;
	protected List<BehaviorInfo> sys = null;
	protected List<BehaviorInfo> aux = null;
	
	List<Integer> traceList = null;
	
	public TraceInfoBuilder(GameModel gm) {
		this.gm = gm;
		env = new ArrayList<BehaviorInfo>(gm.getEnvBehaviorInfo());
		sys = new ArrayList<BehaviorInfo>(gm.getSysBehaviorInfo());
		aux = new ArrayList<BehaviorInfo>(gm.getAuxBehaviorInfo());
		createTraceList();
	}
	
	/**
	 * return the list of all traces which are relevant to the module
	 */
	public List<Integer> getTraceList() {
		return traceList;
	}
	
	/**
	 * restore the modle according to original traces
	 * 
	 * @return restored model
	 */
	public GameModel restore() {
		GameBuilderUtil.buildEnv(gm, env);
		
		List<BehaviorInfo> gameAux = gm.getAuxBehaviorInfo();
		gameAux.clear();
		gameAux.addAll(aux);	
		GameBuilderUtil.buildSys(gm, sys);
		
		return gm;
	}
	
	/**
	 * create a list of all traces which are relevant to the module
	 */
	protected abstract void createTraceList();
	
	/**
	 * Build and return a model based on the one in the class which according to the subset of the trace list
	 * @param taken
	 * @return
	 */
	public abstract GameModel build(List<Integer> taken);
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

public enum GR1StrategyType {
	ZYX, ZXY, YZX, YXZ, XZY, XYZ;

	/**
	 * 3 - Z Y X.<br>
	 * 7 - Z X Y.<br>
	 * 11 - Y Z X.<br>
	 * 15 - Y X Z.<br>
	 * 19 - X Z Y.<br>
	 * 23 - X Y Z.<br>
	 * 
	 * @param st_kind
	 * @return
	 */
	public int old_value() {
		switch (this) {
		case ZYX:
			return 3;
		case ZXY:
			return 7;
		case YZX:
			return 11;
		case YXZ:
			return 15;
		case XZY:
			return 19;
		case XYZ:
			return 23;
		default:
			break;
		}
		return -1;
	}

	public int hashValue() {
		return old_value();
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.logs;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.jtlv.CoreUtil;
import tau.smlab.syntech.jtlv.Env;

public class BDDLogWriter {

  private BufferedWriter writer;
  private BDDVarSet vars;

  /**
   * by default logging all unprimed vars
   * 
   * @param fileName
   * @throws IOException
   */
  public BDDLogWriter(String fileName) throws IOException {
    this.writer = initWriter(fileName);
    this.vars = Env.globalUnprimeVars();
  }

  public BDDLogWriter(String fileName, BDDVarSet vars) throws IOException {
    this.writer = initWriter(fileName);
    this.vars = vars;
  }

  /**
   * create new buffered writer
   * 
   * @param fileName
   * @return
   * @throws IOException
   */
  private BufferedWriter initWriter(String fileName) throws IOException {
    return new BufferedWriter(new FileWriter(fileName));
  }

  /**
   * write the BDD to the log
   * 
   * if the BDD has more than one assignment, writes one of them, if the BDD has no assignments writes FALSE
   * 
   * @param entry
   * @throws IOException
   */
  public void write(BDD entry) throws IOException {
    if (entry.isZero()) {
      writer.write("FALSE");
    } else if (entry.satCount() > 1 && !vars.isEmpty()) {
      BDD one = CoreUtil.satOne(entry, vars);
      writer.write(one.toStringWithDomains(Env.stringer));
      one.free();
    } else if (vars.isEmpty() && !entry.isZero()) {
      writer.write("TRUE");
    } else {
      writer.write(entry.toStringWithDomains(Env.stringer));
    }
    writer.newLine();
    writer.flush();
  }

  /**
   * closes the file
   * 
   * @throws IOException
   */
  public void close() throws IOException {
    writer.close();
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.enumerate;

import java.util.Vector;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.games.AbstractGamesException;
import tau.smlab.syntech.games.GamesStrategyException;

public class EnumStateImpl implements EnumStateI {
	private EnumStrategyI holder;
	private int id;
	private boolean ini;
	private AbstractRankInfo just;
	private BDD state;
	private Vector<EnumStateI> succ;
	
	private int numInEdges;
	private int numOutEdges;
	private int distFromIni;

	public EnumStateImpl(EnumStrategyI holder, int id, boolean ini, BDD state,
			AbstractRankInfo just) {
		this.holder = holder;
		this.id = id;
		this.ini = ini;
		this.state = state;
		this.just = just;
		this.succ = new Vector<EnumStateI>(10);
		this.numInEdges = 0;
		this.numOutEdges = 0;
		this.distFromIni = 0;
	}

	@Override
	public void addSuccessor(StateI add) throws AbstractGamesException {
		if (!(add instanceof EnumStateI))
			throw new GamesStrategyException("Cannot add successor from"
					+ " different type");
		succ.add((EnumStateI) add);
	}

	@Override
	public EnumStrategyI getHolder() {
		return this.holder;
	}

	@Override
	public int getStateId() {
		return this.id;
	}

	@Override
	public AbstractRankInfo get_rank_info() {
		return this.just;
	}

	@Override
	public Vector<EnumStateI> getSuccessors() {
	  return this.succ;
	}

	@Override
	public boolean equals(Object other) {
		if (!(other instanceof EnumStateImpl))
			return false;
		EnumStateImpl other_raw = (EnumStateImpl) other;

		return ((this.just == other_raw.just) && (this.ini == other_raw.ini) && (this.state
				.equals(other_raw.state)));
	}
	
	@Override
	public int hashCode() {
		return this.just.hashCode() * this.state.hashCode() + (this.ini?1:0);
	}

	@Override
	public boolean isInitial() {
		return this.ini;
	}

	@Override
	public BDD getData() {
		return this.state;
	}
	
	@Override
	public int getNumOutEdges() {
		return this.numOutEdges;
	}
	
	@Override
	public int getNumInEdges() {
		return this.numInEdges;
	}

	@Override
    public int getDistFromIni() {
		return this.distFromIni;
    }
	
	@Override
	public void incNumOutEdges() {
		this.numOutEdges++;
	}

	@Override
	public void incNumInEdges() {
		this.numInEdges++;
	}
	
	@Override
	public boolean updateDistFromIni(int neighborDist) {
		if (isInitial()) {
			return false;
		}
		if (this.distFromIni == 0) {
			this.distFromIni = neighborDist + 1;
			return true;
		}
		if (this.distFromIni > neighborDist + 1) {
			this.distFromIni = neighborDist + 1;
			return true;
		}
		
		return false;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Player implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -5085525976634287802L;
	
	private List<Variable> vars = new ArrayList<>();
	private List<Constraint> constraints = new ArrayList<>();
	private List<PatternConstraint> patterns = new ArrayList<>();
	private List<TriggerConstraint> triggers = new ArrayList<>();
	private List<ExistentialConstraint> existentialConstraints = new ArrayList<>();

	public Player() {
		this.vars = new  ArrayList<>();
		this.constraints = new ArrayList<>();
		this.patterns = new ArrayList<>();
		this.triggers = new ArrayList<>();
		this.existentialConstraints = new ArrayList<>();
	}

	public String toString()
	{
		return "Player:[vars: " + vars + " constraints: " + constraints + "patterns: " + patterns+"]";
	}
	public List<Variable> getVars() {
		return vars;
	}

	public void setVars(List<Variable> vars) {
		this.vars = vars;
	}

	public List<Constraint> getConstraints() {
		return constraints;
	}

	public void setConstraints(List<Constraint> constraints) {
		this.constraints = constraints;
	}

	public List<PatternConstraint> getPatterns() {
		return patterns;
	}

	public void setPatterns(List<PatternConstraint> patterns) {
		this.patterns = patterns;
	}

	public void setExistentialConstraints(List<ExistentialConstraint> existentialConstraints) {
		this.existentialConstraints = existentialConstraints;
	}

	public List<ExistentialConstraint> getExistentialConstraints() {
		return existentialConstraints;
	}

	public void addVar(Variable variable)
	{
		this.vars.add(variable);
	}

	public void addConstraint(Constraint constraint)
	{
		this.constraints.add(constraint);
	}

	public void addPatternConstraint(PatternConstraint patternConstraint)
	{
		this.patterns.add(patternConstraint);
	}

	public void addExistentialConstraint(ExistentialConstraint existentialConstraint)
	{
		this.existentialConstraints.add(existentialConstraint);
	}

	public void addTrigger(TriggerConstraint trigger) {
		this.triggers.add(trigger);
	}

	public List<TriggerConstraint> getTriggers() {
		return triggers;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

/**
 * <p>
 * Specification expression.
 * </p>
 * 
 * @author <NAME>.
 * 
 */
public class SpecExp implements Spec {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6833233099417793276L;
	
	private Operator theOp;
	private Spec[] elements;

	/**
	 * <p>
	 * Constructor for an unary specification.
	 * </p>
	 * 
	 * @param op
	 *          The operator.
	 * @param e1
	 *          The sub specification.
	 */
	public SpecExp(Operator op, Spec e1) {
		this.theOp = op;
		this.elements = new Spec[] { e1 };
	}

	public SpecExp(Operator op, SpecWrapper e1) {
		this(op, e1.getSpec());
	}

	/**
	 * <p>
	 * Constructor for a binary specification.
	 * </p>
	 * 
	 * @param op
	 *          The operator.
	 * @param e1
	 *          The first sub specification.
	 * @param e2
	 *          The second sub specification.
	 */
	public SpecExp(Operator op, Spec e1, Spec e2) {
		this.theOp = op;
		this.elements = new Spec[] { e1, e2 };
	}

	public SpecExp(Operator op, SpecWrapper e1, SpecWrapper e2) {
		this(op, e1.getSpec(), e2.getSpec());
	}

	public String toString() {
		if (this.theOp.isUnary()) {
			return theOp.toString() + "(" + elements[0].toString() + ")";
		} else {
			return elements[0].toString() + " " + theOp.toString() + " " + elements[1].toString();
		}
	}

	/**
	 * <p>
	 * The operator representing this node.
	 * </p>
	 * 
	 * @return An operator representing this node.
	 */
	public Operator getOperator() {
		return theOp;
	};

	/**
	 * <p>
	 * Get the children specification of this node.
	 * <p>
	 * 
	 * @return The children specification.
	 */
	public Spec[] getChildren() {
		return this.elements;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.wis.jtlv.env.spec.Spec#isPastLTLSpec()
	 */
	public boolean isPastLTLSpec() {
		// checking that all children are prop.
		for (Spec s : this.getChildren()) {
			if (s.isPastLTLSpec()) {
				return true;
			}
		}
		// checking that I'm prop or pastLTL
		return this.getOperator().isPastLTLOp();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.wis.jtlv.env.spec.Spec#isPropSpec()
	 */
	public boolean isPropSpec() {
		// checking that all children are prop.
		for (Spec s : this.getChildren())
			if (!s.isPropSpec()) {
				System.out.println("I am operator " + getOperator().name() + " and child " + s.toString() + " returned false");
				return false;
			}
		// checking that I'm prop
		return this.getOperator().isProp();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.wis.jtlv.env.spec.Spec#hasTemporalOperators()
	 */
	public boolean hasTemporalOperators() {
		// if one of my elements is temporal.
		for (Spec s : this.getChildren())
			if (s.hasTemporalOperators())
				return true;
		// or I'm temporal.
		return this.theOp.isTemporalOp();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object other) {
		if (!(other instanceof SpecExp))
			return false;
		SpecExp otherExp = (SpecExp) other;
		if (this.getOperator() != otherExp.getOperator())
			return false;

		Spec[] this_children = this.getChildren();
		Spec[] other_children = otherExp.getChildren();
		if (this_children.length != other_children.length)
			return false;

		for (int i = 0; i < this_children.length; i++)
			if (!this_children[i].equals(other_children[i]))
				return false;

		return true;
	}

	public SpecExp clone() throws CloneNotSupportedException {
		int elementsSize = this.elements.length;
		if (elementsSize == 1) {
			return new SpecExp(this.theOp, this.elements[0].clone());
		} else {
			return new SpecExp(this.theOp, this.elements[0].clone(), this.elements[1].clone());
		}
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel.util;

import java.util.ArrayList;
import java.util.List;

import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;

/**
 * This class finds and builds game models according to traces of system behaviors
 * Auxiliary behaviors not attached to system or environment (like monitors, counters) count as system
 * 
 * @author shalom
 *
 */

public class SysTraceInfoBuilder extends TraceInfoBuilder {
	public SysTraceInfoBuilder(GameModel gm) {
		super(gm);
	}
	
	public GameModel build(List<Integer> taken) {
		// make sure that we ask only for listed behaviors. All non listed are taken
		assert(traceList.containsAll(taken));
		
		List<BehaviorInfo> gameSys = new ArrayList<BehaviorInfo>();
		
		for (BehaviorInfo bi : sys) {
			if (!traceList.contains(bi.traceId) || taken.contains(bi.traceId)) {
				gameSys.add(bi);
			}
		}
		
		List<BehaviorInfo> gameAux = gm.getAuxBehaviorInfo();
		gameAux.clear();
		for (BehaviorInfo bi : aux) {
			if (!traceList.contains(bi.traceId) || taken.contains(bi.traceId)) {
				gameAux.add(bi);
			}
		}		
		
		GameBuilderUtil.buildSys(gm, gameSys);
		return gm;
		
	}
	
	protected void createTraceList() {
		TraceIdentifier iden = new TraceIdentifier(gm);
		traceList = iden.getSysTraces();
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.logs.BDDLogWriter;

public class LoggingController extends AbstractController {

	private BDDLogWriter log;
	
	public LoggingController(Controller controller) {
		super(controller);
	}

	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
		
		controller.load(folder, name, sysVars, envVars);
		
		// Creates folder ./logs if it doesn't exist. Prepares the log object to write a BDD log
		File lp = new File("logs");
		if (!lp.exists()) {
			lp.mkdir();
		}
		String ts = "" + System.currentTimeMillis();
		String logName = lp.getPath() + "/" + ts + ".gol";
		try {
			log = new BDDLogWriter(logName, Env.globalUnprimeVars());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public BDD next(BDD currentState, BDD inputs) {
		
		BDD nextStates = controller.next(currentState, inputs);
		
		//try to log the current state
		try {
			log.write(currentState);
		} catch (IOException e) {
			System.err.println("There was an error writing to log during controller execution: " + e.getMessage());
		}
		
		return nextStates;
	}

	@Override
	public void init(BDD currentState) {
		controller.init(currentState);
	}

	@Override
	public void saveState() {
		controller.saveState();
		
	}

	@Override
	public void loadState() {
		controller.loadState();
	}

	@Override
	public BDD kSucc(BDD from, int k) {
		return controller.kSucc(from, k);
	}
	
	@Override
	public BDD kPred(BDD to, int k) {
		return controller.kPred(to, k);
	}

	@Override
	public BDD succ(BDD from) {
		return controller.succ(from);
	}

	@Override
	public BDD pred(BDD to) {
		return controller.pred(to);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package net.sf.javabdd;

import java.util.List;

import net.sf.javabdd.BDDFactory.ReorderMethod;

public class CUDDPipeCallerMethodInfo {

  public static final int MAX_METHOD_ARGS = 8;  /*maximum number of arguments that all library functions have*/
  
  public static class ReturnValue<T> {

    protected T value;

    public ReturnValue() {
      this.value = null;
    }

    public ReturnValue(T value) {
      this.value = value;
    }

    public void setValue(T value) {
      this.value = value;
    }

    public T getValue() {
      return this.value;
    }
  }

  public static class ReturnIntValue extends 
  ReturnValue <Integer> {

    public ReturnIntValue(int val) {
      this.value = val;
    }

  }

  public static class ReturnLongValue extends 
  ReturnValue <Long> {

    public ReturnLongValue(long val) {
      this.value = val;
    }
  }

  public static class ReturnBooleanValue extends 
  ReturnValue <Boolean> {

    public ReturnBooleanValue(boolean val) {
      this.value = val;
    }
  }

  public static class ReturnDoubleValue extends 
  ReturnValue <Double> {

    public ReturnDoubleValue(double val) {
      this.value = val;
    }
  }

  public static class ReturnReorderMethodValue extends 
  ReturnValue <ReorderMethod> {

    public ReturnReorderMethodValue(ReorderMethod val) {
      this.value = val;
    }
  }

  public static class ReturnIntListValue extends 
  ReturnValue <List<Integer>> {

    public ReturnIntListValue(List<Integer> val) {
      this.value = val;
    }

    public int[] toPrimitiveIntArray() {
      int size = this.value.size();
      Integer[] arr = new Integer[size];
      this.value.toArray(arr);
      int[] converted =  new int[size];
      for(int i = 0; i < size; i++) {
        converted[i] = arr[i];
      }
      return converted;
    }

  }

  public static class ReturnLongListValue extends 
  ReturnValue <List<Long>> {

    public ReturnLongListValue(List<Long> val) {
      this.value = val;
    }
  }

  public static class ReturnDoubleListValue extends 
  ReturnValue <List<Double>> {

    public ReturnDoubleListValue(List<Double> val) {
      this.value = val;
    }
  }


  
  public static enum ReturnType {
	    BOOLEAN(0,4), INTEGER(1,4), LONG(2,8),  DOUBLE(3,8), VOID(4,4), INT_LIST(5,4), LONG_LIST(6,8), DOUBLE_LIST(7,8), REORDER_METHOD(8,4);

	    private final int id;
	    private final int numBytes;
	    private ReturnType(int id, int numBytes) {
	        this.id = id;
	        this.numBytes = numBytes;
	    }

	    public int getId() {
	        return id;
	    }
	    public int getnumBytes() {
	        return numBytes;
	    }
	    
	    public static ReturnType resolveReturnType(Class<?> type) {
	      if(type.equals(Boolean.class) || type.equals(boolean.class)) {
	        return BOOLEAN;
	      }
	      if(type.equals(Integer.class) || type.equals(int.class)) {
          return INTEGER;
        }
	      if(type.equals(Long.class) || type.equals(long.class)) {
          return LONG;
        }
	      if(type.equals(Double.class) || type.equals(double.class)) {
          return DOUBLE;
        }
	      if(type.equals(Integer[].class) || type.equals(int[].class)) {
          return INT_LIST;
        }
	      if(type.equals(Long[].class) || type.equals(long[].class)) {
          return LONG_LIST;
        }
	      if(type.equals(Double[].class) || type.equals(double[].class)) {
          return DOUBLE_LIST;
        }
	      if(type.equals(ReorderMethod.class)) {
          return REORDER_METHOD;
        }
	      return VOID;
	    }
	    
	}


  public static enum MethodEntry {

    INITIALIZE0("initialize0", 1, 2, ReturnType.LONG_LIST),
    IS_INITIALIZED0("isInitialized0", 2, 0, ReturnType.BOOLEAN),
    DONE0("done0", 3, 0, ReturnType.VOID),
    VAR_NUM0("varNum0", 4, 0, ReturnType.INTEGER),
    GET_SIZE0("getSize0", 5, 1, ReturnType.INTEGER),
    SET_VAR_NUM0("setVarNum0", 6, 2, ReturnType.INTEGER),
    ITH_VAR0("ithVar0", 7, 2, ReturnType.LONG),
    LEVEL2_VAR0("level2Var0", 8, 1, ReturnType.INTEGER),
    VAR2_LEVEL0("var2Level0", 9, 1, ReturnType.INTEGER),
    SET_VAR_ORDER0("setVarOrder0", 10, 1, ReturnType.VOID),
    GET_ALLOC_NUM0("getAllocNum0", 11, 0, ReturnType.INTEGER),
    GET_NODE_NUM0("getNodeNum0", 12, 0, ReturnType.INTEGER),
    GET_CACHE_SIZE0("getCacheSize0", 13, 0, ReturnType.INTEGER),
    VAR0("var0", 14, 1, ReturnType.INTEGER),
    HIGH0("high0", 15, 2,  ReturnType.LONG),
    LOW0("low0", 16, 2, ReturnType.LONG),
    NOT0("not0", 17, 2, ReturnType.LONG),
    ITE0("ite0", 18, 4, ReturnType.LONG),
    RELPROD0("relprod0", 19, 3, ReturnType.LONG),
    COMPOSE0("compose0", 20, 4, ReturnType.LONG),
    EXIST0("exist0", 21, 3, ReturnType.LONG),
    FOR_ALL0("forAll0", 22, 3, ReturnType.LONG),
    SIMPLIFY0("simplify0", 23, 3, ReturnType.LONG),
    RESTRICT0("restrict0", 24, 2, ReturnType.LONG),
    RESTRICT_WITH0("restrictWith0", 25, 3, ReturnType.LONG),
    SUPPORT0("support0", 26, 2, ReturnType.LONG),
    APPLY0("apply0", 27, 6, ReturnType.LONG),
    SAT_ONE0("satOne0", 28, 3, ReturnType.LONG), //changed by Or: 3rd arg: 2 -> 3
    NODE_COUNT0("nodeCount0", 29, 1, ReturnType.INTEGER),
    PATH_COUNT0("pathCount0", 30, 1, ReturnType.DOUBLE),
    SAT_COUNT0("satCount0", 31, 1, ReturnType.DOUBLE),
    ADD_REF("addRef", 32, 1, ReturnType.VOID),
    DEL_REF("delRef", 33, 2, ReturnType.VOID),
    VECCOMPOSE0("veccompose0", 34, 3, ReturnType.LONG),
    REPLACE0("replace0", 35, 3, ReturnType.LONG),
    ALLOC("alloc", 36, 1, ReturnType.LONG),
    SET0("set0", 37, 4, ReturnType.VOID),
    SET2("set2", 38, 3, ReturnType.VOID),
    RESET0("reset0", 39, 2, ReturnType.VOID),
    FREE0("free0", 40, 2, ReturnType.VOID),
    IS_ZERO_ONE_ADD0("isZeroOneADD0", 41, 1, ReturnType.BOOLEAN),
    ADD_CONST0("addConst0", 42, 1, ReturnType.LONG),
    IS_ADD_CONST0("isAddConst0", 43, 1, ReturnType.BOOLEAN),
    ADD_FIND_MAX0("addFindMax0", 44, 1, ReturnType.LONG),
    ADD_FIND_MIN0("addFindMin0", 45, 1, ReturnType.LONG),
    RETRIEVE_CONST_VALUE0("retrieveConstValue0", 46, 1, ReturnType.DOUBLE),
    ADD_ADDITIVE_NEG0("addAdditiveNeg0", 47, 1, ReturnType.LONG),
    ADD_APPLY_LOG0("addApplyLog0", 48, 1, ReturnType.LONG),
    REORDER0("reorder0", 49, 1, ReturnType.VOID),
    AUTO_REORDER0("autoReorder0", 50, 3, ReturnType.VOID),
    GETREORDERMETHOD0("getreordermethod0", 51, 0, ReturnType.INTEGER),
    AUTO_REORDER1("autoReorder1", 52, 0, ReturnType.VOID),
    REORDER_VERBOSE0("reorderVerbose0", 53, 1, ReturnType.INTEGER),
    ADD_VAR_BLOCK0("addVarBlock0", 54, 3, ReturnType.VOID),
    CLEAR_VAR_BLOCKS0("clearVarBlocks0", 55, 0, ReturnType.VOID),
    PRINT_STAT0("printStat0", 56, 0, ReturnType.VOID),
    TO_ADD0("toADD0", 57, 1, ReturnType.LONG),
    TO_BDD0("toBDD0", 58, 1, ReturnType.LONG),
    TO_BDD_THRESHOLD("toBDDThreshold", 59, 2, ReturnType.LONG),
    TO_BDD_STRICT_THRESHOLD("toBDDStrictThreshold", 60, 2, ReturnType.LONG),
    TO_BDD_INTERVAL("toBDDInterval", 61, 3, ReturnType.LONG),
    TO_BDD_ITH_BIT("toBDDIthBit", 62, 2, ReturnType.LONG),
    VAR_SUPPORT_INDEX0("varSupportIndex0", 63, 1, ReturnType.INT_LIST),
    PRINT_SET0("printSet0", 64, 2, ReturnType.VOID),
    ARITHMETIC_ZERO0("arithmeticZero0", 65, 0, ReturnType.LONG),
    LOGIC_ZERO0("logicZero0", 66, 0, ReturnType.LONG),
    REPLACE_WITH0("replaceWith0", 67, 3, ReturnType.LONG),
    ADD_ABSTRACT_MIN0("addAbstractMin0", 68, 2, ReturnType.LONG),   
    ADD_ABSTRACT_MAX0("addAbstractMax0", 69, 2, ReturnType.LONG),
    ARITHMETIC_MINUS_INFINITY0("arithmeticMinusInfinity0", 70, 0, ReturnType.LONG), 
    ARITHMETIC_PLUS_INFINITY0("arithmeticPlusInfinity0", 71, 0, ReturnType.LONG),
    DETERMINIZE_CONTROLLER0("determinizeController0", 72, 2, ReturnType.LONG),
    REORDER_ENABLED0("reorderEnabled0", 73, 0, ReturnType.BOOLEAN), //Or added this method instead of negCycleCheck0!!!
    ARITHMETIC_LOGIC_ONE0("arithmeticLogicOne0", 74, 0, ReturnType.LONG), 
    ADD_MINIMIZE_VAL0("addMinimizeVal0", 75, 2, ReturnType.LONG),
    REORDER_TIMES0("reorderTimes0", 76, 0, ReturnType.INTEGER),  
    PRINT_VAR_TREE0("printVarTree0", 77, 0, ReturnType.VOID),
    ADD_ENG_SUBTRACT0("addEngSubtract0", 78, 3, ReturnType.LONG), 
    CONVERT_TO_ZERO_ONE_ADD_BY_THRES0("convertToZeroOneADDByThres0", 79, 3, ReturnType.LONG),       
    PRINT_DOT0("printDot0", 80, 1, ReturnType.VOID),
    ARITHMETIC_EXIST0("arithmeticExist0", 81, 2, ReturnType.LONG);

    private final String name; /*method name*/
    private final int methodIndex, argNum; /*method index, number of arguments (BOTH must be consistent with the native code!)*/
    private final ReturnType retType; /*return type (must be consistent with the native code!)*/

    private MethodEntry(String name, int methodIndex, int argNum, ReturnType retType) {
      this.name = name;
      this.methodIndex = methodIndex;
      this.argNum = argNum;
      this.retType = retType;
    }

    public String getName() {
      return this.name;
    }

    public int getIndex() {
      return this.methodIndex;
    }

    public int getReturnTypeId() {
      return this.retType.getId();
    }

    public ReturnType getReturnType() {
      return this.retType;
    }

    public int getArgNumber() {
      return this.argNum;
    }

    public static int getMaxNumberOfArgs() {
      int result = 0;
      for(MethodEntry method: MethodEntry.values()) {
        if(method.argNum > result) {
          result = method.argNum; 
        }
      }
      return result;
    }

  } 
  
  
  
  
  
  
  
  
  
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.spectragameinput.translator;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import tau.smlab.syntech.spectra.LTLAsm;
import tau.smlab.syntech.spectra.LTLGar;

/**
 * Tracer maintains a connection between EObjects (e.g., elements of a Spectra specification) and traceIds
 * (integers).<br>
 * Clients can look up this connection in both ways.
 *
 */
public class Tracer {

  public static int ID = 0;
  private Map<EObject, Integer> tracingMap = new HashMap<>();
  private static Map<Integer, EObject> trace = new HashMap<>();

  public Tracer() {
    tracingMap = new HashMap<>();
    trace = new HashMap<>();
  }

  /**
   * creates a new entry for the EObject with a fresh traceID
   * 
   * does not check whether the object already exists!
   * 
   * @param eobject
   * @return the ID of the added object
   */
  public int addTrace(EObject eobject) {
    trace.put(ID, eobject);
    tracingMap.put(eobject, ID);
    ID++;
    return ID-1;
  }

  /**
   * looks up the traceId of an EObject
   * 
   * @param eobject
   * @return ID of the traced eobject if exists. -1 otherwise.
   */
  public int getTrace(EObject eobject) {
    if (!tracingMap.containsKey(eobject)) {
      return -1;
    }
    return tracingMap.get(eobject);
  }

  /**
   * returns the EObject of this traceId (e.g., returns an element of the Spectra specification)
   * 
   * @param traceId
   * @return
   */
  public static EObject getTarget(int traceId) {
    return trace.get(traceId);
  }

  /**
   * translates the element with the given traceId to a string (e.g., prints a guarantee from the specification)
   * 
   * @param traceId
   * @return
   */
  public static String getNiceStringForId(int traceId) {
    if (traceId == -1) {
      return "TRUE";
    }
    EObject obj = getTarget(traceId);
    if (obj instanceof LTLGar) {
      LTLGar gar = (LTLGar) obj;
      if (gar.getName() != null) {
        return "guarantee " + gar.getName();
      }
    } else if (obj instanceof LTLAsm) {
      LTLAsm asm = (LTLAsm) obj;
      if (asm.getName() != null) {
        return "assumption " + asm.getName();
      }
    }
    return NodeModelUtils.getTokenText(NodeModelUtils.findActualNodeFor(obj));
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.jits;

import java.util.List;
import java.util.Map;

import net.sf.javabdd.BDD;

/**
 * 
 * @author Ilia
 *
 */
public class BookkeepingController extends AbstractJitController {

	public BookkeepingController(JitController jitController) {
		super(jitController);
	}

	private boolean[] bookkeepingArray;
	private boolean master;

	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
		jitController.load(folder, name, sysVars, envVars);
		bookkeepingArray = new boolean[jitController.getJusticeGar().size()];
	}

	@Override
	public BDD next(BDD currentState, BDD inputs) {
		
		int jx = jitController.getJitState().getJx();
		List<BDD> justiceGar = jitController.getJusticeGar();
		int n = justiceGar.size();
		
		// Update bookkeeping array
		for (int j = jx; j < n; j++) {
        	if (bookkeepingArray[j] == master) {
        		if (!justiceGar.get(j).and(currentState).isZero()) {
        			bookkeepingArray[j] = !master;
        		}
        	}
		}
		for (int j = 0; j < jx; j++) {
        	if (bookkeepingArray[j] == !master) {
        		if (!justiceGar.get(j).and(currentState).isZero()) {
        			bookkeepingArray[j] = master;
        		}
        	}
		}
		
		return jitController.next(currentState, inputs);
	}

	@Override
	public void init(BDD currentState) {
		jitController.init(currentState);
		jitController.getJitState().setGoalFinder(new NextJusticeGoalFinder() {
			
			@Override
			public int findNextJusticeGoal(int jx) {
				
				for (int j = jx + 1; j < jitController.getJusticeGar().size(); j++) {
		        	if (bookkeepingArray[j] == master) {
		        		return j;
		        	}
				}
				
				master = !master;
				for (int j = 0; j < jx; j++) {
		        	if (bookkeepingArray[j] == master) {
		            	return j;
		        	}
				}
				
				return jx;
			}
		});
	}

	@Override
	public void saveState() {
		this.controller.saveState();
	}

	@Override
	public void loadState() {
		this.controller.loadState();
	}

	@Override
	public BDD succ(BDD from) {
		return jitController.succ(from);
	}

	@Override
	public BDD pred(BDD to) {
		return jitController.pred(to);
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.ModuleVariableException;
import tau.smlab.syntech.jtlv.VarKind;
import tau.smlab.syntech.jtlv.env.module.ModuleBDDField;

/**
 * module representing a player by
 * <li>variables as ModuleBDDField including their domains</li>
 * <li>BDD initial</li>
 * <li>BDD trans</li>
 * <li>List<BDD> justice</li>
 * 
 * The BDDs initial and trans are restricted according to the domains of the variables (while adding variables). The
 * composed domain restrictions are also kept in BDD doms.
 */
public class PlayerModule {

	public static boolean TEST_MODE = false;

	public enum TransFuncType {
		SINGLE_FUNC, DECOMPOSED_FUNC, PARTIAL_DECOMPOSED_FUNC
	}

	private class TransQuantPair {
		public TransQuantPair(BDD partTrans, BDDVarSet quantSet) {
			this.partTrans = partTrans;
			this.quantSet = quantSet;
		}


		public BDD partTrans;
		public BDDVarSet quantSet;
	}
	
	/**
	 * 
	 * A nested class that represents an existential requirement of this player module.
	 *
	 */
	public class ExistentialRequirement {
		List<BDD> existFinallyAssrts;
		SFAModuleConstraint regExpSfaConstraint;
		
		public ExistentialRequirement(List<BDD> existFinallyAssrts) {
			this.existFinallyAssrts = existFinallyAssrts;
		}
		
		public ExistentialRequirement(SFAModuleConstraint regExpSfaConstraint) {
			this.regExpSfaConstraint = regExpSfaConstraint;
		}
		
		public boolean hasRegExp() {
			return this.regExpSfaConstraint != null;
		}

		public List<BDD> getExistFinallyAssrts() {
			return existFinallyAssrts;
		}

		public SFAModuleConstraint getRegExpSfaConstraint() {
			return regExpSfaConstraint;
		}
		
		public int rank() {
			if(this.existFinallyAssrts != null) {
				return this.existFinallyAssrts.size();
			}
			return 0;
		}
	}

	private String name;
	private BDD initial = Env.TRUE();
	private BDD doms = Env.TRUE();
	private boolean simConjunctAbs;
	private TransFuncType transFunc;
	private BDD trans = Env.TRUE();
	private List<TransQuantPair> transQuantList = new ArrayList<>();
	private List<BDD> transList = new ArrayList<>();
	private List<BDD> justice = new ArrayList<>();
	private Map<Integer, Integer> justiceIDs = new HashMap<>();
	private List<ExistentialRequirement> existential = new ArrayList<>();
	private int existRegExpReqNum = 0;
	private Map<Integer, Integer> existentialIDs = new HashMap<>();

	/**
	 * was called all_couples
	 */
	private List<ModuleBDDField> allFields = new ArrayList<ModuleBDDField>();
	private List<ModuleBDDField> auxFields = new ArrayList<ModuleBDDField>();
	private List<ModuleBDDField> nonAuxFields = new ArrayList<ModuleBDDField>();

	private BDDVarSet cachedPrimeVars;
	private int cachedVarsLen;
	private BDDVarSet cachedUnprimeVars;

	/**
	 * returns set of all primed variables of the module
	 * 
	 * (do not consume)
	 * 
	 * @return
	 */
	public BDDVarSet modulePrimeVars() {
		if (cachedPrimeVars == null || this.getAllFields().size() != cachedVarsLen) {
			computeVarSets();
		}
		return cachedPrimeVars;
	}

	/**
	 * computes the cachedPrimeVars and cachedUnprimeVars
	 */
	private void computeVarSets() {
		cachedPrimeVars = Env.getEmptySet();
		cachedUnprimeVars = Env.getEmptySet();
		cachedVarsLen = this.getAllFields().size();

		for (ModuleBDDField c : this.getAllFields()) {
			if (c.isPrime()) {
				cachedPrimeVars = cachedPrimeVars.union(c.support());
				cachedUnprimeVars = cachedUnprimeVars.union(c.unprime().support());
			} else {
				cachedPrimeVars = cachedPrimeVars.union(c.prime().support());
				cachedUnprimeVars = cachedUnprimeVars.union(c.support());
			}
		}
	}

	public BDDVarSet moduleUnprimeVars() {
		if (cachedUnprimeVars == null || this.getAllFields().size() != cachedVarsLen) {
			computeVarSets();
		}
		return cachedUnprimeVars;
	}

	/**
	 * all fields including auxiliary fields (auxFields + nonAuxFields)
	 * 
	 * @see getAuxFields()
	 * @see getNonAuxFields()
	 * @return
	 */
	public List<ModuleBDDField> getAllFields() {
		return allFields;
	}

	/**
	 * remove the given field from the module's field lists (all/aux/nonAux)
	 * 
	 * @param f
	 */
	public void removeField(ModuleBDDField f) {
		allFields.remove(f);
		auxFields.remove(f);
		nonAuxFields.remove(f);
	}

	public void setSCA(boolean sca) {
		simConjunctAbs = sca;
	}
	/**
	 * returns original initial states
	 * 
	 * @return
	 */
	public BDD initial() {
		return initial;
	}

	/**
	 * returns original transition relation
	 * 
	 * @return
	 */
	public BDD trans() {
		return trans;
	}

	public int existReqNum() {
		return existential.size();
	}
	
	/**
	 * Returns the number of existential requirements that have regular expressions.
	 * 
	 * @return
	 */
	public int existRegExpReqNum() {
		return existRegExpReqNum;
	}
	
	/**
	 * Checks whether this module has any existential requirements.
	 * 
	 * @return
	 */
	public boolean hasExistReqs() {
		return !this.existential.isEmpty();
	}

	/**
	 * Returns the existential requirement at index <code>k</code>.
	 * 
	 * @param k
	 * @return
	 */
	public ExistentialRequirement existReqAt(int k) {
		try {
			return existential.get(k);
		} catch (IndexOutOfBoundsException e) {
			throw new IndexOutOfBoundsException("No existential requirement at index " + k);
		}
	}
	
	/**
	 * 
	 * Checks whether the existential requirement at index <code>k</code> contains a regular expression.
	 * 
	 * @param k
	 * @return
	 */
	public boolean existReqHasRegExp(int k) {
		try {
			return existential.get(k).hasRegExp();
		} catch (IndexOutOfBoundsException e) {
			throw new IndexOutOfBoundsException("No existential requirement at index " + k);
		} 
	}

	/**
	 * Returns the rank of the {@code k}-th existential requirement.
	 * The rank is nesting depth of finally (F) temporal operators.
	 * If the {@code k}-th existential requirement consists of a regular expression, its rank is 0.
	 * 
	 * @param k
	 * @return 
	 */
	public int existReqRank(int k) {
		try {
			return existential.get(k).rank();
		} catch (IndexOutOfBoundsException e) {
			throw new IndexOutOfBoundsException("No existential requirement at index " + k);
		}
	}

	/**
	 * Adds the specified existential requirement.
	 * 
	 * @param exReq the existential requirement
	 */
	public void addExistReq(ExistentialRequirement exReq) {
		this.existential.add(exReq);
		if(exReq.hasRegExp()) {
			existRegExpReqNum++;
		}
	}
	
	/**
	 * Adds a new existential requirement with the assertions in {@code existFinallyAssrts}.
	 * 
	 * @param existFinallyAssrts the assertions
	 */
	public void addExistReq(List<BDD> existFinallyAssrts) {
		this.addExistReq(new ExistentialRequirement(existFinallyAssrts));
	}
	
	/**
	 * Adds a new existential requirement that contains the specified regular expression
	 * given by the BDD encoding of its corresponding SFA.
	 * 
	 * @param regExpSfaConstraint the BDD encoding of the SFA that corresponds to the regular expression 
	 */
	public void addExistReq(SFAModuleConstraint regExpSfaConstraint) {
		this.addExistReq(new ExistentialRequirement(regExpSfaConstraint));
	}
	
	/**
	 * Adds a new existential requirement that contains the specified regular expression
	 * given by the BDD encoding of its corresponding SFA.
	 * 
	 * @param regExpSfaConstraint the BDD encoding of the SFA that corresponds to the regular expression
	 * @param traceId
	 */
	public void addExistReq(SFAModuleConstraint regExpSfaConstraint, int traceId) {
		this.addExistReq(new ExistentialRequirement(regExpSfaConstraint), traceId);
	}
	
	/**
	 * Adds a new existential requirement with the assertions in {@code existFinallyAssrts}.
	 * 
	 * @param existFinallyAssrts the assertions
	 * @param traceId
	 */
	public void addExistReq(List<BDD> existFinallyAssrts, int traceId) {
		this.addExistReq(new ExistentialRequirement(existFinallyAssrts), traceId);
	}
	
	/**
	 * Adds the specified existential requirement.
	 * 
	 * @param exReq the existential requirement
	 * @param traceId
	 */
	public void addExistReq(ExistentialRequirement exReq, int traceId) {
		this.addExistReq(exReq);
		this.existentialIDs.put(traceId, this.existential.size() - 1);
	}

	public Map<Integer, Integer> getTraceIdToExistReqIndexMap() {
		return this.existentialIDs;
	}

	public int justiceNum() {
		return justice.size();
	}

	/**
	 * Returns the original justice at index <code>i</code>
	 * 
	 * @param i
	 * @return
	 */
	public BDD justiceAt(int i) {
		try {
			return justice.get(i);
		} catch (Exception e) {
			throw new ArrayIndexOutOfBoundsException("No justice at index " + i);
		}
	}

	/**
	 * Adds the justice (does not free it!)
	 * 
	 * @param j
	 */
	public void addJustice(BDD j) {
		this.justice.add(j);
	}

	public void addJustice(BDD j, int id) {
		this.justice.add(j);
		this.justiceIDs.put(id, this.justice.size() - 1);
	}

	public Map<Integer, Integer> getJusticeIndexToIDMap() {
		return this.justiceIDs;
	}
	
	public BDD[] getJustices() {
		return this.justice.toArray(new BDD[this.justice.size()]);
	}

	/**
	 * conjunct transitions with <code>moreTrans</code> (consumed)
	 * 
	 * @param moreTrans
	 */
	public void conjunctTrans(BDD moreTrans) {
		trans.andWith(moreTrans);
	}

	/**
	 * conjunct transitions with <code>moreIni</code> (consumed)
	 * 
	 * @param moreIni
	 */
	public void conjunctInitial(BDD moreIni) {
		initial.andWith(moreIni);
	}

	/**
	 * Sets the type of the transition function that will be used in yield states.
	 * 
	 * @param type
	 *          the type of the transition function
	 * */
	public void setTransFuncType(TransFuncType type) {
		transFunc = type;
	}

	/**
	 * Gets the type of the transition function that will be used in yield states.
	 * */
	public TransFuncType getTransFuncType() {
		return transFunc;
	}

	/**
	 * Add a partial transition function to the transition functions list
	 * 
	 * @param trans
	 *          the partial transition function
	 * */
	public void addToTransList(BDD trans) {
		//    System.out.println("addToTransList: " + trans.support());
		BDDVarSet transSet = getIntersectSupportWithPrimed(trans);
		boolean isAdded = false;
		for (int i = 0; i < transList.size(); i++) {
			BDDVarSet set = getIntersectSupportWithPrimed(transList.get(i));
			if (transSet.equals(set)) {
				transList.get(i).andWith(trans);
				isAdded = true;
				break;
			}
		}
		if (!isAdded) {
			transList.add(trans);
		}    
	}

	public void simpleAddToTransList(BDD trans) {
		//    System.out.println("simpleAddToTransList: " + trans.support());
		transList.add(trans);
	}


	/**
	 * Create a single transition function from the partitioned transition function
	 * */
	public void createTransFromPartTrans() {
		if(trans != null && !trans.isFree()) {
			trans.free();
		}
		trans = Env.TRUE();
		for (TransQuantPair p : transQuantList) {
			conjunctTrans(p.partTrans);
		}
	}

	public List<TransQuantPair> getTransQuantList() {
		return transQuantList;
	}

	public BDD[] getPartTransArray() {
		if (transFunc == TransFuncType.SINGLE_FUNC) {
			return new BDD[0];
		}

		BDD[] partTransArr = new BDD[transQuantList.size()];
		for (int i = 0; i < transQuantList.size(); i++) {
			partTransArr[i] = transQuantList.get(i).partTrans;
		}
		return partTransArr;
	}

	public BDDVarSet[] getQuantSetArray() {
		if (transFunc == TransFuncType.SINGLE_FUNC) {
			return new BDDVarSet[0];
		}

		BDDVarSet[] quantSetArr = new BDDVarSet[transQuantList.size()];
		for (int i = 0; i < transQuantList.size(); i++) {
			quantSetArr[i] = transQuantList.get(i).quantSet;
		}
		return quantSetArr;
	}

	private BDDVarSet getIntersectSupportWithPrimed(BDD bdd) {    
		BDDVarSet set1 = bdd.support();
		BDDVarSet intr = getIntersectSupportWithPrimed(set1);
		set1.free();
		return intr;
	}

	private BDDVarSet getIntersectSupportWithPrimed(BDDVarSet set1) {
		BDDVarSet intr = Env.getEmptySet();
		BDDVarSet set2 = modulePrimeVars();
		int[] arr1 = set1.toArray();
		int[] arr2 = set2.toArray();

		for (int i = 0; i < arr1.length; i++) {
			for (int j = 0; j < arr2.length; j++) {
				if (arr1[i] == arr2[j]) {
					intr.unionWith(arr1[i]);
					break;
				}
			}
		}
		return intr;
	}

	@SuppressWarnings("unused")
	private BDDVarSet getMinus(BDDVarSet set1, BDDVarSet set2) {
		BDDVarSet minus = Env.getEmptySet();

		int[] arr1 = set1.toArray();
		int[] arr2 = set2.toArray();

		for (int i = 0; i < arr1.length; i++) {
			boolean isEqual = false;
			for (int j = 0; j < arr2.length; j++) {
				if (arr1[i] == arr2[j]) {
					isEqual = true;
					break;

				}
			}
			if (!isEqual) {
				minus.unionWith(arr1[i]);
			}
		}

		return minus;
	}

	// map from primed support set to the quantification set
	//  private Map<BDDVarSet, BDDVarSet> partTransQuantMap = new HashMap<>();
	private Map<Set<Integer>, BDDVarSet> partTransQuantMap = new HashMap<>();
	//  private List<BDDVarSet> orderTransList = new ArrayList<>();
	private List<Set<Integer>> orderTransList = new ArrayList<>();
	//private Map<BDD, Set<Integer>> primeSuppSet = new HashMap<>();

	public void addToPartTransList(BDD trans) {   
		BDDVarSet pSupp = getIntersectSupportWithPrimed(trans);
		//    partTransQuantMap.put(toIntSet(pSupp), Env.getEmptySet());
		Set<Integer> set = toIntSet(pSupp);
		if (!partTransQuantMap.containsKey(set)) {
			partTransQuantMap.put(set, Env.getEmptySet());
		}
		//    partTransQuantMap.put(pSupp, Env.getEmptySet());
	}

	/*
	 * Calculate the the order of the quantifications according to:
	 * 1. Largest set that can be quantified out
	 * 2. Largest (primed) support set
	 */
	public void partCalcTransQuantList() {
//		System.out.println("partTransQuantMap size =  " + partTransQuantMap.size());
//		int idx = 0;
//		for (Set<Integer> supp : partTransQuantMap.keySet()) {
//			System.out.println("partTransQuantMap support("+idx+") =  " + supp);
//			idx++;
//		}

		Set<Set<Integer>> keySets = new HashSet<Set<Integer>>();//partTransQuantMap.keySet());
		for (Set<Integer> key : partTransQuantMap.keySet()) {
			keySets.add(key.stream().collect(Collectors.toSet()));
		}

		while (!keySets.isEmpty()) {
			Set<Integer> maxSet = new HashSet<>();
			Set<Integer> keyMaxSet = new HashSet<>(); //Env.getEmptySet();
			for (Set<Integer> key : keySets) {
				Set<Integer> eset = key.stream().collect(Collectors.toSet());//toIntSet(key);
				for (Set<Integer> otherKey : keySets) {
					if (!key.equals(otherKey)) {
						Set<Integer> otherSet = otherKey;//toIntSet(otherKey);
						eset.removeAll(otherSet);
						if (eset.isEmpty()) {
							break;
						}
					}
				}
				if (maxSet.size() < eset.size()) {
					maxSet = eset;
					keyMaxSet = key.stream().collect(Collectors.toSet());//key;
				}
			}

			if (!maxSet.isEmpty()) {
//				System.out.println("found maximum E: " + maxSet + ", for key support set: " + keyMaxSet);
				partTransQuantMap.put(keyMaxSet, toVarSet(maxSet));
				orderTransList.add(keyMaxSet);
				keySets.remove(keyMaxSet);
				continue;
			}

//			System.out.println("no maximum E set - take the largest primed support set: ");
			Set<Integer> maxKey = new HashSet<>();
			for (Set<Integer> key : keySets) {
				if (key.size() > maxKey.size()) {
					maxKey = key;
				}
			}

			System.out.println("max primed support set: " + maxKey);
			if (!maxKey.isEmpty()) {
				orderTransList.add(maxKey);
				keySets.remove(maxKey);
			} else {
//				System.out.println("Can't decompose further, left trans: " + keySets.size());
				for (Set<Integer> k : keySets) {
					orderTransList.add(k);
				}
				break;
			}
		}
		keySets.clear();

//		System.out.println("orderTransList size =  " + orderTransList.size());
//		System.out.println("Order of quantification:");
//		for (int i = 0; i < orderTransList.size(); i++) {
//			System.out.println("support = " + orderTransList.get(i) + ", E_"+i+" = " + partTransQuantMap.get(orderTransList.get(i)));
//		}
	}

	/*
	 * Create the list of partitioned transitions and the sets to quantify,
	 * according to the calculations done in partCalcTransQuantList()
	 */
	public void createPartialTransQuantList() {
//		System.out.println("Curr transList size =  " + transList.size());
//		System.out.println("OrderTransList size =  " + orderTransList.size());

		//    for (int i = 0; i < orderTransList.size(); i++) {
		//      System.out.println("orderTransList.get("+i+").support() = " + orderTransList.get(i) 
		//      + ", E_"+i+" = " + partTransQuantMap.get(orderTransList.get(i)));      
		//    }
		//    
		//    for (int i = 0; i < transList.size(); i++) {
		//      System.out.println("transList.get("+i+").support() = " + transList.get(i).support() 
		//          + ", primed support = " +getIntersectSupportWithPrimed(transList.get(i).support()));      
		//    }

		Set<Integer> modulePrimeVars = toIntSet(modulePrimeVars());
		Set<Integer> leftoverSet = new HashSet<>(modulePrimeVars);

		Map<BDDVarSet, Integer> transSuppToIdx = new HashMap<>();
		Map<Set<Integer>, BDDVarSet> transPrimedSuppToSupp = new HashMap<>();
		for (int i = 0; i < transList.size(); i++) {
			BDDVarSet supp = transList.get(i).support();
			transSuppToIdx.put(supp, i);
			transPrimedSuppToSupp.put(toIntSet(getIntersectSupportWithPrimed(supp)), supp);
		}

		for (Set<Integer> psupp : orderTransList) {
			if (transList.isEmpty()) {
				break;
			}
			//check if elem in transPrimedSuppToSupp contained in psupp
			if (!transPrimedSuppToSupp.containsKey(psupp)) {
				BDDVarSet quantSet = partTransQuantMap.get(psupp);
				int last_idx = transQuantList.size() - 1;
				if (!transQuantList.isEmpty()) { // && transQuantList.get(last_idx).quantSet.isEmpty()) {
					transQuantList.get(last_idx).quantSet.unionWith(quantSet.id());
					leftoverSet.removeAll(toIntSet(quantSet));
				}
				continue;
			}

			BDDVarSet quantSet = partTransQuantMap.get(psupp);
			BDD partTrans = transList.get(transSuppToIdx.get(transPrimedSuppToSupp.get(psupp)));

			if (!quantSet.isEmpty()) {
				leftoverSet.removeAll(toIntSet(quantSet));

				int last_idx = transQuantList.size() - 1;
				if (!transQuantList.isEmpty() && transQuantList.get(last_idx).quantSet.isEmpty()) {
					transQuantList.get(last_idx).partTrans.andWith(partTrans);
					transQuantList.get(last_idx).quantSet = quantSet.id();
				} else {
					transQuantList.add(new TransQuantPair(partTrans, quantSet.id()));
				}
			} else {
				//        transQuantList.add(new TransQuantPair(partTrans.id(), quantSet.id()));
				if (transQuantList.isEmpty()) {
					transQuantList.add(new TransQuantPair(partTrans.id(), quantSet.id()));
				} else {
					transQuantList.get(transQuantList.size()-1).partTrans.andWith(partTrans);
				}
			}
		}

		int last_idx = transQuantList.size() - 1;
		if (last_idx > 0 && transQuantList.get(last_idx).quantSet.isEmpty()) {
			transQuantList.get(last_idx-1).partTrans.andWith(transQuantList.get(last_idx).partTrans);
			transQuantList.remove(last_idx);
		}

		if (!leftoverSet.isEmpty()) {
			System.out.println("leftoverSet =  " + leftoverSet);
			transQuantList.get(0).quantSet.unionWith(toVarSet(leftoverSet));
		}   

		// NOTE: group quantify sets with 1 variable to groups of 2 or 3 variables
		List<TransQuantPair> tmpList = new ArrayList<>();
		int setSize = 3;
		for (int j = 0; j < transQuantList.size(); j++) {
			if (j + 1 < transQuantList.size() && (transQuantList.get(j).quantSet.size() + transQuantList.get(j+1).quantSet.size() <= setSize)) {
				TransQuantPair p = new TransQuantPair(transQuantList.get(j).partTrans.andWith(transQuantList.get(j+1).partTrans), 
						transQuantList.get(j).quantSet.unionWith(transQuantList.get(j+1).quantSet));

				if (j + 2 < transQuantList.size() && (transQuantList.get(j+2).quantSet.size() + p.quantSet.size() <= setSize)) {
					p.partTrans.andWith(transQuantList.get(j+2).partTrans);
					p.quantSet.unionWith(transQuantList.get(j+2).quantSet);
					j++;
				}

				j++;
				tmpList.add(p);
			} else {
				tmpList.add(transQuantList.get(j));
			}

		}

		transQuantList.clear();
		transQuantList = tmpList;

		for (int j = 0; j < transQuantList.size(); j++) {
			BDDVarSet supp = transQuantList.get(j).partTrans.support();
//			System.out.println("transQuantList["+j+"].support = " + supp + ", E_"+j+" = " + transQuantList.get(j).quantSet);
			supp.free();
		}
	}

	/**
  public void partCalcTransQuantList() {
    System.out.println("partTransList size =  " + partTransList.size());

//    if (PlayerModule.TEST_MODE) {
//      System.out.println("trans support: " + trans.support());
//      BDD calcTrans = Env.TRUE();
//      for (int i = 0; i < transList.size(); i++) {
//        calcTrans.andWith(transList.get(i).id());
//      }
//      
//      if (!calcTrans.equals(trans)){
//        System.err.println("ERROR: The oroginal transition function doesn't equal the conjuction of the decomposed functions!" );
//      }
//      
//      System.out.println("calcTrans.support: " + calcTrans.support()); 
//      calcTrans.free();
//    }

    Map<BDD, Set<Integer>> primeSuppSet = new HashMap<>();
    List<BDD> currList = partTransList;
    Set<Integer> modulePrimeVars = toIntSet(modulePrimeVars());
//    for (BDD b : currList) {
//      Set<Integer> primedSup = toIntSuppSet(b);
//      primedSup.retainAll(modulePrimeVars);
//      primeSuppSet.put(b, primedSup);
//    }

    while (!currList.isEmpty()) {
      Set<Integer> maxSet = new HashSet<>();
      int maxIdx = -1;
      for (int j = 0; j < currList.size(); j++) {
//        Set<Integer> eset = new HashSet<Integer>(primeSuppSet.get(currList.get(j)));
//        Set<Integer> eset_orig = new HashSet<Integer>(primeSuppSet.get(currList.get(j)));  

        Set<Integer> eset = new HashSet<Integer>(primeSuppSet.get(currList.get(j)));
        for (int h = 0; h < currList.size(); h++) {
          if (h != j) {
            Set<Integer> otherSet = new HashSet<Integer>(primeSuppSet.get(currList.get(h)));
//            if (eset_orig.equals(otherSet)) { //TODO: NEW!!!
//              continue;
//            }
            eset.removeAll(otherSet);
            if (eset.isEmpty()) {
              break;
            }
          }
        }

        if (maxSet.size() < eset.size()) {
          maxSet = eset;
          maxIdx = j;
        }
      }

      if (maxIdx == -1) {
        System.out.println("no maximum - take the largest primed support set: ");
        Set<Integer> maxSupp = new HashSet<>();
        int maxSuppIdx = -1;
        for (int q = 0; q < currList.size(); q++) {
          Set<Integer> supp = primeSuppSet.get(currList.get(q));
          System.out.println("  " + supp);
          if (supp.size() > maxSupp.size()) {
            maxSupp = supp;
            maxSuppIdx = q;
          }
        }

        System.out.println("max support: " + maxSupp + ", maxSuppIdx: " + maxSuppIdx);
        if (maxSuppIdx > -1) {
          partTransQuantList.add(new TransQuantPair(currList.get(maxSuppIdx), Env.getEmptySet()));
          currList.remove(maxSuppIdx);
        } else {
          System.out.println("Can't decompose further, left trans: " + currList.size());
          for (BDD b : currList) {
            partTransQuantList.add(new TransQuantPair(b, Env.getEmptySet()));
          }
          break;
        }
      } else {
        System.out.println("found maximum E: " + maxSet);
        partTransQuantList.add(new TransQuantPair(currList.get(maxIdx), toVarSet(maxSet)));
        currList.remove(maxIdx);
      }
    }

//    for (BDD b : currList) {
//      b.free();
//    }
    currList.clear();

    for (int j = 0; j < partTransQuantList.size(); j++) {
      BDDVarSet supp = partTransQuantList.get(j).partTrans.support();
      System.out.println("partTransQuantList["+j+"].support = " + supp + ", E_"+j+" = " + partTransQuantList.get(j).quantSet);
      supp.free();
    }
  }
	 */

	/*
	 * Create the list of partitioned transitions and the sets to quantify,
	 * according to the calculations done in partCalcTransQuantList()
	 */
	/**
  public void createPartialTransQuantList() {
    System.out.println("Curr transList size =  " + transList.size());
    System.out.println("left partTransList size =  " + partTransList.size());

    Set<Integer> modulePrimeVars = toIntSet(modulePrimeVars());
    BDDVarSet leftoverSet = modulePrimeVars().id();

    for (TransQuantPair tq : partTransQuantList) {
      if (transList.isEmpty()) {
        break;
      }
      BDDVarSet supp = tq.partTrans.support();
      if (transList.remove(tq.partTrans)) {
        if (!tq.quantSet.isEmpty()) {
          leftoverSet = getMinus(leftoverSet, tq.quantSet);
          if (!transQuantList.isEmpty() && 
              (transQuantList.get(transQuantList.size()-1).quantSet.isEmpty() 
//                //TODO: NEW!!!
               || (transQuantList.get(transQuantList.size()-1).quantSet.equals(tq.quantSet) && 
                   transQuantList.get(transQuantList.size()-1).partTrans.support().equals(tq.partTrans.support()))
                  )) {
            transQuantList.get(transQuantList.size()-1).partTrans.andWith(tq.partTrans.id());
            transQuantList.get(transQuantList.size()-1).quantSet = tq.quantSet.id();
          } else {
            transQuantList.add(new TransQuantPair(tq.partTrans.id(), tq.quantSet.id()));
          }
        } else {

          if (transQuantList.isEmpty()) {
            transQuantList.add(new TransQuantPair(tq.partTrans.id(), tq.quantSet.id()));
          } else {
            transQuantList.get(transQuantList.size()-1).partTrans.andWith(tq.partTrans.id());
          }
        }
      }
    }

    for (BDD b : transList) {
      System.out.println("left in transList: " + b.support());
    }

    Set<Integer> e = new HashSet<>();
    BDD leftTrans = Env.TRUE();
    System.out.println("intersect the remaining trans: " + transList.size());
    for (BDD trans : transList) {
      BDDVarSet inter = getIntersectSupportWithPrimed(trans);
      System.out.println("  " + inter);
      inter.free();
      leftTrans.andWith(trans);
    }
    e = toIntSuppSet(leftTrans);
    e.retainAll(modulePrimeVars);
    System.out.println("leftoverSet: " + leftoverSet);
    leftoverSet = getMinus(leftoverSet, toVarSet(e));

    System.out.println("resulting E: " + e);
//    System.out.println("leftTrans: " + leftTrans.support());
//    System.out.println("leftoverSet: " + leftoverSet);

    if (!e.isEmpty() || transQuantList.isEmpty()) {
      transQuantList.add(new TransQuantPair(leftTrans, toVarSet(e)));
    } else {
      transQuantList.get(transQuantList.size()-1).partTrans.andWith(leftTrans);
    } 
    transList.clear();

    if (!leftoverSet.isEmpty()) {
      transQuantList.get(transQuantList.size()-1).quantSet.unionWith(leftoverSet);
    }



    // NOTE: group quantify sets with 1 variable to groups of 2 or 3 variables
    List<TransQuantPair> tmpList = new ArrayList<>();
    int setSize = 3;
    for (int j = 0; j < transQuantList.size(); j++) {
      if (j + 1 < transQuantList.size() && (transQuantList.get(j).quantSet.size() + transQuantList.get(j+1).quantSet.size() <= setSize)) {
        TransQuantPair p = new TransQuantPair(transQuantList.get(j).partTrans.andWith(transQuantList.get(j+1).partTrans), 
            transQuantList.get(j).quantSet.unionWith(transQuantList.get(j+1).quantSet));

        if (j + 2 < transQuantList.size() && (transQuantList.get(j+2).quantSet.size() + p.quantSet.size() <= setSize)) {
          p.partTrans.andWith(transQuantList.get(j+2).partTrans);
          p.quantSet.unionWith(transQuantList.get(j+2).quantSet);
          j++;
        }

        j++;
        tmpList.add(p);
      } else {
        tmpList.add(transQuantList.get(j));
      }

    }

//    System.err.println("7. " + (System.nanoTime() - startTimeNano));
    transQuantList.clear();
    transQuantList = tmpList;

    for (int j = 0; j < transQuantList.size(); j++) {
      BDDVarSet supp = transQuantList.get(j).partTrans.support();
      System.out.println("transQuantList["+j+"].support = " + supp + ", E_"+j+" = " + transQuantList.get(j).quantSet);
      supp.free();
    }
  }
	 */
	public void calcTransQuantList() {
//		long start = System.nanoTime();
		//    long startTimeNano = System.nanoTime();

//		System.out.println("modulePrimeVars: " + modulePrimeVars());
//		for (int i = 0; i < transList.size(); i++) {
//			System.out.println("transList.get("+i+").support() = " + transList.get(i).support());      
//		}


		if (transList.size() ==1 && transList.get(0).isOne()) {
//			System.out.println("Trans is TRUE");
			transQuantList.add(new TransQuantPair(transList.get(0), modulePrimeVars()));
			return;
		}
		//    System.err.println("1. " + (System.nanoTime() - startTimeNano));

		//    if (PlayerModule.TEST_MODE) {
		//      System.out.println("trans support: " + trans.support());
		//      BDD calcTrans = Env.TRUE();
		//      for (int i = 0; i < transList.size(); i++) {
		//        calcTrans.andWith(transList.get(i).id());
		//      }
		//      
		//      if (!calcTrans.equals(trans)){
		//        System.err.println("ERROR: The oroginal transition function doesn't equal the conjuction of the decomposed functions!" );
		//      }
		//      
		//      System.out.println("calcTrans.support: " + calcTrans.support()); 
		//      calcTrans.free();
		//    }

		//    System.err.println("2. " + (System.nanoTime() - startTimeNano));

		List<BDD> currList = transList;
		Set<Integer> modulePrimeVars = toIntSet(modulePrimeVars());
		Set<Integer> leftoverSet = new HashSet<>(modulePrimeVars);
		Map<BDD, Set<Integer>> primeSuppSet = new HashMap<>();
		for (BDD b : currList) {
			Set<Integer> primedSup = toIntSuppSet(b);
			primedSup.retainAll(modulePrimeVars); // currently leftoverSet is the primed vars
			primeSuppSet.put(b, primedSup);
		}

		//    System.err.println("3. " + (System.nanoTime() - startTimeNano));
		while (!currList.isEmpty()) {
			Set<Integer> maxSet = new HashSet<>();
			int maxIdx = -1;
			for (int j = 0; j < currList.size(); j++) {
				Set<Integer> eset = new HashSet<Integer>(primeSuppSet.get(currList.get(j)));        
				for (int h = 0; h < currList.size(); h++) {
					if (h != j) {
						Set<Integer> otherSet = new HashSet<Integer>(primeSuppSet.get(currList.get(h)));
						eset.removeAll(otherSet);
						if (eset.isEmpty()) {
							break;
						}
					}
				}
				if (maxSet.size() < eset.size()) {
					maxSet = eset;
					maxIdx = j;
				}
			}

			if (maxIdx > -1) {
				leftoverSet.removeAll(maxSet);
//				System.out.println("found maximum E: " + maxSet);
				transQuantList.add(new TransQuantPair(currList.get(maxIdx), toVarSet(maxSet)));
				currList.remove(maxIdx);
				continue;
			}

//			System.out.println("no maximum - take the largest support set: ");
			Set<Integer> maxSupp = new HashSet<>();
			int maxSuppIdx = -1;
			for (int q = 0; q < currList.size(); q++) {
				Set<Integer> supp = primeSuppSet.get(currList.get(q));
//				System.out.println("  " + supp);
				if (supp.size() > maxSupp.size()) {
					maxSupp = supp;
					maxSuppIdx = q;
				}
			}

//			System.out.println("max support: " + maxSupp + ", maxSuppIdx: " + maxSuppIdx);
			if (maxSuppIdx > -1) {
				transQuantList.add(new TransQuantPair(currList.get(maxSuppIdx), Env.getEmptySet()));
				currList.remove(maxSuppIdx);
			} else {
				Set<Integer> e = new HashSet<>();
				BDD leftTrans = Env.TRUE();
//				System.out.println("no maximum - intersect the remaining trans ");
				for (int q = 0; q < currList.size(); q++) {
//					Set<Integer> inter = primeSuppSet.get(currList.get(q));
//					System.out.println("  " + inter);
					leftTrans.andWith(currList.get(q));
				}
				e = toIntSuppSet(leftTrans);
				e.retainAll(modulePrimeVars);

//				System.out.println("resulting E: " + e);
				if (!e.isEmpty() || transQuantList.isEmpty()) {
					transQuantList.add(new TransQuantPair(leftTrans, toVarSet(e)));
				} else {
					transQuantList.get(transQuantList.size()-1).partTrans.andWith(leftTrans);
				} 
				leftoverSet.removeAll(e);
				currList.clear();
			}
		}

		//    System.err.println("4. " + (System.nanoTime() - startTimeNano));

		if (!leftoverSet.isEmpty()) {
			transQuantList.get(0).quantSet.unionWith(toVarSet(leftoverSet));
		}

		//    System.err.println("5. " + (System.nanoTime() - startTimeNano));

		// NOTE: handle the support sets with empty quantify sets
		List<TransQuantPair> tmpList = new ArrayList<TransQuantPair>(transQuantList);
		transQuantList.clear();
		Iterator<TransQuantPair> itr = tmpList.iterator();
		while (itr.hasNext()) {
			TransQuantPair p = itr.next();
			if (!p.quantSet.isEmpty()) {
				transQuantList.add(p);
			} else {
				boolean first = true;
				do {
					if (first) {
						transQuantList.add(p);
						first = false;
					} else {
						transQuantList.get(transQuantList.size()-1).partTrans.andWith(p.partTrans);
					}
					if (itr.hasNext()) {
						p = itr.next();
					} else {
						break;
					}
				} while (p.quantSet.isEmpty()); 
				transQuantList.get(transQuantList.size()-1).partTrans.andWith(p.partTrans);
				transQuantList.get(transQuantList.size()-1).quantSet = p.quantSet;
			}
		}

		//    System.err.println("6. " + (System.nanoTime() - startTimeNano));

		// NOTE: group quantify sets with 1 variable to groups of 2 or 3 variables
		tmpList = new ArrayList<>();
		int setSize = 3;
		for (int j = 0; j < transQuantList.size(); j++) {
			if (j + 1 < transQuantList.size() && (transQuantList.get(j).quantSet.size() + transQuantList.get(j+1).quantSet.size() <= setSize)) {
				TransQuantPair p = new TransQuantPair(transQuantList.get(j).partTrans.andWith(transQuantList.get(j+1).partTrans), 
						transQuantList.get(j).quantSet.unionWith(transQuantList.get(j+1).quantSet));

				if (j + 2 < transQuantList.size() && (transQuantList.get(j+2).quantSet.size() + p.quantSet.size() <= setSize)) {
					p.partTrans.andWith(transQuantList.get(j+2).partTrans);
					p.quantSet.unionWith(transQuantList.get(j+2).quantSet);
					j++;
				}

				j++;
				tmpList.add(p);
			} else {
				tmpList.add(transQuantList.get(j));
			}

		}

		//    System.err.println("7. " + (System.nanoTime() - startTimeNano));
		transQuantList.clear();
		transQuantList = tmpList;

		//    System.err.println("8. " + (System.nanoTime() - startTimeNano));

		//    BDDVarSet allSet = Env.getEmptySet();
		for (int j = 0; j < transQuantList.size(); j++) {
			BDDVarSet supp = transQuantList.get(j).partTrans.support();
//			System.out.println("transQuantList["+j+"].support = " + supp + ", E_"+j+" = " + transQuantList.get(j).quantSet);
//			System.out.println("nodes count = " +  transQuantList.get(j).partTrans.nodeCount());
			supp.free();
		}

//		long end = System.nanoTime() - start;
//		System.out.println("overall time of calcTransQuantList time = " + end);

		//    System.err.println("9. " + (System.nanoTime() - startTimeNano));

		//    if (!allSet.equals(modulePrimeVars())) {
		//      System.err.println("All the quant sets not equal to prime sets!!! ");
		//      System.err.println("  allSet = " + allSet);
		//      System.err.println("  cachedPrimeVars = " + modulePrimeVars());
		//    }  
		//    allSet.free();
	}

	/**
	 * create a BDDVarSet that contains the variables in e 
	 * @param e
	 * @return
	 */
	private BDDVarSet toVarSet(Set<Integer> e) {
		BDDVarSet res = Env.getEmptySet();
		for (int i : e) {
			res.unionWith(i);
		}
		return res;
	}

	/**
	 * create set that contains all integers of the BDDVarSet 
	 * @param varSet
	 * @return
	 */
	private Set<Integer> toIntSet(BDDVarSet varSet) {
		return Arrays.stream(varSet.toArray()).boxed().collect(Collectors.toSet());
	}

	private Set<Integer> toIntSuppSet(BDD b) {
		BDDVarSet supp = b.support();
		Set<Integer> res = toIntSet(supp); 
		supp.free();
		return res;
	}

	@SuppressWarnings("unused")
	private void calcTransQuantList2() { 
		computeVarSets();

		Iterator<BDD> transItr = transList.iterator();
		List<List<BDD>> tmpSets = new ArrayList<>();

		while (transItr.hasNext())
		{
			BDD bdd = transItr.next();
			BDDVarSet currVarSet = bdd.support().intersect(cachedUnprimeVars);
//			System.out.println("currVarSet = " + currVarSet);

			// TODO: add all the safeties to a list - conjunct just the ones with the same vars.
			// Then perform all the calculations of the E sets in some function inside the Player module. it can be called at the first yield. 
			boolean isDisjoint = true; 
			for (int k = 0; k < tmpSets.size(); k++) {
				for (int j = 0; j < tmpSets.get(k).size(); j++) {
					//System.out.println("k = " + k + ", j = " + j);
					//System.out.println("tmpSet.support() = " + tmpSets.get(k).get(j).support());
					BDDVarSet tmpVarSet = tmpSets.get(k).get(j).support().intersect(cachedUnprimeVars);
					BDDVarSet intersectSet = currVarSet.intersect(tmpVarSet);
					//System.out.println("tmpVarSet = " + tmpVarSet);
					//System.out.println("intersectSet = " + intersectSet);

					// TODO: handle disjoint sets separately?? 
					//          if (intersectSet.isEmpty()) {
					//            System.out.println("empty intersection, continue ");
					//            continue;
					//          }

					isDisjoint = false;
					boolean contains = intersectSet.equals(tmpVarSet);
					boolean contained = intersectSet.equals(currVarSet);
					if (contains && contained) {
//						System.out.println("equal support, add to this bdd");
						tmpSets.get(k).get(j).andWith(bdd.id());
						break;
					} else if (j == (tmpSets.get(k).size() - 1)) {
//						System.out.println("add to the end of the list ");
						tmpSets.get(k).add(bdd.id());
						break;
					} 
				}

				if (!isDisjoint) {
					break;
				}
			}

			if (isDisjoint && !bdd.support().isEmpty()) {
				List<BDD> l = new ArrayList<>();
				l.add(bdd.id());
				tmpSets.add(l);
//				System.out.println("found disjoint set, add list " + bdd.support());
			}

			if (bdd.support().isEmpty()) {
//				System.out.println("bdd with empty support: " + bdd);
			}
		}

//		for (int k = 0; k < tmpSets.size(); k++) {
//			System.out.println("set " + k);
//			for (int j = 0; j < tmpSets.get(k).size(); j++) { 
//				System.out.println("  " + tmpSets.get(k).get(j).support());   
//			}
//		}

//		System.out.println("trans support: " + trans.support());

		List<List<TransQuantPair>> finalTrans = new ArrayList<>();

		for (int k = 0; k < tmpSets.size(); k++) {
//			System.out.println("set " + k);

			List<TransQuantPair> partTransQuantList = new ArrayList<>();

			List<BDD> currList = tmpSets.get(k);
			while (!currList.isEmpty()) {
				BDDVarSet maxSet = Env.getEmptySet();
				int maxIdx = -1;
				for (int j = 0; j < currList.size(); j++) {           
					BDDVarSet set = currList.get(j).support().intersect(cachedUnprimeVars);
					BDDVarSet eset = set;

					for (int h = 0; h < currList.size(); h++) {
						if (h != j) {
							eset = eset.minus(currList.get(h).support().intersect(cachedUnprimeVars));  
						}
					}

					if (maxSet.size() < eset.size()) {
						maxSet = eset;
						maxIdx = j;
					}
				}

				if (maxIdx == -1) {
//					System.out.println("no maximum - intersect the remaining trans ");
					BDD leftTrans = Env.TRUE();
					for (int q = 0; q < currList.size(); q++) {
						leftTrans.andWith(currList.get(q));
					}
					BDDVarSet e = leftTrans.support().intersect(cachedUnprimeVars);
//					System.out.println("resulting E: " + e);
//					System.out.println("intersect with prime: " + leftTrans.support().intersect(cachedPrimeVars));
//					System.out.println("is TRUE: " + leftTrans.isOne());
//					System.out.println("is FALSE: " + leftTrans.isZero());
					if (!e.isEmpty()) {
						partTransQuantList.add(new TransQuantPair(leftTrans, e));
					}
					currList.clear();
				} else {
//					System.out.println("found maximum E: " + maxSet);
					partTransQuantList.add(new TransQuantPair(currList.get(maxIdx), maxSet));
					currList.remove(maxIdx);
				}
			}

			finalTrans.add(partTransQuantList);
		}

		// NOTE: keep the order of sets of every list, but order according the BDDVarSets between the lists. 
		//    while (!finalTrans.isEmpty()) {
		//      int maxSize = 0;
		//      int maxIdx = -1;
		//      for (int k = 0; k < finalTrans.size(); k++) {
		//        System.out.println("------------------------------------" + finalTrans.get(k).get(0).quantSet.size());
		//        if (maxSize < finalTrans.get(k).get(0).quantSet.size()) {
		//          maxSize = finalTrans.get(k).get(0).quantSet.size();
		//          maxIdx = k;
		//        }
		//      }
		//      transQuantList.add(finalTrans.get(maxIdx).get(0));
		//      finalTrans.get(maxIdx).remove(0);
		//      if (finalTrans.get(maxIdx).isEmpty()) {
		//        finalTrans.remove(maxIdx);
		//      }
		//    }

		for (int j = 0; j < transQuantList.size(); j++) {
			BDDVarSet supp = transQuantList.get(j).partTrans.support();
			System.out.println("transQuantList["+j+"].support = " + supp + ", E_"+j+" = " + transQuantList.get(j).quantSet);
			supp.free();
		}

	}
	/**
	 * <p>
	 * A state s in included in the returning result if responder module can force this module to reach a state in
	 * "to".<br>
	 * That is, regardless of how this module will move from the result, the responder module can choose an appropriate
	 * move into "to".
	 * </p>
	 * 
	 * @param responder
	 *          The module which moves (i.e. this is the responder).
	 * @param to
	 *          The states to reach.
	 * @return The states which can be controlled by this module.
	 */
	public BDD yieldStatesTransDecomposed(PlayerModule responder, BDD to) {    
		List<TransQuantPair> responder_transQuantList = responder.getTransQuantList();
		//    System.out.println("to.support: " + to.support());
		BDD res = Env.prime(to);

		for (int i = 0; i < responder_transQuantList.size(); i++) {
			//      BDD tmp = res.and(responder_transQuantList.get(i).partTrans);
			//      System.out.println("sys is trans: " + responder_transQuantList.get(i).equals(responder.trans()));
			//      res.free();
			//      res = tmp.exist(responder_transQuantList.get(i).quantSet);
			//      tmp.free();

			BDD tmp;
			if (simConjunctAbs) {
				tmp = res.relprod(responder_transQuantList.get(i).partTrans, responder_transQuantList.get(i).quantSet);
				res.free();
				res = tmp;
			} else {
				tmp = res.and(responder_transQuantList.get(i).partTrans);
				res.free();
				res = tmp.exist(responder_transQuantList.get(i).quantSet);
				tmp.free();
			}
		}

		if (PlayerModule.TEST_MODE) {
//			System.out.println("-------res.nodeCount = " + res.nodeCount());
			BDD tmpPrimedBdd = Env.prime(to);
			BDD tmpAndBdd = tmpPrimedBdd.and(responder.trans());
			BDD exy = tmpAndBdd.exist(responder.modulePrimeVars());

			if (!exy.equals(res)){
				System.err.println("exy not equals res" );
				System.err.println("  exy.support() = " + exy.support());
				System.err.println("  res.support() = " + res.support());
				assert(false);
			}

			exy.free();
			tmpAndBdd.free();
			tmpPrimedBdd.free();
		}

		for (int i = 0; i < this.transQuantList.size(); i++) {
			BDD tmp = this.transQuantList.get(i).partTrans.imp(res);
			res.free();
			res = tmp.forAll(this.transQuantList.get(i).quantSet);
			tmp.free();
		}

		if (PlayerModule.TEST_MODE) {
			BDDVarSet intrTest = getIntersectSupportWithPrimed(res);
			if (!intrTest.isEmpty()) {
				System.err.println("ERR: has prime vars!!!");
				System.err.println("  res.support() = " + res.support());
				System.err.println("  res.support().intersect(cachedPrimeVars) = " + intrTest);
			}
			intrTest.free();

			BDD res2 = yieldStatesOrig(responder, to);
			if (!res2.equals(res))
			{
				System.err.println("ERR: Not equal yield states! ");
				System.err.println("res.support() = " + res.support());
				System.err.println("res2.support() = " + res2.support());
				assert(false);
			}
			res2.free();  
		}
		return res;
	}

	public BDD yieldStatesOrig(PlayerModule responder, BDD to) {
		//    System.out.println("yieldStatesOrig");
		BDDVarSet responder_prime = responder.modulePrimeVars();
		BDDVarSet this_prime = this.modulePrimeVars();
		BDD tmpPrimedBdd = Env.prime(to);

		//    System.out.println("tmpPrimedBdd.nodeCount() = " + tmpPrimedBdd.nodeCount());
		//    System.out.println("responder.trans().nodeCount() = " + responder.trans().nodeCount());

		BDD exy;
		if (simConjunctAbs) {
			exy = tmpPrimedBdd.relprod(responder.trans(), responder_prime);
		} else {
			BDD tmpAndBdd = tmpPrimedBdd.and(responder.trans());
			//      System.out.println("after and: tmpAndBdd.nodeCount() = " + tmpAndBdd.nodeCount());
			//      System.out.println("to == responder.justiceAt(0): " +to.equals(responder.justiceAt(0)));
			//      System.out.println("tmpPrimedBdd == tmpAndBdd: " + tmpPrimedBdd.equals(tmpAndBdd));
			exy = tmpAndBdd.exist(responder_prime);
			tmpAndBdd.free();
		}

		//    System.out.println("after exist: exy = " + exy.toStringWithDomains());
		//    System.out.println("after exist: exy.nodeCount() = " + exy.nodeCount());
		//    System.out.println("after exist: exy.isOne() = " + exy.isOne());
		//    System.out.println("after exist: exy.isZero() = " + exy.isZero());
		BDD exyImp = this.trans().imp(exy);
		BDD res = exyImp.forAll(this_prime);

		//    System.out.println("res.nodeCount() = " + res.nodeCount());
		tmpPrimedBdd.free();
		exy.free();
		exyImp.free();
		return res;
	}

	public BDD yieldStates(PlayerModule responder, BDD to) {
		switch (transFunc) {
		case SINGLE_FUNC: 
			return yieldStatesOrig(responder, to);
		case DECOMPOSED_FUNC:
			return yieldStatesTransDecomposed(responder,to);
		case PARTIAL_DECOMPOSED_FUNC:
			return yieldStatesTransDecomposed(responder,to);
		default:
			System.err.println("Unknown type: transFunc = " + transFunc);
			break;
		}

		return Env.FALSE();  
	}

	public BDD yieldStatesTrans(PlayerModule responder, BDD trans) {
		BDDVarSet responder_prime = responder.modulePrimeVars();
		BDDVarSet this_prime = this.modulePrimeVars();
		BDD tmpAndBdd = trans.and(responder.trans());
		BDD exy = tmpAndBdd.exist(responder_prime);
		BDD exyImp = this.trans().imp(exy);
		BDD res = exyImp.forAll(this_prime);
		tmpAndBdd.free();
		exy.free();
		exyImp.free();
		return res;
	}
	/**
	 * <p>
	 * A state s is included in the returning result if the this module can force the responder to reach a state in
	 * "to".<br>
	 * </p>
	 * 
	 * @param responder
	 *          The module to check for.
	 * @param to
	 *          The states to reach.
	 * @return The states which can be controlled by this module.
	 */
	public BDD controlStates(PlayerModule responder, BDD to) {
		BDDVarSet responder_prime = responder.modulePrimeVars();
		BDDVarSet this_prime = this.modulePrimeVars();
		BDD tmpPrimeBdd = Env.prime(to);
		BDD tmpAndBdd = responder.trans().imp(tmpPrimeBdd);
		BDD exy = tmpAndBdd.forAll(responder_prime);
		BDD exyAnd = this.trans().and(exy);
		BDD res = exyAnd.exist(this_prime);
		tmpPrimeBdd.free();
		tmpAndBdd.free();
		exy.free();
		exyAnd.free();
		return res;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
	/**
	 * <p>
	 * Add a Boolean variable to this module.
	 * </p>
	 * 
	 * @param new_var the new variable name
	 * @param restrictIniTrans if true, then initials and transitions are restricted to the domain of the newly created variable
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, boolean aux, boolean restrictIniTrans) throws ModuleException,
	ModuleVariableException {
		return addVar(new_var, VarKind.BOOLEAN, 2, null, Integer.MIN_VALUE, aux, restrictIniTrans);
	}
	
	
	/**
	 * <p>
	 * Add a Boolean variable to this module.
	 * </p>
	 * 
	 * @param new_var the new variable name
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, boolean aux) throws ModuleException,
	ModuleVariableException {
		return addVar(new_var, VarKind.BOOLEAN, 2, null, Integer.MIN_VALUE, aux, true);
	}

	/**
	 * <p>
	 * Add a set of values variable to this module.
	 * </p>
	 * 
	 * @param new_var
	 *          The new variable name.
	 * @param val_names
	 *          The set of values that this variable can be assigned with.
	 * @param restrictIniTrans if true, then initials and transitions are restricted to the domain of the newly created variable
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, String[] val_names, boolean aux, boolean restrictIniTrans)
			throws ModuleException, ModuleVariableException {
		return addVar(new_var, VarKind.ENUMERATION, val_names.length, val_names, Integer.MIN_VALUE, aux, restrictIniTrans);
	}
	
	/**
	 * <p>
	 * Add a set of values variable to this module.
	 * </p>
	 * 
	 * @param new_var
	 *          The new variable name.
	 * @param val_names
	 *          The set of values that this variable can be assigned with.
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, String[] val_names, boolean aux)
			throws ModuleException, ModuleVariableException {
		return addVar(new_var, val_names, aux, true);
	}

	/**
	 * <p>
	 * Add a range variable to this module.
	 * </p>
	 * 
	 * @param new_var
	 *          The new variable name.
	 * @param range_start
	 *          The starting range of the variable.
	 * @param range_end
	 *          The ending range of the variable.
	 * @param restrictIniTrans if true, then initials and transitions are restricted to the domain of the newly created variable
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, int range_start, int range_end, boolean aux, boolean restrictIniTrans)
			throws ModuleException, ModuleVariableException {
		return addVar(new_var, VarKind.RANGE, (range_end - range_start + 1), null, range_start, aux, restrictIniTrans);
	}
	
	/**
	 * <p>
	 * Add a range variable to this module.
	 * </p>
	 * 
	 * @param new_var
	 *          The new variable name.
	 * @param range_start
	 *          The starting range of the variable.
	 * @param range_end
	 *          The ending range of the variable.
	 * @return The newly created field.
	 * @throws ModuleException
	 *           If an illegal manipulation to the module had been done. e.g. duplicate variable names.
	 * @throws ModuleVariableException
	 */
	public ModuleBDDField addVar(String new_var, int range_start, int range_end, boolean aux)
			throws ModuleException, ModuleVariableException {
		return addVar(new_var, range_start, range_end, aux, true);
	}
	
	/**
	 * <p>
	 * Check whether a variable with the given name exists.
	 * </p>
	 * 
	 * @param addr
	 *          The variable full name relative to this module.
	 * @return true if the variable field exists.
	 */
	public boolean hasVar(String addr) {
		if (addr == null || addr.equals("")) {
			return false;
		}
		for (ModuleBDDField coup : this.getAllFields()) {
			if (coup.getName().equals(addr)) {
				return true;
			}
		}
		return false;
	}
	
//	private ModuleBDDField addVar(String new_var, VarKind kind, int values_size,
//			String[] val_names, int range_start, boolean aux) throws ModuleException, ModuleVariableException {
//		return addVar(new_var, kind, values_size, val_names, range_start, aux, true);
//	}

	private ModuleBDDField addVar(String new_var, VarKind kind, int values_size,
			String[] val_names, int range_start, boolean aux, boolean restrictIniTrans) throws ModuleException, ModuleVariableException {
		if (new_var == null || new_var.equals(""))
			throw new ModuleException("Couldn't declare a variable with no " + "name.");

		ModuleBDDField bdd_var = Env.getVar(new_var);
		if (bdd_var != null) {
			List<String> evs = Env.getValueNames(new_var);
			switch (kind) {
			case BOOLEAN:
				if (evs.size() != 2 || !evs.contains("true") || !evs.contains("false")) {
					throw new ModuleException("Variable " + new_var + " already declared with different domain.");
				}
				break;
			case RANGE:
				if (evs.size() != values_size || !evs.contains("" + range_start)
				|| !evs.contains("" + (range_start + values_size - 1))) {
					throw new ModuleException("Variable " + new_var + " already declared with different domain.");
				}
				break;
			case ENUMERATION:
				if (evs.size() != values_size || !evs.containsAll(Arrays.asList(val_names))) {
					throw new ModuleException("Variable " + new_var + " already declared with different domain.");
				}
				break;
			}
		} else {
			bdd_var = Env.newVar(new_var, values_size);

			// register value names
			switch (kind) {
			case BOOLEAN:
				Env.addBDDValueLookup(new_var, "false", bdd_var.getDomain().ithVar(0));
				Env.addBDDValueLookup(new_var, "true", bdd_var.getDomain().ithVar(1));
				Env.addBDDValueLookup(new_var + "'", "false", bdd_var.getOtherDomain().ithVar(0));
				Env.addBDDValueLookup(new_var + "'", "true", bdd_var.getOtherDomain().ithVar(1));
				break;
			case RANGE:
				Env.stringer.register_domain_module_values(bdd_var.getDomain(), range_start, values_size);
				Env.stringer.register_domain_module_values(bdd_var.getOtherDomain(), range_start, values_size);
				for (long i = range_start; i < range_start + values_size; i++) {
					Env.addBDDValueLookup(new_var, "" + i, bdd_var.getDomain().ithVar(i - range_start));
					Env.addBDDValueLookup(new_var + "'", "" + i, bdd_var.getOtherDomain().ithVar(i - range_start));
				}
				break;
			case ENUMERATION:
				if (values_size != val_names.length)
					throw new ModuleException("Internal error: values list do " + "not match the size");
				Env.stringer.register_domain_module_values(bdd_var.getDomain(), val_names);
				Env.stringer.register_domain_module_values(bdd_var.getOtherDomain(), val_names);
				for (long i = 0; i < val_names.length; i++) {
					Env.addBDDValueLookup(new_var, val_names[(int) i], bdd_var.getDomain().ithVar(i));
					Env.addBDDValueLookup(new_var + "'", val_names[(int) i], bdd_var.getOtherDomain().ithVar(i));
				}
				break;
			default:
				break;
			}
		}

		this.allFields.add(bdd_var);
		if (aux) {
			this.auxFields.add(bdd_var);
		} else {
			this.nonAuxFields.add(bdd_var);
		}
		// update doms with domains of variables
		this.doms.andWith(bdd_var.getDomain().domain());
		this.doms.andWith(bdd_var.getOtherDomain().domain());
		
		if(restrictIniTrans) {
			// restrict trans to domains
			conjunctTrans(doms.id());
			// restrict initials to domains
			conjunctInitial(bdd_var.getDomain().domain());
		}
		return bdd_var;
	}

	/**
	 * <p>
	 * Given a set of states, this procedure returns all states which can lead in a single module step to these states.
	 * </p>
	 * 
	 * @param to
	 *          The set of state to be reach.
	 * @return The set of states which can lead in a single module step to the given states.
	 */
	public BDD pred(BDD to) {
		return Env.pred(trans, to);
	}
	
	/**
	 * Given a set of states {@code to}, returns all states from which this and the responder module can reach {@code to} together in a single step.
	 * 
	 * @param responder
	 * @param to
	 * @return
	 */
	public BDD pred(PlayerModule responder, BDD to) {
		return pred(responder, to, null);
	}
	
	/**
	 * <p>Given a set of states {@code to}, returns all states from which this and the responder module can reach {@code to} together in a single step.
	 * However, as opposed to {@link #pred(PlayerModule, BDD)}, in addition to the transitions of this and the responder module, the single step also respects
	 * the transitions of the {@link SFAModuleConstraint} associated with the specified existential requirement at position {@code regExpSfaExReqIdx}.</p>
	 * 
	 * <p>Consequently, the returned set of states are of the form (s,q) where s is over the (unprimed) variables of both modules and q is over
	 * the variables that encode the states of the specified {@link SFAModuleConstraint}.</p>
	 * 
	 * @param responder
	 * @param to
	 * @param regExpSfaExReqIdx the index of the existential requirement, expected to have a regular expression
	 * @return
	 */
	public BDD pred(PlayerModule responder, BDD to, int regExpSfaExReqIdx) {
		ExistentialRequirement regExpExReq = this.existReqAt(regExpSfaExReqIdx);
		if(!regExpExReq.hasRegExp()) {
			throw new RuntimeException("The existential requirement at position " + regExpSfaExReqIdx + " does not have a regular expression (an SFA)");
		}
		return pred(responder, to, regExpExReq.getRegExpSfaConstraint());
	}
	
	/**
	 * <p>Given a set of states {@code to}, returns all states from which this and the responder module can reach {@code to} together in a single step.
	 * However, as opposed to {@link #pred(PlayerModule, BDD)}, in addition to the transitions of this and the responder module, the single step also respects
	 * the transitions of the specified {@link SFAModuleConstraint}, {@code exReqSfa}.</p>
	 * 
	 * <p>Consequently, the returned set of states are of the form (s,q) where s is over the (unprimed) variables of both modules and q is over
	 * the variables that encode the states {@code exReqSfa}.</p>
	 * 
	 * <p>However, if {@code exReqSfa} is {@code null}, it is ignored, and the result is as if {@link #pred(PlayerModule, BDD)} was invoked.</p>
	 * 
	 * @param responder
	 * @param to
	 * @param exReqSfa
	 * @return
	 */
	public BDD pred(PlayerModule responder, BDD to, SFAModuleConstraint exReqSfa) {
		switch (transFunc) {
		case SINGLE_FUNC: 
			return predSingleTrans(responder, to, exReqSfa);
		case DECOMPOSED_FUNC:
			return predTransDecomposed(responder,to, exReqSfa);
		case PARTIAL_DECOMPOSED_FUNC:
			return predTransDecomposed(responder,to, exReqSfa);
		default:
			System.err.println("Unknown type: transFunc = " + transFunc);
			break;
		}
		return Env.FALSE();  
	}
	
	private BDD predSingleTrans(PlayerModule responder, BDD to, SFAModuleConstraint exReqSfa) {
		BDD modulesTrans = (exReqSfa != null) ? (trans.and(responder.trans())).andWith(exReqSfa.getTrans().id()) : trans.and(responder.trans());
		BDD primedTo = Env.prime(to);		
		BDDVarSet modulesPrimeVars = this.modulePrimeVars().union(responder.modulePrimeVars());
		BDD result;
		if (simConjunctAbs) {
			result = primedTo.relprod(modulesTrans, modulesPrimeVars);
		}
		else {
			BDD transAndTo = modulesTrans.and(primedTo);
			result = transAndTo.exist(modulesPrimeVars);
			transAndTo.free();
		}


		if (PlayerModule.TEST_MODE) {
			BDD resSCA =  primedTo.relprod(modulesTrans, modulesPrimeVars);

			BDD transAndTo = modulesTrans.and(primedTo);
			BDD resAndEx = transAndTo.exist(modulesPrimeVars);
			transAndTo.free();

			if (!resSCA.equals(resAndEx)){
				System.err.println("resSCA not equals resAndEx" );
				assert(false);
			}
			resSCA.free();
			resAndEx.free();
		}

		modulesTrans.free();
		primedTo.free();		
		modulesPrimeVars.free();

		return result;
	}

	private BDD predTransDecomposed(PlayerModule responder, BDD to, SFAModuleConstraint exReqSfa) {
		List<TransQuantPair> responder_transQuantList = responder.getTransQuantList();
		BDD res = Env.prime(to);
		BDD tmp;
		if(exReqSfa != null) {
			if(simConjunctAbs) {
				tmp = res.relprod(exReqSfa.getTrans(), exReqSfa.getStatesVar().prime().support());
				res.free();
				res = tmp;
			}
			else {
				tmp = res.and(exReqSfa.getTrans());
				res.free();
				res = tmp.exist(exReqSfa.getStatesVar().prime().support());
				tmp.free();
			}
		}
		for (int i = 0; i < responder_transQuantList.size(); i++) {
			if (simConjunctAbs) {
				tmp = res.relprod(responder_transQuantList.get(i).partTrans, responder_transQuantList.get(i).quantSet);
				res.free();
				res = tmp;
			} else {
				tmp = res.and(responder_transQuantList.get(i).partTrans);
				res.free();
				res = tmp.exist(responder_transQuantList.get(i).quantSet);
				tmp.free();
			}
		}

		for (int i = 0; i < this.transQuantList.size(); i++) {
			if	(simConjunctAbs) {
				tmp = res.relprod(this.transQuantList.get(i).partTrans, this.transQuantList.get(i).quantSet);
				res.free();
				res = tmp;
			}
			else {
				tmp = res.and(this.transQuantList.get(i).partTrans);
				res.free();
				res = tmp.exist(this.transQuantList.get(i).quantSet);
				tmp.free();
			}
		}

		if (PlayerModule.TEST_MODE) {
			BDD singleRes = predSingleTrans(responder, to, exReqSfa);
			//				System.out.println("-------res.nodeCount = " + res.nodeCount());

			if (!singleRes.equals(res)){
				System.err.println("singleRes not equals res" );
				System.err.println("  singleRes.support() = " + singleRes.support());
				System.err.println("  res.support() = " + res.support());
				assert(false);
			}
			singleRes.free();
		}
		return res;
	}
	

	/**
	 * <p>
	 * Given a set of state, this procedure return all states which can lead in any number of module steps to these
	 * states.
	 * </p>
	 * 
	 * @param to
	 *          The set of state to be reach.
	 * @return The set of states which can lead in any number of module step to the given states.
	 */
	public BDD allPred(BDD to) {
		return Env.allPred(trans, to);
	}

	/**
	 * <p>
	 * This procedure return all states which the module can reach in a single step from given a set of state.
	 * </p>
	 * 
	 * @param from
	 *          The set of state to start from.
	 * @return The set of states which the module can reach in a single module step from the given states.
	 */
	public BDD succ(BDD from) {
		return Env.succ(from, trans);
	}

	/**
	 * <p>
	 * This procedure return all states which the module can reach in any number of steps from given a set of state.
	 * </p>
	 * 
	 * @param from
	 *          (consumed/freed) The set of state to start from.
	 * @return The set of states which the module can reach in any number of module steps from the given states.
	 */
	public BDD allSucc(BDD from) {
		return Env.allSucc(from, trans);
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer("PlayerModule ");
		if (name != null) {
			buf.append(name);
		}
		buf.append("\n");
		buf.append("Variables\n");
		for (ModuleBDDField field : allFields) {
			String name = field.getName();
			buf.append("{");
			for (String val : Env.getValueNames(name)) {
				buf.append(val + ", ");
			}
			buf.replace(buf.length() - 2, buf.length(), "");
			buf.append("} ");
			buf.append(name + "\n");
		}
		buf.append("\n");
		buf.append("Initial\n");
		buf.append(Env.toNiceString(initial));
		buf.append("\n\n");
		buf.append("Safety\n");
		buf.append(Env.toNiceString(trans));
		buf.append("\n\n");
		buf.append("Justice\n");
		int i = 0;
		for (BDD j : justice) {
			buf.append(i++ + ": ");
			buf.append(Env.toNiceString(j));
		}
		buf.append("\n\n");
		buf.append("Existential\n");
		i = 0;
		for(ExistentialRequirement existReq : existential) {
			buf.append(i++ + ": ");
			if(existReq.hasRegExp()) {
				buf.append(existReq.getRegExpSfaConstraint().toString());
			}
			else {
				int j = 0;
				buf.append("The following ordered list of assertions:");
				for(BDD fAssrt : existReq.getExistFinallyAssrts()) {
					buf.append("\n");
					buf.append(j++ + ": ");
					buf.append(Env.toNiceString(fAssrt));
				}
			}
			buf.append("\n");
		}
		buf.append("\n\n");

		return buf.toString();
	}

	/**
	 * fields that are marked as auxiliary
	 * 
	 * @return
	 */
	public List<ModuleBDDField> getAuxFields() {
		return auxFields;
	}

	/**
	 * fields that are not marked as auxiliary
	 * 
	 * @return
	 */
	public List<ModuleBDDField> getNonAuxFields() {
		return nonAuxFields;
	}

	/**
	 * set initial to TRUE (restricted by variable domain constraint)
	 */
	public void resetInitial() {
		this.initial.free();
		this.initial = this.doms.exist(this.modulePrimeVars());
	}

	/**
	 * set trans to TRUE (restricted by variable domain constraint).
	 * Always sets the single trans to TRUE; if a decomposed trans is used, then it is also set to TRUE
	 */
	public void resetTrans() {    
		//an implementation which assumes that a single transition relation is always constructued
		this.trans.free();
		this.trans = this.doms.id();
		if (transFunc == TransFuncType.DECOMPOSED_FUNC ||
				transFunc == TransFuncType.PARTIAL_DECOMPOSED_FUNC) {
			this.transList.clear();
			this.transList.add(this.doms.id());
			this.transQuantList.clear();
		}
		//		if (transFunc == TransFuncType.SINGLE_FUNC) {
		//			this.trans.free();
		//			this.trans = this.doms.id();
		//		} else {
		//			if (TEST_MODE) {
		//				this.trans.free();
		//				this.trans = this.doms.id();
		//			}
		//			this.transList.clear();
		//			this.transList.add(this.doms.id());
		//			this.transQuantList.clear();
		//		}
	}

	/**
	 * set single trans to TRUE (restricted by variable domain constraint)
	 */
	public void resetSingleTrans() {
		this.trans.free();
		this.trans = this.doms.id();
	}

	/**
	 * frees and removes all justices
	 */
	public void resetJustice() {
		for (BDD b : justice) {
			b.free();
		}
		justice.clear();
		justiceIDs.clear();
	}

	/**
	 * calls resetInitial(); resetTrans(); resetJustice(); to free all BDDs and start from clean module with only domain
	 * restrictions
	 * 
	 */
	public void reset() {
		resetInitial();
		resetTrans();
		resetJustice();
	}

	public void free() {
		initial.free();
		trans.free();
		Env.free(justice);
		if (cachedPrimeVars != null) {
			cachedPrimeVars.free();
		}
		if (cachedUnprimeVars != null) {
			cachedUnprimeVars.free();
		}
	}

	public BDD getDoms() {
		return doms;
	}

	/**
	 * Used for returning a new module composed of current module and the given module.
	 * 
	 * Doesn't change current or given module.
	 * 
	 * @param other
	 * @return
	 */
	public PlayerModule compose(PlayerModule other) {
		PlayerModule composed = new PlayerModule();
		composed.setName(this.name + "_composed_" + other.getName());
		
		composed.doms = this.doms.and(other.doms);
		
		composed.allFields.addAll(this.allFields);
		composed.allFields.addAll(other.allFields);
		composed.auxFields.addAll(this.auxFields);
		composed.auxFields.addAll(other.auxFields);
    composed.nonAuxFields.addAll(this.nonAuxFields);
    composed.nonAuxFields.addAll(other.nonAuxFields);


		composed.conjunctInitial(this.initial().id());
		composed.conjunctInitial(other.initial().id());
		composed.conjunctTrans(this.trans().id());
		composed.conjunctTrans(other.trans().id());

		for (int i = 0; i < this.justiceNum(); i++) {
			composed.addJustice(this.justiceAt(i).id());
		}
		for (int i = 0; i < other.justiceNum(); i++) {
			composed.addJustice(other.justiceAt(i).id());
		}

		return composed;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.action;

import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.part.FileEditorInput;

import tau.smlab.syntech.bddgenerator.BDDGenerator.TraceInfo;
import tau.smlab.syntech.gameinput.kind.PitermanSyntacticReduction;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinputtrans.TranslationException;
import tau.smlab.syntech.gameinputtrans.TranslationProvider;
import tau.smlab.syntech.gameinputtrans.translator.DefaultTranslators;
import tau.smlab.syntech.gameinputtrans.translator.Translator;
import tau.smlab.syntech.spectragameinput.ErrorsInSpectraException;
import tau.smlab.syntech.spectragameinput.SpectraInputProvider;
import tau.smlab.syntech.spectragameinput.SpectraTranslationException;
import tau.smlab.syntech.ui.jobs.CheckRealizabilityJob;
import tau.smlab.syntech.ui.jobs.ChecksJob;
import tau.smlab.syntech.ui.jobs.CounterStrategyJob;
import tau.smlab.syntech.ui.jobs.MarkerKind;
import tau.smlab.syntech.ui.jobs.SyntechBDDEngineExclusiveRule;
import tau.smlab.syntech.ui.jobs.SyntechJob;
import tau.smlab.syntech.ui.jobs.SynthesizeSharedControllerJob;
import tau.smlab.syntech.ui.jobs.SynthesizeConcreteControllerJob;
import tau.smlab.syntech.ui.jobs.SynthesizeJitSymbolicControllerJob;
import tau.smlab.syntech.ui.jobs.SynthesizeSymbolicControllerJob;
import tau.smlab.syntech.ui.logger.SpectraLogger;
import tau.smlab.syntech.ui.preferences.PreferencePage;
import tau.smlab.syntech.ui.preferences.PreferenceConstants;

public class SynthesisAction implements IObjectActionDelegate, IEditorActionDelegate {

	private IFile specFile;
	private Shell shell;

	@Override
	public void run(IAction action) {
		if (specFile == null) {
			MessageDialog.openInformation(shell, "SYNTECH", "Please select one (and only one) Spectra file.");
		}

		if (!savePage()) {
			return;
		}

		SyntechJob job = null;
		closeOldProblemView();
		switch (action.getId()) {
		case "tau.smlab.syntech.syntSymbAction":
			job = new SynthesizeSymbolicControllerJob();
			break;
		case "tau.smlab.syntech.syntJitSymbAction":
			job = new SynthesizeJitSymbolicControllerJob();
			break;
		case "tau.smlab.syntech.syntSharedSymbAction":
			job = new SynthesizeSharedControllerJob();
			break;
		case "tau.smlab.syntech.syntCmpAction":
			job = new SynthesizeConcreteControllerJob();
			break;
		case "tau.smlab.syntech.checkRealAction":
			job = new CheckRealizabilityJob();
//			job.setTrace(TraceInfo.ALL);
			break;
		case "tau.smlab.syntech.checksAction":
			job = new ChecksJob();
			job.setTrace(TraceInfo.ALL);
			break;
		case "tau.smlab.syntech.debugCmpAction":
			job = new CounterStrategyJob();
			break;

		default:
			System.err.println("Unhandled action id: " + action.getId());
			break;
		}

		MessageConsole console = getConsole();
		console.clearConsole();
		showConsole();

		long setupTime = 0, parsingTime, simplificationTime;
		long start = System.currentTimeMillis();

		job.setSpecFile(specFile);
		job.setConsole(console);
		job.setUser(true);
		job.clearMarkers();

		GameInput gi = null;
		try {
			gi = SpectraInputProvider.getGameInput(specFile.getFullPath().toString());
		} catch (ErrorsInSpectraException e) {
			job.printToConsole("Errors in input file:");
			job.printToConsole(e.getMessage());
			setupTime = System.currentTimeMillis() - start;
			job.printToConsole("Setup time: " + setupTime + "ms");
			return;
		} catch (SpectraTranslationException e) {
			job.printToConsole("Problems encountered in input file:");
			job.printToConsole(e.getMessage());
			setupTime = System.currentTimeMillis() - start;
			job.printToConsole("Setup time: " + setupTime + "ms");
			job.createMarker(e.getTraceId(), e.getMessage(), MarkerKind.CUSTOM_TEXT_ERROR);
			return;
		}
		parsingTime = System.currentTimeMillis() - start;
		job.printToConsole("Parsing: " + parsingTime + "ms");
		if (PreferencePage.getSynthesisMethod().equals(PreferenceConstants.SYNTHESIS_METHOD_PITERMAN_REDUCTION))
			PitermanSyntacticReduction.doReduction(gi);
		
		if (job.needsBound() && !gi.getWeightDefs().isEmpty()) {
			InputDialog d = new InputDialog(shell, "Specify Energy Bound",
					"Please specify a suitable bound for the Energy Game:", "20", new IInputValidator() {
						@Override
						public String isValid(String newText) {
							try {
								Integer.parseInt(newText);
							} catch (Exception e) {
								return "Unable to parse integer!";
							}
							return null;
						}
					});
			if (d.open() == Window.OK) {
				gi.setEnergyBound(Integer.parseInt(d.getValue()));
			} else {
				gi.setEnergyBound(20);
			}
			job.printToConsole("Bound set to: " + gi.getEnergyBound());
		}

		start = System.currentTimeMillis();
		try {
			List<Translator> transList = DefaultTranslators.getDefaultTranslators();
			TranslationProvider.translate(gi, transList);
			job.setTranslators(transList);
		} catch (TranslationException e) {
			job.printToConsole(e.getMessage());
			if (e.getTraceId() >= 0) {
				job.createMarker(e.getTraceId(), e.getMessage(), MarkerKind.CUSTOM_TEXT_ERROR);
			}
			return;
		}
		simplificationTime = System.currentTimeMillis() - start;
		job.printToConsole("Simplification: " + simplificationTime + "ms");

		job.setGameInput(gi);

		job.setRule(new SyntechBDDEngineExclusiveRule());
		job.schedule();
		
		SpectraLogger.logOperationStart(specFile, action.getId());
	}

	/**
	 * Closes problem view(s) (if it was opened) from previous actions.
	 */
	private void closeOldProblemView() {
		PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
			public void run() {
				String[] possibleViewsId = { "unrealizableCoreMarker", "wellSeparatedCoreMarker",
						"specAnalysisMarker" };
				for (int i = 0; i < possibleViewsId.length; i++) {
					// check if possibleViewsId[i] was opened
					IViewPart viewPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
							.findView(possibleViewsId[i]);
					if (viewPart != null) {
						// possibleViewsId[i] was opened. close it.
						PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().hideView(viewPart);
					}
				}
			}
		});
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		if (selection instanceof StructuredSelection && !selection.isEmpty()) {
			StructuredSelection s = (StructuredSelection) selection;
			if (s.size() > 1) {
				specFile = null;
			} else {
				specFile = (IFile) s.iterator().next();
			}
		}
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
	}

	private MessageConsole getConsole() {
		String name = "SYNTECH Console";
		ConsolePlugin plugin = ConsolePlugin.getDefault();
		IConsoleManager conMan = plugin.getConsoleManager();
		IConsole[] existing = conMan.getConsoles();
		for (int i = 0; i < existing.length; i++)
			if (name.equals(existing[i].getName()))
				return (MessageConsole) existing[i];
		// no console found, so create a new one
		MessageConsole myConsole = new MessageConsole(name, null);
		conMan.addConsoles(new IConsole[] { myConsole });
		return myConsole;
	}

	/**
	 * If the page is unsaved, ask user if he wants to save it first
	 * 
	 * @return false if the user has chosen to abort
	 */
	private boolean savePage() {
		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();

		// check if file is saved
		IEditorPart editorPart = page.getActiveEditor();
		if (editorPart != null && editorPart.isDirty()) {
			boolean isYes = MessageDialog.openQuestion(shell, "SYNTECH",
					"The file is not saved. Select 'Yes' to save and 'No' to abort.");
			if (isYes) {
				editorPart.doSave(null);
			} else {
				return false;
			}
		}
		return true;
	}

	private void showConsole() {
		try {
			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
			IConsoleView view = (IConsoleView) page.showView(IConsoleConstants.ID_CONSOLE_VIEW);
			view.display(getConsole());
		} catch (PartInitException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void setActiveEditor(IAction action, IEditorPart targetEditor) {
		if (targetEditor != null) {
			IEditorInput input = targetEditor.getEditorInput();
			if (input != null && input instanceof FileEditorInput) {
				IFile ifile = ((FileEditorInput) input).getFile();
				if (ifile != null) {
					if ("spectra".equals(ifile.getFileExtension())) {
						specFile = ifile;
					}
				}
			}
		}
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.Constraint.Kind;
import tau.smlab.syntech.gameinput.model.ExistentialConstraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.model.Player;
import tau.smlab.syntech.gameinput.model.TypeDef;
import tau.smlab.syntech.gameinput.model.Variable;
import tau.smlab.syntech.gameinput.model.WeightDefinition;
import tau.smlab.syntech.gameinput.spec.Operator;
import tau.smlab.syntech.gameinput.spec.PrimitiveValue;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.VariableReference;
import tau.smlab.syntech.gameinputtrans.AuxVariableGenerator;
import tau.smlab.syntech.gameinputtrans.TranslationException;

/**
 * translate every operator to a variable added to AUX the SpecExp with the past operator becomes a VariableReference to
 * the new variable the variable value is defined by initial and safety constraints that are added to the AUX module
 * (details what constraints to add are in code below)
 * 
 * https://smlab.unfuddle.com/svn/smlab_synthesis1/trunk/AspectLTL/net.games.core/src/net/games/core/parser/SpecificationParser.java
 * 
 * Depends on DefinesTranslator, CounterTranslator, MonitorTranslator, PatternConstraintTranslator, PredicateInstanceTranslator
 * 
 */
public class PastLTLTranslator implements Translator {

	private Player auxPlayer;
	private Map<Integer, VariableReference> pasLTLSpecsHashMap;
	private List<Constraint> auxPastConstraints;
	private Map<VariableReference, List<Constraint>> varRefToConstraints;
	@Override
	public void translate(GameInput input) {

		auxPlayer = input.getAux();
		pasLTLSpecsHashMap = new HashMap<>();
		auxPastConstraints = new ArrayList<Constraint>();
		varRefToConstraints = new HashMap<>();

		// sys constraints
		for (Constraint c : input.getSys().getConstraints()) {
			if (c.getSpec().isPastLTLSpec()) {
				try {
					c.setSpec(replacePastOperators(c.getSpec(), c.getTraceId()));
				} catch (CloneNotSupportedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		// sys existential constraints
		for (ExistentialConstraint exC : input.getSys().getExistentialConstraints()) {
			Spec currSpec;
			if(!exC.isRegExp()) {
				for(int i = 0; i < exC.getSize() ; i++) {
					currSpec = exC.getSpec(i);
					if (currSpec.isPastLTLSpec()) {
						try {
							exC.replaceSpec(i, replacePastOperators(currSpec, exC.getTraceId()));
						} catch (CloneNotSupportedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		}

		// env constraints
		for (Constraint c : input.getEnv().getConstraints()) {
			if (c.getSpec().isPastLTLSpec()) {
				try {
					c.setSpec(replacePastOperators(c.getSpec(), c.getTraceId()));
				} catch (CloneNotSupportedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		// aux constraints
		for (Constraint c : input.getAux().getConstraints()) {
			if (c.getSpec().isPastLTLSpec()) {
				try {
					c.setSpec(replacePastOperators(c.getSpec(), c.getTraceId()));
				} catch (CloneNotSupportedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		// weights
		for (WeightDefinition w : input.getWeightDefs()) {
			if (w.getDefinition().getSpec().isPastLTLSpec()) {
				try {
					w.getDefinition().setSpec(replacePastOperators(w.getDefinition().getSpec(), w.getDefinition().getTraceId()));
				} catch (CloneNotSupportedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		input.getAux().getConstraints().addAll(auxPastConstraints);
	}

	private Spec replacePastOperators(Spec spec, int traceId) throws CloneNotSupportedException {

		if (spec instanceof SpecExp) {
			int specHash = -1;
			SpecExp se = (SpecExp) spec;
			if (se.getOperator().isPastLTLOp()) {
				specHash= getHashCode(spec, traceId);
				VariableReference hashedReference = pasLTLSpecsHashMap.get(specHash);
				if (hashedReference != null) {
					return hashedReference;
				}
			}

			for (int i = 0; i < se.getChildren().length; i++) {
				se.getChildren()[i] = replacePastOperators(se.getChildren()[i], traceId);
			}
			if (se.getOperator().isPastLTLOp()) {        
				// prepare common variables
				Variable aux = addFreshAuxVariable(se.getOperator(), traceId);
				Spec p_aux = new SpecExp(Operator.PRIME, new VariableReference(aux));
				Spec safetySpec;
				switch (se.getOperator()) {
				case PREV:
					// negation of aux var
					Spec iniSpec = new SpecExp(Operator.NOT, new VariableReference(aux));
					auxPastConstraints.add(new Constraint(Kind.INI, iniSpec, null, traceId));

					// update of aux var
					safetySpec = new SpecExp(Operator.IFF, p_aux, se.getChildren()[0]);
					auxPastConstraints.add(new Constraint(Kind.SAFETY, safetySpec, null, traceId));
					break;
				case ONCE:
					iniSpec = new SpecExp(Operator.IFF, new VariableReference(aux), se.getChildren()[0]);
					auxPastConstraints.add(new Constraint(Kind.INI, iniSpec, null, traceId));

					Spec auxOrPChild = new SpecExp(Operator.OR, new VariableReference(aux), new SpecExp(Operator.PRIME, se.getChildren()[0].clone()));
					safetySpec = new SpecExp(Operator.IFF, p_aux, auxOrPChild);
					auxPastConstraints.add(new Constraint(Kind.SAFETY, safetySpec, null, traceId));
					break;
				case HISTORICALLY:
					iniSpec = new SpecExp(Operator.IFF, new VariableReference(aux), se.getChildren()[0]);
					auxPastConstraints.add(new Constraint(Kind.INI, iniSpec, null, traceId));

					Spec auxAndPChild = new SpecExp(Operator.AND, new VariableReference(aux), new SpecExp(Operator.PRIME, se.getChildren()[0].clone()));
					safetySpec = new SpecExp(Operator.IFF, p_aux, auxAndPChild);
					auxPastConstraints.add(new Constraint(Kind.SAFETY, safetySpec, null, traceId));
					break;          
				case SINCE:
					// aux initially set by second child
					iniSpec = new SpecExp(Operator.IFF, new VariableReference(aux), se.getChildren()[1]);
					auxPastConstraints.add(new Constraint(Kind.INI, iniSpec, null, traceId));

					Spec primedChild1 = new SpecExp(Operator.PRIME, se.getChildren()[0].clone());
					Spec primedChild2 = new SpecExp(Operator.PRIME, se.getChildren()[1].clone());
					Spec child1AndAux = new SpecExp(Operator.AND, new VariableReference(aux), primedChild1);
					Spec child2_Or_Child1AndAux = new SpecExp(Operator.OR,primedChild2, child1AndAux);
					safetySpec = new SpecExp(Operator.IFF, p_aux, child2_Or_Child1AndAux);
					auxPastConstraints.add(new Constraint(Kind.SAFETY, safetySpec, null, traceId));
					break;
				case TRIGGERED:
					Spec child1OrChild2 = new SpecExp(Operator.OR, se.getChildren()[0], se.getChildren()[1]);
					iniSpec = new SpecExp(Operator.IFF, new VariableReference(aux), child1OrChild2);
					auxPastConstraints.add(new Constraint(Kind.INI, iniSpec, null, traceId));

					primedChild1 = new SpecExp(Operator.PRIME, se.getChildren()[0].clone());
					primedChild2 = new SpecExp(Operator.PRIME, se.getChildren()[1].clone());
					child1AndAux = new SpecExp(Operator.AND, new VariableReference(aux), primedChild1);
					child2_Or_Child1AndAux = new SpecExp(Operator.OR,primedChild2, child1AndAux);
					safetySpec = new SpecExp(Operator.IFF, p_aux, child2_Or_Child1AndAux);
					auxPastConstraints.add(new Constraint(Kind.SAFETY, safetySpec, null, traceId));
					break;

				default:
					throw new TranslationException("Unsupported PastLTL operator " + se.getOperator(), traceId);
				}
				VariableReference variableReference = new VariableReference(aux);
				pasLTLSpecsHashMap.put(specHash, variableReference);
				varRefToConstraints.put(variableReference, new ArrayList<>(auxPastConstraints.subList
						(auxPastConstraints.size()-2, auxPastConstraints.size())));
				return variableReference;
			}
		}

		return spec;
	}

	private int getHashCode(Spec spec, int traceId) {
		if (spec instanceof VariableReference)
		{
			VariableReference variableReference = (VariableReference)spec;
			return variableReference.getReferenceName().hashCode();
		}
		else if (spec instanceof PrimitiveValue)
		{
			PrimitiveValue primitiveValue = (PrimitiveValue)spec;
			return primitiveValue.getValue().hashCode();
		}
		else if (! (spec instanceof SpecExp))
		{
			throw new TranslationException("PastLTL Spec is not VariableReference / PrimitiveValue / SpecExp", traceId);
		}
		SpecExp specExp = (SpecExp)spec;
		int hashCode = specExp.getOperator().hashCode();
		for (int i = 0; i <specExp.getChildren().length; i++)
		{
			Spec child = specExp.getChildren()[i];
			hashCode *= 31;
			hashCode += getHashCode(child, traceId);
		}

		return hashCode;
	}

	private Variable addFreshAuxVariable(Operator operator, int traceId) {
		String varName = operator.toString() + "_aux_" + AuxVariableGenerator.useVar();
		Variable aux = new Variable(varName, new TypeDef());
		auxPlayer.addVar(aux);
		return aux;
	}

	public List<Constraint> getConstraintsOfVarRef(VariableReference varRef) {
		return this.varRefToConstraints.get(varRef);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

import java.util.List;

import tau.smlab.syntech.gameinput.model.Pattern;

public class SpecWrapper {

  private Spec spec;
  private boolean hasPatternReference;
  private Pattern pattern;
  private List<Spec> parameters;

  
  /**
   * Use this constructor to create a regular spec (without pattern reference)
   * @param spec
   */
  public SpecWrapper(Spec spec)
  {
    this.spec = spec;
    this.hasPatternReference = false;
    this.pattern = null;
    this.parameters = null;
  }
  
  /**
   * Use this constructor to create a spec that describes a pattern reference
   * @param pattern
   * @param parameters the passed parameters to the pattern (must be a boolean expression)
   */
  public SpecWrapper(Pattern pattern, List<Spec> parameters)
  {
    this.spec = null;
    this.hasPatternReference = true;
    this.pattern = pattern;
    this.parameters = parameters;
  }
  
  public Spec getSpec() {
    return spec;
  }

  public boolean isHasPatternReference() {
    return hasPatternReference;
  }

  public Pattern getPattern() {
    return pattern;
  }

  public List<Spec> getParameters() {
    return parameters;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.sfa;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;

////imports for toString() method (returns a DOT representation of the SFA)
//import org.eclipse.gef.dot.internal.DotAttributes;
//import org.eclipse.gef.dot.internal.DotExport;
//import org.eclipse.gef.dot.internal.language.dot.GraphType;
//import org.eclipse.gef.graph.Graph;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.sfa.PowerSetIterator.PowerSetIteratorType;


/**
 * 
 * @author <NAME>
 * @author <NAME>
 *
 * @param <T> the type of the states the SFA has
 */
@SuppressWarnings("restriction")
public abstract class BaseSFA<T extends BaseSFAState<T>> implements SFA {
	
	final public static String EPS_LABEL = "\u03B5"; //Unicode code point of 'Epsilon'
	
	protected T ini; // the initial state of this automaton
	protected PowerSetIteratorType psIterType; // the type of the powerset (of outgoing transitions) iterator used for by the determinization algorithm
	
	protected BaseSFA(SFAState ini, PowerSetIteratorType psIterType) {
		this.setIni(ini);
		this.psIterType = psIterType;
	}

	protected BaseSFA() {
		this(null, PowerSetIteratorType.EFFICIENT);
	}

	protected BaseSFA(SFAState ini) {
		this(ini, PowerSetIteratorType.EFFICIENT);
	}

	protected BaseSFA(PowerSetIteratorType psIterType) {
		this(null, psIterType);
	}

	protected abstract BaseSFA<T> newSfaInstance();

	protected abstract BaseSFA<T> newSfaInstance(T ini);

	@Override
	public T getIni() {
		return ini;
	}
	
	@Override
	public boolean enablesEpsTrans() {
		return false;
	}
	
	
	@Override
	public abstract T newSfaState(boolean isAccepting);
	
	/**
	 * Returns the type information of the states this automaton has.
	 * 
	 * @return
	 */
	protected abstract Class<T> getStatesType();
	
	/**
	 * Sets the initial state of this automaton.
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void setIni(SFAState ini) {
		if ((ini != null) && (!ini.getClass().equals(this.getStatesType()))) {
			throw new SFAException("The specified state has an invalid type. The initial state must be of type " + this.getStatesType().getSimpleName());
		}
		this.ini = (T) ini;
	}

	@Override
	public PowerSetIteratorType getPsIterType() {
		return psIterType;
	}

	@Override
	public void setPsIterType(PowerSetIteratorType powerSetIteratorType) {
		this.psIterType = powerSetIteratorType;
	}

	@Override
	public Set<T> finalStates() {
		Queue<T> worklist = new LinkedList<>();
		Set<T> seen = new LinkedHashSet<>();
		Set<T> finalStates = new LinkedHashSet<>();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();
			if (s.isAccepting()) {
				finalStates.add(s);
			}
			// add successors which have not been checked yet
			for (T succ : s.getSuccessors()) {
				if (!seen.contains(succ)) {
					worklist.add(succ);
					seen.add(succ);
				}
			}
		}
		return finalStates;
	}

	@Override
	public void free() {
		Queue<T> worklist = new LinkedList<>();
		Set<T> seen = new LinkedHashSet<>();

		worklist.add(ini);
		seen.add(ini);

		while (!worklist.isEmpty()) {
			T s = worklist.remove();

			// free the guards of all outgoing transitions
			for (BDD guard : s.getSucc().values()) {
				if (!guard.isFree()) {
					guard.free();
				}
			}

			// add successors which have not been searched
			for (T succ : s.getSuccessors()) {
				if (!seen.contains(succ)) {
					worklist.add(succ);
					seen.add(succ);
				}
			}
		}
	}

	@Override
	public boolean isDeterministic() {
		Queue<T> worklist = new LinkedList<>();
		Set<T> seen = new LinkedHashSet<>();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();
			// check determinism of outgoing transitions
			if (hasOverlap(s.getSucc().values())) {
				return false;
			}
			// add successors not checked yet
			for (T succ : s.getSuccessors()) {
				if (!seen.contains(succ)) {
					worklist.add(succ);
					seen.add(succ);
				}
			}
		}
		return true;
	}
	
	@Override
	public boolean hasOneFinalState() {
		return false;
	}

	@Override
	public SFAState getFinalState() {
		throw new SFAException("This automaton does not have a single, unique final state.");
	}

	@Override
	public void setFinalState(SFAState finalState) {
		throw new SFAException("This automaton does not have a single, unique final state.");
	}
	
	@Override
	public abstract BaseSFA<T> copy();

	
	@Override
	public BaseSFA<T> eliminateEpsTrans() {
		return this.copy();
	}
	
	@Override
	public boolean hasEpsTrans() {
		return false;
	}
	
	
	@Override
	public BaseSFA<T> determinize() {
		return this.buildDetAutomaton();
	}
	
	/**
	 * Returns a deterministic SFA (DSFA) that is equivalent to this SFA,
	 * which is assumed to be without epsilon transitions.
	 * 
	 * @return
	 */
	protected BaseSFA<T> buildDetAutomaton() {

		// create a fresh copy of this automaton and remove all the dead states from the
		// fresh copy
		BaseSFA<T> copySfa = this.copy();
		copySfa.removeDeadStates();

		// check if the removal of dead states has resulted in a deterministic automaton
		if (copySfa.isDeterministic()) {
			return copySfa; // we have a deterministic automaton so we are done
		}

		// we have that copySfa is non-deterministic so we need to determinize it
		BaseSFA<T> deterministicAutomaton = this.newSfaInstance();

		/*
		 * To distinguish between different states in the DSFA, we need to remember a
		 * mapping between sets of states in this SFA to the new states in the DSFA that
		 * we create.
		 */
		Map<Set<T>, T> stateSubsetsToDeterministicStatesMapping = new HashMap<>();
		Set<T> iniSingletonSet = new HashSet<>(Arrays.asList(copySfa.ini));

		/*
		 * The initial state in the DSFA is a singleton containing the SFA's initial
		 * state.
		 */
		T determinsticAutomatonInitialState = copySfa.ini.cloneWithoutSucc();
		stateSubsetsToDeterministicStatesMapping.put(iniSingletonSet, determinsticAutomatonInitialState);

		deterministicAutomaton.setIni(determinsticAutomatonInitialState);

		/*
		 * We use a stack to do a DFS search on (the copy without dead states of) this
		 * SFA. It will contain the state sets of the DSFA that we create.
		 */
		List<Set<T>> workStack = new Stack<>();
		workStack.add(0, iniSingletonSet);
		while (!workStack.isEmpty()) {
			Map<T, BDD> allTransitionsMap = new HashMap<>();
			Set<T> currentStateSet = workStack.remove(0), tautologySuccs = new HashSet<>();
			for (T state : currentStateSet) {
				for (Map.Entry<T, BDD> transition : state.getSucc().entrySet()) {
					/*
					 * Optimization 1: We don't need to add to the transitions set (denoted by
					 * delta_A(q) in the paper) unsatisfiable transitions, since each subset t of
					 * delta_A(q) that contains that transition will result a unsatisfiable formula
					 * phi_t, since the left conjunction will not be satisfiable.
					 *
					 * Optimization 2: If a subset t of delta_A(q) DOESN'T contains a tautology
					 * transition, then the resulting phi_t will be unsatisfiable, since the right
					 * conjunction will be unsatisfiable. Thus, it suffice to go over delta_A(q)'s
					 * subsets that contain all delta_A(q)'s tautology transitions, which is
					 * equivalent to going over all the subsets of delta_A(q)\{tautologies} and
					 * adding to each subset {tautologies} (the set of all tautology transitions).
					 * 
					 * Optimization 3: If there are multiple transitions to the SAME target state,
					 * then we can transform them into a single transition by taking their
					 * disjunction. This may save (exponentially many but redundant) iterations over
					 * subsets of delta_A(q) that contain different combinations of transitions to
					 * the SAME successor state. In case the disjunction evaluates to a tautology
					 * (i.e., it is trivially true), then we treat the "new" transition as in
					 * Optimization 2.
					 * 
					 */
					if (!transition.getValue().isZero()) {
						if (allTransitionsMap.containsKey(transition.getKey())) {
							allTransitionsMap.get(transition.getKey()).orWith(transition.getValue().id());
							if (allTransitionsMap.get(transition.getKey()).isOne()) {
								// the guard of the transition to the successor state transition.getKey() is
								// TRUE
								allTransitionsMap.get(transition.getKey()).free();
								allTransitionsMap.remove(transition.getKey());
								tautologySuccs.add(transition.getKey());
							}
						} else if (!tautologySuccs.contains(transition.getKey())) {
							// this is the first time a transition to this target/successor state is seen
							if (transition.getValue().isOne()) {
								// tautology transition
								tautologySuccs.add(transition.getKey());
							} else {
								allTransitionsMap.put(transition.getKey(), transition.getValue().id());
							}
						}
					}
				}
			}
			
			/*
			 * Optimization 3: If delta_A(q) contains two transitions with semantically equivalent guards, psi_1 and psi_2, then a subset t that only contains
			 * one of them would yield an unsatisfiable phi_t (since psi_1 and not(psi_2) is unsatisfiable).
			 * Thus, we only consider subsets of delta_A(q) that either contain ALL the transitions in delta_A(q) that have 
			 * equivalent guards or contain none of them. To achieve this, we only iterate over satisfiable subsets of delta_A(q) that contain
			 * at most one (arbitrarily chosen) representative of each subset of equivalent transitions in delta_A(q).
			 *
			 */
			
			//Map each "representative" successor state to all other successor states that have semantically equivalent transitions' guards (BDDs)
			//Note: this might be an empty set			
			Map<T, Set<T>> reprSuccToSameGuardSuccs = new HashMap<>();
			Set<T> sameGuardSuccs, seenSuccs = new HashSet<>();
			BDD succGuard;
			for(T succ : allTransitionsMap.keySet()) {
				if(!seenSuccs.contains(succ)) {
					seenSuccs.add(succ);
					sameGuardSuccs = new HashSet<>();				
					reprSuccToSameGuardSuccs.put(succ, sameGuardSuccs);
					succGuard = allTransitionsMap.get(succ);
					for(T otherSucc : allTransitionsMap.keySet()) {
						if(succ != otherSucc && allTransitionsMap.get(otherSucc).equals(succGuard)) {
							sameGuardSuccs.add(otherSucc);
							seenSuccs.add(otherSucc);
						}
					}
				}
			}
			
			Map<T, BDD> reprTransitionsMap = new HashMap<>();
			for(T repr : reprSuccToSameGuardSuccs.keySet()) {
				reprTransitionsMap.put(repr, allTransitionsMap.get(repr));
			}
			
			allTransitionsMap = reprTransitionsMap;
			
			Set<Map.Entry<T, BDD>> allTransitionsSet = allTransitionsMap.entrySet();
			Iterator<Pair<Set<Map.Entry<T, BDD>>, BDD>> psIter = PowerSetIterator.getIterator(this.psIterType, allTransitionsSet);
			Pair<Set<Map.Entry<T, BDD>>, BDD> nextPair;

			Set<Map.Entry<T, BDD>> transitionsSubset, transitionsSubsetComplement;
			boolean newDeterministicStateIsAccepting;
			Set<T> allSuccStatesSet, missingSameGuardSuccs;
			BDD transitionsGuardsConjunction;
			T detCurrentState = stateSubsetsToDeterministicStatesMapping.get(currentStateSet), detSuccessorState;

			while (psIter.hasNext()) {
				nextPair = psIter.next();
				transitionsSubset = nextPair.getLeft();
				
				/*
				 * An empty transitions set is not interesting since its successor states set is
				 * empty (this corresponds to taking no transitions at all).
				 */
				if (!transitionsSubset.isEmpty() || !tautologySuccs.isEmpty()) {
					transitionsGuardsConjunction = nextPair.getRight();
					transitionsSubsetComplement = SFAUtil.getComplementOfTransSet(allTransitionsSet, transitionsSubset);
					for (Map.Entry<T, BDD> t : transitionsSubsetComplement) {
						if (transitionsGuardsConjunction.isZero()) {
							break;
						}
						transitionsGuardsConjunction.andWith(t.getValue().not());
					}
					if (!transitionsGuardsConjunction.isZero()) {
						allSuccStatesSet = SFAUtil.getTransitionsTargetStates(transitionsSubset);
						
						//Add successor states that we removed/omitted, each of which has a transition guard equivalent to that of
						//a "representative" successor state in allSuccStatesSet (See Optimization 3 above)
						missingSameGuardSuccs = new HashSet<>();
						for(T repr : allSuccStatesSet) {
							missingSameGuardSuccs.addAll(reprSuccToSameGuardSuccs.get(repr));
						}						
						allSuccStatesSet.addAll(missingSameGuardSuccs);
						
						//Add successor states with TRUE (tautology) guards (see Optimization 2 above)
						allSuccStatesSet.addAll(tautologySuccs);
						
						if (!stateSubsetsToDeterministicStatesMapping.containsKey(allSuccStatesSet)) {
							/*
							 * If some state in successorStatesSet is an accepting SFA state, then the
							 * corresponding new DFSA state should be an accepting state (as indicated by
							 * 'newDeterministicStateIsAccepting').
							 */
							newDeterministicStateIsAccepting = SFAUtil.containsAcceptingState(allSuccStatesSet);
							detSuccessorState = this.newSfaState(newDeterministicStateIsAccepting);

							stateSubsetsToDeterministicStatesMapping.put(allSuccStatesSet, detSuccessorState);
							workStack.add(0, allSuccStatesSet);
						} else {
							detSuccessorState = stateSubsetsToDeterministicStatesMapping.get(allSuccStatesSet);
						}
						detCurrentState.addTrans(transitionsGuardsConjunction, detSuccessorState);
					} else {
						transitionsGuardsConjunction.free();
					}
				}
			}
			SFAUtil.freeTransitionsSet(allTransitionsSet);
		}
		copySfa.free();
		return deterministicAutomaton;
	}

	@Override
	public void completeTransitionFunction() {
		// Create a black hole, sink state, from where we are stuck forever.
		T sinkState = this.newSfaState(false);
		sinkState.addTrans(Env.TRUE(), sinkState);

		Queue<T> worklist = new LinkedList<>();
		List<T> seen = new ArrayList<>();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();

			// add successors not checked yet and complete the transition function
			BDD blackHoleTransGuard = Env.TRUE();
			for (Map.Entry<T, BDD> transition : s.getSucc().entrySet()) {
				if (!seen.contains(transition.getKey())) {
					worklist.add(transition.getKey());
					seen.add(transition.getKey());
				}
				blackHoleTransGuard.andWith(transition.getValue().not());
			}

			// if there is an undefined transition for some assignment
			if (!blackHoleTransGuard.isZero()) {
				s.addTrans(blackHoleTransGuard, sinkState);
			} else {
				blackHoleTransGuard.free();
			}
		}
	}


	@Override
	public BaseSFA<T> minimize() {
		if (this.isEmptyLanguage()) {
			T initialState = this.newSfaState(false);
			initialState.addTrans(Env.TRUE(), initialState);
			return this.newSfaInstance(initialState);
		}

		BaseSFA<T> deterministicAutomaton = this.determinize();
		deterministicAutomaton.completeTransitionFunction();

		// Moore’s minimization algorithm (a.k.a. the standard algorithm) lifted to SFAs
		
		// find all reachable states
		List<T> reachableStates = deterministicAutomaton.reachableStates();

		// remember each seen state's index in the seen list
		Map<T, Integer> seenStatesIndices = new HashMap<>();
		for (int i = 0; i < reachableStates.size(); ++i) {
			seenStatesIndices.put(reachableStates.get(i), i);
		}
		
		// initialize the equivalence relation E
		Set<Pair<T, T>> e = new HashSet<>();
		for (int i = 0; i < reachableStates.size(); ++i) {
			for (int j = 0; j < i; ++j) {
				T p = reachableStates.get(i);
				T q = reachableStates.get(j);
				if ((p.isAccepting() && q.isAccepting()) || (!p.isAccepting() && !q.isAccepting())) {
					e.add(new Pair<T, T>(p, q));
				}
			}
		}

		// refine E
		Set<Pair<T, T>> pairsToDelete = new HashSet<>();
		while (true) {
			for (Pair<T, T> pair : e) {
				T p = pair.getLeft();
				T q = pair.getRight();
				for (Map.Entry<T, BDD> pTransition : p.getSucc().entrySet()) {
					for (Map.Entry<T, BDD> qTransition : q.getSucc().entrySet()) {
						T p1 = pTransition.getKey();
						T q1 = qTransition.getKey();
						if (!p1.equals(q1) && !e.contains(new Pair<T, T>(p1, q1))
								&& !e.contains(new Pair<T, T>(q1, p1))) {	
							BDD pTransitionBdd = pTransition.getValue();
							BDD qTransitionBdd = qTransition.getValue();
							BDD conjunctionBdd = pTransitionBdd.and(qTransitionBdd);
							if(!conjunctionBdd.isZero()) {
								pairsToDelete.add(pair);
							}
							conjunctionBdd.free();							
						}
					}
				}
			}

			if (pairsToDelete.isEmpty()) {
				// reached a fixed point!
				break;
			}

			e.removeAll(pairsToDelete);
			pairsToDelete.clear();
		}

		// compute E-equivalence classes using a union find data structure
		QuickUnionPathCompressionUF unionFindDataStructure = new QuickUnionPathCompressionUF(reachableStates.size());
		for (Pair<T, T> pair : e) {
			unionFindDataStructure.union(seenStatesIndices.get(pair.getLeft()), seenStatesIndices.get(pair.getRight()));
		}

		// build the minimal automaton
		Map<T, T> eClassReprStateToMinimalSfaStateMap = new HashMap<>();
		T initialStateRepresentative = reachableStates
				.get(unionFindDataStructure.find(seenStatesIndices.get(deterministicAutomaton.ini)));
		eClassReprStateToMinimalSfaStateMap.put(initialStateRepresentative,
				initialStateRepresentative.cloneWithoutSucc());

		Queue<T> worklist = new LinkedList<>();
		worklist.add(initialStateRepresentative);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();
			// add successors not checked yet
			for (Map.Entry<T, BDD> transition : s.getSucc().entrySet()) {
				T succStateRepresentative = reachableStates
						.get(unionFindDataStructure.find(seenStatesIndices.get(transition.getKey())));
				if (!eClassReprStateToMinimalSfaStateMap.containsKey(succStateRepresentative)) {
					eClassReprStateToMinimalSfaStateMap.put(succStateRepresentative,
							succStateRepresentative.cloneWithoutSucc());
					worklist.add(succStateRepresentative);
				}
				eClassReprStateToMinimalSfaStateMap.get(s).addTrans(transition.getValue().id(),
						eClassReprStateToMinimalSfaStateMap.get(succStateRepresentative));
			}
		}

		BaseSFA<T> minimalAutomaton = this.newSfaInstance();
		minimalAutomaton.setIni(eClassReprStateToMinimalSfaStateMap.get(initialStateRepresentative));
		minimalAutomaton.removeDeadStates();
		return minimalAutomaton;
	}

	@Override
	public List<T> reachableStates() {
		Queue<T> worklist = new LinkedList<>();
		List<T> seen = new ArrayList<>();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();

			// add successors not checked yet
			for (T nextState : s.getSuccessors()) {
				if (!seen.contains(nextState)) {
					worklist.add(nextState);
					seen.add(nextState);
				}
			}
		}
		return seen;
	}

	@Override
	public int numStates() {
		return reachableStates().size();
	}

	/**
	 * Computes this Automaton's complement, by determinizing it and flipping its
	 * states' acceptance.
	 * 
	 * NOTE: IN ORDER FOR THIS ALGORITHM TO WORK, WE MUST MAKE SURE THAT THE
	 * TRANSITION FUNCTION IS COMPLETE, AND THAT WE ACHIVE WITH THE
	 * completeTransitionFunction() METHOD!
	 */
	@Override
	public BaseSFA<T> complement() {
		BaseSFA<T> deterministicAutomaton = this.determinize();
		deterministicAutomaton.completeTransitionFunction();

		Queue<T> worklist = new LinkedList<>();
		List<T> seen = new ArrayList<>();
		worklist.add(deterministicAutomaton.ini);
		seen.add(deterministicAutomaton.ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();
			// Flip each accepting (final) state to a non-accepting one, and vice-versa
			s.flipAcceptance();

			// Add successors not checked yet
			for (T nextState : s.getSuccessors()) {
				if (!seen.contains(nextState)) {
					worklist.add(nextState);
					seen.add(nextState);
				}
			}
		}

		return deterministicAutomaton;
	}
	
	@Override
	public void removeDeadStates() {
		// search for all final states, while building the reversed automaton
		Set<T> finalStates = new HashSet<>();
		Map<T, T> originalToReversedStatesMapping = new HashMap<>();

		Queue<T> worklist = new LinkedList<>();
		worklist.add(ini);
		originalToReversedStatesMapping.put(ini, ini.cloneWithoutSucc());
		BDD dummyGuard = Env.TRUE();

		while (!worklist.isEmpty()) {
			T s = worklist.remove();
			if (s.isAccepting()) {
				finalStates.add(s);
			}

			// add successors not checked yet
			for (T nextState : s.getSuccessors()) {
				if (!originalToReversedStatesMapping.containsKey(nextState)) {
					worklist.add(nextState);
					originalToReversedStatesMapping.put(nextState, nextState.cloneWithoutSucc());
				}

				// build reversed edges in the reversed automaton
				// the transitions' guards don't really matter so we add the SAME dummy TRUE
				// guard for all transitions (to save memory and avoid memory leaks in the BDD
				// engine)

				// originalToReversedStatesMapping.get(nextState).addTrans(Env.TRUE(),
				// originalToReversedStatesMapping.get(s));

				originalToReversedStatesMapping.get(nextState).getSucc().put(originalToReversedStatesMapping.get(s),
						dummyGuard);
			}
		}

		// search for reachable states from the final states in the reversed automaton
		List<T> seen = new ArrayList<>();
		Set<T> reachableFromFinalStatesInReversed = new HashSet<>();
		for (T finalState : finalStates) {
			worklist.clear();
			worklist.add(originalToReversedStatesMapping.get(finalState));

			seen.clear();
			seen.add(originalToReversedStatesMapping.get(finalState));

			while (!worklist.isEmpty()) {
				T sRev = worklist.remove();

				// add successors not checked yet
				for (T nextStateRev : sRev.getSuccessors()) {
					if (!seen.contains(nextStateRev)) {
						worklist.add(nextStateRev);
						seen.add(nextStateRev);
					}
				}
			}

			reachableFromFinalStatesInReversed.addAll(seen);
		}

		// free the dummy guard
		dummyGuard.free();

		// delete all states in the original automaton which are reachable from the
		// initial state but from which no accepting state can be reached
		worklist.clear();
		seen.clear();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();

			// mark all transitions to dead states
			Set<T> nextSatesToRemove = new HashSet<>();
			for (T nextState : s.getSuccessors()) {
				if (!reachableFromFinalStatesInReversed.contains(originalToReversedStatesMapping.get(nextState))) {
					nextSatesToRemove.add(nextState);
				}
			}

			// delete all dead transitions
			for (T nextState : nextSatesToRemove) {
				s.removeTrans(nextState);
			}

			// add successors not checked yet
			for (T nextState : s.getSuccessors()) {
				if (!seen.contains(nextState)) {
					worklist.add(nextState);
					seen.add(nextState);
				}
			}
		}
	}

	@Override
	public boolean isEmptyLanguage() {
		if (ini.isAccepting()) {
			return false;
		}

		Queue<T> worklist = new LinkedList<>();
		List<T> seen = new ArrayList<>();
		worklist.add(ini);
		seen.add(ini);
		while (!worklist.isEmpty()) {
			T s = worklist.remove();

			for (T succ : s.getSuccessors()) {
				if (succ.isAccepting()) {
					return false;
				}

				// add the current successor if it has not been searched yet
				if (!seen.contains(succ)) {
					worklist.add(succ);
					seen.add(succ);
				}
			}
		}
		return true;
	}

	@Override
	public boolean isSubsetOf(SFA other) {
		SFA notOtherSfa = other.complement();
		SFA thisAndNotOtherSfa = SFAs.productSfa(this, notOtherSfa);
		boolean isSubset = thisAndNotOtherSfa.isEmptyLanguage();
		
		//Free BDDs
		notOtherSfa.free();
		thisAndNotOtherSfa.free();
		
		return isSubset;
	}

	@Override
	public boolean isEquivalent(SFA other) {
		return this.isSubsetOf(other) && other.isSubsetOf(this);
	}
	
	@Override
	public boolean isTrueStarLanguage() {
		SFA trueStarSfa = SFAs.trueStarSimpleSfa();
		boolean thisIsTrueStar = trueStarSfa.isSubsetOf(this);
		trueStarSfa.free();
		return thisIsTrueStar;
	}
	
	@Override
	public boolean acceptsTheEmptyString() {
		return this.ini.isAccepting();
	}
	
	/*
	 * Creates a string representation of this SFA in the DOT language.
	 */
//	@Override
//	public String toString() {
//		if(ini == null) {return super.toString(); }
//		
//		Graph.Builder builder = new Graph.Builder().attr(DotAttributes::_setType, GraphType.DIGRAPH).attr(DotAttributes::setRankdir, "LR");
//		
//		Queue<T> worklist = new LinkedList<>();
//		List<T> seen = new ArrayList<>();
//		worklist.add(ini);
//		seen.add(ini);
//		addDotNode(builder, ini, 0);
//		
//		while (!worklist.isEmpty()) {
//			T s = worklist.remove();
//			
//			// add successors not checked yet
//			for (Map.Entry<T, BDD> transition : s.getSucc().entrySet()) {
//				if (!seen.contains(transition.getKey())) {
//					worklist.add(transition.getKey());
//					seen.add(transition.getKey());
//					addDotNode(builder, transition.getKey(), seen.size()-1);
//				}
//				builder.edge(s, transition.getKey()).attr(DotAttributes::setLabel, Env.toNiceString(transition.getValue()));
//			}
//			
//			if(s.hasEpsSuccessors()) {
//				for(T epsSucc : s.getEpsSucc()) {
//					if (!seen.contains(epsSucc)) {
//						worklist.add(epsSucc);
//						seen.add(epsSucc);
//						addDotNode(builder, epsSucc, seen.size()-1);
//					}
//					builder.edge(s, epsSucc).attr(DotAttributes::setLabel, BaseSFA.EPS_LABEL);
//				}
//			}
//		}
//		return new DotExport().exportDot(builder.build());
//	}
	
	/*
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 **************************************************************
	 * Private methods*********************************************
	 **************************************************************
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
//	private void addDotNode(Graph.Builder builder, T sfaState, int stateIdx) {
//		if(sfaState.isAccepting()) {
//			builder.node(sfaState).attr(DotAttributes::_setName, "s" + stateIdx).attr(DotAttributes::setLabel, "s" + stateIdx).attr(DotAttributes::setShape, "doublecircle");
//		}
//		else {
//			builder.node(sfaState).attr(DotAttributes::_setName, "s" + stateIdx).attr(DotAttributes::setLabel, "s" + stateIdx).attr(DotAttributes::setShape, "circle"); 
//		}
//		if(sfaState == ini) {
//			T dummyState = this.newSfaState(false);
//			builder.node(dummyState).attr(DotAttributes::_setName, "start").attr(DotAttributes::setShape, "point");
//			builder.edge(dummyState, sfaState);
//		}
//	}
	
	
	/**
	 * Checks whether the given collection of BDDs has no overlap between any two.
	 * 
	 * @param values
	 * @return
	 */
	private boolean hasOverlap(Collection<BDD> values) {
		BDD seen = Env.FALSE(), inter;
		for (BDD b : values) {
			inter = b.and(seen);
			if (!inter.isZero()) {
				inter.free();
				seen.free();
				return true;
			}
			inter.free();
			seen.orWith(b.id());
		}
		seen.free();
		return false;
	}
	
	/*
	 * 
	 * 
	 * 
	 * 
	 * ***********************************
	 * Private nested classes
	 * **********************************
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
	
	/**
	 * CODE COPIED FROM:
	 * https://algs4.cs.princeton.edu/15uf/QuickUnionPathCompressionUF.java.html
	 * 
	 * The {@code QuickUnionPathCompressionUF} class represents a union find data
	 * structure. It supports the <em>union</em> and <em>find</em> operations, along
	 * with methods for determining whether two sites are in the same component and
	 * the total number of components.
	 * <p>
	 * This implementation uses quick union (no weighting) with full path
	 * compression. Initializing a data structure with <em>n</em> sites takes linear
	 * time. Afterwards, <em>union</em>, <em>find</em>, and <em>connected</em> take
	 * logarithmic amortized time <em>count</em> takes constant time.
	 * <p>
	 * For additional documentation, see
	 * <a href="https://algs4.cs.princeton.edu/15uf">Section 1.5</a> of
	 * <i>Algorithms, 4th Edition</i> by <NAME> and <NAME>.
	 * 
	 * @author <NAME>
	 * @author <NAME>
	 */
	@SuppressWarnings("unused")
	static private class QuickUnionPathCompressionUF {
		private int[] id; // id[i] = parent of i
		private int count; // number of components

		/**
		 * Initializes an empty unionï¿½find data structure with n isolated components 0
		 * through n-1.
		 * 
		 * @param n
		 *            the number of sites
		 * @throws java.lang.IllegalArgumentException
		 *             if n < 0
		 */
		QuickUnionPathCompressionUF(int n) {
			count = n;
			id = new int[n];
			for (int i = 0; i < n; i++) {
				id[i] = i;
			}
		}

		/**
		 * Returns the number of components.
		 *
		 * @return the number of components (between {@code 1} and {@code n})
		 */
		int count() {
			return count;
		}

		/**
		 * Returns the component identifier for the component containing site {@code p}.
		 *
		 * @param p
		 *            the integer representing one object
		 * @return the component identifier for the component containing site {@code p}
		 * @throws IllegalArgumentException
		 *             unless {@code 0 <= p < n}
		 */
		int find(int p) {
			int root = p;
			while (root != id[root])
				root = id[root];
			while (p != root) {
				int newp = id[p];
				id[p] = root;
				p = newp;
			}
			return root;
		}

		/**
		 * Returns true if the the two sites are in the same component.
		 *
		 * @param p
		 *            the integer representing one site
		 * @param q
		 *            the integer representing the other site
		 * @return {@code true} if the two sites {@code p} and {@code q} are in the same
		 *         component; {@code false} otherwise
		 * @throws IllegalArgumentException
		 *             unless both {@code 0 <= p < n} and {@code 0 <= q < n}
		 */
		boolean connected(int p, int q) {
			return find(p) == find(q);
		}

		/**
		 * Merges the component containing site {@code p} with the the component
		 * containing site {@code q}.
		 *
		 * @param p
		 *            the integer representing one site
		 * @param q
		 *            the integer representing the other site
		 * @throws IllegalArgumentException
		 *             unless both {@code 0 <= p < n} and {@code 0 <= q < n}
		 */
		void union(int p, int q) {
			int rootP = find(p);
			int rootQ = find(q);
			if (rootP == rootQ)
				return;
			id[rootP] = rootQ;
			count--;
		}
	}


	/*
	 *
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * Deprecated code for documentation and validation
	 *
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
	
//	/**
//	 * Returns a string representation of the automaton, which describes its states
//	 * and transitions.
//	 */
//	@Override
//	public String toString() {
//		Queue<T> worklist = new LinkedList<>();
//		List<T> seen = new ArrayList<>();
//		worklist.add(ini);
//		seen.add(ini);
//		int numTransitions = 0;
//		List<String> acceptingTransitionsList = new ArrayList<>();
//		StringBuilder transitionsStr = new StringBuilder();
//		while (!worklist.isEmpty()) {
//			T s = worklist.remove();
//			if (s.isAccepting()) {
//				acceptingTransitionsList.add("s" + seen.indexOf(s));
//			}
//
//			// add successors not checked yet
//			for (Map.Entry<T, BDD> transition : s.getSucc().entrySet()) {
//				if (!seen.contains(transition.getKey())) {
//					worklist.add(transition.getKey());
//					seen.add(transition.getKey());
//				}
//
//				transitionsStr.append("s" + seen.indexOf(s) + " -> s" + seen.indexOf(transition.getKey()) + " : "
//						+ transition.getValue().toString() + System.lineSeparator());
//				++numTransitions;
//			}
//		}
//
//		StringBuilder prefix = new StringBuilder();
//		prefix.append("Number of states: " + seen.size() + System.lineSeparator());
//		prefix.append("Number of accepting states: " + acceptingTransitionsList.size() + System.lineSeparator());
//		prefix.append("Accepting states:" + System.lineSeparator() + acceptingTransitionsList + System.lineSeparator());
//		prefix.append("Number of transitions: " + numTransitions + System.lineSeparator());
//		prefix.append("Transitions description:" + System.lineSeparator());
//
//		return prefix.append(transitionsStr).toString();
//	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.triggers;

import java.util.List;

import dk.brics.automaton.Automaton;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;

	/** The trigger class
	 * @param traceId
	 * @param init - The trigger's init regular expression
	 * @param effect - The trigger's effect regular expression
	 * @param initAutomaton - A bricks automaton that matches the regular expression: init
	 * @param effectAutomaton - A bricks automaton that matches the regular expression: effect
	 * @param symbols -  a list of all variables that appear in the automatons, init and effect
	 * @param isBoolean - specifies which variables in 'symbols' are boolean
	 * @param from - specifies for each variable the minimal value of its range. 
	 * <br> For a variable var, this value is stored in from.symbols.getindexof(var).
	 * @param to - specifies for each variable the maximal value of its range. 
	 * <br> For a variable var, this value is stored in to.symbols.getindexof(var).<p>
	 * Hence, if var is stored at index 'i' in the list symbols, var get values in the range from[i]...to[i].
	 */

@Deprecated
public class DeprecatedTrigger {

	private SpecRegExp init;
	private Automaton initAutomaton;
	private SpecRegExp effect;
//	private Map<Spec, SpecSymbols> specSymbolsMap; 
	private Automaton effectAutomaton;
	private int traceId;
	private List<String> symbols;
	private List<Boolean> isBoolean;
	private List<Integer> from;
	private List<Integer> to;
	
	
//	private String initString;
//	private String effectString;
//	private Map<VarDecl, String> varSymbolMap;
	
	
	

//	public Trigger(SpecRegExp init, SpecRegExp effect, int traceId) {
//		this.init = init;
//		this.effect = effect;
//		this.traceId = traceId;
//	}
	
// A constructor. Receives the init and effect regular expressions as SpecRegExps, 
//	and a list that includes all (names of the) boolean variables that appear in the regular expressions
	
	public DeprecatedTrigger(SpecRegExp init, SpecRegExp effect, List<String> symbols, List<Boolean> isBoolean,
			List<Integer> from , List<Integer> to, int traceId ) {
		this.init = init;
		this.effect = effect;
		this.symbols = symbols;
		this.isBoolean = isBoolean;
		this.from = from;
		this.to = to;
		this.traceId = traceId;
	}
	
// to create the trigger with Strings that match brics regular expressions 
	
//	public Trigger(String init, String effect, Map<VarDecl, String> varSymolMap, int traceId) {
//		this.initString = init;
//		this.effectString = effect;
//		this.traceId = traceId;
//		this.varSymbolMap = varSymolMap;
//	}
	
	
	 /**
   * @param traceId
   * @param init
   * @param effect
   */
//   public Trigger(SpecWrapper init, SpecWrapper effect, int traceId) {
//     this.init = init.getRegExp();
//     this.effect = effect.getRegExp();
//     this.traceId = traceId;
//   }
	
//	public Map<Spec, SpecSymbols> getSpecSymbolsMap() {
//		return specSymbolsMap;
//	}

	public void setTraceId(int traceId) {
	    this.traceId = traceId;
	 }
	
//	public void setSpecSymbolsMap(Map<Spec, SpecSymbols> specSymbolsMap) {
//		this.specSymbolsMap = specSymbolsMap;
//	}

	public SpecRegExp getInitiator() {
		return this.init;
	}
	
	public Automaton getInitAutomaton() {
		return initAutomaton;
	}

	public void setInitAutomaton(Automaton initAutomaton) {
		this.initAutomaton = initAutomaton;
	}

	public Automaton getEffectAutomaton() {
		return effectAutomaton;
	}

	public void setEffectAutomaton(Automaton effectAutomaton) {
		this.effectAutomaton = effectAutomaton;
	}

	public SpecRegExp getEffect() {
		return this.effect;
	}
	
	public int getTraceId() {
		return this.traceId;
	}
	
	public boolean hasInitEffectAutomatons() {
	  return this.effectAutomaton != null &&
	      this.initAutomaton != null;
	}
	
	public List<String> getSymbols() {
		return this.symbols;
	}
	
	public List<Boolean> getBooleans() {
		return this.isBoolean;
	}
	
	public List<Integer> getFrom() {
		return this.from;
	}
	
	public List<Integer> getTo() {
		return this.to;
	}
}<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.jits;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

public class JitContext {
	
	private BDD envIni;
	private BDD envTrans;
	private BDD sysIni;
	private BDD sysTrans;
	
	private BDD[][] mY;
	private BDD[][][] mX;
	
	private BDD[][] mYunprimed;
	private BDD[][][] mXunprimed;
	
	// The transition BDD to be used during the execution
	private BDD trans;
	private BDD ini;

	public JitContext(BDD envIni, BDD envTrans, BDD sysIni, BDD sysTrans) {
		super();
		this.envIni = envIni;
		this.envTrans = envTrans;
		this.sysIni = sysIni;
		this.sysTrans = sysTrans;
	}
	
	public BDD getEnvIni() {
		return envIni;
	}
	public BDD getEnvTrans() {
		return envTrans;
	}
	public BDD getSysIni() {
		return sysIni;
	}
	public BDD getSysTrans() {
		return sysTrans;
	}

	public BDD getTrans() {
		return trans;
	}

	public void setTrans(BDD trans) {
		this.trans = trans;
	}
	
	public BDD getIni() {
		return ini;
	}

	public void setIni(BDD ini) {
		this.ini = ini;
	}
	
	public void free() {
		Env.free(mY);
		Env.free(mX);
		Env.free(mYunprimed);
		Env.free(mXunprimed);
		this.envIni.free();
		this.envTrans.free();
		this.sysIni.free();
		this.sysTrans.free();
		if (this.ini != null) {
			this.ini.free();	
		}
		if (this.trans != null) {
			this.trans.free();	
		}
	}
	
	public int rank(int j) {
		return mY[j].length;
	}
	
	public BDD Y(int j, int r) {
		if (r == -1) {
			return Env.FALSE();
		}
		return mY[j][r];
	}
	
	public BDD Yunprimed(int j, int r) {
		if (r == -1) {
			return Env.FALSE();
		}
		return mYunprimed[j][r];
	}
	
	public BDD X(int j, int i, int r) {
		return mX[j][i][r];
	}
	
	public BDD Xunprimed(int j, int i, int r) {
		return mXunprimed[j][i][r];
	}
	
	public void setMX(BDD[][][] mX) {
		this.mX = mX;
	}
	
	public void setMY(BDD[][] mY) {
		this.mY = mY;
	}
	
	public void setMXunprimed(BDD[][][] mX) {
		this.mXunprimed = mX;
	}
	
	public void setMYunprimed(BDD[][] mY) {
		this.mYunprimed = mY;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package net.sf.javabdd;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Stack;

import tau.smlab.syntech.jtlv.Env;

/**
 * <p>
 * Binary Decision Diagrams (BDDs) {@code Interface}
 * </p>
 * .
 **/
public interface BDD {

  /**
   * <p>
   * Returns the factory that created this BDD.
   * </p>
   * 
   * @return factory that created this BDD
   */
  public BDDFactory getFactory();

  /**
   * <p>
   * Returns true if this BDD is the zero (false) BDD.
   * </p>
   * 
   * @return true if this BDD is the zero (false) BDD
   */
  public boolean isZero();

  /**
   * <p>
   * Returns true if this BDD is the one (true) BDD.
   * </p>
   * 
   * @return true if this BDD is the one (true) BDD
   */
  public boolean isOne();

  /**
   * <p>
   * Returns true if this BDD is the universe BDD. The universal BDD differs from the one BDD in ZDD mode.
   * </p>
   * 
   * @return true if this BDD is the universe BDD
   */
  public boolean isUniverse();

  /**
   * <p>
   * Converts this BDD to a new BDDVarSet.
   * </p>
   * 
   * <p>
   * This BDD must be a boolean function that represents the all-true minterm of the BDD variables of interest.
   * </p>
   * 
   * @return the contents of this BDD as a new BDDVarSet
   */
  public BDDVarSet toVarSet();

  /**
   * <p>
   * Gets the variable labeling the BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_var.
   * </p>
   * 
   * @return the index of the variable labeling the BDD
   */
  public abstract int var();

  /**
   * <p>
   * Returns true if this BDD is an ADD
   * </p>
   * 
   * @return true if this BDD is an ADD
   */
  public boolean isADD();

  /**
   * <p>
   * Gets the level of this BDD.
   * </p>
   * 
   * <p>
   * Compare to LEVEL() macro.
   * </p>
   * 
   * @return the level of this BDD
   */
  public int level();

  /**
   * <p>
   * Gets the true branch of this BDD. If this DD is a constant, then null is returned.
   * </p>
   * 
   * <p>
   * Compare to bdd_high.
   * </p>
   * 
   * @return null if this is a constant DD; Otherwise,true branch of this BDD
   */
  public abstract BDD high();

  /**
   * <p>
   * Gets the false branch of this BDD. If this DD is a constant, then null is returned.
   * </p>
   * 
   * <p>
   * Compare to bdd_low.
   * </p>
   * 
   * @return null if this is a constant DD; Otherwise, false branch of this BDD
   */
  public abstract BDD low();

  /**
   * <p>
   * Identity function. Returns a copy of this BDD. Use as the argument to the "xxxWith" style operators when you do not
   * want to have the argument consumed.
   * </p>
   * 
   * <p>
   * Compare to bdd_addref.
   * </p>
   * 
   * @return copy of this BDD
   */
  public abstract BDD id();

  /**
   * <p>
   * Negates this BDD by exchanging all references to the zero-terminal with references to the one-terminal and
   * vice-versa.
   * </p>
   * 
   * <p>
   * Compare to bdd_not.
   * </p>
   * 
   * @return the negated BDD
   */
  public abstract BDD not();
  
  /**
   * like not() but adds domain restrictions afterwards
   * @return
   */
  public abstract BDD notWithDoms();

  /**
   * <p>
   * Returns the logical 'and' of two BDDs. This is a shortcut for calling "apply" with the "and" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_and.
   * </p>
   * 
   * @param that
   *          BDD to 'and' with
   * @return the logical 'and' of two BDDs
   */
  public BDD and(BDD that);

  /**
   * <p>
   * Makes this BDD be the logical 'and' of two BDDs. The "that" BDD is consumed, and can no longer be used. This is a
   * shortcut for calling "applyWith" with the "and" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_and and bdd_delref.
   * </p>
   * 
   * @param that
   *          the BDD to 'and' with
   */
  public BDD andWith(BDD that);

  /**
   * <p>
   * Returns the logical 'or' of two BDDs. This is a shortcut for calling "apply" with the "or" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_or.
   * </p>
   * 
   * @param that
   *          the BDD to 'or' with
   * @return the logical 'or' of two BDDs
   */
  public BDD or(BDD that);

  /**
   * <p>
   * Makes this BDD be the logical 'or' of two BDDs. The "that" BDD is consumed, and can no longer be used. This is a
   * shortcut for calling "applyWith" with the "or" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_or and bdd_delref.
   * </p>
   * 
   * @param that
   *          the BDD to 'or' with
   */
  public BDD orWith(BDD that);

  /**
   * <p>
   * Returns the logical 'xor' of two BDDs. This is a shortcut for calling "apply" with the "xor" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_xor.
   * </p>
   * 
   * @param that
   *          the BDD to 'xor' with
   * @return the logical 'xor' of two BDDs
   */
  public BDD xor(BDD that);

  /**
   * <p>
   * Makes this BDD be the logical 'xor' of two BDDs. The "that" BDD is consumed, and can no longer be used. This is a
   * shortcut for calling "applyWith" with the "xor" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_xor and bdd_delref.
   * </p>
   * 
   * @param that
   *          the BDD to 'xor' with
   */
  public BDD xorWith(BDD that);

  /**
   * <p>
   * Returns the logical 'implication' of two BDDs. This is a shortcut for calling "apply" with the "imp" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_imp.
   * </p>
   * 
   * @param that
   *          the BDD to 'implication' with
   * @return the logical 'implication' of two BDDs
   */
  public BDD imp(BDD that);

  /**
   * <p>
   * Makes this BDD be the logical 'implication' of two BDDs. The "that" BDD is consumed, and can no longer be used.
   * This is a shortcut for calling "applyWith" with the "imp" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_imp and bdd_delref.
   * </p>
   * 
   * @param that
   *          the BDD to 'implication' with
   */
  public BDD impWith(BDD that);

  /**
   * <p>
   * Returns the logical 'bi-implication' of two BDDs. This is a shortcut for calling "apply" with the "biimp" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_biimp.
   * </p>
   * 
   * @param that
   *          the BDD to 'bi-implication' with
   * @return the logical 'bi-implication' of two BDDs
   */
  public BDD biimp(BDD that);

  /**
   * <p>
   * Makes this BDD be the logical 'bi-implication' of two BDDs. The "that" BDD is consumed, and can no longer be used.
   * This is a shortcut for calling "applyWith" with the "biimp" operator.
   * </p>
   * 
   * <p>
   * Compare to bdd_biimp and bdd_delref.
   * </p>
   * 
   * @param that
   *          the BDD to 'bi-implication' with
   */
  public BDD biimpWith(BDD that);

  /**
   * <p>
   * if-then-else operator, i.e. computes: (this and then) or (not(this) and else)
   * </p>
   * 
   * <p>
   * Compare to bdd_ite.
   * </p>
   * 
   * @param thenBDD
   *          the 'then' BDD
   * @param elseBDD
   *          the 'else' BDD
   * @return the result of the if-then-else operator on the three BDDs
   */
  public BDD ite(BDD thenBDD, BDD elseBDD);

  /**
   * <p>
   * Relational product. Calculates the relational product of the two BDDs as this AND that with the variables in var
   * quantified out afterwards. Identical to applyEx(that, and, var).
   * </p>
   * 
   * <p>
   * Compare to bdd_relprod.
   * </p>
   * 
   * @param that
   *          the BDD to 'and' with
   * @param var
   *          the BDDVarSet to existentially quantify with
   * @return the result of the relational product
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD relprod(BDD that, BDDVarSet var);

  /**
   * <p>
   * Functional composition. Substitutes the variable var with the BDD that in this BDD: result = f[g/var].
   * </p>
   * 
   * <p>
   * Compare to bdd_compose.
   * </p>
   * 
   * @param g
   *          the function to use to replace
   * @param var
   *          the variable number to replace
   * @return the result of the functional composition
   */
  public BDD compose(BDD g, int var);

  /**
   * <p>
   * Simultaneous functional composition. Uses the pairs of variables and BDDs in pair to make the simultaneous
   * substitution: f [g1/V1, ... gn/Vn]. In this way one or more BDDs may be substituted in one step. The BDDs in pair
   * may depend on the variables they are substituting. BDD.compose() may be used instead of BDD.replace() but is not as
   * efficient when gi is a single variable, the same applies to BDD.restrict(). Note that simultaneous substitution is
   * not necessarily the same as repeated substitution.
   * </p>
   * 
   * <p>
   * Compare to bdd_veccompose.
   * </p>
   * 
   * @param pair
   *          the pairing of variables to functions
   * @return BDD the result of the simultaneous functional composition
   */
  public BDD veccompose(BDDPairing pair);

  /**
   * <p>
   * Generalized cofactor. Computes the generalized cofactor of this BDD with respect to the given BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_constrain.
   * </p>
   * 
   * @param that
   *          the BDD with which to compute the generalized cofactor
   * @return the result of the generalized cofactor
   */
  public BDD constrain(BDD that);

  /**
   * <p>
   * Existential quantification of variables. Removes all occurrences of this BDD in variables in the set var by
   * existential quantification.
   * </p>
   * 
   * <p>
   * Compare to bdd_exist.
   * </p>
   *
   * @param var
   *          BDDVarSet containing the variables to be existentially quantified
   * @return the result of the existential quantification
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD exist(BDDVarSet var);

  /**
   * <p>
   * Universal quantification of variables. Removes all occurrences of this BDD in variables in the set var by universal
   * quantification.
   * </p>
   * 
   * <p>
   * Compare to bdd_forall.
   * </p>
   * 
   * @param var
   *          BDDVarSet containing the variables to be universally quantified
   * @return the result of the universal quantification
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD forAll(BDDVarSet var);

  /**
   * <p>
   * Unique quantification of variables. This type of quantification uses a XOR operator instead of an OR operator as in
   * the existential quantification.
   * </p>
   * 
   * <p>
   * Compare to bdd_unique.
   * </p>
   * 
   * @param var
   *          BDDVarSet containing the variables to be uniquely quantified
   * @return the result of the unique quantification
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD unique(BDDVarSet var);

  /**
   * <p>
   * Restrict a set of variables to constant values. Restricts the variables in this BDD to constant true if they are
   * included in their positive form in var, and constant false if they are included in their negative form.
   * </p>
   * 
   * <p>
   * <i>Note that this is quite different than Coudert and Madre's restrict function.</i>
   * </p>
   * 
   * <p>
   * Compare to bdd_restrict.
   * </p>
   * 
   * @param var
   *          BDD containing the variables to be restricted
   * @return the result of the restrict operation
   * @see net.sf.javabdd.BDD#simplify(BDD)
   */
  public BDD restrict(BDD var);

  /**
   * <p>
   * Mutates this BDD to restrict a set of variables to constant values. Restricts the variables in this BDD to constant
   * true if they are included in their positive form in var, and constant false if they are included in their negative
   * form. The "that" BDD is consumed, and can no longer be used.
   * </p>
   * 
   * <p>
   * <i>Note that this is quite different than Coudert and Madre's restrict function.</i>
   * </p>
   * 
   * <p>
   * Compare to bdd_restrict and bdd_delref.
   * </p>
   * 
   * @param var
   *          BDD containing the variables to be restricted
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD restrictWith(BDD var);

  /**
   * <p>
   * Coudert and Madre's restrict function. Tries to simplify the BDD f by restricting it to the domain covered by d. No
   * checks are done to see if the result is actually smaller than the input. This can be done by the user with a call
   * to nodeCount().
   * </p>
   * 
   * <p>
   * Compare to bdd_simplify.
   * </p>
   * 
   * @param d
   *          BDDVarSet containing the variables in the domain
   * @return the result of the simplify operation
   */
  public BDD simplify(BDDVarSet d);

  /**
   * <p>
   * Returns the variable support of this BDD. The support is all the variables that this BDD depends on.
   * </p>
   * 
   * <p>
   * Compare to bdd_support.
   * </p>
   * 
   * @return the variable support of this BDD
   */
  public BDDVarSet support();

  /**
   * <p>
   * Returns the result of applying the binary operator <tt>opr</tt> to the two BDDs.
   * </p>
   * <p>
   * Note that some operators might not be valid for every type of decision diagram (BDD, ADD, 0-1 ADD). It is the
   * caller's responsibility to check for the binary operator's validity.
   * </p>
   * 
   * <p>
   * Compare to bdd_apply.
   * </p>
   * 
   * @see {@link net.sf.javabdd.BDDFactory.BDDOp}
   * @param that
   *          the BDD to apply the operator on
   * @param opr
   *          the operator to apply
   * @return the result of applying the operator
   */
  public BDD apply(BDD that, BDDFactory.BDDOp opr);

  /**
   * <p>
   * Makes this BDD be the result of the binary operator <tt>opr</tt> of two BDDs. The "that" BDD is consumed, and can
   * no longer be used. Attempting to use the passed in BDD again will result in an exception being thrown.
   * </p>
   * 
   * <p>
   * Note that some operators might not be valid for every type of decision diagram (BDD, ADD, 0-1 ADD). It is the
   * caller's responsibility to check for the binary operator's validity.
   * </p>
   * 
   * @see {@link net.sf.javabdd.BDDFactory.BDDOp}
   * @param that
   *          the BDD to apply the operator on
   * @param opr
   *          the operator to apply
   */
  public BDD applyWith(BDD that, BDDFactory.BDDOp opr);

  /**
   * <p>
   * Applies the binary operator <tt>opr</tt> to two BDDs and then performs a universal quantification of the variables
   * from the variable set <tt>var</tt>.
   * </p>
   * 
   * <p>
   * Compare to bdd_appall.
   * </p>
   * 
   * @param that
   *          the BDD to apply the operator on
   * @param opr
   *          the operator to apply
   * @param var
   *          BDDVarSet containing the variables to quantify
   * @return the result
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD applyAll(BDD that, BDDFactory.BDDOp opr, BDDVarSet var);

  /**
   * <p>
   * Applies the binary operator <tt>opr</tt> to two BDDs and then performs an existential quantification of the
   * variables from the variable set <tt>var</tt>.
   * </p>
   * 
   * <p>
   * Compare to bdd_appex.
   * </p>
   * 
   * @param that
   *          the BDD to apply the operator on
   * @param opr
   *          the operator to apply
   * @param var
   *          BDDVarSet containing the variables to quantify
   * @return the result
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD applyEx(BDD that, BDDFactory.BDDOp opr, BDDVarSet var);

  /**
   * <p>
   * Applies the binary operator <tt>opr</tt> to two BDDs and then performs a unique quantification of the variables
   * from the variable set <tt>var</tt>.
   * </p>
   * 
   * <p>
   * Compare to bdd_appuni.
   * </p>
   * 
   * @param that
   *          the BDD to apply the operator on
   * @param opr
   *          the operator to apply
   * @param var
   *          BDDVarSet containing the variables to quantify
   * @return the result
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD applyUni(BDD that, BDDFactory.BDDOp opr, BDDVarSet var);
  /**
   * <p>
   * Finds one satisfying variable assignment of this BDD which restricts each variable of the set <tt>var</tt>.
   * The only variables mentioned in the result are those of <tt>var</tt>. All other variables would be undefined, i.e., don't
   * cares, in the resulting BDD.
   * </p>
   * 
   * @param var
   *          BDDVarSet the set of variables that are mentioned in the result
   * @return one satisfying variable assignment
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDD satOne(BDDVarSet var);  
  /**
   * <p>
   * Finds all satisfying variable assignments.
   * </p>
   * 
   * <p>
   * Compare to bdd_allsat.
   * </p>
   * 
   * @return all satisfying variable assignments
   */
  public AllSatIterator allsat();

  /**
   * Iterator that returns all satisfying assignments as byte arrays. In the byte arrays, -1 means dont-care, 0 means 0,
   * and 1 means 1.
   */
  public static class AllSatIterator implements Iterator<byte[]> {

    protected final BDDFactory f;
    protected BDD original;
    protected byte[] allsatProfile;
    protected Stack<Integer> choices;
    protected LinkedList<Integer> freeVars;

    /**
     * Constructs a satisfying-assignment iterator on the given BDD. next() will returns a byte array, the byte array
     * will be indexed by BDD variable number.
     * 
     * @param r
     *          BDD to iterate over
     */
    public AllSatIterator(BDD r) {
      f = r.getFactory();
      if (f.isZDD()) {
        throw new RuntimeException("Sorry, lost ZDD compatibility.");
      }
      original = r.id();
      if (original.isZero()) {
        freeVars = null;
        return;
      }
      allsatProfile = new byte[f.varNum()];
      Arrays.fill(allsatProfile, (byte)-1);
      choices = new Stack<Integer>();
      // find relevant variables (not don't cares)
      freeVars = new LinkedList<>();
      for (int v : original.support().toArray()) {
        freeVars.add(v);
      }
      Collections.sort(freeVars);
      if (!r.isOne()) {
        if (!gotoNext()) {
          allsatProfile = null;
          original.free();
        }
      }
    }
    
    public void free() {
      if (!original.isFree()) {
        original.free();
      }
    }

    /**
     * compute next assignment of allsatProfile
     * 
     * @return true if there is a next assignment false otherwise
     */
    private boolean gotoNext() {
      if (original.isZero() || original.isOne()) {
        return false;
      }

      BDD next = Env.FALSE();
      do {
        if (next.isZero() && !choices.isEmpty()) {
          // pop all dead-ends
          int var = choices.pop();
          while (var > 0 && !choices.isEmpty()) {
            // remember to later set this variable
            freeVars.addFirst(var - 1);
            var = choices.pop();
          }

          if (var > 0 && choices.isEmpty()) {
            return false;
          }

          // now we have a negaive var and can try alternative
          var = -var - 1;
          choices.push(var + 1);
        } else if (!freeVars.isEmpty()){
          // add negated var choice
          choices.push(-(freeVars.removeFirst() + 1));
        }
        // prepare next BDD based on choices
        next.free();
        next = original.id();
        for (int i : choices) {
          if (i < 0) {
            next.andWith(f.nithVar(-i - 1));
          } else {
            next.andWith(f.ithVar(i - 1));
          }
        }
      } while (!freeVars.isEmpty() || next.isZero());
      next.free();

      // assign value to every variable
      for (int v = 0; v < allsatProfile.length; v++) {
        if (choices.contains(v+1)) {
            allsatProfile[v] = 1;
        } else if (choices.contains(-(v+1))) {
            allsatProfile[v] = 0;
        } else {
          // v is don't care
          allsatProfile[v] = -1;
        }
      }
      return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#hasNext()
     */
    public boolean hasNext() {
      return allsatProfile != null;
    }

    /**
     * Return the next satisfying var setting.
     * 
     * @return byte[]
     */
    public byte[] nextSat() {
      if (allsatProfile == null)
        throw new NoSuchElementException();
      byte[] b = new byte[allsatProfile.length];
      System.arraycopy(allsatProfile, 0, b, 0, b.length);
      if (!gotoNext()) {
        allsatProfile = null;
        original.free();
      }
      return b;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#next()
     */
    public byte[] next() {
      return nextSat();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#remove()
     */
    public void remove() {
      throw new UnsupportedOperationException();
    }

  }

  /**
   * <p>
   * Finds one satisfying assignment of the domain <tt>d</tt> in this BDD and returns that value.
   * </p>
   * 
   * <p>
   * Compare to fdd_scanvar.
   * </p>
   * 
   * @param d
   *          domain to scan
   * @return one satisfying assignment for that domain
   */
  public BigInteger scanVar(BDDDomain d);

  /**
   * <p>
   * Finds one satisfying assignment in this BDD of all the defined BDDDomain's. Each value is stored in an array which
   * is returned. The size of this array is exactly the number of BDDDomain's defined.
   * </p>
   * 
   * <p>
   * Compare to fdd_scanallvar.
   * </p>
   * 
   * @return array containing one satisfying assignment of all the defined domains
   */
  public BigInteger[] scanAllVar();

  /**
   * <p>
   * Returns an iteration of the satisfying assignments of this BDD. Returns an iteration of minterms. The <tt>var</tt>
   * argument is the set of variables that will be mentioned in the result.
   * </p>
   * 
   * @param var
   *          set of variables to mention in result
   * @return an iteration of minterms
   * @see net.sf.javabdd.BDDDomain#set()
   */
  public BDDIterator iterator(final BDDVarSet var);

  public static class BDDIterator implements Iterator<BDD> {
    final BDDFactory f;
    AllSatIterator i;
    // Reference to the initial BDD object, used to support the remove() operation.
    final BDD initialBDD;
    BDD remainder;
    /**
     * relevant variables numbers
     */
    final int[] vars;

    /**
     * Current bit assignmentof variables in vars.
     */
    final boolean[] varVals;
    /**
     * Latest result from allsat iterator. Here, array indexed by variable number. Can contain don't cares (-1).
     */
    byte[] allSatRes;
    /**
     * Last BDD returned. Used to support the remove() operation.
     */
    BDD lastReturned;

    /**
     * Construct a new BDDIterator on the given BDD. The var argument is the set of variables that will be mentioned in
     * the result.
     * 
     * @param bdd
     *          BDD to iterate over
     * @param var
     *          variable set to mention in result
     */
    public BDDIterator(BDD bdd, BDDVarSet var) {
      initialBDD = bdd;
      remainder = bdd.id();
      f = bdd.getFactory();
      i = new AllSatIterator(bdd);

      vars = var.toArray();

      varVals = new boolean[vars.length];
      gotoNext();
    }

    protected void gotoNext() {
      if (i.hasNext()) {
        // here we need to remove everything we have seen before for the current VarSet (by removing lastReturned)
        i.free();
        i = new AllSatIterator(remainder);
        if (!i.hasNext()) {
          allSatRes = null;
          return;
        }
        allSatRes = (byte[]) i.next();
      } else {
        allSatRes = null;
        return;
      }
      for (int i = 0; i < vars.length; ++i) {
        if (allSatRes[vars[i]] == 1) {
          varVals[i] = true;
        } else {
          varVals[i] = false;
        }
      }
    }

    protected boolean gotoNextA() {
      for (int i = vars.length - 1; i >= 0; --i) {
        if (allSatRes[vars[i]] != -1)
          continue;
        if (varVals[i] == false) {
          varVals[i] = true;
          return true;
        }
        varVals[i] = false;
      }
      return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#hasNext()
     */
    public boolean hasNext() {
      return allSatRes != null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#next()
     */
    public BDD next() {
      return nextBDD();
    }

    /**
     * next value in the given domain (encoding of the bools in varVals into a number)
     * 
     * @param dom
     * @return null if the domain was not in the varset when the iterator was created
     */
    public BigInteger nextValue(BDDDomain dom) {
      if (allSatRes == null) {
        throw new NoSuchElementException();
      }
      if (lastReturned != null) {
        lastReturned.free();
      }
      lastReturned = null;
      BigInteger val = BigInteger.ZERO;
      int[] ivar = dom.vars();
      for (int m = dom.varNum() - 1; m >= 0; m--) {
        val = val.shiftLeft(1);
        int varPos = Arrays.binarySearch(vars, ivar[m]);
        if (varPos < 0) {
          val = null;
          break;
        }
        if (varVals[varPos]) {
          val = val.add(BigInteger.ONE);
        }
      }
      if (!gotoNextA()) {
        gotoNext();
      }
      return val;
    }

    /**
     * Return the next BDD in the iteration.
     * 
     * @return the next BDD in the iteration
     */
    public BDD nextBDD() {
      if (allSatRes == null) {
        throw new NoSuchElementException();
      }
      if (lastReturned != null) {
        lastReturned.free();
      }
      lastReturned = f.universe();
      for (int i = 0; i < varVals.length; i++) {
        if (varVals[i] == true) {
          lastReturned.andWith(f.ithVar(vars[i]));
        } else {
          lastReturned.andWith(f.nithVar(vars[i]));
        }
      }
      remainder.andWith(lastReturned.not());
      if (!gotoNextA()) {
        gotoNext();
      }
      return lastReturned.id();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Iterator#remove()
     */
    public void remove() {
      if (lastReturned == null)
        throw new IllegalStateException();
      initialBDD.applyWith(lastReturned, BDDFactory.diff);
      lastReturned = null;
    }

    /**
     * <p>
     * Returns true if the given BDD variable number is a dont-care. <tt>var</tt> must be a variable in the iteration
     * set.
     * </p>
     * 
     * @param var
     *          variable number to check
     * @return if the given variable is a dont-care
     */
    public boolean isDontCare(int var) {
      if (allSatRes == null) {
        return false;
      }
      return allSatRes[var] == -1;
    }

    /**
     * <p>
     * Returns true if the BDD variables in the given BDD domain are all dont-care's.
     * <p>
     * 
     * @param d
     *          domain to check
     * @return if the variables are all dont-cares
     * @throws BDDException
     *           if d is not in the iteration set
     */
    public boolean isDontCare(BDDDomain d) {
      if (allSatRes == null) {
        return false;
      }
      int[] vars = d.vars();
      for (int i = 0; i < vars.length; ++i) {
        if (!isDontCare(vars[i]))
          return false;
      }
      return true;
    }

    /**
     * Fast-forward the iteration such that the given variable number is true.
     * 
     * @param var
     *          number of variable
     */
    public void fastForward(int var) {
      if (allSatRes == null) {
        throw new BDDException();
      }
      int varPos = Arrays.binarySearch(vars, var);
      if (varPos < 0 || allSatRes[var] != -1) {
        throw new BDDException();
      }
      varVals[varPos] = true;
    }

    /**
     * Fast-forward the iteration such that the given set of variables are true.
     * 
     * @param vars
     *          set of variable indices
     */
    public void fastForward(int[] vars) {
      for (int i = 0; i < vars.length; ++i) {
        fastForward(vars[i]);
      }
    }

    /**
     * Assuming <tt>d</tt> is a dont-care, skip to the end of the iteration for <tt>d</tt>
     * 
     * @param d
     *          BDD domain to fast-forward past
     */
    public void skipDontCare(BDDDomain d) {
      int[] vars = d.vars();
      fastForward(vars);
      if (!gotoNextA()) {
        gotoNext();
      }
    }
    
    public void free() {
      i.free();
      if (lastReturned != null) {
        lastReturned.free();
      }
    }
  }

  /**
   * <p>
   * Returns a BDD where all variables are replaced with the variables defined by pair. Each entry in pair consists of a
   * old and a new variable. Whenever the old variable is found in this BDD then a new node with the new variable is
   * inserted instead.
   * </p>
   * 
   * <p>
   * Compare to bdd_replace.
   * </p>
   * 
   * @param pair
   *          pairing of variables to the BDDs that replace those variables
   * @return result of replace
   */
  public BDD replace(BDDPairing pair);

  /**
   * <p>
   * Replaces all variables in this BDD with the variables defined by pair. Each entry in pair consists of a old and a
   * new variable. Whenever the old variable is found in this BDD then a new node with the new variable is inserted
   * instead. Mutates the current BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_replace and bdd_delref.
   * </p>
   * 
   * @param pair
   *          pairing of variables to the BDDs that replace those variables
   */
  public BDD replaceWith(BDDPairing pair);

  /**
   * <p>
   * Prints the set of truth assignments specified by this BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_printset.
   * </p>
   */
  public void printSet();

  /**
   * <p>
   * Prints this BDD in dot graph notation.
   * </p>
   * 
   * <p>
   * Compare to bdd_printdot.
   * </p>
   */
  public void printDot();

  /**
   * <p>
   * Counts the number of distinct nodes used for this BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_nodecount.
   * </p>
   * 
   * @return the number of distinct nodes used for this BDD
   */
  public int nodeCount();

  /**
   * <p>
   * Counts the number of paths leading to the true terminal.
   * </p>
   * 
   * <p>
   * Compare to bdd_pathcount.
   * </p>
   * 
   * @return the number of paths leading to the true terminal
   */
  public double pathCount();

  /**
   * <p>
   * Calculates the number of satisfying variable assignments.
   * </p>
   * 
   * <p>
   * Compare to bdd_satcount.
   * </p>
   * 
   * @return the number of satisfying variable assignments
   */
  public double satCount();

  /**
   * <p>
   * Calculates the number of satisfying variable assignments to the variables in the given varset. ASSUMES THAT THE BDD
   * DOES NOT HAVE ANY ASSIGNMENTS TO VARIABLES THAT ARE NOT IN VARSET. You will need to quantify out the other
   * variables first.
   * </p>
   * 
   * <p>
   * Compare to bdd_satcountset.
   * </p>
   * 
   * @return the number of satisfying variable assignments
   */
  public double satCount(BDDVarSet varset);

  /**
   * <p>
   * Calculates the logarithm of the number of satisfying variable assignments.
   * </p>
   * 
   * <p>
   * Compare to bdd_satcount.
   * </p>
   * 
   * @return the logarithm of the number of satisfying variable assignments
   */
  public double logSatCount();

  /**
   * <p>
   * Calculates the logarithm of the number of satisfying variable assignments to the variables in the given varset.
   * </p>
   * 
   * <p>
   * Compare to bdd_satcountset.
   * </p>
   * 
   * @return the logarithm of the number of satisfying variable assignments
   */
  public double logSatCount(BDDVarSet varset);

  /**
   * <p>
   * Counts the number of times each variable occurs in this BDD. The result is stored and returned in an integer array
   * where the i'th position stores the number of times the i'th printing variable occurred in the BDD.
   * </p>
   * 
   * <p>
   * Compare to bdd_varprofile.
   * </p>
   */
  public abstract int[] varProfile();

  /**
   * <p>
   * Returns true if this BDD equals that BDD, false otherwise.
   * </p>
   * 
   * @param that
   *          the BDD to compare with
   * @return true iff the two BDDs are equal
   */
  public boolean equals(BDD that);


  /**
   * <p>
   * Returns a string representation of this BDD on the defined domains, using the given BDDToString converter.
   * </p>
   * 
   * @see net.sf.javabdd.BDD.BDDToString
   * 
   * @return string representation of this BDD using the given BDDToString converter
   */
  public String toStringWithDomains(BDDToString ts);

  /**
   * <p>
   * BDDToString is used to specify the printing behavior of BDDs with domains. Subclass this type and pass it as an
   * argument to toStringWithDomains to have the toStringWithDomains function use your domain names and element names,
   * instead of just numbers.
   * </p>
   */
  public static class BDDToString {
    /**
     * <p>
     * Singleton instance that does the default behavior: domains and elements are printed as their numbers.
     * </p>
     */
    public static final BDDToString INSTANCE = new BDDToString();

    /**
     * <p>
     * Protected constructor.
     * </p>
     */
    protected BDDToString() {
    }

    /**
     * <p>
     * Given a domain index and an element index, return the element's name. Called by the toStringWithDomains()
     * function.
     * </p>
     * 
     * @param i
     *          the domain number
     * @param j
     *          the element number
     * @return the string representation of that element
     */
    public String elementName(int i, BigInteger j) {
      return j.toString();
    }

    /**
     * <p>
     * Given a domain index and an inclusive range of element indices, return the names of the elements in that range.
     * Called by the toStringWithDomains() function.
     * </p>
     * 
     * @param i
     *          the domain number
     * @param lo
     *          the low range of element numbers, inclusive
     * @param hi
     *          the high range of element numbers, inclusive
     * @return the string representation of the elements in the range
     */
    public String elementNames(int i, BigInteger lo, BigInteger hi) {
      return lo.toString() + "-" + hi.toString();
    }
  }

  /**
   * <p>
   * Converts this BDD into a 0-1 ADD.<br>
   * If this is an ADD then it is equivalent to {@link #id() id}.
   * </p>
   * 
   * @return the converted 0-1 ADD
   */
  public ADD toADD();

  /**
   * <p>
   * Frees this BDD. Further use of this BDD will result in an exception being thrown.
   * </p>
   */
  public abstract void free();

  /**
   * Checks whether this BDD has already been freed.
   * 
   * @return true if this BDD is freed
   */
  public abstract boolean isFree();

  public long rootId();
  
  /**
   * <p>Returns a deterministic version of this BDD. It is assumed that this BDD represents a controller or a strategy.<br>
   * The controller is deterministic such that for every combination of variable assignments that are not in d, there is at most one assignment of variables in d 
   * that goes to 1 constant, i.e there is at most one valid choice for the module that controls the variables that appear in d.</p>
   * 
   * @param d BDD containing the variables of the module whose choices should be deterministic
   * @return A deterministic version of this controller
   */
  public BDD determinizeController(BDDVarSet d);
}<file_sep># Spectra Synthesizer
This repository contains the code of the GR(1) synthesizer, which is based on the Spectra specification language that can be found in `spectra-lang` repository.

## Packaged Version
To download a packaged version of Eclipse with spectra tools installed, go to http://smlab.cs.tau.ac.il/syntech/spectra/index.html.
We provide also an update site to install occasional updates in the following link: `http://smlab.cs.tau.ac.il/syntech/spectra/tools/update/`.

## Installation
The synthesizer and its tools are developed over the Eclipse framework, therefore a working installation of Eclipse IDE for Java and DSL Developers (preferably version above or equals 2022-09) is a prerequisite.

In order to compile Spectra synthesizer from source code:
- As a prerequisite, follow the instructions in the `spectra-lang` repository.
- `git clone` this repository into your computer.
- Import all existing projects from both repositories into an Eclipse workspace. After the clone you should have two folders called `spectra-lang` and `spectra-synt` in your file system, containing many Java projects. `spectra-lang` projects should be already imported into your workspace. Import the projects of this repository by 'Import -> Projects from Folder or Archive', the choosing `spectra-synt` directory, and selecting all the projects from there *except* the spectra-synt folder itself (it is not a real project and it might cause problems if imported together with the other real projects).
- Run an Eclipse instance by creating a new `Eclipse Application` configuration in the `Run Configurations` window.

## Documentation
Information about Spectra language and tools can be found here: http://smlab.cs.tau.ac.il/syntech/.
A comprehensive hands-on tutorial can be found here: https://smlab.cs.tau.ac.il/syntech/tutorial/.
A detailed user guide can be downloaded from here: http://smlab.cs.tau.ac.il/syntech/spectra/userguide202210.pdf.

## Licensing
Spectra project is licensed under BSD-3-Clause. It uses CUDD library, which is also licensed under BSD-3-Clause, and whose modified code can be found in `spectra-cudd` repository. It also uses Brics automaton library, licensed under BSD-2-Clause and available here: https://www.brics.dk/automaton/.
<file_sep>source.. = src/
output.. = bin/
bin.includes = META-INF/,\
               .,\
               cudd.dll,\
               libcudd.so,\
               lib/automaton.jar,\
               src/

<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.rabin;

import java.util.Stack;
import java.util.Vector;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import net.sf.javabdd.BDD.BDDIterator;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.AbstractGamesException;
import tau.smlab.syntech.games.GamesStrategyException;
import tau.smlab.syntech.games.controller.enumerate.ConcreteControllerConstruction;
import tau.smlab.syntech.games.controller.enumerate.EnumStateI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyImpl;
import tau.smlab.syntech.jtlv.Env;

public class RabinConcreteControllerConstruction extends ConcreteControllerConstruction {
	protected RabinMemory mem;

	public RabinConcreteControllerConstruction(RabinMemory mem, GameModel m) {
		super(mem, m);
		this.mem = mem;
	}

	@Override
	public EnumStrategyI calculateConcreteController() throws AbstractGamesException {
		return this.calculateConcreteController(false);
	}

	public EnumStrategyI calculateConcreteController(boolean calcLongestSimplePath) throws AbstractGamesException {
		System.out.println("extract strategy - Start");

		if (mem.getWin() == null || mem.getWin().isFree()) {
			throw new GamesStrategyException("BDD of winning states invalid.");
		}

		Stack<EnumStateI> st_stack = new Stack<EnumStateI>();
		EnumStrategyI aut = new EnumStrategyImpl(calcLongestSimplePath);

		BDD sysDeadOrEnvWin = sys.initial().imp(mem.getWin());
		BDD allIni = env.initial().id().andWith(sysDeadOrEnvWin.forAll(sys.moduleUnprimeVars()));
		sysDeadOrEnvWin.free();
		if (allIni.isZero()) {
			throw new GamesStrategyException("No environment winning states.");
		}
		// select one env choice
		BDD ini = (BDD) allIni.iterator(env.moduleUnprimeVars()).next();
		allIni.free();
		// add all system choices
		ini.andWith(sys.initial().id());

		for (BDDIterator iter = ini.iterator(allUnprime()); iter.hasNext();) {
			BDD cand = iter.nextBDD();
			int iniZ = mem.getZRank(cand);
			int iniK = 0;
			int iniX = mem.getXRank(iniZ, iniK, cand);
			RabinRankInfo iniR = new RabinRankInfo(iniZ, iniK, iniX);
			st_stack.push(aut.getState(cand, iniR));
		}

		try {
			// int state_counter = 0;
			while (!st_stack.isEmpty()) {
				// System.out.println("num of states is: " + state_counter++);
				EnumStateI st = st_stack.pop();
				st_stack.addAll(getSysStepsToEnvChoice(aut, st));
			}
		} catch (AbstractGamesException e) {
			System.err.println("failed generating counter strategy");
			e.printStackTrace();
		}
		System.out.println("extract strategy - End");
		return aut;
	}

	// returns a vector of states representation of the next environment step
	// from a given state, and the possible set of system responses.
	private Vector<EnumStateI> getSysStepsToEnvChoice(EnumStrategyI aut, EnumStateI state)
			throws AbstractGamesException {
		if (!(state.get_rank_info() instanceof RabinRankInfo))
			throw new GamesStrategyException("cannot build rabin automata for" + "streett state");
		RabinRankInfo rri = (RabinRankInfo) state.get_rank_info();

		// int zRank = rri.get_row_count();
		// int kGoal = rri.get_env_goal();
		// int kRank = rri.get_env_goal_count();
		//
		// System.out.println("is state " + state.get_id() + " winning? "
		// + !state.get_state().and(player1_winning).isZero() + " env"
		// + kGoal + ":" + kRank + " sys rank:" + zRank);
		// System.out.println("for state " + state.get_id()
		// + " the row ranks is :" + zRank + " the conjunct rank is:"
		// + kRank);
		//

		// ////////////////////////////////////////////////////////////////////
		// ////////////////////////////////////////////////////////////////////
		// ////////////////////////////////////////////////////////////////////
		// The general idea is the first try to move as low as possible in the
		// vector of z (the lowest possible zRank). If not possible then trying
		// to move as low as possible in the relevant vector of K, and if
		// reached the lowest K, moving to the next K. Namely:
		// 1) lowering Z. // not a relevant value... can return immediately.
		// 2) if reached lowest K moving to the next K.
		// 3) try to lower K.
		// 4) not found good choice yet.
		// int priority = 4;
		// ////////////////////////////////////////////////////////////////////

		Vector<EnumStateI> ret = null;
		BDD envSuccs = env.succ(state.getData());
		BDD bestSuccs = Env.FALSE();
		int bestKind = 4;
		for (BDDIterator iter = envSuccs.iterator(env.moduleUnprimeVars()); iter.hasNext();) {
			BDD envSucc = (BDD) iter.next();

			BDD sysSuccs = sys.succ(state.getData()).and(envSucc);
			BDD succSysWin = sysSuccs.and(mem.getWin().not());
			if (!succSysWin.isZero()) {
				succSysWin.free();
				continue; // not one of the relevant environment choices.
			}
			succSysWin.free();

			int kind = getBestKind(state, rri, sysSuccs);

			if (kind == -1)
				// not a relevant env choice - one of the sys choices leads to a higher z-rank
				continue;

			if (kind == 1)
				// all sys choices for this env choice lead to a lower z-rank - this env choice
				// can force to a lower z-rank
				return calcResponses(aut, state, rri, sysSuccs, kind);

			if (kind < bestKind) {
				bestKind = kind;
				bestSuccs = sysSuccs;
			}
		}

		if (bestKind == -1)
			throw new GamesStrategyException(
					"No environment successor found from" + " state " + state.getData().toString());

		ret = calcResponses(aut, state, rri, bestSuccs, bestKind);

		if (ret == null)
			throw new GamesStrategyException(
					"No environment successor found from" + " state " + state.getData().toString());

		return ret;
		// throw new
		// GameException("we have a problem in succs of state "
		// + state.get_state().toString() + ". One of the next "
		// + "step Z rank is not decreasing");
		// throw new GameException("we have a problem in succs of state "
		// + state.get_state().toString() + ". One of the next "
		// + "step X rank is not decreasing (the Z is identical)");
	}

	// Kinds:
	// 1 - all system choices for this env choice lead to a lower z-rank
	// 2 - all system choices for this env choice either lead to a lower z-rank or
	// not,
	// and at least one sys choice doesn't lead to lower z-rank and we've reached
	// the final cell
	// (cell 0) in the current x-matrix row.
	// 3 - At least one sys choice for this env choice doesn't lead to lower z-rank
	// and we're in
	// the middle of the current x-matrix row, and this sys choice leads to some
	// lower x-cell in this
	// row
	// -1 - at least one sys choice leads to a higher z-rank
	private int getBestKind(EnumStateI state, RabinRankInfo rri, BDD succs) {
		int ret_kind = 1;
		for (BDDIterator iter = succs.iterator(allUnprime()); iter.hasNext();) {
			BDD cand = iter.nextBDD();

			int nextZ, nextK, nextX;
			nextZ = mem.getZRank(cand);
			if (nextZ > rri.get_row_count())
				return -1;

			if (nextZ < rri.get_row_count())
				continue;

			if (rri.get_env_goal_count() == 0) {
				// TODO - I think this internal if is redundant - add some assert to ensure
				// it indeed can't be > 2 and remove this internal if (just set ret_kind = 2)
				if (ret_kind <= 2)
					ret_kind = 2;
				continue;
			}

			nextK = rri.get_env_goal();
			nextX = mem.getXRank(nextZ, nextK, cand);
			if (nextX >= rri.get_env_goal_count())
				return -1;
			ret_kind = 3;
		}

		return ret_kind;
	}

	/**
	 * @param aut
	 * @param state
	 * @param rri
	 * @param succs
	 * @param kind
	 *            the priority from which this next step is allowed (or below). 1 -
	 *            dec row, 2 - next K, 3 - dec K.
	 * @param monitoring_expr
	 * @return The vector of next states, or null if not a valid set of succ.
	 * @throws GameException
	 */
	private Vector<EnumStateI> calcResponses(EnumStrategyI aut, EnumStateI state, RabinRankInfo rri, BDD succs,
			int kind) throws AbstractGamesException {
		Vector<EnumStateI> ret = new Vector<EnumStateI>();
		for (BDDIterator iter = succs.iterator(allUnprime()); iter.hasNext();) {
			BDD cand = iter.nextBDD();

			int nextZ, nextK, nextX;
			RabinRankInfo nextR;

			nextZ = mem.getZRank(cand);
			// if cannot move forward
			if (nextZ > rri.get_row_count())
				return null;

			// else if reducing Z rank
			if (nextZ < rri.get_row_count()) {
				nextK = 0;
				nextX = mem.getXRank(nextZ, nextK, cand);
				nextR = new RabinRankInfo(nextZ, nextK, nextX);
				EnumStateI newSt = aut.addSuccessorState(state, cand, nextR);
				if (newSt != null) // really a new state.
					ret.add(newSt);
				continue;
			}

			if (kind <= 1)
				return null;

			// else nextZRank == rri.get_row_count(), namely, cannot reduce Z,
			// and if we reached the K goal (suppose to satisfy the environment
			// justice K)
			if (rri.get_env_goal_count() == 0) {
				nextK = (rri.get_env_goal() + 1) % env.justiceNum();
				nextX = mem.getXRank(nextZ, nextK, cand);
				nextR = new RabinRankInfo(nextZ, nextK, nextX);
				EnumStateI newSt = aut.addSuccessorState(state, cand, nextR);
				if (newSt != null) // really a new state.
					ret.add(newSt);
				continue;
			}

			if (kind <= 2)
				return null;

			// else still did not reach the K goal
			nextK = rri.get_env_goal();
			nextX = mem.getXRank(nextZ, nextK, cand);
			if (nextX >= rri.get_env_goal_count())
				return null;
			nextR = new RabinRankInfo(nextZ, nextK, nextX);
			EnumStateI newSt = aut.addSuccessorState(state, cand, nextR);
			if (newSt != null) // really a new state.
				ret.add(newSt);
			continue;
		}

		return ret;
	}

	private BDDVarSet allUnprime() {
		return sys.moduleUnprimeVars().union(env.moduleUnprimeVars());
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

import java.util.List;

public class InExpSpec implements Spec {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8081328673447088736L;
	
	private Spec variable; // The main var of the expression
	private boolean isNot;
	private List<String> setOfvalues;
	
	public InExpSpec(Spec variable, boolean isNot, List<String> setOfvalues) {
		this.variable = variable;
		this.setNot(isNot);
		this.setSetOfvalues(setOfvalues);
	}

	public String toString() {
		return this.getVariable().toString() + (this.isNot() ? " not " : " ") + Operator.IN.toString() + " expr : " + this.getSetOfvalues();
	}

	@Override
	public boolean isPastLTLSpec() {
		return false;
	}

	@Override
	public boolean isPropSpec() {
		return false;
	}

	@Override
	public boolean hasTemporalOperators() {
		return false;
	}

	@Override
	public Spec clone() throws CloneNotSupportedException {
		return new InExpSpec(this.variable, this.isNot(), this.getSetOfvalues());
	}

	public Spec getVariable() {
		return variable;
	}

	public void setVariable(Spec variable) {
		this.variable = variable;
	}

	public boolean isNot() {
		return isNot;
	}

	public void setNot(boolean isNot) {
		this.isNot = isNot;
	}

	public List<String> getSetOfvalues() {
		return setOfvalues;
	}

	public void setSetOfvalues(List<String> setOfvalues) {
		this.setOfvalues = setOfvalues;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.modelchecker;

import java.util.Vector;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.jtlv.CoreUtil;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

public class FeasibilityChecker {
	
	public void FeasiblityChecker() {}
	
	/**
	 * <p>
	 * Eliminate states from scc which have no successors within scc. scc is
	 * supposed to be a strongly connected component, however, it also contains
	 * chains of states which exit the scc, but are not in it. This procedure
	 * eliminates these chains.
	 * </p>
	 * 
	 * @param scc
	 *            The set of states to find scc for.
	 * @return The scc of the given set of states.
	 */
	private BDD elimSuccChains(PlayerModule module, BDD scc) {
		BDD res = scc.id();
		for (FixPoint iscc = new FixPoint(true /*freeOnAdvance*/); iscc.advance(res);) {
			res = res.and(Env.pred(module.trans(), res));
		}
		return res;
	}
	
	/**
	 * <p>
	 * Get the subset of states which has successor to the other given set of
	 * states.
	 * </p>
	 * 
	 * @param module
	 * 			  The relevant PlayerModule
	 * @param state
	 *            The first set of states.
	 * @param to
	 *            The second set of states.
	 * @return the subset of "state" which has successors to "to".
	 */
	public BDD hasSuccessorsTo(PlayerModule module, BDD state, BDD to) {
		return state.and(Env.prime(to)).and(module.trans()).exist(Env.globalPrimeVars());
	}

	
	
	/**
	 * <p>
	 * This is essentially algorithm "FEASIBLE", from the article: <br>
	 * <NAME>, <NAME>, <NAME>, <NAME>, "Model checking with
	 * strong fairness".
	 * </p>
	 * <p>
	 * The line numbers are the line numbers of that algorithm. Read the article
	 * for further details.
	 * </p>
	 * 
	 * 
	 * @return Returns a set of states which induce a graph which contains all
	 *         the fair SCS's reachable from an initial state.
	 */
	public BDD check(PlayerModule module) {
		// saving the previous restriction state.
		BDD trans = module.trans().id();

		// Line 2
		BDD res = Env.allSucc(module.initial().id(), module.trans().id());
		BDD reachable = res.id();

		// Determine whether fairness conditions refer to primed variables.
		// If so, they are treated differently.
		boolean[] has_primed_j = new boolean[module.justiceNum()];
		BDDVarSet primes = Env.globalPrimeVars();
		for (int i = 0; i < has_primed_j.length; i++) {
			has_primed_j[i] = !module.justiceAt(i).biimp(
					module.justiceAt(i).exist(primes)).isUniverse();
		}

		// Line 3
		module.conjunctTrans(res.id());

		// Lines 4-11
		for (FixPoint ires = new FixPoint(true /*freeOnAdvance*/); ires.advance(res);) {
			// Lines 6-7
			// Eliminate states from res which have no successors within res.
			res = elimSuccChains(module, res);
			module.conjunctTrans(res.id());

			// Lines 8-9
			// Ensure fulfillment of justice requirements.
			// Remove from "res" all states which are not R^*-successors
			// of some justice state.
			for (int i = module.justiceNum() - 1; i >= 0; i--) {
				BDD localj = has_primed_j[i] ? hasSuccessorsTo(module, module.justiceAt(i), res) : module.justiceAt(i);
				res = Env.allPred(module.trans().id(), res.and(localj));
				module.conjunctTrans(res.id());
			}
		}
		module.resetTrans();
		module.conjunctTrans(trans.id());

		// Line 12
		module.conjunctTrans(reachable);

		res = Env.allPred(module.trans().id(), res);
		module.resetTrans();
		module.conjunctTrans(trans.id());

		// Line 13
		return res;
	}
	
	/**
	 * <p>
	 * Compute the shortest path from source to destination. <br>
	 * Algorithm from: <NAME>, <NAME>, <NAME>, <NAME>,
	 * "Model Checking with Strong Fairness".
	 * </p>
	 * 
	 * @param source
	 *            The states to start look for path.
	 * @param dest
	 *            The states to reach in the path.
	 * @return An array representing a path, null if the algorithm could not
	 *         find a path.
	 */
	public BDD[] shortestPath(PlayerModule module, BDD source, BDD dest) {
		BDD statesPassed = Env.FALSE(), last = dest.id();
		Vector<BDD> blurredPath = new Vector<BDD>();
		// blurredPath.add(last);

		while (last.and(source).isZero()) { // found source
			blurredPath.add(last);
			statesPassed = statesPassed.id().or(last);
			last = Env.pred(module.trans().id(), last).and(statesPassed.not());
			if (last.isZero()) // failed to find a path.
				return null;
		}
		blurredPath.add(last);

		BDD[] res = new BDD[blurredPath.size()];

		BDD blurredSt = blurredPath.elementAt(blurredPath.size() - 1);
		res[0] = CoreUtil.satOne(source.and(blurredSt), module.moduleUnprimeVars());
		for (int i = 1; i < res.length; i++) {
			blurredSt = blurredPath.elementAt(blurredPath.size() - i - 1);
			res[i] = CoreUtil.satOne(Env.succ(res[i - 1], module.trans().id()).and(blurredSt),
					module.moduleUnprimeVars());
		}

		return res;
	}

	
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import tau.smlab.syntech.gameinput.model.TypeDef;
import tau.smlab.syntech.gameinput.model.Variable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;

/**
 * A class that represents a regular expression.
 * 
 * 
 * @author <NAME>
 * @author <NAME>
 * 
 */

public class SpecRegExp implements Spec {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5557869841294255345L;
	
	private static final String FALSE = "false";
	private static final String TRUE = "true";

	private SpecRegExp left; //the left (resp. only) sub regular expression in case this is a binary (resp. an unary) expression
	private SpecRegExp right; //the right sub regular expression in case this is a binary expression
	private List<String> values; //if this is a variable or a Boolean constant regular expression, these are the values this expression accepts
	private VariableReference varRef; //if this is a variable regular expression, that is the variable reference that appears in this expression
	private Spec predicate; //if this is a Boolean term (formula/predicate) regular expression, that is the predicate that appears in the expression
	private RegExpKind kind; //the kind (i.e., either the main operator or the base kind) of this regular expression
	private RegExpQuantifier quantifier; //if this is a 'REPEAT' unary regular expression, that is its quantifier

	public enum RegExpKind {

		UNION(true, false), INTERSECTION(true, false), CONCAT(true, false), REPEAT(false, false), COMPLEMENT(false, false), EMPTY_STR(false, true),
		VAR(false, true), PREDICATE(false, true), BOOLEAN_CONST(false, true);
		
		
		private static final List<RegExpKind> NULLARY_KINDS =
				Collections.unmodifiableList(Arrays.stream(RegExpKind.values()).filter(RegExpKind::isNullary).collect(Collectors.toList()));
		private static final List<RegExpKind> UNARY_KINDS = 
				Collections.unmodifiableList(Arrays.stream(RegExpKind.values()).filter(RegExpKind::isUnary).collect(Collectors.toList()));
		private static final List<RegExpKind> BINARY_KINDS = 
				Collections.unmodifiableList(Arrays.stream(RegExpKind.values()).filter(RegExpKind::isBinary).collect(Collectors.toList()));
		
		private boolean isNullary; //true if this kind of regular expression is nullary
		private boolean isBinary; //true if this kind of regular expression is binary
		
		private RegExpKind(boolean isBinary, boolean isNullary) {
			this.isNullary = isNullary;
			this.isBinary = isBinary;
		}

		public boolean isNullary() {
			return this.isNullary;
		}

		public boolean isBinary() {
			return this.isBinary;
		}

		public boolean isUnary() {
			return !this.isBinary && !this.isNullary;
		}
		
		public static List<RegExpKind> nullaryKinds() {
			return NULLARY_KINDS;
		}
		
		public static List<RegExpKind> unaryKinds() {
			return UNARY_KINDS;
		}
		
		public static List<RegExpKind> binaryKinds() {
			return BINARY_KINDS;
		}
		
	}

	/**
	 * 
	 * An enum class that represents types of regular expressions' quantifier operators.
	 *
	 */
	public enum QuantifierType {

		ZERO_OR_MORE, ONE_OR_MORE, ZERO_OR_ONE, EXACT_REPETITION,
		AT_LEAST, RANGE;
	};

	/**
	 * A class that represents regular expressions' quantifier operators.
	 *
	 */
	public static class RegExpQuantifier implements Spec {
		/**
		 * 
		 */
		private static final long serialVersionUID = 3852513999102523898L;
		
		private QuantifierType type;
		private int least, most;


		private RegExpQuantifier(QuantifierType type, int least, int most) {
			this.type = type;
			this.least = least;
			this.most = most;
		}

		public QuantifierType getType() {
			return this.type;
		}

		public int getLeastRepetitionsNum() {
			return this.least;
		}

		public int getMaxRepetitionsNum() {
			return this.most;
		}

		public void setLeastRepetitionsNum(int least) {
			this.least = least;
		}

		public void setMaxRepetitionsNum(int most) {
			this.most = most;
		}

		/**
		 * 
		 * @return Kleene star '*' quantifier 
		 */
		public static RegExpQuantifier zeroOrMoreRepetitions() {
			return new RegExpQuantifier(QuantifierType.ZERO_OR_MORE, 0, Integer.MAX_VALUE);
		}

		/**
		 * 
		 * @return '+' quantifier
		 */
		public static RegExpQuantifier oneOrMoreRepetitions() {
			return new RegExpQuantifier(QuantifierType.ONE_OR_MORE, 1, Integer.MAX_VALUE);
		}

		/**
		 * 
		 * @return '?' quantifier
		 */
		public static RegExpQuantifier zeroOrOneRepetition() {
			return new RegExpQuantifier(QuantifierType.ZERO_OR_ONE, 0, 1);
		}

		/**
		 * 
		 * @param exactNum the number of occurrences/repetitions
		 * @return '{{@code exactNum}}' quantifier
		 */
		public static RegExpQuantifier exactRepetitions(int exactNum) {
			return new RegExpQuantifier(QuantifierType.EXACT_REPETITION, exactNum, exactNum);
		}

		/**
		 * 
		 * @param atLeastNum the least number of occurrences/repetitions
		 * @return '{{@code atLeastNum},}' quantifier
		 */
		public static RegExpQuantifier atLeastRepetitions(int atLeastNum) {
			return new RegExpQuantifier(QuantifierType.AT_LEAST, atLeastNum, Integer.MAX_VALUE);
		}

		/**
		 * 
		 * @param atLeastNum the least number of occurrences/repetitions
		 * @param atMostNum the maximal number of occurrences/repetitions (inclusive)
		 * @return  '{{@code atLeastNum},{@code atMostNum}}' quantifier
		 */
		public static RegExpQuantifier repetitionsInRange(int atLeastNum, int atMostNum) {
			return new RegExpQuantifier(QuantifierType.RANGE, atLeastNum, atMostNum);
		}

		@Override
		public String toString() {
			switch(this.type) {
			case AT_LEAST:
				return "{" + this.least + ",}";
			case EXACT_REPETITION:
				return "{" + this.least + "}";
			case ONE_OR_MORE:
				return "+";
			case RANGE:
				return "{" + this.least + "," + this.most + "}";
			case ZERO_OR_MORE:
				return "*";
			case ZERO_OR_ONE:
				return "?";
			default:
				break;			
			}
			return "INVALID QUANTIFIER TYPE";
		}


		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (this.getClass() != obj.getClass()) {
				return false;
			}
			RegExpQuantifier other = (RegExpQuantifier) obj;
			if(this.type == null) {
				if(other.type != null) {
					return false;
				}
				return true; //both quantifiers are of type null;
			}
			else {
				if(!this.type.equals(other.type)) {
					return false;
				}
				//both quantifiers have the same type
				return this.least == other.least &&
						this.most == other.most;
			}
		}

		@Override
		public boolean isPastLTLSpec() {
			return false;
		}

		@Override
		public boolean isPropSpec() {
			return false;
		}

		@Override
		public boolean hasTemporalOperators() {
			return false;
		}

		@Override
		public RegExpQuantifier clone() throws CloneNotSupportedException {
			return new RegExpQuantifier(this.type, this.least, this.most);
		}
	}

	/**
	 * 
	 * Use a {@link RandomGenerator} to randomly generate
	 * instances of {@link SpecRegExp}. 
	 * 
	 * 
	 * @author <NAME>
	 *
	 */
	public static class RandomGenerator  {
		
		private static final boolean GENERATE_PREDICATE_KIND = true;
		
		private static final List<RegExpKind> REGEXP_NULLARY_KINDS = GENERATE_PREDICATE_KIND ? RegExpKind.nullaryKinds() : Arrays.asList(new RegExpKind[] {RegExpKind.EMPTY_STR, RegExpKind.BOOLEAN_CONST, RegExpKind.VAR});
		private static final int NULLARY_KIND_NUM = REGEXP_NULLARY_KINDS.size();

		private static final List<RegExpKind> REGEXP_KINDS = initRegExpKinds();
		private static final int REGEXP_KIND_NUM = REGEXP_KINDS.size();

		private static final List<QuantifierType> QUANTIFIER_TYPES = Arrays.asList(QuantifierType.values());
		private static final int QUANTIFIER_TYPE_NUM = QUANTIFIER_TYPES.size();
		
		enum SpecKind {INEQ_OP(false), EQ_OP(false), ARITH_OP(false), PROP_OP(false), INT_VAR(true), INT_CONST(true), BOOLEAN_VAR(true), BOOLEAN_CONST(true);
			
			private static Operator[] propOps = {Operator.AND, Operator.OR, Operator.IFF, Operator.IMPLIES, Operator.NOT, Operator.XOR};
			private static Operator[] arithOps = {Operator.ADD, Operator.SUBSTRACT, Operator.MULTIPLY};
			private static Operator[] arithOpsWithMod = {Operator.ADD, Operator.SUBSTRACT, Operator.MOD, Operator.MULTIPLY};
			private static Operator[] ineqOps = Operator.inqOp;
			
			private boolean isNullary;
			
			private SpecKind(boolean isNullary) {
				this.isNullary = isNullary;
			}
			
			public boolean isNullary() {
				return this.isNullary;
			}
			
			public static Operator[] getOps(SpecKind opKind) {
				return getOps(opKind, false);
			}
			
			public static Operator[] getOps(SpecKind opKind, boolean excludeMod) {
				if(INEQ_OP.equals(opKind)) {
					return ineqOps;
				}
				if(ARITH_OP.equals(opKind)) {
					return excludeMod ? arithOps : arithOpsWithMod;
				}
				if(PROP_OP.equals(opKind)) {
					return propOps;
				}
				return null;
			}
		}
		
		private final List<Variable> variables, booleanVariables, intVariables, nonZeroIntVariables, enumVariables;
		private final List<SpecKind> propSpecKinds, nullaryPropSpecKinds, arithSpecKinds, nullaryArithSpecKinds;
		
		private final Random random;
		private int maxDepth, predMaxDepth, maxLeastRepNum, maxRepRange, maxIntConst;
	
		private static List<RegExpKind> initRegExpKinds() {
			List<RegExpKind> regExpKinds = new ArrayList<>();

			regExpKinds.addAll(RegExpKind.unaryKinds());
			regExpKinds.addAll(RegExpKind.binaryKinds());
			regExpKinds.addAll(REGEXP_NULLARY_KINDS);

			return regExpKinds;	
		}

		/**
		 * Returns a new {@link RandomGenerator} that randomly generates
		 * instances of {@link SpecRegExp}, which may have atomic 
		 * subexpressions that exclusively use the variables in {@code variables}.
		 * 
		 * @param variables
		 * @param maxDepth the maximal depth of the generated regular expressions
		 * @param predMaxDepth the maximal depth of each predicate that appears in the generated regular expression
		 * @param maxLeastRepNum the maximal value that may appear in repetition quantifiers as the least number of repetitions
		 * @param maxRepRange the maximal interval size that "repetitions in range" {@link QuantifierType#RANGE} quantifiers may have 
		 */		
		public RandomGenerator(int maxDepth, int predMaxDepth, List<Variable> variables,
				int maxLeastRepNum, int maxRepRange) {
			this.variables = variables;
			
			this.booleanVariables = variables.stream().filter(var -> var.getType().isBoolean()).collect(Collectors.toList());
			this.intVariables = variables.stream().filter(var -> var.getType().isInteger()).collect(Collectors.toList());
			this.nonZeroIntVariables = variables.stream().filter(var -> (var.getType().isInteger() && var.getType().getLower() > 0)).collect(Collectors.toList());
			this.enumVariables = variables.stream().filter(var -> (!var.getType().isInteger() && !var.getType().isBoolean())).collect(Collectors.toList());
			
			this.propSpecKinds = new ArrayList<>();
			this.arithSpecKinds = new ArrayList<>();
			this.nullaryPropSpecKinds = new ArrayList<>();
			this.nullaryArithSpecKinds = new ArrayList<>();
			this.fillSpecKindsLists();
			this.maxIntConst = getMaxIntConstValue();
			
			this.random = new Random();
			this.maxDepth = maxDepth;
			this.predMaxDepth = predMaxDepth;
			this.maxLeastRepNum = maxLeastRepNum;
			this.maxRepRange = maxRepRange;
		}
		
		private int getMaxIntConstValue() {
			if(this.intVariables.isEmpty()) {return 0;}
			int minMaxUpperValue = this.intVariables.get(0).getType().getUpper();
			for(int i = 1; i < this.intVariables.size(); i++) {
				if(this.intVariables.get(i).getType().getUpper() < minMaxUpperValue) {
					minMaxUpperValue = this.intVariables.get(i).getType().getUpper();
				}
			}
			return minMaxUpperValue;
		}
		
		private void fillSpecKindsLists() {
			this.propSpecKinds.add(SpecKind.BOOLEAN_CONST);
			this.nullaryPropSpecKinds.add(SpecKind.BOOLEAN_CONST);
			
			if(!this.enumVariables.isEmpty() || !this.intVariables.isEmpty() || !this.booleanVariables.isEmpty()) {
				this.propSpecKinds.add(SpecKind.PROP_OP);
			}
			if(!this.enumVariables.isEmpty() || !this.intVariables.isEmpty()) {
				this.propSpecKinds.add(SpecKind.EQ_OP);
			}
			if(!this.intVariables.isEmpty()) {
				this.propSpecKinds.add(SpecKind.INEQ_OP);
				
				this.arithSpecKinds.add(SpecKind.INT_CONST);
				this.nullaryArithSpecKinds.add(SpecKind.INT_CONST); 
				this.arithSpecKinds.add(SpecKind.INT_VAR);
				this.nullaryArithSpecKinds.add(SpecKind.INT_VAR); 
				this.arithSpecKinds.add(SpecKind.ARITH_OP);
			}
			if(!this.booleanVariables.isEmpty()) {
				this.propSpecKinds.add(SpecKind.BOOLEAN_VAR);
				this.nullaryPropSpecKinds.add(SpecKind.BOOLEAN_VAR);
			}
		}

		public SpecRegExp nextSpecRegExp() {
			SpecRegExp res = this.genRandRegExp(this.maxDepth);
			if(res == null) {
				System.out.println("null regexp");
			}
			return res;
		}

		public List<Variable> getVariables() {
			return variables;
		}

		public int getMaxDepth() {
			return maxDepth;
		}

		public void setMaxDepth(int maxDepth) {
			this.maxDepth = maxDepth;
		}

		public int getMaxLeastRepNum() {
			return maxLeastRepNum;
		}

		public void setMaxLeastRepNum(int maxLeastRepNum) {
			this.maxLeastRepNum = maxLeastRepNum;
		}

		public int getMaxRepRange() {
			return maxRepRange;
		}

		public void setMaxRepRange(int maxRepRange) {
			this.maxRepRange = maxRepRange;
		}

		private SpecRegExp genRandRegExp(int maxDepth) {
			if(maxDepth == 0) {
				return genRandNullaryRegExp(REGEXP_NULLARY_KINDS.get(this.random.nextInt(NULLARY_KIND_NUM)));
			}
			RegExpKind regExpKind = REGEXP_KINDS.get(this.random.nextInt(REGEXP_KIND_NUM));
			if(regExpKind.isNullary()) {
				return genRandNullaryRegExp(regExpKind);
			}
			if(regExpKind.isUnary()) {
				return genRandUnaryRegExp(maxDepth, regExpKind);
			}
			if(regExpKind.isBinary()) {
				return genRandBinaryRegExp(maxDepth, regExpKind);
			}
			throw new RuntimeException("The regexp kind " + regExpKind + " is unsupported");
		}

		private SpecRegExp genRandNullaryRegExp(RegExpKind nullaryKind) {
			switch(nullaryKind) {
			case EMPTY_STR:
				return SpecRegExp.newEmptyStringRegExp();
			case BOOLEAN_CONST:
				return SpecRegExp.newBooleanConstRegExp(this.random.nextBoolean());
			case VAR:
				VariableReference varRef = new VariableReference(variables.get(this.random.nextInt(this.variables.size())));
				TypeDef variableType = varRef.getVariable().getType();
				List<String> values = new ArrayList<>();
				int varDomainSize;
				if(variableType.isBoolean()) {
					varDomainSize = 2;
					values.add(String.valueOf(this.random.nextBoolean()));
				}
				else if(variableType.isInteger()) {
					for(int value = variableType.getLower(); value <= variableType.getUpper(); value++) {
						if(this.random.nextBoolean()) {
							values.add(String.valueOf(value));
						}
					}
					varDomainSize = variableType.getUpper()-variableType.getLower()+1;
				}
				else { //Enum
					for(String value : variableType.getValues()) {
						if(this.random.nextBoolean()) {
							values.add(value);
						}
					}
					varDomainSize = variableType.getValues().size();
				}
				return SpecRegExp.newVariableRegExp(varRef, values, getAcceptValues(values, varDomainSize));
			case PREDICATE:
				return SpecRegExp.newPredicateRegExp(genRandPredicate(this.predMaxDepth));
			default:
				throw new RuntimeException("The nullary regexp kind " + nullaryKind + " is unsupported");
			}
		}
		
		private Spec genRandPredicate(int predMaxDepth) {
			SpecKind propKind = predMaxDepth > 0 ? this.propSpecKinds.get(this.random.nextInt(this.propSpecKinds.size())) :
				this.nullaryPropSpecKinds.get(this.random.nextInt(this.nullaryPropSpecKinds.size()));
			if(propKind.isNullary()) { //predMaxDepth >= 0
				switch(propKind) {
				case BOOLEAN_CONST:
					return new PrimitiveValue(this.random.nextBoolean() ? TRUE : FALSE);
				case BOOLEAN_VAR:
					return new VariableReference(this.booleanVariables.get(this.random.nextInt(this.booleanVariables.size())));
				default:
					throw new RuntimeException("The nullary propositional spec kind " + propKind + " is unsupported");
				}
			}
			else { //predMaxDepth > 0
				switch(propKind) {
				case EQ_OP:
					boolean enumComparison = this.intVariables.isEmpty() || (!this.enumVariables.isEmpty() && this.random.nextBoolean());
					if(enumComparison) { //Create a spec of the form 'enumVar = enumConstantValue'
						Variable enumVariable = this.enumVariables.get(this.random.nextInt(this.enumVariables.size()));
						String enumValue = enumVariable.getType().getValues().get(this.random.nextInt(enumVariable.getType().getValues().size()));
						return new SpecExp(Operator.EQUALS, new VariableReference(enumVariable), new PrimitiveValue(enumValue));
					}
					else { //Integer comparison: create a spec of the form 'arithmetic expression = integer constant'
						Spec leftArithExp = genRandArithmeticSpec(predMaxDepth-1, false);
						int randValue = randEvalArithSpec(leftArithExp); //choose a random value to which the LHS can evaluate
						return new SpecExp(Operator.EQUALS, leftArithExp, new PrimitiveValue(randValue));
					}				
				case INEQ_OP: //Integer comparison: create a spec of the form 'arithmetic expression (> | < | >= | <=) integer constant'
					Operator ineqOp = SpecKind.getOps(SpecKind.INEQ_OP)[this.random.nextInt(SpecKind.getOps(SpecKind.INEQ_OP).length)];
					Spec leftArithExp = genRandArithmeticSpec(predMaxDepth-1, false);
					int randValue = randEvalArithSpec(leftArithExp); //choose a random value to which the LHS can evaluate
					return new SpecExp(ineqOp, leftArithExp, new PrimitiveValue(randValue));
				case PROP_OP:
					Operator propOp = SpecKind.getOps(SpecKind.PROP_OP)[this.random.nextInt(SpecKind.getOps(SpecKind.PROP_OP).length)];
					Spec leftPropSpec = genRandPredicate(predMaxDepth-1);
					if(propOp.isBinary()) {
						return new SpecExp(propOp, leftPropSpec, genRandPredicate(predMaxDepth-1));
					}
					//Unary propositional operator
					return new SpecExp(propOp, leftPropSpec);
				default:
					throw new RuntimeException("The propositional spec operator kind " + propKind + " is unsupported");
				}
			}
		}
		
		private Spec genRandArithmeticSpec(int predMaxDepth, boolean modOpDivisor) {
			SpecKind arithKind;
			if(modOpDivisor && this.nonZeroIntVariables.isEmpty()) {
				arithKind = SpecKind.INT_CONST;
			}
			else {
				arithKind = (predMaxDepth > 0 && !modOpDivisor) ? this.arithSpecKinds.get(this.random.nextInt(this.arithSpecKinds.size())) :
				this.nullaryArithSpecKinds.get(this.random.nextInt(this.nullaryArithSpecKinds.size()));
			}
			if(arithKind.isNullary()) { //predMaxDepth >= 0
				switch(arithKind) {
				case INT_CONST:
					int intVal = this.random.nextInt(this.maxIntConst+1);
					if(modOpDivisor && intVal == 0) { //Avoid a zero divisor
						intVal+=1;
					}
					return new PrimitiveValue(intVal);
				case INT_VAR:
					Variable intVariable;
					if(modOpDivisor) {
						intVariable = this.nonZeroIntVariables.get(this.random.nextInt(this.nonZeroIntVariables.size()));
					}
					else {
						intVariable = this.intVariables.get(this.random.nextInt(this.intVariables.size()));
					}
					return new VariableReference(intVariable);
				default:
					throw new RuntimeException("The arithmetic spec operator kind " + arithKind + " is unsupported");
				}
			}
			else { //predMaxDepth > 0
				switch(arithKind) {
				case ARITH_OP:
					Operator arithOp = SpecKind.getOps(SpecKind.ARITH_OP)[this.random.nextInt(SpecKind.getOps(SpecKind.ARITH_OP).length)];
					Spec leftArithSpec = genRandArithmeticSpec(predMaxDepth-1, false);
					Spec rightArithSpec = genRandArithmeticSpec(predMaxDepth-1, Operator.MOD.equals(arithOp));
					return new SpecExp(arithOp, leftArithSpec, rightArithSpec);
				default:
					throw new RuntimeException("The arithmetic spec operator kind " + arithKind + " is unsupported");
				}
			}
		}
		
		private int randEvalArithSpec(Spec arithSpec) {
			if (arithSpec instanceof PrimitiveValue) {
				PrimitiveValue intVal = (PrimitiveValue) arithSpec;
				try {
					return Integer.parseInt(intVal.getValue());
				} catch (NumberFormatException e) {
					throw new RuntimeException("The arithmetic spec " + arithSpec + " cannot be evaluated");
				}
			}
			else if (arithSpec instanceof VariableReference) {
				VariableReference varRef = (VariableReference) arithSpec;
				int domSize = varRef.getVariable().getType().getUpper() - varRef.getVariable().getType().getLower() + 1;
				return this.random.nextInt(domSize) + varRef.getVariable().getType().getLower();
			}
			else if (arithSpec instanceof SpecExp) {
				SpecExp specExp = (SpecExp) arithSpec;
				Operator arithOp = specExp.getOperator();

				int leftRandEval = randEvalArithSpec(specExp.getChildren()[0]);
				int rightRandEval = randEvalArithSpec(specExp.getChildren()[1]);

				if (Operator.MOD.equals(arithOp)) {
					return leftRandEval % rightRandEval;
				}
				if (Operator.ADD.equals(arithOp)) {
					return leftRandEval + rightRandEval;
				}
				if (Operator.SUBSTRACT.equals(arithOp)) {
					return leftRandEval - rightRandEval;
				}
				if (Operator.MULTIPLY.equals(arithOp)) {
					return leftRandEval * rightRandEval;
				}
			}
			throw new RuntimeException("The arithmetic spec " + arithSpec + " cannot be evaluated");
		}

		private boolean getAcceptValues(List<String> values, int varDomainSize) {
			boolean acceptValues;
			if(values.size() == varDomainSize) {
				acceptValues = true;
			}
			else if (values.isEmpty()){
				acceptValues = false;
			}
			else {
				acceptValues = this.random.nextBoolean();
			}
			return acceptValues;
		}

		private SpecRegExp genRandBinaryRegExp(int maxDepth, RegExpKind binaryKind) {
			SpecRegExp leftSubExp = genRandRegExp(maxDepth-1);
			SpecRegExp rightSubExp = genRandRegExp(maxDepth-1);

			switch(binaryKind) {
			case UNION:
				return SpecRegExp.newUnionRegExp(leftSubExp, rightSubExp);
			case INTERSECTION:
				return SpecRegExp.newIntersectionRegExp(leftSubExp, rightSubExp);
			case CONCAT:
				return SpecRegExp.newConcatRegExp(leftSubExp, rightSubExp);
			default:
				throw new RuntimeException("The binary regexp kind " + binaryKind + " is unsupported");
			}
		}


		private SpecRegExp genRandUnaryRegExp(int maxDepth, RegExpKind unaryKind) {
			SpecRegExp subExp = genRandRegExp(maxDepth-1);
			switch(unaryKind) {
			case REPEAT:
				return genRandRepRegExp(subExp);
			case COMPLEMENT:
				return SpecRegExp.newComplementationRegExp(subExp);
			default:
				throw new RuntimeException("The unary regexp kind " + unaryKind + " is unsupported");
			}
		}

		private SpecRegExp genRandRepRegExp(SpecRegExp subRegExp) {
			QuantifierType quantifierType = QUANTIFIER_TYPES.get(this.random.nextInt(QUANTIFIER_TYPE_NUM));
			int repRangeSize = -1, leastRepNum = -1; 
			switch(quantifierType) {
			case ZERO_OR_MORE:
				return SpecRegExp.newZeroOrMoreRepRegExp(subRegExp);	
			case ONE_OR_MORE:
				return SpecRegExp.newOneOrMoreRepRegExp(subRegExp);
			case ZERO_OR_ONE:
				return SpecRegExp.newZeroOrOneRepRegExp(subRegExp);
			case RANGE:
				repRangeSize = 1 + this.random.nextInt(this.maxRepRange);
			default:
				leastRepNum = this.random.nextInt(this.maxLeastRepNum+1);	
			}
			switch(quantifierType) {
			case RANGE:
				return SpecRegExp.newRepInRangeRegExp(subRegExp, leastRepNum, leastRepNum + repRangeSize - 1);
			case AT_LEAST:
				return SpecRegExp.newAtLeastRepRegExp(subRegExp, leastRepNum);
			case EXACT_REPETITION:
				return SpecRegExp.newExactRepRegExp(subRegExp, leastRepNum);
			default:
				throw new RuntimeException("The regexp repetition quantifier " + quantifierType + " is unsupported");
			}
		}
	}


	/*
	 * 
	 * Public methods
	 * 
	 */

	public RegExpKind getRegExpKind(){
		return this.kind;
	}


	public boolean isNullaryRegExp() {
		if(this.kind != null) {
			return this.kind.isNullary();
		}
		return false;
	}

	public boolean isBinaryRegExp() {
		if(this.kind != null) {
			return this.kind.isBinary() && this.left != null && this.right != null;
		}
		return false;
	}

	public boolean isUnaryRegExp() {
		if(this.kind != null) {
			return this.kind.isUnary();
		}
		return false;
	}

	public boolean hasLeft() {
		return this.left != null;
	}

	public boolean hasRight() {
		return this.right != null;
	}

	/**
	 * Checks whether this regular expression consists of a variable and asserts that this variable
	 * should be equal to at least one value.
	 * 
	 * @return
	 */
	public boolean isVariable() {
		return RegExpKind.VAR.equals(this.kind)
				&& this.varRef != null
				&& this.varRef.getReferenceName() != null
				&& this.varRef.getVariable() != null
				&& this.varRef.getVariable().getName() != null
				&& this.values != null
				&& !this.values.isEmpty();
	}

	public boolean isPredicate() {
		return RegExpKind.PREDICATE.equals(this.kind)
				&& this.predicate != null;
	}

	public Spec getPredicate() {
		return this.predicate;
	}

	public void setPredicate(Spec predicate) {
		this.predicate = predicate;
	}
	
	/**
	 * Serializes this {@link SpecRegExp} object in the specified file.
	 * 
	 * @param fileName the file name
	 */
	public void save(String fileName) throws IOException {   
		//Saving of this regexp in a file 
		FileOutputStream file = new FileOutputStream(fileName);
		ObjectOutputStream out = new ObjectOutputStream(file);
		
		//Serialization of this regexp 
		out.writeObject(this);

		out.close();
		file.close(); 
	}
	
	
	/**
	 * 
	 * Deserializes the {@link SpecRegExp} object serialized in the file with the name {@code fileName}.
	 * 
	 * 
	 * @param fileName the file name
	 * @return The {@link SpecRegExp} object serialized in the file
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static SpecRegExp loadRegExp(String fileName) throws IOException, ClassNotFoundException {
		//Reading the object from a file 
		FileInputStream file = new FileInputStream(fileName); 
		ObjectInputStream in = new ObjectInputStream(file);
		
		//Deserialization of the current regexp object
		SpecRegExp regExp = (SpecRegExp)in.readObject();
		
		in.close(); 
		file.close();
		
		return regExp;
	}
	
	/**
	 * Returns a list that consists of all the subexpressions of the form '[Boolean term (assertion)]'
	 * in this regular expression.
	 * 
	 * @return
	 */
	public List<SpecRegExp> getPredicateSubExps() {
		List<SpecRegExp> predicateExps = new ArrayList<>();
		this.addAllPredicateSubExps(predicateExps);
		return predicateExps;
	}

	/**
	 * Returns a list that consists of all the variables referenced in the atomic subexpressions
	 * of this regular expression. Each variable appears in the returned list exactly once.
	 * 
	 * @return
	 */
	public List<Variable> getVariables() {
		List<Variable> regExpVars = new ArrayList<>();
		this.addAllVariables(regExpVars);
		return regExpVars;
	}
	
	/**
	 * <p>Returns a mapping of all the variable references (reference names) that appear in this regular expression
	 * to the referenced variable objects.</p>
	 * 
	 * <p>Note: The reference name may be different than the name of the referenced variable in case the variable
	 * is an array. For example, 'arrVar[0][2]' references the two-dimensional array variable 'arrVar'.</p> 
	 * 
	 * @return
	 */
	public Map<String, Variable> getRefToVarMapping() {
		Map<String, Variable> refToVar = new HashMap<>();
		fillRefToVarMapping(refToVar);
		return refToVar;
		
	}
	
	/**
	 * Checks whether this regular expression contains a subexpression with a complementation/negation operator.
	 * 
	 * @return
	 */
	public boolean containsComplement() {
		if(RegExpKind.COMPLEMENT.equals(this.kind)) {
			return true;
		}
		if(this.hasLeft() && this.left.containsComplement()) {
			return true;
		}
		if(this.hasRight() && this.right.containsComplement()) {
			return true;
		}
		return false;
	}

	/**
	 * Checks whether this regular expression consists of a Boolean constant, either TRUE or FALSE.
	 * 
	 * @return
	 */
	public boolean isBooleanConst() {
		return isBooleanConstKind() && (hasSingleBooleanValue(true) || hasSingleBooleanValue(false));
	}

	/**
	 * Checks whether this regular expression is the TRUE Boolean constant.
	 * 
	 * @return
	 */
	public boolean isTrueBooleanConst() {
		return isBooleanConstKind() && hasSingleBooleanValue(true);
	}

	/**
	 * Checks whether this regular expression is the FALSE Boolean constant.
	 * 
	 * @return
	 */
	public boolean isFalseBooleanConst() {
		return isBooleanConstKind() && hasSingleBooleanValue(false);
	}

	public boolean isEmptyString() {
		return RegExpKind.EMPTY_STR.equals(this.kind);
	}

	public boolean isComplementation() {
		return isUnaryKind(RegExpKind.COMPLEMENT);
	}

	/**
	 * Checks whether this regular expression asserts a repetition (via a quantifier) of a
	 * sub-expression.
	 * 
	 * @return
	 * @see #getQuantifier()
	 * @see #getQuantifierType()
	 * @see QuantifierType
	 * @see RegExpQuantifier
	 */
	public boolean isRepetition() {
		return isUnaryKind(RegExpKind.REPEAT) && this.quantifier != null;
	}
	/**
	 * Checks whether this regular expression is a concatenation of two regular expressions.
	 * 
	 * @return
	 */
	public boolean isConcat() {
		return isBinaryKind(RegExpKind.CONCAT);
	}

	/**
	 * Checks whether this regular expression is a union of two regular expressions.
	 * 
	 * @return
	 */
	public boolean isUnion() {
		return isBinaryKind(RegExpKind.UNION);
	}

	/**
	 * Checks whether this regular expression is an intersection of two regular expressions.
	 * 
	 * @return
	 */
	public boolean isIntersection() {
		return isBinaryKind(RegExpKind.INTERSECTION);
	}

	public QuantifierType getQuantifierType() {
		return isRepetition() ? this.quantifier.type : null;
	}

	public RegExpQuantifier getQuantifier() {
		return this.quantifier;
	}

	public SpecRegExp getLeft(){
		return left;
	}

	public SpecRegExp getRight(){
		return right;
	}

	public Variable getVariable() {
		return this.isVariable() ? this.varRef.getVariable() : null;
	}
	
	public VariableReference getVariableReference() {
		return this.varRef;
	}

	public String getVariableName() {
		return this.isVariable() ? this.varRef.getVariable().getName() : null;
	}
	
	public String getVariableReferenceName() {
		return this.isVariable() ? this.varRef.getReferenceName() : null;
	}

	/**
	 * Checks whether this regular expression consists of a Boolean variable and asserts that this variable
	 * should be equal to either TRUE or FALSE (or both).
	 * 
	 * @return
	 */
	public boolean isBooleanVariable() {
		return this.isVariable()
				&& this.varRef.getVariable().getType() != null 
				&& this.varRef.getVariable().getType().isBoolean()
				&& allValuesAreBooleans();
	}

	/**
	 * Checks whether this regular expression consists of an integer variable and asserts that this variable
	 * should be equal to an element in a non-empty set of integer values.
	 * @return
	 */
	public boolean isIntegerVariable() {
		return this.isVariable()
				&& this.varRef.getVariable().getType() != null 
				&& this.varRef.getVariable().getType().isInteger()
				&& allValuesAreInts();
	}

	/**
	 * Checks whether this regular expression consists of an enumeration variable and asserts that this variable
	 * should be equal to an element in a non-empty set of values.
	 * @return
	 */
	public boolean isEnumVariable() {
		return this.isVariable()
				&& this.varRef.getVariable().getType() != null 
				&& !this.varRef.getVariable().getType().isInteger()
				&& !this.varRef.getVariable().getType().isBoolean();
	}

	/**
	 * If this is a regular expression which is a Boolean constant,
	 * returns the underlying Boolean value. Otherwise, returns {@code null}.
	 * @return
	 */
	public String getBooleanValue() {
		if(this.isBooleanConst()) {
			return this.values.get(0);
		}
		return null;
	}

	public Set<String> getValues(){
		return new HashSet<>(this.values);
	}

	@Override
	public boolean isPastLTLSpec() {
		return false;
	}

	@Override
	public boolean isPropSpec() {
		return false;
	}

	@Override
	public boolean hasTemporalOperators() {
		return false;
	}

	@Override
	public SpecRegExp clone() throws CloneNotSupportedException {
		return new SpecRegExp(this.left != null ? this.left.clone() : null, this.right != null ? this.right.clone() : null, this.values != null ? new ArrayList<>(this.values) : null,
				this.varRef != null ? this.varRef.clone() : null, this.predicate != null ? this.predicate.clone() : null, this.kind,
						this.quantifier != null ? this.quantifier.clone() : null);
	}

	@Override
	public String toString() {
		if(this.isEmptyString()) { //regExp = '()' 
			return "()";
		}
		if(this.isTrueBooleanConst()) { //regExp = 'TRUE' 
			return "true";
		}
		if(this.isFalseBooleanConst()) { //regExp = 'FALSE' 
			return "false";
		}
		if(this.isVariable()) { //regExp = '[var in {set of values}]' 
			StringBuilder res = new StringBuilder();
			res.append("[");
			res.append(this.getVariableReferenceName());
			res.append(" in {");
			this.values.subList(0, this.values.size()-1).forEach(s -> res.append(s + ", "));
			res.append(this.values.get(this.values.size()-1));
			res.append("}]");
			return res.toString();
		}
		if(this.isPredicate()) { //regExp = '[Boolean term (assertion)]'
			return "[" + this.predicate.toString() + "]";
		}

		if(!this.hasLeft()) {
			return "INVALID REGEXP: expected non-null left subexpession attribute";
		}

		String leftRes = this.left.toString();

		if(this.isRepetition()) {
			return "(" + leftRes + ")" + this.quantifier.toString();
		}

		if(this.isComplementation()) {
			return "~(" + leftRes + ")";
		}

		if(!this.hasRight()) {
			return "INVALID REGEXP: expected non-null right subexpession attribute";
		}

		String rightRes = this.right.toString();

		if(this.isConcat()) {
			return "(" + leftRes + ") (" + rightRes + ")";
		}

		if(this.isUnion()) {
			return "(" + leftRes + ")|(" + rightRes + ")";
		}

		if(this.isIntersection()) {
			return "(" + leftRes + ")&(" + rightRes + ")";
		}

		return "INVALID REGEXP KIND: cannot generate string for this regular expression";

	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (this.getClass() != obj.getClass()) {
			return false;
		}
		SpecRegExp other = (SpecRegExp) obj;

		if(this.kind != other.kind) {return false;}

		//this.kind == other.kind
		if(this.kind == null || RegExpKind.EMPTY_STR.equals(this.kind)) {return true;}

		if(RegExpKind.BOOLEAN_CONST.equals(this.kind)) { //Both kinds are Boolean constants
			if(this.values != null) {
				return this.values.equals(other.values);
			}
			else {
				return other.values == null;
			}
		}
		if(RegExpKind.VAR.equals(this.kind)) { //Both kinds are variables
			if(this.varRef != null) {
				if(other.varRef == null) {
					return false;
				}
				if(this.varRef.getReferenceName() != null) {
					if(!this.varRef.getReferenceName().equals(other.varRef.getReferenceName())) {
						return false;
					}
					if(this.values != null) {
						if(other.values == null) {
							return false;
						}
						//Compare the two values' lists, but ignore the elements' order
						Set<String> thisValSet = new HashSet<>(this.values);
						Set<String> otherValSet = new HashSet<>(other.values);
						return thisValSet.equals(otherValSet);
					}
					else {
						return other.values == null;
					}
				}
				else {
					return other.varRef.getReferenceName() == null;
				}
			}
			else {
				return other.varRef == null;
			}
		}
		if(RegExpKind.PREDICATE.equals(this.kind)) {  //Both kinds are predicates
			if(this.predicate != null) {
				return this.predicate.equals(other.predicate);
			}
			else {
				return other.predicate == null;
			}
		}
		if(this.kind.isUnary()) { //Both kinds are unary
			if(RegExpKind.REPEAT.equals(this.kind)) { //Check that both have the same repetition quantifier
				if(this.quantifier != null) {
					if(!this.quantifier.equals(other.quantifier)) {return false;}
				}
				else if(other.quantifier != null) {return false;}
			}
			//Check that the (left and only) subexpressions are equal
			if(this.left != null) {
				return this.left.equals(other.left);
			}
			else {
				return this.left == null;
			}
		}
		else { //Both kinds are binary
			boolean leftEquals;

			//Check that the left subexpressions are equal
			if(this.left != null) {
				leftEquals = this.left.equals(other.left);
			}
			else {
				leftEquals = (other.left == null);
			}
			
			if(!leftEquals) {
				//The left subexpressions are not equal
				return false;
			}

			//Check that the right subexpressions are equal
			if(this.right != null) {
				return this.right.equals(other.right);
			}
			else {
				return other.right == null;
			}
		}
	}

	/*
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * Static factory methods
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */

	public static SpecRegExp newVariableRegExp(VariableReference varRef, List<String> values, boolean acceptValues) {
		if(varRef == null || varRef.getVariable() == null || varRef.getVariable().getType() == null || values == null || (acceptValues && values.isEmpty())) {
			throw new RuntimeException("Could not create a new variable SpecRegExp object."
					+ " The given arguments would lead to the creation of an invalid regular expression");
		}
		SpecRegExp newRegExp = new SpecRegExp(varRef, values, acceptValues);
		if(!acceptValues && newRegExp.values.isEmpty()) {
			//the complementation of the values set has resulted in an empty set of values
			//this is an invalid regular expression (as it requires that the variable should not be equal to any value)
			return null;
		}
		return newRegExp;
	}

	public static SpecRegExp newPredicateRegExp(Spec predicate) {
		if(predicate == null){
			throw new RuntimeException("Could not create a new predicate SpecRegExp object."
					+ " The predicate (a Spec object) that has been specified is null"); 
		}
		return new SpecRegExp(predicate);
	}

	public static SpecRegExp newBooleanConstRegExp(boolean booleanValue) {
		return new SpecRegExp(booleanValue);
	}

	public static SpecRegExp newEmptyStringRegExp() {
		return new SpecRegExp();
	}

	public static SpecRegExp newUnionRegExp(SpecRegExp leftSubExp, SpecRegExp rightSubExp) {
		if(leftSubExp == null || rightSubExp == null) {
			throw new RuntimeException("Could not create a new union SpecRegExp object. "
					+ (leftSubExp == null ? "The left" : "The right") + " subexpression that has been specified is null"); 
		}
		return new SpecRegExp(leftSubExp, rightSubExp, RegExpKind.UNION);
	}

	public static SpecRegExp newConcatRegExp(SpecRegExp leftSubExp, SpecRegExp rightSubExp) {
		if(leftSubExp == null || rightSubExp == null) {
			throw new RuntimeException("Could not create a new concatenation SpecRegExp object. "
					+ (leftSubExp == null ? "The left" : "The right") + " subexpression that has been specified is null"); 
		}
		return new SpecRegExp(leftSubExp, rightSubExp, RegExpKind.CONCAT);
	}

	public static SpecRegExp newIntersectionRegExp(SpecRegExp leftSubExp, SpecRegExp rightSubExp) {
		if(leftSubExp == null || rightSubExp == null) {
			throw new RuntimeException("Could not create a new intersection SpecRegExp object. "
					+ (leftSubExp == null ? "The left" : "The right") + " subexpression that has been specified is null"); 
		}
		return new SpecRegExp(leftSubExp, rightSubExp, RegExpKind.INTERSECTION);
	}

	public static SpecRegExp newComplementationRegExp(SpecRegExp subExp) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new complement SpecRegExp object."
					+ " The subexpression that has been specified is null"); 
		}
		return new SpecRegExp(subExp, RegExpKind.COMPLEMENT);
	}

	public static SpecRegExp newZeroOrOneRepRegExp(SpecRegExp subExp) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'zero or one' repetitions SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		return new SpecRegExp(subExp);
	}

	public static SpecRegExp newZeroOrMoreRepRegExp(SpecRegExp subExp) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'zero or more' repetitions SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		return new SpecRegExp(subExp, true);
	}

	public static SpecRegExp newOneOrMoreRepRegExp(SpecRegExp subExp) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'one or more' repetitions SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		return new SpecRegExp(subExp, false);
	}

	public static SpecRegExp newExactRepRegExp(SpecRegExp subExp, int repNum) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'exact' repetitions SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		if(repNum < 0) {
			throw new RuntimeException("Could not create a new 'exact' repetitions SpecRegExp object."
					+ " The number of repetitions that has been specified is negative (must be non-negative)"); 
		}
		return new SpecRegExp(subExp, true, repNum);
	}

	public static SpecRegExp newAtLeastRepRegExp(SpecRegExp subExp, int repNum) {
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'at least' repetitions SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		if(repNum < 0) {
			throw new RuntimeException("Could not create a new 'at least' repetitions SpecRegExp object."
					+ " The number of repetitions that has been specified is negative (must be non-negative)"); 
		}
		return new SpecRegExp(subExp, false, repNum);
	}

	public static SpecRegExp newRepInRangeRegExp(SpecRegExp subExp, int leastRepNum, int maxRepNum) {
		//if(subExp == null || leastRepNum < 0 || maxRepNum < leastRepNum) {return null;}
		if(subExp == null) {
			throw new RuntimeException("Could not create a new 'repetitions in range' SpecRegExp object."
					+ " The quantified subexpression that has been specified is null"); 
		}
		if(leastRepNum < 0) {
			throw new RuntimeException("Could not create a new 'repetitions in range' SpecRegExp object."
					+ " The least number of repetitions that has been specified is negative (must be non-negative)"); 
		}
		if(maxRepNum < leastRepNum) {
			throw new RuntimeException("Could not create a new 'repetitions in range' SpecRegExp object."
					+ " The maximal number of repetitions that has been specified is smaller than the least one"); 
		}
		return new SpecRegExp(subExp, leastRepNum, maxRepNum);
	}

	/*
	 * 
	 * 
	 * 
	 * 
	 * 
	 * Private constructors
	 * 
	 * 
	 * 
	 * 
	 * 
	 */

	/**
	 * 
	 * 
	 * Constructor for a regular expression that consists of a Boolean term/formula/predicate.
	 * 
	 * @param predicate the Boolean predicate/formula
	 */
	private SpecRegExp(Spec predicate) {
		this.kind = RegExpKind.PREDICATE;
		this.predicate = predicate;
	}

	/**
	 * 
	 * Constructor for a regular expression that specifies a variable and a set of values, either of which should be assigned to that variable.
	 * 
	 * @param varRef the variable reference
	 * @param values non-empty set of the values, each of which is ASSUMED to be in the domain of {@code variable}
	 * @param acceptValues {@code true} (resp. {@code false}) if either (resp. neither) of the values in {@code values} should be accepted by the regular expression
	 */
	private SpecRegExp(VariableReference varRef, List<String> values, boolean acceptValues) {
		this.kind = RegExpKind.VAR; 
		this.varRef = varRef;
		if(acceptValues) {
			this.values = values;
		}
		else { //we assume that (varRef != null && varRef.getVariable() != null && varRef.getVariable().getType() != null && values != null)
			//this.values should be the complement of the given list of values (w.r.t. the domain of the variable)
			if(varRef.getVariable().getType().isBoolean()) {
				//Boolean variable
				this.values = new ArrayList<>();
				this.values.add(TRUE);
				this.values.add(FALSE);
			}
			else if (varRef.getVariable().getType().isInteger()) {
				this.values = IntStream.rangeClosed(varRef.getVariable().getType().getLower(), varRef.getVariable().getType().getUpper()).
						mapToObj(String::valueOf).collect(Collectors.toList());
			}
			else { //Enum variable
				this.values = new ArrayList<>(varRef.getVariable().getType().getValues());					
			}
			//this.values now contains all the values in the domain of the given variable
			//thus to obtain the complement list, we remove all the values that are in the given list
			this.values.removeAll(values);
		}
	}

	/**
	 * 
	 * Constructor for a regular expression of a constant Boolean value, either 'true' or 'false'.
	 * 
	 * @param booleanValue the Boolean value
	 */
	private SpecRegExp(boolean booleanValue) {
		this.kind = RegExpKind.BOOLEAN_CONST;
		String constValue = booleanValue ? TRUE : FALSE;
		this.values = new ArrayList<>();
		this.values.add(constValue);
	}

	/**
	 * 
	 * Constructor for the empty string regular expression.
	 *
	 */
	private SpecRegExp() {
		this.kind = RegExpKind.EMPTY_STR;
	}

	/**
	 * Constructor for an unary regular expression.
	 * 
	 * @param left the sub regular expression
	 * @param kind the kind of the unary operator, e.g., complementation
	 */
	private SpecRegExp(SpecRegExp left, RegExpKind kind) {
		this(left, null, kind);
	}

	/**
	 * 
	 * Constructor for a binary regular expression.
	 * 
	 * @param left the left sub regular expression
	 * @param right the right sub regular expression
	 * @param kind the kind of the binary operator, e.g., union, intersection, concatenation.
	 */
	private SpecRegExp(SpecRegExp left, SpecRegExp right, RegExpKind kind) {
		this(left, right, null, null, null, kind, null);
	}

	/**
	 * 
	 * Constructor for a regular expression of any kind.
	 * 
	 * @param left the left sub regular expression
	 * @param right the right sub regular expression
	 * @param values set of the values
	 * @param varRef the variable reference
	 * @param predicate the Boolean predicate/formula
	 * @param kind the kind of the regular expression
	 * @param quantifier the repetitions quantifier
	 */
	private SpecRegExp(SpecRegExp left, SpecRegExp right, List<String> values,
			VariableReference varRef, Spec predicate, RegExpKind kind, RegExpQuantifier quantifier) {
		this.left = left;
		this.right = right;
		this.values = values;
		this.varRef = varRef;
		this.predicate = predicate;
		this.kind = kind;
		this.quantifier = quantifier;
	}


	/**
	 * Constructor for an unary regular expression with a 'zero or one repetitions' quantifier ('?').
	 * 
	 * @param left the sub regular expression
	 */
	private SpecRegExp(SpecRegExp left) {
		this(left, RegExpKind.REPEAT);
		this.quantifier = RegExpQuantifier.zeroOrOneRepetition();
	}

	/**
	 * Constructor for an unary regular expression with either of the following two quantifiers:<br>
	 * 
	 * - 'Zero or more repetitions' (Kleene iteration, '*')<br>
	 * - 'One or more repetitions' ('+')
	 * 
	 * @param left the sub regular expression
	 * @param zeroOrMore whether the regular expression has a Kleene iteration quantifier
	 */
	private SpecRegExp(SpecRegExp left, boolean zeroOrMore) {
		this(left, RegExpKind.REPEAT);
		if(zeroOrMore) {
			this.quantifier = RegExpQuantifier.zeroOrMoreRepetitions();
		}
		else {
			this.quantifier = RegExpQuantifier.oneOrMoreRepetitions();
		}
	}

	/**
	 * Constructor for an unary regular expression with either of the following quantifiers:<br>
	 * 
	 * - 'Exact repetitions' ('{{@code n}}') <br>
	 * - 'At least repetitions' ('{{@code n},}')
	 * 
	 * @param left the sub regular expression
	 * @param isExact whether the regular expression has an 'exact repetitions' quantifier
	 * @param n the number of repetitions
	 */
	private SpecRegExp(SpecRegExp left, boolean isExact, int n) {
		this(left, RegExpKind.REPEAT);
		if(isExact) {
			this.quantifier = RegExpQuantifier.exactRepetitions(n);
		}
		else {
			this.quantifier = RegExpQuantifier.atLeastRepetitions(n);
		}
	}

	/**
	 * Constructor for an unary regular expression with 'repetitions in range' ('{{@code n},{@code m}}') quantifier.
	 * 
	 * 
	 * @param left the sub regular expression
	 * @param n the least number of repetitions
	 * @param m the maximal number of repetitions (inclusive)
	 */
	private SpecRegExp(SpecRegExp left, int n, int m) {
		this(left, RegExpKind.REPEAT);
		this.quantifier = RegExpQuantifier.repetitionsInRange(n, m);
	}

	/*
	 * 
	 * Private methods
	 * 
	 * 
	 * 
	 */

	private void addAllPredicateSubExps(List<SpecRegExp> predicateExps) {
		if(this.isPredicate()) {
			if(!predicateExps.contains(this)) { //regExp = '[Boolean term (assertion)]'
				predicateExps.add(this);
			}
		}
		else {
			if(this.hasLeft()) {
				this.left.addAllPredicateSubExps(predicateExps);
			}
			if(this.hasRight()) {
				this.right.addAllPredicateSubExps(predicateExps);
			}
		}
	}

	private void addAllVariables(List<Variable> regExpVars) {
		if(this.isVariable()) { //regExp = '[variable in {set of values}]'
			if(!regExpVars.contains(this.varRef.getVariable())) { 
				regExpVars.add(this.varRef.getVariable());
			}
		}
		else if(this.isPredicate()) { //regExp = '[Boolean term (instance of Spec)]'
			this.addAllSpecVariables(this.predicate, regExpVars);
		}
		else {
			if(this.hasLeft()) {
				this.left.addAllVariables(regExpVars);
			}
			if(this.hasRight()) {
				this.right.addAllVariables(regExpVars);
			}
		}
	}
	
	private void addAllSpecVariables(Spec spec, List<Variable> regExpVars) {
		if(spec instanceof VariableReference) {
			VariableReference vr = (VariableReference) spec;
			Variable var = vr.getVariable();
			if(var != null && !regExpVars.contains(var)) {
				regExpVars.add(var);
			}
		}
		else if(spec instanceof SpecExp) {
			SpecExp specExp = (SpecExp) spec;
			for(Spec childSpec : specExp.getChildren()) {
				addAllSpecVariables(childSpec, regExpVars);
			}
		}
	}
	
	private void fillRefToVarMapping(Map<String, Variable> refToVar) {
		if(this.isVariable()) { //regExp = '[variable in {set of values}]'
			if(!refToVar.containsKey(this.varRef.getReferenceName())) { 
				refToVar.put(this.varRef.getReferenceName(), this.varRef.getVariable());
			}
		}
		else if(this.isPredicate()) { //regExp = '[Boolean term (instance of Spec)]'
			this.fillSpecRefToVarMapping(this.predicate, refToVar);
		}
		else {
			if(this.hasLeft()) {
				this.left.fillRefToVarMapping(refToVar);
			}
			if(this.hasRight()) {
				this.right.fillRefToVarMapping(refToVar);
			}
		}
	}
	
	private void fillSpecRefToVarMapping(Spec spec, Map<String, Variable> refToVar) {
		if(spec instanceof VariableReference) {
			VariableReference varRef = (VariableReference) spec;
			if(!refToVar.containsKey(varRef.getReferenceName())) {
				refToVar.put(varRef.getReferenceName(), varRef.getVariable());
			}
		}
		else if(spec instanceof SpecExp) {
			SpecExp specExp = (SpecExp) spec;
			for(Spec childSpec : specExp.getChildren()) {
				fillSpecRefToVarMapping(childSpec, refToVar);
			}
		}
	}

	private boolean hasSingleBooleanValue(boolean trueValue) {
		return this.values != null && this.values.size() == 1 && (trueValue ? TRUE.equalsIgnoreCase(this.values.get(0)) : FALSE.equalsIgnoreCase(this.values.get(0)));
	}

	private boolean isBooleanConstKind() {
		return RegExpKind.BOOLEAN_CONST.equals(this.kind);
	}

	private boolean isBinaryKind(RegExpKind kind) {
		return kind.equals(this.kind) && this.left != null && this.right != null;
	}

	private boolean isUnaryKind(RegExpKind kind) {
		return kind.equals(this.kind) && this.left != null;
	}

	private boolean allValuesAreInts() {
		for(String val : this.values) {
			try {
				Integer.valueOf(val);
			} catch (NumberFormatException e) {
				return false;
			}
		}
		return true;
	}

	private boolean allValuesAreBooleans() {
		for(String val : this.values) {
			if(!(TRUE.equalsIgnoreCase(val) || FALSE.equalsIgnoreCase(val))) {
				return false;
			}
		}
		return true;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

import java.util.Map;
import tau.smlab.syntech.gameinput.model.Variable;

public class SpecHelper {

	// Get underlying variable of temporal expression inside index. We assume that
	// there is only one variable
	// in each index since it was verified during type check phase
	public static void getUnderlyingVariables(Spec index, Map<String, Variable> vars) {

		if (index instanceof VariableReference) {
			Variable var = ((VariableReference) index).getVariable();
			vars.put(var.getName(), var);
		} else if (index instanceof SpecExp) {
			SpecExp indexExp = (SpecExp) index;
			for (Spec child : indexExp.getChildren()) {
				getUnderlyingVariables(child, vars);
			}
		}
	}
	
	public static void updateDefineReference(DefineReference defRef, Variable var, PrimitiveValue primVal) throws Exception {
		
		for (int i = 0; i < defRef.getIndexSpecs().size(); i++) {
			Spec interpreted = SpecHelper.interpretWithVariable(defRef.getIndexSpecs().get(i), var, primVal);
			defRef.getIndexSpecs().set(i, interpreted);
		}
		defRef.getIndexVars().remove(var.getName());
		
		if (defRef.getIndexVars().isEmpty()) {
			for (int i = 0; i < defRef.getIndexSpecs().size(); i++) {
				Integer indexValue = SpecHelper.calculateSpec(defRef.getIndexSpecs().get(i));
				if (indexValue < 0 || indexValue >= defRef.getIndexDimensions().get(i)) {
					throw new Exception(String.format("Index %d out of bounds for variable %s", indexValue,
							defRef.getDefine().getName()));
				}
			}
		}
	}	

	public static void updateRefName(VariableReference varRef) throws Exception {
		String refName = varRef.getVariable().getName();
		if (varRef.getIndexVars().isEmpty()) {
			for (int i = 0; i < varRef.getIndexSpecs().size(); i++) {
				Integer indexValue = SpecHelper.calculateSpec(varRef.getIndexSpecs().get(i));
				if (indexValue < 0 || indexValue >= varRef.getIndexDimensions().get(i)) {
					throw new Exception(String.format("Index %d out of bounds for variable %s", indexValue,
							varRef.getVariable().getName()));
				}
				refName += String.format("[%d]", indexValue);
			}
		}
		varRef.setReferenceName(refName);
	}

	public static Spec interpretWithVariable(Spec spec, Variable var, PrimitiveValue value) throws Exception {
		// Assign value to varRef
		if (spec instanceof VariableReference) {
			VariableReference varRef = (VariableReference) spec;
			if (varRef.getVariable().equals(var)) {
				return value;
			} else {
				return varRef;
			}
		} else if (spec instanceof PrimitiveValue) {
			return spec;
		} else if (spec instanceof DefineReference) {
			DefineReference def = (DefineReference) spec;
			// For the time being, cannot interpret define arrays inside index spec
			if (def.getDefine().getExpression() != null) {
				def.getDefine().setExpression((interpretWithVariable(def.getDefine().getExpression(), var, value)));
				return def;
			} else {
				throw new Exception("Spec cannot be interpreted with variable, has invalid inner specs");
			}

		} else if (spec instanceof SpecExp) {
			SpecExp exp = (SpecExp) spec;
			return new SpecExp(exp.getOperator(), interpretWithVariable(exp.getChildren()[0], var, value),
					interpretWithVariable(exp.getChildren()[1], var, value));
		} else {
			throw new Exception("Spec cannot be interpreted with variable, has invalid inner specs");
		}
	}

	public static Integer calculateSpec(Spec spec) throws Exception {
		if (spec instanceof PrimitiveValue) {
			PrimitiveValue intVal = (PrimitiveValue) spec;
			try {
				return Integer.parseInt(intVal.getValue());
			} catch (NumberFormatException e) {
				throw new Exception("Spec cannot be calculated, is non integer");
			}
		} else if (spec instanceof DefineReference) {
			DefineReference def = (DefineReference) spec;
			if (def.getDefine().getExpression() != null) {
				return calculateSpec(def.getDefine().getExpression());
			} else {
				throw new Exception("Spec cannot be calculated, contains define references");
			}

		} else if (spec instanceof SpecExp) {
			SpecExp specExp = (SpecExp) spec;
			Operator op = specExp.getOperator();

			Integer res1 = calculateSpec(specExp.getChildren()[0]);
			Integer res2 = calculateSpec(specExp.getChildren()[1]);

			if (Operator.MOD.equals(op)) {
				return ((res1 % res2) + res2) % res2;
			} else if (Operator.ADD.equals(op)) {
				return res1 + res2;
			} else if (Operator.SUBSTRACT.equals(op)) {
				return res1 - res2;
			} else if (Operator.MULTIPLY.equals(op)) {
				return res1 * res2;
			} else if (Operator.DIVIDE.equals(op)) {
				return res1 / res2;
			} else {
				throw new Exception("Spec cannot be calculated, is non integer");
			}
		} else if (spec instanceof VariableReference) {
			throw new Exception("Spec cannot be calculated, contains variable references");
		} else {
			throw new Exception("Spec cannot be calculated, is non integer");
		}
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package net.sf.javabdd;

import net.sf.javabdd.BDDFactory.ReorderMethod;

public interface CUDDCaller {
	
	public void initialize0Caller(int nodenum, int cachesize);
	public boolean isInitialized0Caller();
	public void done0Caller();
	public int varNum0Caller();
	public int setVarNum0Caller(int num, boolean ADD);
	public long ithVar0Caller(int var, boolean ADD);
	public int level2Var0Caller(int level);
	public int var2Level0Caller(int var);
	public void setVarOrder0Caller(int[] neworder);
	public int getAllocNum0Caller();
	public int getNodeNum0Caller();
	public int getCacheSize0Caller();
	public int var0Caller(long b);
	public long high0Caller(long b, boolean ADD);
	public long low0Caller(long b, boolean ADD);
	public long not0Caller(long b, boolean ADD);
	public long ite0Caller(long b, long c, long d, boolean ADD);
	public long relprod0Caller(long b, long c, long d);
	public long compose0Caller(long b, long c, int var, boolean ADD);
	public long exist0Caller(long b, long c, boolean ADD);
	public long forAll0Caller(long b, long c, boolean ADD);
	public long restrict0Caller(long b, long var);
	public long restrictWith0Caller(long b, long c, boolean deref_other);
	public long simplify0Caller(long b, long var, boolean ADD);
	public long support0Caller(long b, boolean is_add);
	public long apply0Caller(long b, long c, int opr, boolean ADD, boolean apply_with, boolean deref_other);
	public long satOne0Caller(long b, long c, boolean ADD);
	public int nodeCount0Caller(long b);
	public double pathCount0Caller(long b);
	public double satCount0Caller(long b);
	public void addRefCaller(long p);
	public void delRefCaller(long p, boolean ADD);
	public long veccompose0Caller(long b, long p, boolean ADD);
	public long replace0Caller(long b, long p, boolean ADD);
	public long allocCaller(boolean ADD);
	public void set0Caller(long p, int oldvar, int newvar, boolean ADD);
	public void set2Caller(long p, int oldvar, long newbdd);
	public void reset0Caller(long ptr, boolean ADD);
	public void free0Caller(long ptr);
	public boolean isZeroOneADD0Caller(long ptr);
	public long addConst0Caller(double constval);
	public boolean isAddConst0Caller(long ptr);
	public long addFindMax0Caller(long ptr);
	public long addFindMin0Caller(long ptr);
	public double retrieveConstValue0Caller(long ptr);
	public long addAdditiveNeg0Caller(long ptr);
	public long addApplyLog0Caller(long ptr);
	public void reorder0Caller(ReorderMethod method);
	public void autoReorder0Caller(ReorderMethod method, boolean setmax, int maxval);
	public ReorderMethod getreordermethod0Caller();
	public void autoReorder1Caller();
	public int reorderVerbose0Caller(int v);
	public void addVarBlock0Caller(int first, int last, boolean fixed);
	public void clearVarBlocks0Caller();
	public void printStat0Caller();
	public long toADD0Caller(long b);
	public long toBDD0Caller(long b);
	public long toBDDThresholdCaller(long b, double threshold);
	public long toBDDStrictThresholdCaller(long b, double threshold);
	public long toBDDIntervalCaller(long b, double lower, double upper);
	public long toBDDIthBitCaller(long b, int bit);
	public int[] varSupportIndex0Caller(long b);
	public void printSet0Caller(long b, int printMode);
	public long logicZero0Caller();
	public long arithmeticZero0Caller();
	public long arithmeticLogicOne0Caller();
	public long arithmeticPlusInfinity0Caller();
	public long arithmeticMinusInfinity0Caller();
	public long replaceWith0Caller(long b, long c, boolean ADD);
	public long addMinimizeVal0Caller(long ptr, double val);
	public long addAbstractMin0Caller(long b, long c);
	public long addAbstractMax0Caller(long b, long c);
	public int reorderTimes0Caller();
	public void printVarTree0Caller();
	public long addEngSubtract0Caller(long a, long b, double maxEnergy);
	public long convertToZeroOneADDByThres0Caller(long a, long opType, double thresValue);
	public void printDot0Caller(long a);
	public long arithmeticExist0Caller(long b, long c);
	public long determinizeController0Caller(long b, long c);
	public int getSize0Caller(long b);
	public long getBddZero();
	public long getAddZero();
	public long getManager();
	public long getOne();
  public boolean reorderEnabled0Caller();
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.extension.console;

import java.io.IOException;
import java.io.PrintStream;

import org.eclipse.core.resources.IFile;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;

import tau.smlab.syntech.ui.logger.SpectraLogger;

public class ConsolePrinter {
	public final static int APPEND = 0;
	public final static int CLEAR_CONSOLE = 1;

	private String pluginName;
	private MessageConsole console;

	/**
	 * 
	 * @param activator should be an Activator object.
	 * @param mode      ConsolePrinter.APPEND or ConsolePrinter.CLEAR_CONSOLE
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public ConsolePrinter(String name, int mode)
			throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
		this.pluginName = name;
		this.console = getConsole();
		if (mode == CLEAR_CONSOLE) {
			clearConsole();
		} else if (mode == APPEND) {
			println("");
		}
		println(pluginName + ":");
		println("");
	}

	public void clearConsole() {
		console.clearConsole();
	}

	private MessageConsole getConsole() {
		String name = "SYNTECH Console";
		ConsolePlugin plugin = ConsolePlugin.getDefault();
		IConsoleManager conMan = plugin.getConsoleManager();
		IConsole[] existing = conMan.getConsoles();
		for (int i = 0; i < existing.length; i++)
			if (name.equals(existing[i].getName())) {
				return (MessageConsole) existing[i];
			}
		// no console found, so create a new one
		MessageConsole myConsole = new MessageConsole(name, null);
		myConsole.activate();
		conMan.addConsoles(new IConsole[] { myConsole });
		return myConsole;
	}

	public void print(String string) {
		print(string, false);
	}

	public void println(String string) {
		print(string, true);
	}

	public void printlnAndLog(IFile specFile, String actionID, String buffer) {
		println(buffer);
		SpectraLogger.logBuffer(specFile, actionID, buffer);
	}

	private void print(String string, boolean isPrintln) {
		MessageConsoleStream mcs = console.newMessageStream();
		if (isPrintln) {
			mcs.println(string);
		} else {
			mcs.print(string);
		}
		try {
			mcs.flush();
			mcs.close();
		} catch (IOException e) {
		}
	}

	/**
	 * Call this function to open the console view
	 */
	public void showConsole(IWorkbenchPage page) {
		try {
			IConsoleView view = (IConsoleView) page.showView(IConsoleConstants.ID_CONSOLE_VIEW);
			view.display(getConsole());
		} catch (PartInitException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public PrintStream getPrintStream() {
		return new PrintStream(console.newOutputStream());
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.jits;

import java.util.Map;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

/**
 * 
 * @author ilia
 *
 */
public class RecoveryController extends AbstractJitController {
		
	public RecoveryController(JitController jitController) {
		super(jitController);
	}

	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
		jitController.load(folder, name, sysVars, envVars);
		
		BDD Z = Env.unprime(getJitContext().Y(0, getJitContext().rank(0) - 1));
		
		// Trans and ini are taken only from sys
		jitController.getJitContext().setTrans(jitController.getJitContext().getSysTrans());
		jitController.getJitContext().setIni(jitController.getJitContext().getSysIni().exist(Env.globalPrimeVars()).and(Z));
		
		Z.free();
		
	}
	
	@Override
	public BDD next(BDD currentState, BDD inputs) {
		
		if (currentState.and(jitController.getJitContext().getEnvTrans()).and(Env.prime(inputs)).isZero()) {
			System.out.println("Environment safety violation detected with given inputs. Trying to continue with execution");
		}
		
		BDD next = jitController.next(currentState, inputs);
		if (next.isZero()) {
			throw new IllegalArgumentException("The inputs are a safety violation for the environment and it is impossible for the system to recover");
		}
		
		return next;
	}

	@Override
	public void init(BDD currentState) {
		
		if (jitController.getJitContext().getEnvIni().and(currentState).isZero()) {
			System.out.println("Environment safety violation detected with given inputs. Trying to continue with execution");
		}
		
		jitController.init(currentState);
	}
	
	@Override
	public void saveState() {
		this.controller.saveState();
	}

	@Override
	public void loadState() {
		this.controller.loadState();
	}

	@Override
	public BDD succ(BDD from) {
		return jitController.succ(from);
	}

	@Override
	public BDD pred(BDD to) {
		return jitController.pred(to);
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.PlayerModule;

public abstract class GameSolver {

  protected GameModel model;
  protected PlayerModule env;
  protected PlayerModule sys;

  public GameSolver(GameModel m) {
    this.model = m;
    env = m.getEnv();
    sys = m.getSys();
  }

  /**
   * check whether player wins
   * 
   * @return
   */
  abstract public boolean checkRealizability();

  abstract public void free();

  /**
   * check whether the system player wins from all initial states if <code>winSys</code> are its winning states
   * 
   * @param winSys
   * @return
   */
  public boolean sysWinAllInitial(BDD winSys) {
    BDD sysWin = winSys.and(sys.initial());
    BDD result = env.initial().id().impWith(sysWin.exist(sys.moduleUnprimeVars()))
        .forAll(env.moduleUnprimeVars());
    sysWin.free();

    boolean allIni = result.isOne();
    result.free();
    return allIni;
  }

  /**
   * check whether the environment player wins if <code>win</code> are the winning states
   * 
   * @param winEnv
   * @return
   */
  public boolean envWinAllInitial(BDD winEnv) {
    BDD envWin = env.initial().id().andWith(sys.initial().id().impWith(winEnv).forAll(sys.moduleUnprimeVars()));

    boolean winSomeIni = !envWin.isZero();
    envWin.free();
    return winSomeIni;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinputtrans.translator;


import tau.smlab.syntech.gameinput.model.Constraint;
import tau.smlab.syntech.gameinput.model.GameInput;
import tau.smlab.syntech.gameinput.spec.InExpSpec;
import tau.smlab.syntech.gameinput.spec.Operator;
import tau.smlab.syntech.gameinput.spec.PrimitiveValue;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;

public class TemporalInTranslator implements Translator {

	@Override
	public void translate(GameInput input) {
		// guarantees
		for (Constraint c : input.getSys().getConstraints()) {
			c.setSpec(replaceInOperator(c.getSpec(), c.getTraceId()));
		}

		// assumptions
		for (Constraint c : input.getEnv().getConstraints()) {
			c.setSpec(replaceInOperator(c.getSpec(), c.getTraceId()));
		}
	} 
	
	private Spec replaceInOperator(Spec spec, int traceId) {
		if (spec instanceof SpecRegExp) {
			SpecRegExp regexpSpec = (SpecRegExp)spec; 
			Spec predicate = regexpSpec.getPredicate();
		
			if (predicate instanceof InExpSpec) {
				InExpSpec inSpec = (InExpSpec) predicate;
								
				regexpSpec.setPredicate(trsanlateInOperator(inSpec));
				
				return regexpSpec;
			}
		}
		else if (spec instanceof InExpSpec) {
			return trsanlateInOperator((InExpSpec)spec);
		}
		else if (spec instanceof SpecExp) {
			SpecExp specExp = (SpecExp) spec; 
			for (int i = 0; i < specExp.getChildren().length; i++) {
				specExp.getChildren()[i] = replaceInOperator(specExp.getChildren()[i], traceId);
			}	
		}
		return spec;
	}

	private Spec trsanlateInOperator(InExpSpec inSpec) {
		Operator mainOp = Operator.OR;
						
		if (inSpec.isNot()) {
			mainOp = Operator.AND;
		}
		
		SpecExp firstEqualExp = new SpecExp(Operator.EQUALS, inSpec.getVariable(), new PrimitiveValue(inSpec.getSetOfvalues().get(0)));
				
		SpecExp translatedSpec = inSpec.isNot() ? new SpecExp(Operator.NOT, firstEqualExp) : firstEqualExp; 

		for (int i = 1; i < inSpec.getSetOfvalues().size(); i++) {
			String value_element = inSpec.getSetOfvalues().get(i);
            SpecExp equalExp = new SpecExp(Operator.EQUALS, inSpec.getVariable(), new PrimitiveValue(value_element));
			SpecExp finalExp = inSpec.isNot() ? new SpecExp(Operator.NOT, equalExp) : equalExp;
			translatedSpec = new SpecExp(mainOp, translatedSpec, finalExp);
        }
		
		return translatedSpec;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

// BDDFactoryIntImpl.java, created Jul 16, 2006 2:59:55 PM by jwhaley
// Copyright (C) 2004-2006 <NAME> <<EMAIL>>
// Licensed under the terms of the GNU LGPL; see COPYING for details.
package net.sf.javabdd;

import java.util.Collection;
import java.util.Iterator;

/**
 * A shared superclass for BDD factories that refer to BDDs as ints.
 * 
 * @author jwhaley
 * @version $Id: BDDFactoryIntImpl.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
 */
public abstract class BDDFactoryIntImpl extends BDDFactory {

  protected abstract void addref_impl(/* bdd */int v);

  protected abstract void delref_impl(/* bdd */int v);

  protected abstract /* bdd */int zero_impl();

  protected abstract /* bdd */int one_impl();

  protected /* bdd */int universe_impl() {
    return one_impl();
  }

  protected abstract /* bdd */int invalid_bdd_impl();

  protected abstract int var_impl(/* bdd */int v);

  protected abstract int level_impl(/* bdd */int v);

  protected abstract /* bdd */int low_impl(/* bdd */int v);

  protected abstract /* bdd */int high_impl(/* bdd */int v);

  protected abstract /* bdd */int ithVar_impl(int var);

  protected abstract /* bdd */int nithVar_impl(int var);

  protected abstract /* bdd */int makenode_impl(int lev, /* bdd */int lo, /* bdd */int hi);

  protected abstract /* bdd */int ite_impl(/* bdd */int v1, /* bdd */int v2, /* bdd */int v3);

  protected abstract /* bdd */int apply_impl(/* bdd */int v1, /* bdd */int v2, BDDOp opr);

  protected abstract /* bdd */int not_impl(/* bdd */int v1);

  protected abstract /* bdd */int applyAll_impl(/* bdd */int v1, /* bdd */int v2, BDDOp opr, /* bdd */int v3);

  protected abstract /* bdd */int applyEx_impl(/* bdd */int v1, /* bdd */int v2, BDDOp opr, /* bdd */int v3);

  protected abstract /* bdd */int applyUni_impl(/* bdd */int v1, /* bdd */int v2, BDDOp opr, /* bdd */int v3);

  protected abstract /* bdd */int compose_impl(/* bdd */int v1, /* bdd */int v2, int var);

  protected abstract /* bdd */int constrain_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int restrict_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int simplify_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int support_impl(/* bdd */int v);

  protected abstract /* bdd */int exist_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int forAll_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int unique_impl(/* bdd */int v1, /* bdd */int v2);

  protected abstract /* bdd */int replace_impl(/* bdd */int v, BDDPairing p);

  protected abstract /* bdd */int veccompose_impl(/* bdd */int v, BDDPairing p);

  protected abstract int nodeCount_impl(/* bdd */int v);

  protected abstract double pathCount_impl(/* bdd */int v);

  protected abstract double satCount_impl(/* bdd */int v);

  protected abstract int nodeCount_impl2(/* bdd */int[] v);

  protected abstract int[] varProfile_impl(/* bdd */int v);

  protected abstract void printTable_impl(/* bdd */int v);

  public class IntBDD extends AbstractBDD {
    protected /* bdd */int v;

    protected IntBDD(/* bdd */int v) {
      this.v = v;
      addref_impl(v);
    }

    public BDD apply(BDD that, BDDOp opr) {
      return makeBDD(apply_impl(v, unwrap(that), opr));
    }

    public BDD applyAll(BDD that, BDDOp opr, BDDVarSet var) {
      return makeBDD(applyAll_impl(v, unwrap(that), opr, unwrap(var)));
    }

    public BDD applyEx(BDD that, BDDOp opr, BDDVarSet var) {
      return makeBDD(applyEx_impl(v, unwrap(that), opr, unwrap(var)));
    }

    public BDD applyUni(BDD that, BDDOp opr, BDDVarSet var) {
      return makeBDD(applyUni_impl(v, unwrap(that), opr, unwrap(var)));
    }

    public BDD applyWith(BDD that, BDDOp opr) {
      /* bdd */int v2 = unwrap(that);
      /* bdd */int v3 = apply_impl(v, v2, opr);
      addref_impl(v3);
      delref_impl(v);
      if (this != that)
        that.free();
      v = v3;
      return this;
    }

    public BDD compose(BDD g, int var) {
      return makeBDD(compose_impl(v, unwrap(g), var));
    }

    public BDD constrain(BDD that) {
      return makeBDD(constrain_impl(v, unwrap(that)));
    }

    public boolean equals(BDD that) {
      if (that == null) {
        return false;
      }
      return v == unwrap(that);
    }

    public BDD exist(BDDVarSet var) {
      return makeBDD(exist_impl(v, unwrap(var)));
    }

    public BDD forAll(BDDVarSet var) {
      return makeBDD(forAll_impl(v, unwrap(var)));
    }

    public void free() {
      delref_impl(v);
      v = invalid_bdd_impl();
    }

    public BDDFactory getFactory() {
      return BDDFactoryIntImpl.this;
    }

    public int hashCode() {
      return v;
    }

    public BDD high() {
      return makeBDD(high_impl(v));
    }

    public BDD id() {
      return makeBDD(v);
    }

    public boolean isOne() {
      return v == one_impl();
    }

    public boolean isUniverse() {
      return v == universe_impl();
    }

    public boolean isZero() {
      return v == zero_impl();
    }

    public BDD ite(BDD thenBDD, BDD elseBDD) {
      return makeBDD(ite_impl(v, unwrap(thenBDD), unwrap(elseBDD)));
    }

    public BDD low() {
      return makeBDD(low_impl(v));
    }

    public int level() {
      return level_impl(v);
    }

    public int nodeCount() {
      return nodeCount_impl(v);
    }

    public BDD not() {
      return makeBDD(not_impl(v));
    }

    public double pathCount() {
      return pathCount_impl(v);
    }

    public BDD replace(BDDPairing pair) {
      return makeBDD(replace_impl(v, pair));
    }

    public BDD replaceWith(BDDPairing pair) {
      /* bdd */int v3 = replace_impl(v, pair);
      addref_impl(v3);
      delref_impl(v);
      v = v3;
      return this;
    }

    public BDD restrict(BDD var) {
      return makeBDD(restrict_impl(v, unwrap(var)));
    }

    public BDD restrictWith(BDD that) {
      /* bdd */int v2 = unwrap(that);
      /* bdd */int v3 = restrict_impl(v, v2);
      addref_impl(v3);
      delref_impl(v);
      if (this != that)
        that.free();
      v = v3;
      return this;
    }

    public double satCount() {
      return satCount_impl(v);
    }

    public BDD satOne(BDDVarSet var) {
      BDDIterator it = new BDDIterator(this, var);
      BDD one = it.nextBDD();
      it.free();
      return one;
      //original implementation: return makeBDD(satOne_impl(v, unwrap(var)));
    }

    public BDD simplify(BDDVarSet d) {
      return makeBDD(simplify_impl(v, unwrap(d)));
    }

    public BDDVarSet support() {
      return makeBDDVarSet(support_impl(v));
    }

    public BDD unique(BDDVarSet var) {
      return makeBDD(unique_impl(v, unwrap(var)));
    }

    public int var() {
      return var_impl(v);
    }

    public int[] varProfile() {
      return varProfile_impl(v);
    }

    public BDD veccompose(BDDPairing pair) {
      return makeBDD(veccompose_impl(v, pair));
    }

    public BDDVarSet toVarSet() {
      return makeBDDVarSet(v);
    }

    @Override
    public boolean isFree() {
      return this.v == invalid_bdd_impl();
    }
  }

  protected IntBDD makeBDD(/* bdd */int v) {
    return new IntBDD(v);
  }

  protected static final /* bdd */int unwrap(BDD b) {
    return ((IntBDD) b).v;
  }

  protected static final /* bdd */int[] unwrap(Collection<BDD> c) {
    /* bdd */int[] result = new /* bdd */int[c.size()];
    int k = -1;
    for (Iterator<BDD> i = c.iterator(); i.hasNext();) {
      result[++k] = ((IntBDD) i.next()).v;
    }
    return result;
  }

  public class IntBDDVarSet extends BDDVarSet {
    /* bdd */int v;

    protected IntBDDVarSet(/* bdd */int v) {
      this.v = v;
      addref_impl(v);
    }

    public boolean equals(BDDVarSet that) {
      return v == unwrap(that);
    }

    public void free() {
      delref_impl(v);
      v = invalid_bdd_impl();
    }

    public BDDFactory getFactory() {
      return BDDFactoryIntImpl.this;
    }

    public int hashCode() {
      return v;
    }

    public BDDVarSet id() {
      return makeBDDVarSet(v);
    }

    public BDDVarSet intersectWith(BDDVarSet b) {
      BDDVarSet res = intersect(b);
      this.free();
      this.v = res.hashCode();
      return this;
    }

    public boolean isEmpty() {
      return v == one_impl();
    }

    public int size() {
      int result = 0;
      for (/* bdd */int p = v; p != one_impl(); p = high_impl(p)) {
        if (p == zero_impl())
          throw new BDDException("varset contains zero");
        ++result;
      }
      return result;
    }

    public int[] toArray() {
      int[] result = new int[size()];
      int k = -1;
      for (/* bdd */int p = v; p != one_impl(); p = high_impl(p)) {
        result[++k] = var_impl(p);
      }
      return result;
    }

    public BDD toBDD() {
      return makeBDD(v);
    }

    public int[] toLevelArray() {
      int[] result = new int[size()];
      int k = -1;
      for (int p = v; p != one_impl(); p = high_impl(p)) {
        result[++k] = level_impl(p);
      }
      return result;
    }

    protected int do_unionvar(int v, int var) {
      return apply_impl(v, ithVar_impl(var), and);
    }

    protected int do_union(int v1, int v2) {
      return apply_impl(v1, v2, and);
    }

    public BDDVarSet union(BDDVarSet b) {
      return makeBDDVarSet(do_union(v, unwrap(b)));
    }

    public BDDVarSet union(int var) {
      return makeBDDVarSet(do_unionvar(v, var));
    }

    public BDDVarSet unionWith(BDDVarSet b) {
      /* bdd */int v2 = unwrap(b);
      /* bdd */int v3 = do_union(v, v2);
      addref_impl(v3);
      delref_impl(v);
      if (this != b)
        b.free();
      v = v3;
      return this;
    }

    public BDDVarSet unionWith(int var) {
      /* bdd */int v3 = do_unionvar(v, var);
      addref_impl(v3);
      delref_impl(v);
      v = v3;
      return this;
    }
  }

  public class IntZDDVarSet extends IntBDDVarSet {
    protected IntZDDVarSet(/* bdd */int v) {
      super(v);
    }

    protected int do_intersect(int v1, int v2) {
      if (v1 == one_impl())
        return v2;
      if (v2 == one_impl())
        return v1;
      int l1, l2;
      l1 = level_impl(v1);
      l2 = level_impl(v2);
      for (;;) {
        if (v1 == v2)
          return v1;
        if (l1 < l2) {
          v1 = high_impl(v1);
          if (v1 == one_impl())
            return v2;
          l1 = level_impl(v1);
        } else if (l1 > l2) {
          v2 = high_impl(v2);
          if (v2 == one_impl())
            return v1;
          l2 = level_impl(v2);
        } else {
          int k = do_intersect(high_impl(v1), high_impl(v2));
          addref_impl(k);
          int result = makenode_impl(l1, zero_impl(), k);
          delref_impl(k);
          return result;
        }
      }
    }

    protected int do_union(int v1, int v2) {
      if (v1 == v2)
        return v1;
      if (v1 == one_impl())
        return v2;
      if (v2 == one_impl())
        return v1;
      int l1, l2;
      l1 = level_impl(v1);
      l2 = level_impl(v2);
      int vv1 = v1, vv2 = v2, lev = l1;
      if (l1 <= l2)
        vv1 = high_impl(v1);
      if (l1 >= l2) {
        vv2 = high_impl(v2);
        lev = l2;
      }
      int k = do_union(vv1, vv2);
      addref_impl(k);
      int result = makenode_impl(lev, zero_impl(), k);
      delref_impl(k);
      return result;
    }

    protected int do_unionvar(int v, int var) {
      return do_unionlevel(v, var2Level(var));
    }

    private int do_unionlevel(int v, int lev) {
      if (v == one_impl())
        return makenode_impl(lev, zero_impl(), one_impl());
      int l = level_impl(v);
      if (l == lev) {
        return v;
      } else if (l > lev) {
        return makenode_impl(lev, zero_impl(), v);
      } else {
        int k = do_unionlevel(high_impl(v), lev);
        addref_impl(k);
        int result = makenode_impl(l, zero_impl(), k);
        delref_impl(k);
        return result;
      }
    }
  }

  protected IntBDDVarSet makeBDDVarSet(/* bdd */int v) {
    if (isZDD()) {
      return new IntZDDVarSet(v);
    } else {
      return new IntBDDVarSet(v);
    }
  }

  protected static final /* bdd */int unwrap(BDDVarSet b) {
    return ((IntBDDVarSet) b).v;
  }

  public class IntBDDBitVector extends BDDBitVector {

    protected IntBDDBitVector(int bitnum) {
      super(bitnum);
    }

    public BDDFactory getFactory() {
      return BDDFactoryIntImpl.this;
    }

  }

  public BDD ithVar(/* bdd */int var) {
    return makeBDD(ithVar_impl(var));
  }

  public BDD nithVar(/* bdd */int var) {
    return makeBDD(nithVar_impl(var));
  }

  public int nodeCount(Collection<BDD> r) {
    return nodeCount_impl2(unwrap(r));
  }

  public BDD one() {
    return makeBDD(one_impl());
  }

  public BDD universe() {
    return makeBDD(universe_impl());
  }

  public BDDVarSet emptySet() {
    return makeBDDVarSet(one_impl());
  }

  public void printTable(BDD b) {
    printTable_impl(unwrap(b));
  }

  public BDD zero() {
    return makeBDD(zero_impl());
  }

  public void done() {
  }

  protected void finalize() throws Throwable {
    super.finalize();
    this.done();
  }

  protected /* bdd */int[] to_free = new /* bdd */int[8];
  protected /* bdd */int to_free_length = 0;

  public void deferredFree(int v) {
    if (v == invalid_bdd_impl())
      return;
    synchronized (to_free) {
      if (to_free_length == to_free.length) {
        /* bdd */int[] t = new /* bdd */int[to_free.length * 2];
        System.arraycopy(to_free, 0, t, 0, to_free.length);
        to_free = t;
      }
      to_free[to_free_length++] = v;
    }
  }

  public void handleDeferredFree() {
    synchronized (to_free) {
      while (to_free_length > 0) {
        delref_impl(to_free[--to_free_length]);
      }
    }
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.simple;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.GameMemory;
import tau.smlab.syntech.games.GameSolver;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

/**
 * This is an implementation of a generalized coBuchi game. <br>
 * The objective of the system is to prevent the justices of the environment.
 * 
 * <li>implements a check whether we reached a fixed point early</li>
 * <li>computes all winning states</li>
 */
public class CoBuchiGame extends GameSolver {

  protected GameMemory mem;

  public GameMemory getMem() {
    return mem;
  }

  public CoBuchiGame(GameModel model) {
    super(model);
    mem = new GameMemory();
  }

  @Override
  public boolean checkRealizability() {
    BDD Z = Env.FALSE();
    int iterationsWithoutGain = 0;
    while (iterationsWithoutGain < env.justiceNum()) {
      for (int i = 0; i < env.justiceNum(); i++) {
        BDD toPrevWin = env.yieldStates(sys, Z).orWith(env.justiceAt(i).not());
        BDD X = toPrevWin.id(); // instead of TRUE start here (at most what is winning now) 
        FixPoint fX = new FixPoint(true);
        while (fX.advance(X)) {
          X = toPrevWin.id().andWith(env.yieldStates(sys, X));
        }
        BDD newZ = Z.or(X);
        if (newZ.equals(Z)) {
          iterationsWithoutGain++;
        } else {
          iterationsWithoutGain = 0;
        }
        Z.free();
        toPrevWin.free();
        Z = newZ;
      }
    }
    mem.setWin(Z);
    return sysWinAllInitial();
  }

  @Override
  public void free() {
    mem.free();
  }

  public boolean sysWinAllInitial() {
    return this.sysWinAllInitial(mem.getWin());
  }

  public BDD sysWinningStates() {
    return mem.getWin();
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.jits;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

/**
 * A class for the execution of symbolic controllers in a Just-in-time fashion
 * @author ilia
 *
 */
public class BasicJitControllerImplC implements JitController {

	private BDD transitions;
	private BDD initial;
	
	@Override
	public BDD next(BDD currentState, BDD inputs) {
		
		return (Env.TRUE().getFactory()).nextStatesJits(currentState, inputs, Env.allCouplesPairing(), Env.globalUnprimeVars());
	}
	
	@Override
	public void load(String folder, String name, Map<String, String[]> sysVars, Map<String, String[]> envVars) {
				
		try {
			
			String prefix;
			if (name == null) {
				prefix = folder + File.separator;
			} else {
				prefix = folder + File.separator + name + ".";
			}
			
			BufferedReader sizesReader = new BufferedReader(new FileReader(prefix + "sizes"));
			
			int n = Integer.parseInt(sizesReader.readLine());
			int m = Integer.parseInt(sizesReader.readLine());
			int[] ranks = new int[n];
			for (int j = 0; j < n; j++) {
				ranks[j] = Integer.parseInt(sizesReader.readLine());
			}
			
			sizesReader.close();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Read Sizes");
			
			
			int[] jindices = Env.getVar("util_Jn").getDomain().vars();
			int[] iindices = Env.getVar("util_In").getDomain().vars();
			int[] rindices = Env.getVar("util_Rn").getDomain().vars();
			int utilindex = Env.getVar("util_0").getDomain().vars()[0];
			
			// Extract justices
			
			BDD justices = Env.loadBDD(prefix + "justice.bdd");
			(Env.TRUE().getFactory()).loadJusticesJits(justices, jindices, iindices, utilindex, n, m);
			justices.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Loaded Justice BDD");
			
			
			
			// Extract trans and init
			
			BDD trans = Env.loadBDD(prefix + "trans.bdd");
			(Env.TRUE().getFactory()).loadTransJits(trans, jindices, iindices, utilindex);
			trans.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Loaded Transition BDD");
			
			
			// Extract X from fixpoints BDD
			
			BDD fixpoints = Env.loadBDD(prefix + "fixpoints.bdd");
			(Env.TRUE().getFactory()).loadFixpointsJits(fixpoints, jindices, iindices, rindices, ranks, Env.allCouplesPairing(), Env.globalPrimeVars());
			fixpoints.free();
			System.out.println(Env.TRUE().getFactory().getNodeNum() + " - Loaded Fixed-Points BDD");

			
			
			
			initial = (Env.TRUE().getFactory()).getInitialJits();
			transitions = (Env.TRUE().getFactory()).getTransitionsJits();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// Delete vars even though they are not really removed from bdd engine.
		// At least they won't show up in next states enumeration
		Env.deleteVar("util_In");
		Env.deleteVar("util_Jn");
		Env.deleteVar("util_Rn");
		Env.deleteVar("util_0");
	}

	@Override
	public List<BDD> getJusticeGar() {
		return null;
	}

	@Override
	public List<BDD> getJusticeAsm() {
		return null;
	}

	@Override
	public JitContext getJitContext() {
		return null;
	}

	@Override
	public void free() {
		(Env.TRUE().getFactory()).freeControllerJits();
	}

	@Override
	public BDD transitions() {
		return transitions;
	}

	@Override
	public JitState getJitState() {
		return null;
	}

	@Override
	public BDD initial() {
		return initial;
	}

	@Override
	public void init(BDD currentState) {
		
		int result = (Env.TRUE().getFactory()).initControllerJits(currentState, Env.allCouplesPairing());
		
		if (result == -1) {
			throw new IllegalArgumentException("Illegal rank reached. Probably initial environment inputs violate the initial assumptions");
		}
	}

	@Override
	public void saveState() {
	}

	@Override
	public void loadState() {
	}

	@Override
	public BDD succ(BDD from) {
		return null;
	}

	@Override
	public BDD pred(BDD to) {
		return null;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.bddgenerator.sfa.regexp;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.bddgenerator.BDDGenerator;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.sfa.SFA;
import tau.smlab.syntech.sfa.SFAs;

/**
 * 
 * A class for transforming regular expressions into Symbolic finite automatons (SFAs) using 
 * only symbolic BDD operations. This implementation adapts Thompson's construction algorithm.
 * 
 * @author <NAME>
 *
 */
public class SymRegExpSFAGenerator implements RegExpSFAGenerator {

	private SpecRegExp specRegExp; //the regular expression
	private SFA sfa; //the SFA that would be created
	private int traceId; //the trace ID of the constraint where the regular expression appears
	private boolean isPredicate; //indicates whether the regular expression defines a "predicate" language, i.e., a language that only consists
								 //of words of length 1 that may be characterized by a Boolean predicate/assertion

	/**
	 * 
	 * @param specRegExp the regular expression
	 * @param traceId
	 */
	public SymRegExpSFAGenerator(SpecRegExp specRegExp, int traceId) {
		this.traceId = traceId;
		this.isPredicate = false;
		this.specRegExp = specRegExp;
	}
	
	@Override
	public SFA generateRegExpDSfa(boolean minimal) {
		generateRegExpSfa();
		SFA resDSfa;
		if(minimal) {
			resDSfa = this.sfa.minimize();
		}
		else {
			resDSfa = this.sfa.determinize();
		}
		this.sfa.free();
		this.sfa = resDSfa;
		return this.sfa;
	}
	
	@Override
	public SFA generateRegExpSfa() {
		if(this.sfa == null) {
			SFA oFSfa = this.buildRegExpOFSfa();
			this.sfa = oFSfa.eliminateEpsTrans();
			this.sfa.removeDeadStates();
			oFSfa.free();
		}
		return this.sfa;
	}

	@Override
	public void freeRegExpSfa() {
		if(this.sfa != null) {
			this.sfa.free();
		}
		this.sfa = null;
	}

	/**
	 * Checks whether the Epsilon-SFA of this generator either has been freed or
	 * has not been created.
	 * 
	 * @see #generateRegExpSfa()
	 * @see #free()
	 * 
	 * @return
	 */
	public boolean isFree() {
		return this.sfa == null;
	}

	/*
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 *
	 * 
	 * Private methods
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 */

	/**
	 * Returns an OFSFA whose language is that of the regular expression of this generator.
	 * Note that the returned OFSFA may be non-deterministic and have epsilon transitions.
	 * 
	 * @return
	 */
	private SFA buildRegExpOFSfa() {

		if(this.specRegExp == null) {
			throw new RegExpSFAGeneratorException("The regular expression of this transformer is null and thus cannot be translated to an SFA",
					this.traceId);
		}

		if(this.specRegExp.isEmptyString()) { //regExp = '()' 
			return SFAs.emptyWordOFSfa();
		}
		if(this.specRegExp.isTrueBooleanConst()) { //regExp = 'TRUE'
			this.isPredicate = true;
			return SFAs.predicateOFSfa(Env.TRUE());
		}
		if(this.specRegExp.isFalseBooleanConst()) { //regExp = 'FALSE'
			this.isPredicate = true;
			return SFAs.predicateOFSfa(Env.FALSE());
		}
		if(this.specRegExp.isVariable()) { //regExp = 'var in {set of values}' 
			String varName = this.specRegExp.getVariableReferenceName();
			BDD currValue;
			BDD valuesAssrt = Env.FALSE();
			for(String value : this.specRegExp.getValues()) {
				currValue = Env.getBDDValue(varName, value);
				if(currValue == null) {
					throw new RegExpSFAGeneratorException("Unable to transform the regular expression " + this.specRegExp + " into an Epsilon-SFA since "
							+ value + " is not in the domain of the variable " + varName, this.traceId);
				}
				valuesAssrt.orWith(currValue.id());
			}
			this.isPredicate = true;
			return SFAs.predicateOFSfa(valuesAssrt);	
		}
		if(this.specRegExp.isPredicate()) { //regExp = 'Boolean term (i.e., assertion)'
			this.isPredicate = true;
			BDD predicate = BDDGenerator.createBdd(this.specRegExp.getPredicate(), this.traceId);
			return SFAs.predicateOFSfa(predicate);
		}

		if(!this.specRegExp.hasLeft()) {
			throw new RegExpSFAGeneratorException("Unable to transform the regular expression " + this.specRegExp + " into an Epsilon-SFA as it is expected to have a left sub-expression", this.traceId);
		}

		//Perform a recursive call on the left subexpression (might be the only subexpression in case this is an unary expression)
		SymRegExpSFAGenerator leftSfaGenerator = new SymRegExpSFAGenerator(this.specRegExp.getLeft(), this.traceId);
		SFA leftOFSfa = leftSfaGenerator.buildRegExpOFSfa();

		if(this.specRegExp.isRepetition()) {
			int leastRepNum = this.specRegExp.getQuantifier().getLeastRepetitionsNum();
			switch(this.specRegExp.getQuantifierType()) {
			case AT_LEAST: //'{n,}'
				return SFAs.nOrMoreOFSfa(leftOFSfa, leastRepNum);
			case EXACT_REPETITION: //'{n}'
				return SFAs.exactNOFSfa(leftOFSfa, leastRepNum);
			case ONE_OR_MORE: //'+'
				return SFAs.oneOrMoreOFSfa(leftOFSfa);
			case RANGE: //'{n,m}'
				return SFAs.nToMOFSfa(leftOFSfa, leastRepNum, this.specRegExp.getQuantifier().getMaxRepetitionsNum());
			case ZERO_OR_MORE: //'*'
				return SFAs.kleeneClosureOFSfa(leftOFSfa);
			case ZERO_OR_ONE: //'?'
				return SFAs.zeroOrOneOFSfa(leftOFSfa);
			default:
				throw new RegExpSFAGeneratorException("Unable to transform the repetition regular expression " + this.specRegExp + " into an Epsilon-SFA since the quantifier " +
						this.specRegExp.getQuantifierType() + " is not supported", this.traceId);
			}
		}
		
		if(this.specRegExp.isComplementation()) {
			return SFAs.complementOFSfa(leftOFSfa);
		}
		

		if(!this.specRegExp.hasRight()) {
			throw new RegExpSFAGeneratorException("Unable to transform the unary regular expression " + this.specRegExp + " into an Epsilon-SFA. This regular expression is not supported", this.traceId);
		}
		
		//Perform a recursive call on the right subexpression
		SymRegExpSFAGenerator rightSfaGenerator = new SymRegExpSFAGenerator(this.specRegExp.getRight(), this.traceId);
		SFA rightOFSfa = rightSfaGenerator.buildRegExpOFSfa();

		if(this.specRegExp.isUnion()) {
			if(leftSfaGenerator.isPredicate && rightSfaGenerator.isPredicate) {
				this.isPredicate = true;
				return SFAs.unionPredicateOFSfa(leftOFSfa, rightOFSfa);
			}
			else {
				return SFAs.unionOFSfa(leftOFSfa, rightOFSfa);
			}
		}

		if(this.specRegExp.isIntersection()) {
			if(leftSfaGenerator.isPredicate && rightSfaGenerator.isPredicate) {
				this.isPredicate = true;
				return SFAs.productPredicateOFSfa(leftOFSfa, rightOFSfa);
			}
			else {
				return SFAs.productOFSfa(leftOFSfa, rightOFSfa);
			}
		}

		if(this.specRegExp.isConcat()) {
			return SFAs.concatOFSfa(leftOFSfa, rightOFSfa);
		}
		throw new RegExpSFAGeneratorException("Unable to transform the binary regular expression " + this.specRegExp + " into an Epsilon-SFA. This regular expression is not supported", this.traceId);
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.model;

import java.util.ArrayList;
import java.util.List;

import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecRegExp;
/**
 * 
 * @author <NAME>
 *
 */
public class ExistentialConstraint extends Constraint {
	/**
	 * 
	 */
	private static final long serialVersionUID = -336461559302985367L;

	private List<Spec> specs;
	private boolean isRegExp; //Whether this existential constraint is of the form 'GEF regExp'
	private SpecRegExp regExp; //The regular expression of this existential constraint

	/**
	 * 
	 * Returns a new existential constraint of the form 'GE (F(g1 and F (g2 and F (g3 and ..))))'
	 * where each gi is a {@link tau.smlab.syntech.gameinput.spec.Spec} object (represents an assertion). The returned
	 * existential constraint has an empty list of assertions gi.
	 * 
	 * @param name
	 * @param traceId
	 */
	public ExistentialConstraint(String name, int traceId) {
		super(Kind.EXISTS, null, name, traceId);
		this.isRegExp = false;
		this.specs = new ArrayList<>();
	}

	/**
	 * 
	 * Return a new existential constraint of the form 'GEF {@code regExp}'.
	 * 
	 * @param name
	 * @param regExp the regular expression
	 * @param traceId
	 */
	public ExistentialConstraint(String name, SpecRegExp regExp, int traceId) {
		super(Kind.EXISTS, null, name, traceId);
		this.isRegExp = true;
		this.regExp = regExp;
	}

	public boolean isRegExp() {
		return this.isRegExp;
	}


	@Override
	public Kind getKind() {
		return Kind.EXISTS;
	}

	public List<Spec> getSpecs() {
		return this.specs;
	}

	public int getSize() {
		return isRegExp ? 0 : this.specs.size();
	}

	public SpecRegExp getRegExp() {
		return this.regExp;
	}

	/**
	 * 
	 * Adds the specified {@code spec} to the list of existential assertions.
	 * 
	 * @param spec the existential assertion to add
	 * @return true if {@code spec} has been successfully added to the list
	 */
	public boolean addSpec(Spec spec) {
		if(!isRegExp) {
			return this.specs.add(spec);
		}
		return false;
	}

	/**
	 * 
	 * Returns the spec at the specified position in the list of existential assertions.
	 * If the specified position is out of bounds, {@code null} is returned.
	 * 
	 * @param specIdx the position
	 * @return
	 */
	public Spec getSpec(int specIdx) {
		if(!isRegExp && specIdx >= 0 && specIdx < specs.size()) {
			return this.specs.get(specIdx);
		}
		return null;
	}

	/**
	 * 
	 * Replaces the spec at the specified position in the list of existential assertions with the specified spec.
	 *
	 * @param specIdx the position
	 * @param spec the spec
	 * @return the spec previously at the specified position or {@code null} if the specified position is out of bounds
	 */
	public Spec replaceSpec(int specIdx, Spec spec) {
		if(!isRegExp && specIdx >= 0 && specIdx < specs.size()) {
			return this.specs.set(specIdx, spec);
		}
		return null;
	}

	/**
	 * 
	 * Replaces the regular expression of this existential constraint with the specified one.
	 *  
	 * @param regExp the new regular expression
	 * @return the previous regular expression
	 */
	public SpecRegExp replaceRegExp(SpecRegExp regExp) {
		if(isRegExp) {
			SpecRegExp replacedRegExp = this.regExp;
			this.regExp = regExp;
			return replacedRegExp;
		}
		return null;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.bddgenerator.sfa.trigger;

import tau.smlab.syntech.bddgenerator.BDDTranslationException;
import tau.smlab.syntech.gameinput.model.TriggerConstraint;
import tau.smlab.syntech.sfa.SFA;


/**
 * 
 * Use a {@link TriggerSFAGenerator} to translate triggers (instances of {@link TriggerConstraint})
 * to equivalent {@link SFA}s.
 * 
 * @author <NAME>
 *
 */
public interface TriggerSFAGenerator {
	
	/**
	 *
	 * An exception thrown during translations of triggers (instances of {@link TriggerConstraint}) to {@link SFA}s.
	 *
	 */
	public static class TriggerSFAGeneratorException extends BDDTranslationException {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1780939868279839674L;

		public TriggerSFAGeneratorException() {
			super();
		}
		
		public TriggerSFAGeneratorException(String string, int traceId) {
			super(string, traceId);
		}

	}
	
	/**
	 * 
	 * Returns a deterministic and complete {@link SFA} whose language is that of the trigger associated with this generator.
	 * 
	 * @return
	 */
	public SFA generateTriggerSfa();
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.jobs;

import java.io.PrintStream;

import org.eclipse.ui.console.IOConsoleOutputStream;

import tau.smlab.syntech.bddgenerator.energy.BDDEnergyReduction;
import tau.smlab.syntech.games.controller.enumerate.ConcreteControllerConstruction;
import tau.smlab.syntech.games.controller.enumerate.printers.MAAMinimizeAutomatonPrinter;
import tau.smlab.syntech.games.controller.enumerate.printers.SimpleTextPrinter;
import tau.smlab.syntech.games.rabin.RabinConcreteControllerConstruction;
import tau.smlab.syntech.games.rabin.RabinGame;
import tau.smlab.syntech.jtlv.BDDPackage;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.ModuleVariableException;
import tau.smlab.syntech.ui.preferences.PreferencePage;

public class CounterStrategyJob extends SyntechJob {

	@Override
	protected void doWork() {

		if (PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD_ADD) && model.getWeights() != null) {
			BDDEnergyReduction.reduce(model.getSys(), model.getWeights(), gi.getEnergyBound(), PreferencePage.isGroupVarSelection());
		}

		// play actual game
		RabinGame rabin = new RabinGame(model);
		if (rabin.checkRealizability()) {
			this.isRealizable = false;

			if(model.getWeights() != null) {
				try {
					BDDEnergyReduction.updateSysIniTransWithEngConstraintsForCounterStrategy(model, gi.getEnergyBound());
				} catch (ModuleVariableException e) {
					e.printStackTrace();
				}
			}

			Env.disableReorder();

			ConcreteControllerConstruction cc = new RabinConcreteControllerConstruction(rabin.getMem(), model);
			IOConsoleOutputStream cout = console.newOutputStream();
			PrintStream out = new PrintStream(cout);
			try {
				if ("CMP".equals(PreferencePage.getConcreteControllerFormat())) {
					MAAMinimizeAutomatonPrinter.REMOVE_DEAD_STATES = false;
					new MAAMinimizeAutomatonPrinter(model).printController(out, cc.calculateConcreteController());
				} else if ("JTLV".equals(PreferencePage.getConcreteControllerFormat())) {
					new SimpleTextPrinter().printController(out, cc.calculateConcreteController());
				}
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			this.isRealizable = true;
			printToConsole("The selected specification is realizable.");
		}
		model.free();
		rabin.free();
	}

	@Override
	public boolean needsBound() {
		return true;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.checks.ddmin;

import java.util.List;

import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.gamemodel.util.GameBuilderUtil;

public abstract class DdminRealizableCore extends AbstractDdmin<BehaviorInfo> {
  protected GameModel model;

  public DdminRealizableCore(GameModel model) {
    this.model = model;
  }

	/**
	 * This has to be filled by the caller in order to make realizability checks standard and menu opt. sensitive.
	 * See CoreMenu class
	 * 
	 * @param gm
	 * @return
	 */
	public abstract boolean realizable(GameModel gm);
	
  @Override
  protected boolean check(List<BehaviorInfo> part) {
    GameBuilderUtil.buildEnv(model, part);
    return realizable(model);
  }

}<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.modelchecker;

import java.util.HashMap;
import java.util.Set;
import java.util.Vector;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDException;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.jtlv.CoreUtil;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.ModuleVariableException;
import tau.smlab.syntech.jtlv.env.module.ModuleBDDField;
import tau.smlab.syntech.gamemodel.ModuleException;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.gameinput.spec.Spec;
import tau.smlab.syntech.gameinput.spec.SpecBDD;
import tau.smlab.syntech.gameinput.spec.SpecExp;
import tau.smlab.syntech.gameinput.spec.Operator;

/**
 * <p>
 * A checker which knows how to check LTL properties for the given
 * ComposedPlayerModule
 * </p>
 * 
 */
public class LTLModelChecker {

  private PlayerModule design;

  public LTLModelChecker(PlayerModule design) throws ModelCheckException {
    if (design == null)
      throw new ModelCheckException("Cannot instatiate an LTL Model " + "Checker with a null module.");
    this.design = design;
  }

  /**
   * 
   * @param property
   * @return true if property is verified
   */
  public boolean modelCheckWithNoCounterExample(Spec property) {
    Spec negp = new SpecExp(Operator.NOT, property);
    LTLTesterBuilder builder;
    try {
      builder = new LTLTesterBuilder(negp, true);
      PlayerModule composed = design.compose(builder.getTester());
      boolean res = checkVerify(builder.getSpec2BDD(property).not(), composed);
      return res;
    } catch (ModelCheckException e) {
      e.printStackTrace();
    } catch (ModuleVariableException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return false;
  }

  private boolean checkVerify(BDD initial_condition, PlayerModule designWithTester) {
    // saving to the previous restriction state
    BDD initial = designWithTester.initial().id();

    designWithTester.conjunctInitial(initial_condition.id());
    FeasibilityChecker fsChecker = new FeasibilityChecker();
    BDD feas = fsChecker.check(designWithTester);
    // the initial_condition seems redundant
    if (!feas.and(designWithTester.initial().id()).and(initial_condition).isZero()) {
      // returning to the previous restriction state
      designWithTester.resetInitial();
      designWithTester.conjunctInitial(initial.id());
      return false;
    }
    // returning to the previous restriction state
    designWithTester.resetInitial();
    designWithTester.conjunctInitial(initial.id());
    return true;
  }

  /**
   * <p>
   * Given a specification \phi (as a formula in temporal logic) we want to decide
   * whether \phi is valid over finite state program P , i.e. whether all the
   * computations of the design satisfy \phi. This variant of implementation,
   * prints the results to the standard streams.
   * </p>
   * 
   * @param property The property to check.
   * @throws ModuleVariableException
   */
  public void modelCheckStandardOutput(Spec property) {
    System.out.println("model checking property: " + property);
    try {
      this.modelCheck(property);
    } catch (ModelCheckException mce) {
      System.err.println(mce.toString());
      return;
    } catch (ModuleVariableException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    // else - everything is OK.
    System.out.println("*** Property is VALID ***");
  }

  /**
   * <p>
   * Given a specification \phi (as a formula in temporal logic) we want to decide
   * whether \phi is valid over finite state program P , i.e. whether all the
   * computations of the design satisfy \phi.
   * </p>
   * 
   * @param property The property to check.
   * @throws ModelCheckException     When the method is initiated with other then
   *                                 LTL property.
   * @throws CounterExampleException When the property is not valid, a counter
   *                                 example is thrown.
   * @throws ModuleVariableException
   */
  public void modelCheck(Spec property) throws ModelCheckException, CounterExampleException, ModuleVariableException {
    Spec negp = new SpecExp(Operator.NOT, property);
    LTLTesterBuilder builder = new LTLTesterBuilder(negp, true);

    BDD tester_initials = builder.getSpec2BDD(property).not();

    BDDVarSet visibleVars = getRelevantVars(design);
    visibleVars.unionWith(getRelevantVars(builder.getTester())); // FIXME
    visibleVars.unionWith(tester_initials.support().minus(Env.union(builder.getTester().getAuxFields())));

    PlayerModule composed = design.compose(builder.getTester());
    try {
      verify(tester_initials, composed, visibleVars);
      // verify(tester_initials, this.design, null);
    } catch (CounterExampleException mce) {
      throw mce;
    }
  }

  /**
   * <p>
   * The main procedure for verifying.
   * </p>
   * 
   * @param initial_condition
   * @param designWithTester
   * @param relevantVars
   * @throws ModelCheckException
   */
  private static void verify(BDD initial_condition, PlayerModule designWithTester, BDDVarSet relevantVars)
      throws CounterExampleException {
    // saving to the previous restriction state
    BDD initial = designWithTester.initial().id();

    designWithTester.conjunctInitial(initial_condition.id());
    FeasibilityChecker fsChecker = new FeasibilityChecker();
    BDD feas = fsChecker.check(designWithTester);
    // the initial_condition seems redundant
    if (!feas.and(designWithTester.initial()).and(initial_condition).isZero()) {

      BDD[] example = extractWithness(feas, designWithTester, relevantVars, fsChecker);
      CounterExampleException cee = new CounterExampleException("\n*** Property is NOT VALID ***", example);

      // returning to the previous restriction state
      designWithTester.resetInitial();
      designWithTester.conjunctInitial(initial.id());
      throw cee;
    }

    // returning to the previous restriction state
    designWithTester.resetInitial();
    designWithTester.conjunctInitial(initial.id());
  }

//  private static BDDVarSet getRelevantVars(PlayerModule m) {
//    BDDVarSet vars = Env.getEmptySet();
//    if (m != null) {
//      vars.unionWith(m.initial().support());
//      vars.unionWith(m.trans().support());
//
//      // fairness variables are important to illustrate feasibility.
//      for (int i = 0; i < m.justiceNum(); i++) {
//        vars.unionWith(m.justiceAt(i).support());
//      }
//
//      for (ModuleBDDField f : m.getAuxFields()) {
//        BDDVarSet v = vars.minus(f.support());
//        vars.free();
//        vars = v;
//      }
//    }
//    vars.intersectWith(Env.globalUnprimeVars());
//    return vars;
//  }

  private static BDDVarSet getRelevantVars(PlayerModule m) {
    BDDVarSet vars = Env.getEmptySet();
    if (m != null) {
      vars = Env.getEmptySet();
      
      for (ModuleBDDField f : m.getNonAuxFields()) {
        if(!f.isPrime()) {
            vars.unionWith(f.support().id());
        }
      }
    }
    return vars;
  }
  
  /**
   * <p>
   * This is essentially algorithm "Witness", from the article: <NAME>, <NAME>, <NAME>, <NAME>, "Model checking with strong fairness".<br>
   * The line numbers are the line numbers of that algorithm. Read the article for
   * further details.
   * </p>
   * 
   * @param feasible
   * @param designWithTester
   * @return
   */
  private static BDD[] extractWithness(BDD feasible, PlayerModule designWithTester, BDDVarSet relevantVars,
      FeasibilityChecker fsChecker) {
    BDD temp, fulfill;
    // saving the previous restriction state.
    BDD trans = designWithTester.trans().id();

    // Lines 1-2 are handled by the caller. ("verify")

    // Line 3
    designWithTester.conjunctTrans(feasible.and(Env.prime(feasible)));

    // Line 4
    BDD s = CoreUtil.satOne(feasible, designWithTester.moduleUnprimeVars());

    // BDD s = feasible.satOne();

    // Lines 5-6
    while (true) {
      temp = designWithTester.allSucc(s.id()).and(designWithTester.allPred(s.id()).not());
      if (!temp.isZero())
        s = CoreUtil.satOne(temp, designWithTester.moduleUnprimeVars());
      // s = temp.satOne();
      else
        break;
    }
    // Lines 5-6 : better version.
    // temp = tester.allSucc(s).and(tester.allPred(s).not());
    // while (!temp.isZero()){
    // s = temp.satOne(tester.moduleUnprimeVars(), false);
    // temp = tester.allSucc(s).and(tester.allPred(s).not());
    // }

    // Line 7: Compute MSCS containing s.
    BDD feas = designWithTester.allSucc(s.id());

    // Line 9
    // Find prefix - shortest path from initial state to subgraph feas.
    designWithTester.resetTrans();
    designWithTester.conjunctTrans(trans.id());
    Vector<BDD> prefix = new Vector<BDD>();
    BDD[] path = fsChecker.shortestPath(designWithTester, designWithTester.initial(), feas);
    for (int i = 0; i < path.length; i++)
      prefix.add(path[i]);

    // //// Calculate "_period".

    // Line 8: This has to come after line 9, because the way TS.tlv
    // implements restriction.
    designWithTester.conjunctTrans(feasible.and(Env.prime(feas)));

    // Line 10
    Vector<BDD> period = new Vector<BDD>();
    period.add(prefix.lastElement());

    // Since the last item of the prefix is the first item of
    // the period we don't need to print the last item of the prefix.
    temp = prefix.remove(prefix.size() - 1);

    // Lines 11-13
    for (int i = 0; i < designWithTester.justiceNum(); i++) {
      // Line 12, check if j[i] already satisfied
      fulfill = Env.FALSE();
      for (int j = 0; j < period.size(); j++) {
        fulfill = CoreUtil.satOne(period.elementAt(j).and(designWithTester.justiceAt(i)),
            designWithTester.moduleUnprimeVars());
        // fulfill =
        // period.elementAt(j).and(design.justiceAt(i)).satOne();
        if (!fulfill.isZero())
          break;
      }
      // Line 13
      if (fulfill.isZero()) {
        BDD from = period.lastElement();
        BDD to = feas.and(designWithTester.justiceAt(i));
        path = fsChecker.shortestPath(designWithTester, from, to);
        // eliminate the edge since from is already in period
        for (int j = 1; j < path.length; j++)
          period.add(path[j]);
      }
    }

    // Lines 14-16 - removed - we don't support compassion
    /*
     * for (int i = 0; i < designWithTester.compassionNum(); i++) { if
     * (!feas.and(designWithTester.pCompassionAt(i)).isZero()) { // check if C
     * requirement i is already satisfied fulfill = Env.FALSE(); for (int j = 0; j <
     * period.size(); j++) { fulfill = period.elementAt(j).and(
     * designWithTester.qCompassionAt(i)).satOne(
     * designWithTester.moduleUnprimeVars(), false); // fulfill = //
     * period.elementAt(j).and(design.qCompassionAt(i)).satOne(); if
     * (!fulfill.isZero()) break; }
     * 
     * if (fulfill.isZero()) { BDD from = period.lastElement(); BDD to =
     * feas.and(designWithTester.qCompassionAt(i)); path =
     * designWithTester.shortestPath(from, to); // eliminate the edge since from is
     * already in period for (int j = 1; j < path.length; j++) period.add(path[j]);
     * } } }
     */
    //
    // Close cycle
    //

    // A period of length 1 may be fair, but it might be the case that
    // period[1] is not a successor of itself. The routine path
    // will add nothing. To solve this
    // case we add another state to _period, now it will be OK since
    // period[1] and period[n] will not be equal.

    // Line 17, but modified
    if (!period.firstElement().and(period.lastElement()).isZero()) {
      // The first and last states are already equal, so we do not
      // need to extend them to complete a cycle, unless period is
      // a degenerate case of length = 1, which is not a successor of
      // self.
      if (period.size() == 1) {
        // Check if _period[1] is a successor of itself.
        if (period.firstElement().and(designWithTester.succ(period.firstElement())).isZero()) {
          // period[1] is not a successor of itself: Add state to
          // period.
          period
              .add(CoreUtil.satOne(designWithTester.succ(period.firstElement()), designWithTester.moduleUnprimeVars()));
          // period.add(design.succ(period.firstElement()).satOne());

          // Close cycle.
          BDD from = period.lastElement();
          BDD to = period.firstElement();
          path = fsChecker.shortestPath(designWithTester, from, to);
          // eliminate the edges since from and to are already in
          // period
          for (int i = 1; i < path.length - 1; i++)
            period.add(path[i]);
        }
      }
    } else {
      BDD from = period.lastElement();
      BDD to = period.firstElement();
      path = fsChecker.shortestPath(designWithTester, from, to);
      // eliminate the edges since from and to are already in period
      for (int i = 1; i < path.length - 1; i++)
        period.add(path[i]);
    }

    // Yaniv - the last one is for closing the cycle. He won't be printed.
    period.add(period.firstElement());

    // There is no need to have the last state of the period
    // in the counterexample since it already appears in _period[1]
    // if (period.size() > 1)
    // temp = period.remove(period.size() -1);

    // Copy prefix and period.
    prefix.addAll(period);
    BDD[] returned_path = new BDD[prefix.size()];
    prefix.toArray(returned_path);

    // Strip auxiliary variables introduced by tester.
    if (relevantVars != null) {
      BDDVarSet extraVars = Env.globalVarsMinus(relevantVars);
      // BDDVarSet extraVars = Env.globalVarsMinus(relevantVars);
      for (int i = 0; i < returned_path.length; i++) {
        returned_path[i] = CoreUtil.satOne(returned_path[i], relevantVars).exist(extraVars);
      }
    }

    // returning to the previous restriction state
    designWithTester.resetTrans();
    designWithTester.conjunctTrans(trans.id());

    return returned_path;
  }

  private static int tester_id = 0;
  private static int field_id = 0;

  public static class LTLTesterBuilder {
    private Spec root;
    private PlayerModule tester;
    private HashMap<SpecExp, ModuleBDDField> spec2field = new HashMap<SpecExp, ModuleBDDField>();

    public LTLTesterBuilder(Spec root_spec, boolean isWeak) throws ModelCheckException, ModuleVariableException {
      this.root = root_spec;
      if (root == null)
        throw new ModelCheckException("Cannot construct a tester for" + "specification: " + root);

      this.tester = new PlayerModule();
      this.tester.setName("LTLTester_" + (++tester_id));
      createAuxVariable(root);
      constructModule(root, isWeak);
    }

    public PlayerModule getTester() {
      return this.tester;
    }

    public BDD getSpec2BDD(Spec root) throws ModelCheckException {
      if (root instanceof SpecBDD)
        return ((SpecBDD) root).getVal();
      // else it is SpecExp (cannot be a SpecCTLRange)
      SpecExp se = (SpecExp) root;
      Spec[] child = se.getChildren();
      Operator op = se.getOperator();

      if (op == Operator.NOT)
        return getSpec2BDD(child[0]).not();
      if (op == Operator.AND)
        return getSpec2BDD(child[0]).and(getSpec2BDD(child[1]));
      if (op == Operator.OR)
        return getSpec2BDD(child[0]).or(getSpec2BDD(child[1]));
      if (op == Operator.XOR)
        return getSpec2BDD(child[0]).xor(getSpec2BDD(child[1]));
      if (op == Operator.IFF)
        return getSpec2BDD(child[0]).biimp(getSpec2BDD(child[1]));
      if (op == Operator.IMPLIES)
        return getSpec2BDD(child[0]).imp(getSpec2BDD(child[1]));
      if (op.isLTLOp()) {
        ModuleBDDField f = spec2field.get(root);
        if ((f != null) && (f.getDomain().size().intValue() == 2))
          return f.getDomain().ithVar(1);
      }
      // something is wrong
      throw new ModelCheckException("Failed to find corresponding bdd" + " to specification: " + root.toString());
    }

    private void createAuxVariable(Spec s) throws ModelCheckException, ModuleVariableException {
      if (!(s instanceof SpecExp))
        return;
      // else
      SpecExp se = (SpecExp) s;
      try {
        String name = "AUX[" + (++field_id) + "]";
        ModuleBDDField f = tester.addVar(name, true);
        spec2field.put(se, f);
      } catch (ModuleException e) {
        throw new ModelCheckException("Failed naming the extra " + "auxiliary fields");
      }

      Spec[] children = se.getChildren();
      for (int i = 0; i < children.length; i++) {
        createAuxVariable(children[i]);
      }
    }

    private void constructModule(Spec root, boolean isWeak) throws ModelCheckException {
      BDD p_c1, p_c2, p_aux;

      Set<SpecExp> specifications = spec2field.keySet();
      for (SpecExp spec : specifications) {
        // TODO: AVIV (migration)
        // 1. DONE - To check the correctness of unrealizability, take the property
        // forumla from the paper (including
        // "historically", which should be supported in Spectra), and pass it surrounded
        // by negation.
        // 2. DONE - Instead of re-building the initial and safeties spec, do as Jan did
        // in the old env validation -
        // pass it into a SpecBDD, which represents an "atomic" element of the spec.
        // We do not have SpecBDD in the new env - need to add it (it's in jtlv
        // package).
        // 3. The below switch case was for supporting LTL. We only need GR1, so no need
        // for UNTIL, RELEASES, SINCE
        // and TRIGGERED.
        // 4. DONE - The FINALLY operator doesn't exist in spectra - need to add it or
        // figure out what's its equivalent in spectra
        // 5. I will pass a PlayerModule, then create a ComposedPlayerModule which will
        // have in it the original
        // PlayerModule and the tester PlayerModule.
        // 5. implement feasible in a new class - "checker" - and it should get a
        // PlayerModule which is composed
        // 6. Add to PlayerModule "compose(PlayerModule m2)" which:
        // a) create a new PlayerModule which contains:
        // - conjuncts all initials of modules
        // - conjuncts all trans of modules
        // - concatenates the lists of justices - make sure the current module list is
        // first
        // - TODO - what about vars?
        // b) return this new PlayerModule
        // 7. in the feasible - perform the "restrictTrans / Ini" by first saving the
        // ini/trans, then do
        // conjunctIni/Trans and after, reset it with the saved ini/trans.
        //

        try {
          Operator op = spec.getOperator();
          Spec[] child = spec.getChildren();
          BDD aux = getSpec2BDD(spec);
          int noo = op.numOfOperands();
          BDD c1 = (noo > 0) ? getSpec2BDD(child[0]) : null;
          BDD c2 = (noo > 1) ? getSpec2BDD(child[1]) : null;
          switch (op) {
          case PRIME:
            p_c1 = Env.prime(c1);
            tester.conjunctTrans(aux.biimp(p_c1));
            break;
          case FINALLY:
            p_aux = Env.prime(aux);
            tester.conjunctTrans(aux.biimp(c1.or(p_aux)));
            tester.addJustice(c1.or(aux.not()));
            break;
          case GLOBALLY:
            p_aux = Env.prime(aux);
            tester.conjunctTrans(aux.biimp(c1.and(p_aux)));
            tester.addJustice(c1.not().or(aux));
            break;
          case PREV:
            p_aux = Env.prime(aux);
            tester.conjunctInitial(aux.not());
            tester.conjunctTrans(p_aux.biimp(c1));
            break;
          // no BEFORE
          case ONCE:
            p_c1 = Env.prime(c1);
            p_aux = Env.prime(aux);
            tester.conjunctInitial(aux.biimp(c1));
            tester.conjunctTrans(p_aux.biimp(aux.or(p_c1)));
            break;
          case HISTORICALLY:
            p_c1 = Env.prime(c1);
            p_aux = Env.prime(aux);
            tester.conjunctInitial(aux.biimp(c1));
            tester.conjunctTrans(p_aux.biimp(aux.and(p_c1)));
            break;
          case SINCE:
            p_c1 = Env.prime(c1);
            p_c2 = Env.prime(c2);
            p_aux = Env.prime(aux);
            tester.conjunctInitial(aux.biimp(c2));
            tester.conjunctTrans(p_aux.biimp(p_c2.or(p_c1.and(aux))));
            break;
          case TRIGGERED:
            p_c1 = Env.prime(c1);
            p_c2 = Env.prime(c2);
            p_aux = Env.prime(aux);
            tester.conjunctInitial(aux.biimp(c1.or(c2)));
            tester.conjunctTrans(p_aux.biimp(p_c2.or(p_c1.and(aux))));
            break;
          // NOT_PREV_NOT,
          default:
            break;
          }
        } catch (BDDException e) {
          throw new ModelCheckException("Failed to prime BDD " + "assertion for specification: " + spec.toString());
        }
      }
      if (!isWeak) {
        tester.conjunctInitial(getSpec2BDD(root).not());
      }
    }
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.spectragameinput.translator;

public class EntitiesMapper {

  private DefineNameToDefineMapping defineNameToDefineMapping;
  private VariableNameToVariableMapping variableNameToVariableMapping;
  private PredicateNameToPredicateMapping predicateNameToPredicateMapping;
  private PatternNameToPatternMapping patternNameToPatternMapping;
  private MonitorNameToMonitorMapping monitorNameToMonitorMapping;
  private CounterNameToCounterMapping counterNameToCounterMapping;
  
  public EntitiesMapper()
  {
    defineNameToDefineMapping = new DefineNameToDefineMapping();
    variableNameToVariableMapping = new VariableNameToVariableMapping();
    predicateNameToPredicateMapping = new PredicateNameToPredicateMapping();
    patternNameToPatternMapping = new PatternNameToPatternMapping();
    monitorNameToMonitorMapping = new MonitorNameToMonitorMapping();
    counterNameToCounterMapping = new CounterNameToCounterMapping();
  }

  public DefineNameToDefineMapping getDefineNameToDefineMapping() {
    return defineNameToDefineMapping;
  }

  public VariableNameToVariableMapping getVariableNameToVariableMapping() {
    return variableNameToVariableMapping;
  }

  public PredicateNameToPredicateMapping getPredicateNameToPredicateMapping() {
    return predicateNameToPredicateMapping;
  }

  public PatternNameToPatternMapping getPatternNameToPatternMapping() {
    return patternNameToPatternMapping;
  }
  
  public MonitorNameToMonitorMapping getMonitorNameToMonitorMapping() {
    return monitorNameToMonitorMapping;
  }
  
  public CounterNameToCounterMapping getCounterNameToCounterMapping() {
    return counterNameToCounterMapping;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.gr1;

import java.util.Stack;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDD.BDDIterator;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.AbstractGamesException;
import tau.smlab.syntech.games.controller.enumerate.ConcreteControllerConstruction;
import tau.smlab.syntech.games.controller.enumerate.EnumStateI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyImpl;
import tau.smlab.syntech.jtlv.CoreUtil;
import tau.smlab.syntech.jtlv.Env;

public class GR1ConceteControllerConstructionSkip extends ConcreteControllerConstruction {

	private GR1Memory mem;
	private GR1StrategyType kind;

	public GR1ConceteControllerConstructionSkip(GR1Memory mem, GameModel m, GR1StrategyType kind) {
		super(mem, m);
		this.mem = mem;
		this.kind = kind;
	}

	public GR1ConceteControllerConstructionSkip(GR1Memory mem, GameModel m) {
		super(mem, m);
		this.mem = mem;
		this.kind = GR1StrategyType.ZYX;
	}

	@Override
	public EnumStrategyI calculateConcreteController() throws AbstractGamesException {
		return this.calculateConcreteController(false);
	}

	public EnumStrategyI calculateConcreteController(boolean calcLongestSimplePath) throws AbstractGamesException {
		if (!(kind instanceof GR1StrategyType))
			return null;
		int strategy_kind = ((GR1StrategyType) kind).old_value();
		Stack<EnumStateI> st_stack = new Stack<EnumStateI>();
		Stack<Integer> j_stack = new Stack<Integer>();
		Stack<Integer> cy_stack = new Stack<Integer>();

		BDDVarSet envUnprimedVars = env.moduleUnprimeVars();
		BDDVarSet sysUnprimedVars = sys.moduleUnprimeVars();

		EnumStrategyImpl aut = new EnumStrategyImpl(calcLongestSimplePath);

		System.out.println("calculateNewStrategyNewSkip start with node num = " + Env.TRUE().getFactory().getNodeNum());

		// for all initial env states find one possible sys state and add these on
		// the stack with rank 0

		for (BDDIterator it = env.initial().iterator(envUnprimedVars); it.hasNext();) {
			// TODO make this faster by keeping envIni symbolic: search "closest" envIni
			// states, then iterate (this will save individual searches for "closest")
			BDD envIni = it.nextBDD();
			BDD iniWin = envIni.andWith(getWinningInitialStates());
			int cy = 0;
			BDD closest = Env.FALSE();
			// get to the closest state to go to next justice
			while (closest.isZero()) {
				closest.free();
				closest = iniWin.and(mem.y_mem[0][cy++]);
			}
			iniWin.free();
			BDD oneIni = CoreUtil.satOne(closest, envUnprimedVars.union(sysUnprimedVars));
			closest.free();
			st_stack.push(aut.getState(oneIni, new GR1RankInfo(0)));
			cy_stack.push(cy);
			j_stack.push(new Integer(0));
		}

		System.out.println("Initial states of environment: " + st_stack.size());

		// iterating over the stacks.
		while (!st_stack.isEmpty()) {
			// making a new entry.
			EnumStateI new_state = st_stack.pop();
			BDD p_st = new_state.getData();
			int p_j = j_stack.pop();
			int p_cy = cy_stack.pop();

			int succ_cy = 0;

			assert p_cy >= 0 : "Couldn't find p_cy";

			int p_i = -1;
			for (int i = 0; i < env.justiceNum(); i++) {
				BDD b = p_st.and(mem.x_mem[p_j][i][p_cy]);
				if (!b.isZero()) {
					p_i = i;
					b.free();
					break;
				}
				b.free();
			}
			assert p_i >= 0 : "Couldn't find p_i";

			BDD all_succs = env.succ(p_st);

			// For each env successor, find a strategy successor
			for (BDDIterator iter_succ = all_succs.iterator(envUnprimedVars); iter_succ.hasNext();) {
				BDD primed_cur_succ = Env.prime(iter_succ.nextBDD());
				BDD next_s = sys.trans().and(p_st).andWith(primed_cur_succ)
						.exist(envUnprimedVars.union(sysUnprimedVars));
				BDD next_op = Env.unprime(next_s);
				next_s.free();
				BDD candidate = Env.FALSE();
				int jcand = p_j;

				int local_kind = strategy_kind;
				while (candidate.isZero() & (local_kind >= 0)) {
					// a - first successor option in the strategy.
					// just satisfied a justice goal go to next
					if ((local_kind == 3) | (local_kind == 7) | (local_kind == 10) | (local_kind == 13)
							| (local_kind == 18) | (local_kind == 21)) {
						int next_p_j = (p_j + 1) % sys.justiceNum();

						BDD justiceAndSt = p_st.and(sys.justiceAt(p_j));
						if (!justiceAndSt.isZero()) {
							BDD opt = next_op.and(mem.z_mem[next_p_j]);
							if (!opt.isZero()) {
								// prefer existing states
								BDD optEx = opt.and(aut.getStatesOfRank(new GR1RankInfo(next_p_j)));
								if (!optEx.isZero()) {
									opt.free();
									opt = optEx;
								}
								int steps = 0;
								BDD closest = Env.FALSE();
								// get to the closest state to go to next justice
								while (closest.isZero()) {
									closest.free();
									closest = opt.and(mem.y_mem[next_p_j][steps++]);
								}
								candidate = closest;
								jcand = next_p_j;
								succ_cy = steps;
							}
							opt.free();
						}
						justiceAndSt.free();
					}
					// b - second successor option in the strategy.
					// get closest to satisfying current system justice goal
					if ((local_kind == 2) | (local_kind == 5) | (local_kind == 11) | (local_kind == 15)
							| (local_kind == 17) | (local_kind == 22)) {
						if (p_cy > 0) {
							int look_r = 0;
							// look for the fairest r.
							BDD opt = next_op.and(mem.y_mem[p_j][look_r]);
							while (opt.isZero() & (look_r < p_cy)) {
								look_r++;
								opt.free();
								opt = next_op.and(mem.y_mem[p_j][look_r]);
							}

							if ((look_r != p_cy) && (!opt.isZero())) {
								candidate = opt.id();
								succ_cy = look_r;
							}
							opt.free();
						}
					}

					// c - third successor option in the strategy.
					// preventing env justice goal
					if ((local_kind == 1) | (local_kind == 6) | (local_kind == 9) | (local_kind == 14)
							| (local_kind == 19) | (local_kind == 23)) {
						BDD notJustSt = p_st.id().andWith(env.justiceAt(p_i).not());
						if (!notJustSt.isZero()) {
							BDD opt = next_op.and(mem.x_mem[p_j][p_i][p_cy]);
							if (!opt.isZero()) {
								candidate = opt.id();
								succ_cy = p_cy;
								// does not always succeed to prevent, e.g., when justice
								// of env satisfied by successor already
								BDD notJustCand = candidate.id().andWith(env.justiceAt(p_i).not());
								notJustCand.free();
							}
							opt.free();
						}
						notJustSt.free();
					}

					// no successor was found yet.
					assert ((local_kind != 0) & (local_kind != 4) & (local_kind != 8) & (local_kind != 12)
							& (local_kind != 16) & (local_kind != 20)) : "No successor was found";

					local_kind--;
				}

				BDD candGoalEx = candidate.and(aut.getStatesOfRank(new GR1RankInfo(jcand)))
						.andWith(sys.justiceAt(jcand).id());
				BDD candGoalNew = candidate.and(sys.justiceAt(jcand));
				BDD candEx = candidate.and(aut.getStatesOfRank(new GR1RankInfo(jcand)));

				if (!candGoalEx.isZero()) {
					// 1st option take one that reaches goal if possible and exists
					candidate.free();
					candidate = candGoalEx;
					candGoalNew.free();
					candEx.free();
				} else if (!candGoalNew.isZero()) {
					// 2nd option take one that reaches goal if possible (even multiple)
					BDD skip = sys.justiceAt(jcand).id();
					int skipToJustice = (jcand + 1) % sys.justiceNum();
					// TODO check about the BDD z of winning states
					BDD skipTo = candGoalNew.and(sys.justiceAt(skipToJustice));
					while (jcand != skipToJustice && !skipTo.isZero()) {
						skip.andWith(sys.justiceAt(skipToJustice).id());
						skipToJustice = (skipToJustice + 1) % sys.justiceNum();
						skipTo = candidate.id().andWith(skip.id()).andWith(sys.justiceAt(skipToJustice).id());
					}
					candidate.andWith(skip);
					skipTo.free();
					candGoalEx.free();
					candGoalNew.free();
					candEx.free();
					jcand = (skipToJustice + sys.justiceNum() - 1) % sys.justiceNum();
					succ_cy = 0;
				} else if (!candEx.isZero()) {
					// 3rd option take an existing one
					candidate.free();
					candidate = candEx;
					candGoalEx.free();
					candGoalNew.free();
				}

				BDD one_cand = CoreUtil.satOne(candidate, envUnprimedVars.union(sysUnprimedVars));
				candidate.free();
				BDD tmp = one_cand.and(sys.justiceAt(jcand));
				tmp.free();
				// add succ
				EnumStateI succ = aut.addSuccessorState(new_state, one_cand, new GR1RankInfo(jcand));
				if (succ != null) {
					// if a new state was created.
					st_stack.push(succ);
					cy_stack.push(succ_cy);
					j_stack.push(jcand);
				}
			}
			all_succs.free();
		}

		System.out.println("calculateNewStrategyNewSkip end with node num = " + Env.TRUE().getFactory().getNodeNum());

		return aut;
	}

	private BDD getWinningInitialStates() {
		return mem.getWin().and(sys.initial());
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.spectragameinput.translator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tau.smlab.syntech.gameinput.model.Predicate;
import tau.smlab.syntech.spectragameinput.SpectraTranslationException;

public class PredicateNameToPredicateMapping {
  private Map<String, Predicate> predicateNameToPredicateObjectMapping;

  public PredicateNameToPredicateMapping() {
    predicateNameToPredicateObjectMapping = new HashMap<>();
  }


  public List<Predicate> getAllPredicates() {
    return new ArrayList<>(predicateNameToPredicateObjectMapping.values());
  }
  
  /**
   * Computes GameInput Predicate on demand: If computed before, returns immediately. Otherwise computes the predicate, stores it and returns.
   * @param entitiesMapper 
   * @param tracer 
   * @param Spectra Predicate
   * @return GameInput Predicate
   * @throws SpectraTranslationException 
   */
  public Predicate get(tau.smlab.syntech.spectra.Predicate spectraPredicate, EntitiesMapper entitiesMapper, Tracer tracer) throws SpectraTranslationException
  {
    String predicateName = spectraPredicate.getName();
    if (predicateNameToPredicateObjectMapping.containsKey(predicateName))
    {
      return predicateNameToPredicateObjectMapping.get(predicateName);
    }
    else
    {
      // Compute the predicate
      Predicate giPredicate = Spectra2GameInputTranslator.computePredicate(entitiesMapper, tracer, spectraPredicate);
      // Store it for future look ups
      predicateNameToPredicateObjectMapping.put(predicateName, giPredicate);
      return giPredicate;
    }
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.spec;

import tau.smlab.syntech.gameinput.model.Variable;

//This class implements a Spec that represents a QuantifierExpr
public class QuantifiedSpec implements Spec {
	/**
	 * 
	 */
	private static final long serialVersionUID = -355517893664017916L;
	
	Operator op; // The operator of the quantifier expression (forall or exists)
	private Variable domainVar; // The domain var of the quantifier expression
	private Spec tmpExpr; // The inner expression of the quantifier expression

	public QuantifiedSpec(Operator op, Variable domainVar, Spec tmpExpr) {
		this.op = op;
		this.domainVar = domainVar;
		this.tmpExpr = tmpExpr;
	}

	public Operator getOperator() {
		return this.op;
	}

	public void setOperator(Operator op) {
		this.op = op;
	}

	public Operator getExprOperator() {
		return (this.getOperator() == Operator.FORALL) ? Operator.AND : Operator.OR;
	}

	public Variable getDomainVar() {
		return this.domainVar;
	}

	public void setDomainVar(Variable domainVar) {
		this.domainVar = domainVar;
	}

	public Spec getTempExpr() {
		return this.tmpExpr;
	}

	public void setTempExpr(Spec tmpExpr) {
		this.tmpExpr = tmpExpr;
	}

	public String toString() {
		return this.op.toString() + " " + this.domainVar.toString() + " expr : " + this.tmpExpr.toString();
	}

	public boolean isPastLTLSpec() {
		return false;
	}

	@Override
	public boolean isPropSpec() {
		return false;
	}

	@Override
	public boolean hasTemporalOperators() {
		return false;
	}

	public QuantifiedSpec clone() throws CloneNotSupportedException {
		return new QuantifiedSpec(this.op, this.domainVar, this.tmpExpr);
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.rabin;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.games.GameSolver;
import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.lib.FixPoint;

/**
 * winning states of game memory are winning for the environment!
 *
 */

public class RabinGame extends GameSolver {

	public static boolean DETECT_FIX_POINT_EARLY = true;
	public static boolean STOP_WHEN_WIN_FROM_SOME_INITIALS = true;
	public static boolean USE_FIXPOINT_RECYCLE = true;
	/**
	 * Use CUDD function to conjunct and abstract in parallel
	 */
	public static boolean SIMULTANEOUS_CONJUNCTION_ABSTRACTION = false;

	protected RabinMemory mem;

	public RabinGame(GameModel m) {
		super(m);
		mem = new RabinMemory();
		if (sys.justiceNum() == 0) {
			sys.addJustice(Env.TRUE());
		}
		if (env.justiceNum() == 0) {
			env.addJustice(Env.TRUE());
		}
	}

	@Override
	public boolean checkRealizability() {

		this.mem = new RabinMemory();

		BDD x, y, z;
		FixPoint iterX, iterY, iterZ;
		boolean firstFixZ = true;

		z = Env.FALSE();
		for (iterZ = new FixPoint(false); iterZ.advance(z);) {
			for (int j = 0; j < sys.justiceNum(); j++) {
				mem.addXLayer(env.justiceNum());

				BDD nextZ = env.controlStates(sys, z);
				BDD notJj = sys.justiceAt(j).not();

				y = Env.TRUE();
				for (iterY = new FixPoint(false); iterY.advance(y);) {
					mem.clearXLayer();
					BDD nextYandNotJj = env.controlStates(sys, y).andWith(notJj.id());

					y = Env.TRUE();
					for (int i = 0; i < env.justiceNum(); i++) {
						BDD pre = nextZ.id().orWith(env.justiceAt(i).and(nextYandNotJj));
						if (USE_FIXPOINT_RECYCLE && !firstFixZ) {
							x = mem.getXMem().get(mem.getXMem().size() - sys.justiceNum() - 1).get(i).lastElement()
									.or(pre);
						} else {
							x = Env.FALSE();
						}
						for (iterX = new FixPoint(false); iterX.advance(x);) {
							x = pre.id().orWith(notJj.id().andWith(env.controlStates(sys, x)));
							mem.addX(i, x);
						}
						y = y.and(x);
						pre.free();
					}
					nextYandNotJj.free();
				} // end y fix
				z = z.or(y);
				mem.addZ(z);

				nextZ.free();
				notJj.free();

				// breaking as early as possible
				if (DETECT_FIX_POINT_EARLY && mem.sizeZ() > sys.justiceNum()) { // at least one full loop
					int currZpos = mem.sizeZ() - 1;
					if (z.equals(mem.getZ(currZpos - sys.justiceNum()))) {
//						System.out.println("Stops early - found early fixed point");
						// fixpoint reached because last iteration over all
						// system justices
						// did not add anything
						break; // jump to return below
					}
				}

				// NOTE: check if we win from some initials and stop early
				if (STOP_WHEN_WIN_FROM_SOME_INITIALS && envWinAllInitial(z.id())) {
//					System.out.println("Stops early - env wins from some initial states");
					mem.setWin(z.id());
					mem.setComplete(false);
					return true;
				}
			}
			firstFixZ = false;
		}

		mem.setWin(z.id());
		mem.setComplete(true);
		return envWinAllInitial(z.id());
	}

	/**
	 * check existence of an env initial s.t. for all sys initial env wins
	 * 
	 * @return
	 */
	public boolean envWinAllInitial() {
		BDD envWinIni = envWinIni();
		boolean win = !envWinIni.isZero();
		envWinIni.free();
		return win;
	}

	private BDD envWinIni() {
		BDD sysDeadOrEnvWin = sys.initial().imp(mem.getWin());
		BDD envWinIni = env.initial().id().andWith(sysDeadOrEnvWin.forAll(sys.moduleUnprimeVars()));
		sysDeadOrEnvWin.free();
		return envWinIni;
	}

	public BDD getInitialStates() {
		BDD envWinIni = envWinIni();
		BDD ini = envWinIni.andWith(sys.initial().id());
		return ini;
	}

	@Override
	public void free() {
		mem.free();
	}

	public RabinMemory getMem() {
		return mem;
	}

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

// BDDFactory.java, created Jan 29, 2003 9:50:57 PM by jwhaley
// Copyright (C) 2003 <NAME>
// Licensed under the terms of the GNU LGPL; see COPYING for details.
package net.sf.javabdd;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.security.AccessControlException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import tau.smlab.syntech.jtlv.Env;
import tau.smlab.syntech.jtlv.ModuleVariableException;

/**
 * <p>
 * Interface for the creation and manipulation of BDDs.
 * </p>
 * 
 * @see net.sf.javabdd.BDD
 * 
 * @author <NAME>
 * @version $Id: BDDFactory.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
 */
public abstract class BDDFactory {

	public static final String getProperty(String key, String def) {
		try {
			return System.getProperty(key, def);
		} catch (AccessControlException e) {
			return def;
		}
	}

	/**
	 * <p>
	 * Initializes a BDD factory with the given initial node table size and
	 * operation cache size. Tries to use the "buddy" native library; if it fails,
	 * it falls back to the "java" library.
	 * </p>
	 * 
	 * @param nodenum
	 *            initial node table size
	 * @param cachesize
	 *            operation cache size
	 * @return BDD factory object
	 */
	public static BDDFactory init(int nodenum, int cachesize) {
		String bddpackage = getProperty("bdd", "buddy");
		return init(bddpackage, null, nodenum, cachesize);
	}

	/**
	 * <p>
	 * Initializes a BDD factory of the given type with the given initial node table
	 * size and operation cache size. The type is a string that can be "buddy",
	 * "cudd", "cal", "j", "java", "jdd", "test", "typed", or a name of a class that
	 * has an init() method that returns a BDDFactory. If it fails, it falls back to
	 * the "java" factory.
	 * </p>
	 * 
	 * @param bddpackage
	 *            BDD package string identifier
	 * @param nodenum
	 *            initial node table size
	 * @param cachesize
	 *            operation cache size
	 * @return BDD factory object
	 */
	public static BDDFactory init(String bddpackage, int nodenum, int cachesize) {
		return init(bddpackage, null, nodenum, cachesize);
	}

	/**
	 * <p>
	 * Initializes a BDD factory of the given type with the given initial node table
	 * size and operation cache size. The type is a string that can be "buddy",
	 * "cudd", "cal", "j", "java", "jdd", "test", "typed", or a name of a class that
	 * has an init() method that returns a BDDFactory. If it fails, it falls back to
	 * the "java" factory.
	 * </p>
	 * 
	 * @param bddpackage
	 *            BDD package string identifier
	 * @param bddpackageVer
	 *            BDD package version string identifier. If null, the default
	 *            version is used
	 * @param nodenum
	 *            initial node table size
	 * @param cachesize
	 *            operation cache size
	 * @return BDD factory object
	 */
	public static BDDFactory init(String bddpackage, String bddpackageVer, int nodenum, int cachesize) {
		try {
			if (bddpackage.equals("net.sf.javabdd.CUDDFactory")) {
				if (bddpackageVer != null && bddpackageVer.equals("3.0_PIPE")) {
					return CUDDFactoryGeneric.init("3.0_PIPE", nodenum, cachesize);
				}
				return CUDDFactory.init(nodenum, cachesize);
			}
			if (bddpackage.equals("net.sf.javabdd.CUDDFactory$CUDDADDFactory")) {
				if (bddpackageVer != null && bddpackageVer.equals("3.0_PIPE")) {
					return CUDDFactoryGeneric.CUDDADDFactoryGeneric.init("3.0_PIPE", nodenum, cachesize);
				}
				return CUDDFactory.CUDDADDFactory.init(nodenum, cachesize);
			}
		} catch (LinkageError e) {
			System.out.println("Could not load BDD package " + bddpackage + ": " + e.getLocalizedMessage());
		}
		try {
			Class<?> c = Class.forName((bddpackage.equals("cuddadd")) ? "cudd" : bddpackage);
			Method m = (bddpackage.equals("cuddadd"))
					? c.getMethod("init", new Class[] { int.class, int.class, boolean.class })
					: c.getMethod("init", new Class[] { int.class, int.class });
			return (BDDFactory) ((bddpackage.equals("cuddadd"))
					? m.invoke(null, new Object[] { new Integer(nodenum), new Integer(cachesize), new Boolean(true) })
					: m.invoke(null, new Object[] { new Integer(nodenum), new Integer(cachesize) }));
		} catch (Exception e) {
		}
		// falling back to default java implementation.
		return JTLVJavaFactory.init(nodenum, cachesize);
	}

	/**
	 * Logical 'and' (BDDs and ADDs; for non 0-1 ADDs this operator is equivalent to
	 * multiplication).
	 */
	public static final BDDOp and = new BDDOp(0, "and");

	/**
	 * Logical 'xor' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp xor = new BDDOp(1, "xor");

	/**
	 * Logical 'or' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp or = new BDDOp(2, "or");

	/**
	 * Logical 'nand' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp nand = new BDDOp(3, "nand");

	/**
	 * Logical 'nor' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp nor = new BDDOp(4, "nor");

	/**
	 * Logical 'implication' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp imp = new BDDOp(5, "imp");

	/**
	 * Logical 'bi-implication' (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp biimp = new BDDOp(6, "biimp");

	/**
	 * Set difference (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp diff = new BDDOp(7, "diff");

	/**
	 * Less than (BDDs and ADDs).
	 */
	public static final BDDOp less = new BDDOp(8, "less");

	/**
	 * Inverse implication (BDDs and 0-1 ADDs only).
	 */
	public static final BDDOp invimp = new BDDOp(9, "invimp");

	/**
	 * Arithmetic multiplication (ADDs only).
	 */
	public static final BDDOp times = new BDDOp(10, "times");
	/**
	 * Arithmetic division (ADDs only).
	 */
	public static final BDDOp div = new BDDOp(11, "div");
	/**
	 * Arithmetic addition (ADDs only).
	 */
	public static final BDDOp plus = new BDDOp(12, "plus");
	/**
	 * Arithmetic subtraction (ADDs only).
	 */
	public static final BDDOp minus = new BDDOp(13, "minus");
	/**
	 * Maximum (ADDs only).
	 */
	public static final BDDOp max = new BDDOp(14, "max");
	/**
	 * Minimum (ADDs only).
	 */
	public static final BDDOp min = new BDDOp(15, "min");
	/**
	 * <p>
	 * Energy (or Mean Payoff) games Arithmetic subtraction (ADDs only). This
	 * operation is an arithmetic subtraction that is defined differently in the
	 * following cases:
	 * </p>
	 * +INF - y = +INF , for all finite y <br>
	 * y - (+INF) = 0 , for all finite y <br>
	 * y - (-INF) = +INF , for all finite, non negative, y <br>
	 * +INF - (+INF) = 0 <br>
	 * +INF - (-INF) = +INF <br>
	 * x - y = max {x-y, 0} , for all finite, non negative x, and for all y
	 */
	public static final BDDOp engMinus = new BDDOp(16, "engMinus");
	/**
	 * <p>
	 * Energy (or Mean Payoff) games Arithmetic addition (ADDs only). This operation
	 * is an arithmetic addition that is defined differently in the following cases:
	 * </p>
	 * +INF + y = +INF , for all finite y <br>
	 * y + (+INF) = +INF , for all finite y <br>
	 * y + (-INF) = -INF , for all finite y <br>
	 * (-INF) + y = -INF , for all finite y <br>
	 * +INF + (+INF) = +INF <br>
	 * -INF + (-INF) = -INF <br>
	 * +INF + (-INF) = 0 <br>
	 * (-INF) + (+INF) = 0 <br>
	 */
	public static final BDDOp engPlus = new BDDOp(17, "engPlus");
	/**
	 * <p>
	 * Agreement operator (ADDs only). This operator is similar to xnor, such that
	 * <br>
	 * ADD1 op ADD2 = 1 if ADD1==ADD2, and ADD1 op ADD2 = 0 otherwise.
	 * </p>
	 */
	public static final BDDOp agree = new BDDOp(18, "agree");

	/**
	 * <p>
	 * Enumeration class for binary operations on BDDs. Use the static fields in
	 * BDDFactory to access the different binary operations.
	 * </p>
	 */
	public static class BDDOp {
		final int id;
		final String name;

		private BDDOp(int id, String name) {
			this.id = id;
			this.name = name;
		}

		public String toString() {
			return name;
		}
	}

	/**
	 * <p>
	 * Construct a new BDDFactory.
	 * </p>
	 */
	protected BDDFactory() {
		System.out.println(this.getInfo());
	}

	/**
	 * <p>
	 * Get info string of BDD Factory
	 * </p>
	 */
	public String getInfo() {
		String s = this.getClass().toString();
		s = s.substring(s.lastIndexOf('.') + 1);
		return "Using BDD Package: " + s + ", Version: " + this.getVersion();
	}

	/**
	 * <p>
	 * Returns true if this is a ZDD factory, false otherwise.
	 * </p>
	 */
	public boolean isZDD() {
		return false;
	}

	/**
	 * <p>
	 * Returns true if this is an ADD (a.k.a MTBDD) factory, false otherwise.
	 * </p>
	 */
	public boolean isADD() {
		return false;
	}

	/**
	 * <p>
	 * Get a constant BDD by value: <br>
	 * If this is a BDD factory, for value of 0 the constant false BDD is returned.
	 * Otherwise, for any non-zero value the constant true BDD is returned.<br>
	 * If this is an ADD factory, the constant ADD for the value is returned (not
	 * implemented by default).
	 * </p>
	 * <h4>Implementation notes:</h4> This method is not implemented in the
	 * {@code abstract BDDFactory class} for ADDs and must be overridden for ADD
	 * factories.
	 * 
	 * @param value
	 *            the constant BDD\ADD value
	 * @return constant BDD\ADD for the value
	 */
	/*
	 * default implementation: for an ADD factory this method should be overridden
	 */
	public BDD constant(double value) {
		if (value == 0.0) {
			return zero();
		}
		return one();
	}

	/**
	 * <p>
	 * Get the constant plus infinity ADD.
	 * </p>
	 * <h4>Implementation notes:</h4> This method throws by default
	 * {@code UnsupportedOperationException} and must be overridden for ADD
	 * factories.
	 * 
	 * @throws UnsupportedOperationException
	 * @return constant plus infinity ADD
	 */
	public ADD plusInfinity() {
		throw new UnsupportedOperationException();
	}

	/**
	 * <p>
	 * Get the constant minus infinity ADD.
	 * </p>
	 * <h4>Implementation notes:</h4> This method throws by default
	 * {@code UnsupportedOperationException} and must be overridden for ADD
	 * factories.
	 * 
	 * @throws UnsupportedOperationException
	 * @return constant minus infinity ADD
	 */
	public ADD minusInfinity() {
		throw new UnsupportedOperationException();
	}

	/**
	 * <p>
	 * Get the constant false BDD.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_false.
	 * </p>
	 */
	public abstract BDD zero();

	/**
	 * <p>
	 * Get the constant true BDD.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_true.
	 * </p>
	 */
	public abstract BDD one();

	/**
	 * <p>
	 * Get the constant universe BDD. (The universe BDD differs from the one BDD in
	 * ZDD mode.)
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_true.
	 * </p>
	 */
	public BDD universe() {
		return one();
	}

	/**
	 * <p>
	 * Get an empty BDDVarSet.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_true.
	 * </p>
	 */
	public BDDVarSet emptySet() {
		return new BDDVarSet.DefaultImpl(one());
	}

	/**
	 * <p>
	 * Build a cube from an array of variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_buildcube.
	 * </p>
	 */
	public BDD buildCube(int value, List<BDD> variables) {
		BDD result = universe();
		Iterator<BDD> i = variables.iterator();
		while (i.hasNext()) {
			BDD var = i.next();
			if ((value & 0x1) != 0)
				var = var.id();
			else
				var = var.not();
			result.andWith(var);
			value >>= 1;
		}
		return result;
	}

	/**
	 * <p>
	 * Build a cube from an array of variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_ibuildcube./p>
	 */
	public BDD buildCube(int value, int[] variables) {
		BDD result = universe();
		for (int z = 0; z < variables.length; z++, value >>= 1) {
			BDD v;
			if ((value & 0x1) != 0)
				v = ithVar(variables[variables.length - z - 1]);
			else
				v = nithVar(variables[variables.length - z - 1]);
			result.andWith(v);
		}
		return result;
	}

	/**
	 * <p>
	 * Builds a BDD variable set from an integer array. The integer array
	 * <tt>varset</tt> holds the variable numbers. The BDD variable set is
	 * represented by a conjunction of all the variables in their positive form.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_makeset.
	 * </p>
	 */
	public BDDVarSet makeSet(int[] varset) {
		BDDVarSet res = emptySet();
		int varnum = varset.length;
		for (int v = varnum - 1; v >= 0; --v) {
			res.unionWith(varset[v]);
		}
		return res;
	}

	/**** STARTUP / SHUTDOWN ****/

	/**
	 * <p>
	 * Compare to bdd_init.
	 * </p>
	 * 
	 * @param nodenum
	 *            the initial number of BDD nodes
	 * @param cachesize
	 *            the size of caches used by the BDD operators
	 */
	protected abstract void initialize(int nodenum, int cachesize);

	/**
	 * <p>
	 * Returns true if this BDD factory is initialized, false otherwise.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_isrunning.
	 * </p>
	 * 
	 * @return true if this BDD factory is initialized
	 */
	public abstract boolean isInitialized();

	/**
	 * <p>
	 * Reset the BDD factory to its initial state. Everything is reallocated from
	 * scratch. This is like calling done() followed by initialize().
	 * </p>
	 */
	public void reset() {
		int nodes = getNodeTableSize();
		int cache = getCacheSize();
		domain = null;
		fdvarnum = 0;
		firstbddvar = 0;
		done();
		initialize(nodes, cache);
	}

	/**
	 * <p>
	 * This function frees all memory used by the BDD package and resets the package
	 * to its uninitialized state. The BDD package is no longer usable after this
	 * call.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_done.
	 * </p>
	 */
	public abstract void done();

	/**
	 * <p>
	 * Sets the error condition. This will cause the BDD package to throw an
	 * exception at the next garbage collection.
	 * </p>
	 * 
	 * @param code
	 *            the error code to set
	 */
	public abstract void setError(int code);

	/**
	 * <p>
	 * Clears any outstanding error condition.
	 * </p>
	 */
	public abstract void clearError();

	/**** CACHE/TABLE PARAMETERS ****/

	/**
	 * <p>
	 * Set the maximum available number of BDD nodes.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_setmaxnodenum.
	 * </p>
	 * 
	 * @param size
	 *            maximum number of nodes
	 * @return old value
	 */
	public abstract int setMaxNodeNum(int size);

	/**
	 * <p>
	 * Set minimum percentage of nodes to be reclaimed after a garbage collection.
	 * If this percentage is not reclaimed, the node table will be grown. The range
	 * of x is 0..1. The default is .20.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_setminfreenodes.
	 * </p>
	 * 
	 * @param x
	 *            number from 0 to 1
	 * @return old value
	 */
	public abstract double setMinFreeNodes(double x);

	/**
	 * <p>
	 * Set maximum number of nodes by which to increase node table after a garbage
	 * collection.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_setmaxincrease.
	 * </p>
	 * 
	 * @param x
	 *            maximum number of nodes by which to increase node table
	 * @return old value
	 */
	public abstract int setMaxIncrease(int x);

	/**
	 * <p>
	 * Set factor by which to increase node table after a garbage collection. The
	 * amount of growth is still limited by <tt>setMaxIncrease()</tt>.
	 * </p>
	 * 
	 * @param x
	 *            factor by which to increase node table after GC
	 * @return old value
	 */
	public abstract double setIncreaseFactor(double x);

	/**
	 * <p>
	 * Sets the cache ratio for the operator caches. When the node table grows,
	 * operator caches will also grow to maintain the ratio.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_setcacheratio.
	 * </p>
	 * 
	 * @param x
	 *            cache ratio
	 */
	public abstract double setCacheRatio(double x);

	/**
	 * <p>
	 * Sets the node table size.
	 * </p>
	 * 
	 * @param n
	 *            new size of table
	 * @return old size of table
	 */
	public abstract int setNodeTableSize(int n);

	/**
	 * <p>
	 * Sets cache size.
	 * </p>
	 * 
	 * @return old cache size
	 */
	public abstract int setCacheSize(int n);

	/**** VARIABLE NUMBERS ****/

	/**
	 * <p>
	 * Returns the number of defined variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_varnum.
	 * </p>
	 */
	public abstract int varNum();

	/**
	 * <p>
	 * Set the number of used BDD variables. It can be called more than one time,
	 * but only to increase the number of variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_setvarnum.
	 * </p>
	 * 
	 * @param num
	 *            new number of BDD variables
	 * @return old number of BDD variables
	 */
	public abstract int setVarNum(int num);

	/**
	 * <p>
	 * Add extra BDD variables. Extends the current number of allocated BDD
	 * variables with num extra variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_extvarnum.
	 * </p>
	 * 
	 * @param num
	 *            number of BDD variables to add
	 * @return old number of BDD variables
	 */
	public int extVarNum(int num) {
		int start = varNum();
		if (num < 0 || num > 0x3FFFFFFF)
			throw new BDDException();
		setVarNum(start + num);
		return start;
	}

	/**
	 * <p>
	 * Returns a BDD representing the I'th variable. (One node with the children
	 * true and false.) The requested variable must be in the (zero-indexed) range
	 * defined by <tt>setVarNum</tt>.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_ithvar.
	 * </p>
	 * 
	 * @param var
	 *            the variable number
	 * @return the I'th variable on success, otherwise the constant false BDD
	 */
	public abstract BDD ithVar(int var);

	/**
	 * <p>
	 * Returns a BDD representing the negation of the I'th variable. (One node with
	 * the children false and true.) The requested variable must be in the
	 * (zero-indexed) range defined by <tt>setVarNum</tt>.<br>
	 * If it is a MTBDD \ ADD, the negation is the complement ADD, i.e. every zero
	 * terminal becomes one, and every non-zero terminal becomes zero.
	 * </p>
	 * <p>
	 * Compare to bdd_nithvar.
	 * </p>
	 * 
	 * @param var
	 *            the variable number
	 * @return the negated I'th variable on success, otherwise the constant false
	 *         BDD
	 */
	public abstract BDD nithVar(int var);

	/**** INPUT / OUTPUT ****/

	/**
	 * <p>
	 * Prints all used entries in the node table.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_printall.
	 * </p>
	 */
	public abstract void printAll();

	/**
	 * <p>
	 * Prints the node table entries used by a BDD.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_printtable.
	 * </p>
	 */
	public abstract void printTable(BDD b);

	/**
	 * <p>
	 * Loads a BDD from a file.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_load.
	 * </p>
	 */
	public BDD load(String filename) throws IOException {
		BufferedReader r = null;
		try {
			r = new BufferedReader(new FileReader(filename));
			BDD result = load(r);
			return result;
		} finally {
			if (r != null)
				try {
					r.close();
				} catch (IOException e) {
				}
		}
	}
	// TODO: error code from bdd_load (?)

	/**
	 * <p>
	 * Loads a BDD from the given input, translating BDD variables according to the
	 * given map.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_load.
	 * </p>
	 * 
	 * @param ifile
	 *            reader
	 * @param translate
	 *            variable translation map
	 * @return BDD
	 */
	public BDD load(BufferedReader ifile) throws IOException {

		Map<Long, BDD> map = new HashMap<>();
		map.put(0l, zero());
		map.put(1l, universe());
		tokenizer = null;

		long vnum = Long.parseLong(readNext(ifile));

		// Check for constant true / false
		if (vnum == 0) {
			long r = Long.parseLong(readNext(ifile));
			return r == 0 ? zero() : universe();
		}

		if (vnum > varNum()) {
			System.err.println(
					"Warning! Missing some variables. Have " + varNum() + " need " + vnum + ". Filling with dummys.");
			while (vnum > varNum()) {
				try {
					Env.newVar("dummy" + Math.random());
				} catch (ModuleVariableException e) {
					throw new RuntimeException(e);
				}
			}
		} else if (vnum < varNum()) {
			System.err.println("Warning! Env has more vars than expected by BDD.");
		}

		disableReorder(); // FIXME remember whether to enable later

		int[] order = new int[(int) vnum];
		for (int i = 0; i < vnum; i++) {
			order[i] = Integer.parseInt(readNext(ifile));
		}
		setVarOrder(order);

		BDD root = null;

		while (!doneReading(ifile)) {
			long key = Long.parseLong(readNext(ifile));
			int var = Integer.parseInt(readNext(ifile));
			long lowi = Long.parseLong(readNext(ifile));
			long highi = Long.parseLong(readNext(ifile));

			BDD low, high;

			low = map.get(lowi);
			high = map.get(highi);

			if (low == null || high == null || var < 0)
				throw new BDDException("Incorrect file format");

			BDD b = ithVar(var);
			root = b.ite(high, low);
			b.free();

			map.put(key, root);
		}
		BDD tmproot = root.id();

		Env.free(map);

		// FIXME do not always turn it on (only on demand or if it was already enabled)
		enableReorder();
		return tmproot;
	}

	/**
	 * not done reading if the tokenizer still has tokens or if the file has more
	 * content to be read
	 * 
	 * @param ifile
	 * @return true if more tokens or characters; false otherwise
	 */
	private boolean doneReading(BufferedReader ifile) {
		if (tokenizer != null && tokenizer.hasMoreTokens()) {
			return false;
		}
		try {
			if (ifile.ready()) {
				return false;
			}
		} catch (IOException e) {
		}
		return true;
	}

	/**
	 * Used for tokenization during loading.
	 */
	protected StringTokenizer tokenizer;

	/**
	 * Read the next token from the file.
	 * 
	 * @param ifile
	 *            reader
	 * @return next string token
	 */
	protected String readNext(BufferedReader ifile) throws IOException {
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			String s = ifile.readLine();
			if (s == null)
				throw new BDDException("Incorrect file format");
			tokenizer = new StringTokenizer(s);
		}
		return tokenizer.nextToken();
	}

	/**
	 * <p>
	 * Saves a BDD to a file.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_save.
	 * </p>
	 */
	public void save(String filename, BDD var) throws IOException {
		BufferedWriter is = null;
		try {
			is = new BufferedWriter(new FileWriter(filename));

			save(is, var);
		} finally {
			if (is != null)
				try {
					is.close();
				} catch (IOException e) {
				}
		}
	}
	// TODO: error code from bdd_save (?)

	/**
	 * <p>
	 * Saves a BDD to an output writer.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_save.
	 * </p>
	 */
	public void save(BufferedWriter out, BDD r) throws IOException {

		// special encoding of TRUE and FALSE use 0 variables and then 1 (TRUE) or 0
		// (FALSE)
		if (r.isOne() || r.isZero()) {
			out.write("0 " + (r.isOne() ? 1 : 0) + "\n");
			return;
		}

		out.write(varNum() + "\n");
		for (int i : getVarOrder()) {
			out.write(i + " ");
		}
		out.write("\n");

		Set<Long> visited = new HashSet<>();
		save_rec(out, visited, r.id());
	}

	/**
	 * Helper function for save().
	 */
	protected long save_rec(BufferedWriter out, Set<Long> visited, BDD root) throws IOException {
		if (root.isZero()) {
			root.free();
			return 0;
		}
		if (root.isOne()) {
			root.free();
			return 1;
		}
		long i = root.rootId();
		if (visited.contains(i)) {
			root.free();
			return i;
		}
		long v = i;
		visited.add(i);

		BDD h = root.high();

		BDD l = root.low();

		int rootvar = root.var();
		root.free();

		long lo = save_rec(out, visited, l);

		long hi = save_rec(out, visited, h);

		out.write(i + " ");
		out.write(rootvar + " ");
		out.write(lo + " ");
		out.write(hi + "\n");

		return v;
	}

	// TODO: bdd_blockfile_hook
	// TODO: bdd_versionnum, bdd_versionstr

	/**** REORDERING ****/

	/**
	 * <p>
	 * Convert from a BDD level to a BDD variable.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_level2var.
	 * </p>
	 */
	public abstract int level2Var(int level);

	/**
	 * <p>
	 * Convert from a BDD variable to a BDD level.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_var2level.
	 * </p>
	 */
	public abstract int var2Level(int var);

	/**
	 * No reordering.
	 */
	public static final ReorderMethod REORDER_NONE = new ReorderMethod(0, "NONE");

	/**
	 * Reordering using a sliding window of 2.
	 */
	public static final ReorderMethod REORDER_WIN2 = new ReorderMethod(1, "WIN2");

	/**
	 * Reordering using a sliding window of 2, iterating until no further progress.
	 */
	public static final ReorderMethod REORDER_WIN2ITE = new ReorderMethod(2, "WIN2ITE");

	/**
	 * Reordering using a sliding window of 3.
	 */
	public static final ReorderMethod REORDER_WIN3 = new ReorderMethod(5, "WIN3");

	/**
	 * Reordering using a sliding window of 3, iterating until no further progress.
	 */
	public static final ReorderMethod REORDER_WIN3ITE = new ReorderMethod(6, "WIN3ITE");

	/**
	 * Reordering where each block is moved through all possible positions. The best
	 * of these is then used as the new position. Potentially a very slow but good
	 * method.
	 */
	public static final ReorderMethod REORDER_SIFT = new ReorderMethod(3, "SIFT");

	/**
	 * Same as REORDER_SIFT, but the process is repeated until no further progress
	 * is done. Can be extremely slow.
	 */
	public static final ReorderMethod REORDER_SIFTITE = new ReorderMethod(4, "SIFTITE");

	/**
	 * Selects a random position for each variable. Mostly used for debugging
	 * purposes.
	 */
	public static final ReorderMethod REORDER_RANDOM = new ReorderMethod(7, "RANDOM");

	/**
	 * Enumeration class for method reordering techniques. Use the static fields in
	 * BDDFactory to access the different reordering techniques.
	 */
	public static class ReorderMethod {
		final int id;
		final String name;

		private ReorderMethod(int id, String name) {
			this.id = id;
			this.name = name;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#toString()
		 */
		public String toString() {
			return name;
		}
	}

	/**
	 * <p>
	 * Reorder the BDD with the given method.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_reorder.
	 * </p>
	 */
	public abstract void reorder(ReorderMethod m);

	/**
	 * <p>
	 * Enables automatic reordering. If method is REORDER_NONE then automatic
	 * reordering is disabled.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_autoreorder.
	 * </p>
	 */
	public abstract void autoReorder(ReorderMethod method);

	/**
	 * <p>
	 * Enables automatic reordering with the given (maximum) number of reorderings.
	 * If method is REORDER_NONE then automatic reordering is disabled.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_autoreorder_times.
	 * </p>
	 */
	public abstract void autoReorder(ReorderMethod method, int max);

	/**
	 * <p>
	 * Returns the current reorder method as defined by autoReorder.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_getreorder_method.
	 * </p>
	 * 
	 * @return ReorderMethod
	 */
	public abstract ReorderMethod getReorderMethod();

	/**
	 * <p>
	 * Returns the number of allowed reorderings left. This value can be defined by
	 * autoReorder.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_getreorder_times.
	 * </p>
	 */
	public abstract int getReorderTimes();

	/**
	 * <p>
	 * Disable automatic reordering until enableReorder is called. Reordering is
	 * enabled by default as soon as any variable blocks have been defined.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_disable_reorder.
	 * </p>
	 */
	public abstract void disableReorder();

	/**
	 * <p>
	 * Enable automatic reordering after a call to disableReorder.<br>
	 * The reordering method is left unchanged.
	 * </p>
	 * 
	 * 
	 * <p>
	 * Compare to bdd_enable_reorder.
	 * </p>
	 */
	public abstract void enableReorder();

	/**
	 * Returns true if automatic reordering is enabled.
	 * 
	 * @return Whether automatic reordering is enabled
	 */
	public abstract boolean reorderEnabled();

	/**
	 * <p>
	 * Enables verbose information about reordering. A value of zero means no
	 * information, one means some information and greater than one means lots of
	 * information.
	 * </p>
	 * 
	 * @param v
	 *            the new verbose level
	 * @return the old verbose level
	 */
	public abstract int reorderVerbose(int v);

	/**
	 * <p>
	 * This function sets the current variable order to be the one defined by
	 * neworder. The variable parameter neworder is interpreted as a sequence of
	 * variable indices and the new variable order is exactly this sequence. The
	 * array must contain all the variables defined so far. If, for instance the
	 * current number of variables is 3 and neworder contains [1; 0; 2] then the new
	 * variable order is v1<v0<v2.
	 * </p>
	 * 
	 * <p>
	 * Note that this operation must walk through the node table many times, and
	 * therefore it is much more efficient to call this when the node table is
	 * small.
	 * </p>
	 * 
	 * @param neworder
	 *            new variable order
	 */
	public abstract void setVarOrder(int[] neworder);

	/**
	 * <p>
	 * Gets the current variable order.
	 * </p>
	 * 
	 * @return variable order
	 */
	public int[] getVarOrder() {
		int n = varNum();
		int[] result = new int[n];
		for (int i = 0; i < n; ++i) {
			result[i] = level2Var(i);
		}
		return result;
	}

	/**
	 * <p>
	 * Make a new BDDPairing object.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_newpair.
	 * </p>
	 */
	public abstract BDDPairing makePair();

	/**
	 * Make a new pairing that maps from one variable to another.
	 * 
	 * @param oldvar
	 *            old variable
	 * @param newvar
	 *            new variable
	 * @return BDD pairing
	 */
	public BDDPairing makePair(int oldvar, int newvar) {
		BDDPairing p = makePair();
		p.set(oldvar, newvar);
		return p;
	}

	/**
	 * Make a new pairing that maps from one variable to another BDD.
	 * 
	 * @param oldvar
	 *            old variable
	 * @param newvar
	 *            new BDD
	 * @return BDD pairing
	 */
	public BDDPairing makePair(int oldvar, BDD newvar) {
		BDDPairing p = makePair();
		p.set(oldvar, newvar);
		return p;
	}

	/**
	 * Make a new pairing that maps from one BDD domain to another.
	 * 
	 * @param oldvar
	 *            old BDD domain
	 * @param newvar
	 *            new BDD domain
	 * @return BDD pairing
	 */
	public BDDPairing makePair(BDDDomain oldvar, BDDDomain newvar) {
		BDDPairing p = makePair();
		p.set(oldvar, newvar);
		return p;
	}

	/**
	 * <p>
	 * Swap two variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_swapvar.
	 * </p>
	 */
	public abstract void swapVar(int v1, int v2);

	/**** VARIABLE BLOCKS ****/

	/**
	 * <p>
	 * Adds a new variable block for reordering.
	 * </p>
	 * 
	 * <p>
	 * Creates a new variable block with the variables in the variable set var. The
	 * variables in var must be contiguous.
	 * </p>
	 * 
	 * <p>
	 * The fixed parameter sets the block to be fixed (no reordering of its child
	 * blocks is allowed) or free.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_addvarblock.
	 * </p>
	 */
	public void addVarBlock(BDDVarSet var, boolean fixed) {
		int[] v = var.toArray();
		int first, last;
		if (v.length < 1)
			throw new BDDException("Invalid parameter for addVarBlock");

		first = last = v[0];

		for (int n = 1; n < v.length; n++) {
			if (v[n] < first)
				first = v[n];
			if (v[n] > last)
				last = v[n];
		}

		addVarBlock(first, last, fixed);
	}
	// TODO: handle error code for addVarBlock.

	/**
	 * <p>
	 * Adds a new variable block for reordering.
	 * </p>
	 * 
	 * <p>
	 * Creates a new variable block with the variables numbered first through last,
	 * inclusive.
	 * </p>
	 * 
	 * <p>
	 * The fixed parameter sets the block to be fixed (no reordering of its child
	 * blocks is allowed) or free.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_intaddvarblock.
	 * </p>
	 */
	public abstract void addVarBlock(int first, int last, boolean fixed);
	// TODO: handle error code for addVarBlock.
	// TODO: fdd_intaddvarblock (?)

	/**
	 * <p>
	 * Add a variable block for all variables.
	 * </p>
	 * 
	 * <p>
	 * Adds a variable block for all BDD variables declared so far. Each block
	 * contains one variable only. More variable blocks can be added later with the
	 * use of addVarBlock -- in this case the tree of variable blocks will have the
	 * blocks of single variables as the leafs.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_varblockall.
	 * </p>
	 */
	public abstract void varBlockAll();

	/**
	 * <p>
	 * Clears all the variable blocks that have been defined by calls to
	 * addVarBlock.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_clrvarblocks.
	 * </p>
	 */
	public abstract void clearVarBlocks();

	/**
	 * <p>
	 * Prints an indented list of the variable blocks.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_printorder.
	 * </p>
	 */
	public abstract void printOrder();

	/**** BDD STATS ****/

	/**
	 * Get the BDD library version.
	 * 
	 * @return version string
	 */
	public abstract String getVersion();

	/**
	 * <p>
	 * Counts the number of shared nodes in a collection of BDDs. Counts all
	 * distinct nodes that are used in the BDDs -- if a node is used in more than
	 * one BDD then it only counts once.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_anodecount.
	 * </p>
	 */
	public abstract int nodeCount(Collection<BDD> r);

	/**
	 * <p>
	 * Get the number of allocated nodes. This includes both dead and active nodes.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_getallocnum.
	 * </p>
	 */
	public abstract int getNodeTableSize();

	/**
	 * <p>
	 * Get the number of active nodes in use. Note that dead nodes that have not
	 * been reclaimed yet by a garbage collection are counted as active.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_getnodenum.
	 * </p>
	 */
	public abstract int getNodeNum();

	/**
	 * <p>
	 * Get the current size of the cache, in entries.
	 * </p>
	 * 
	 * @return size of cache
	 */
	public abstract int getCacheSize();

	/**
	 * <p>
	 * Calculate the gain in size after a reordering. The value returned is
	 * (100*(A-B))/A, where A is previous number of used nodes and B is current
	 * number of used nodes.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_reorder_gain.
	 * </p>
	 */
	public abstract int reorderGain();

	/**
	 * <p>
	 * Print cache statistics.
	 * </p>
	 * 
	 * <p>
	 * Compare to bdd_printstat.
	 * </p>
	 */
	public abstract void printStat();

	/*
	 * public boolean thereIsNegativeCycle(ADD sourceStates, ADD arena, BDDVarSet
	 * primedVariables, BDDPairing primedUnprimedPairs) { return false; }
	 */

	/**
	 * Stores statistics about garbage collections.
	 * 
	 * @author jwhaley
	 * @version $Id: BDDFactory.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
	 */
	public static class GCStats {
		public int nodes;
		public int freenodes;
		public long time;
		public long sumtime;
		public int num;

		protected GCStats() {
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#toString()
		 */
		public String toString() {
			StringBuffer sb = new StringBuffer();
			sb.append("Garbage collection #");
			sb.append(num);
			sb.append(": ");
			sb.append(nodes);
			sb.append(" nodes / ");
			sb.append(freenodes);
			sb.append(" free");

			sb.append(" / ");
			sb.append((float) time / (float) 1000);
			sb.append("s / ");
			sb.append((float) sumtime / (float) 1000);
			sb.append("s total");
			return sb.toString();
		}
	}

	/**
	 * Singleton object for GC statistics.
	 */
	protected GCStats gcstats = new GCStats();

	/**
	 * <p>
	 * Return the current GC statistics for this BDD factory.
	 * </p>
	 * 
	 * @return GC statistics
	 */
	public GCStats getGCStats() {
		return gcstats;
	}

	/**
	 * Stores statistics about reordering.
	 * 
	 * @author jwhaley
	 * @version $Id: BDDFactory.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
	 */
	public static class ReorderStats {

		public long time;
		public int usednum_before, usednum_after;

		protected ReorderStats() {
		}

		public int gain() {
			if (usednum_before == 0)
				return 0;

			return (100 * (usednum_before - usednum_after)) / usednum_before;
		}

		public String toString() {
			StringBuffer sb = new StringBuffer();
			sb.append("Went from ");
			sb.append(usednum_before);
			sb.append(" to ");
			sb.append(usednum_after);
			sb.append(" nodes, gain = ");
			sb.append(gain());
			sb.append("% (");
			sb.append((float) time / 1000f);
			sb.append(" sec)");
			return sb.toString();
		}
	}

	/**
	 * Singleton object for reorder statistics.
	 */
	protected ReorderStats reorderstats = new ReorderStats();

	/**
	 * <p>
	 * Return the current reordering statistics for this BDD factory.
	 * </p>
	 * 
	 * @return reorder statistics
	 */
	public ReorderStats getReorderStats() {
		return reorderstats;
	}

	/**
	 * Stores statistics about the operator cache.
	 * 
	 * @author jwhaley
	 * @version $Id: BDDFactory.java,v 1.2 2009/10/18 19:30:54 uid228351 Exp $
	 */
	public static class CacheStats {
		public int uniqueAccess;
		public int uniqueChain;
		public int uniqueHit;
		public int uniqueMiss;
		public int opHit;
		public int opMiss;
		public int swapCount;

		protected CacheStats() {
		}

		void copyFrom(CacheStats that) {
			this.uniqueAccess = that.uniqueAccess;
			this.uniqueChain = that.uniqueChain;
			this.uniqueHit = that.uniqueHit;
			this.uniqueMiss = that.uniqueMiss;
			this.opHit = that.opHit;
			this.opMiss = that.opMiss;
			this.swapCount = that.swapCount;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#toString()
		 */
		public String toString() {
			StringBuffer sb = new StringBuffer();
			String newLine = getProperty("line.separator", "\n");
			sb.append(newLine);
			sb.append("Cache statistics");
			sb.append(newLine);
			sb.append("----------------");
			sb.append(newLine);

			sb.append("Unique Access:  ");
			sb.append(uniqueAccess);
			sb.append(newLine);
			sb.append("Unique Chain:   ");
			sb.append(uniqueChain);
			sb.append(newLine);
			sb.append("=> Ave. chain = ");
			if (uniqueAccess > 0)
				sb.append(((float) uniqueChain) / ((float) uniqueAccess));
			else
				sb.append((float) 0);
			sb.append(newLine);
			sb.append("Unique Hit:     ");
			sb.append(uniqueHit);
			sb.append(newLine);
			sb.append("Unique Miss:    ");
			sb.append(uniqueMiss);
			sb.append(newLine);
			sb.append("=> Hit rate =   ");
			if (uniqueHit + uniqueMiss > 0)
				sb.append(((float) uniqueHit) / ((float) uniqueHit + uniqueMiss));
			else
				sb.append((float) 0);
			sb.append(newLine);
			sb.append("Operator Hits:  ");
			sb.append(opHit);
			sb.append(newLine);
			sb.append("Operator Miss:  ");
			sb.append(opMiss);
			sb.append(newLine);
			sb.append("=> Hit rate =   ");
			if (opHit + opMiss > 0)
				sb.append(((float) opHit) / ((float) opHit + opMiss));
			else
				sb.append((float) 0);
			sb.append(newLine);
			sb.append("Swap count =    ");
			sb.append(swapCount);
			sb.append(newLine);
			return sb.toString();
		}
	}

	/**
	 * Singleton object for cache statistics.
	 */
	protected CacheStats cachestats = new CacheStats();

	/**
	 * <p>
	 * Return the current cache statistics for this BDD factory.
	 * </p>
	 * 
	 * @return cache statistics
	 */
	public CacheStats getCacheStats() {
		return cachestats;
	}

	// TODO: bdd_sizeprobe_hook
	// TODO: bdd_reorder_probe

	/**** FINITE DOMAINS ****/

	protected BDDDomain[] domain;
	protected int fdvarnum;
	protected int firstbddvar;

	/**
	 * <p>
	 * Implementors must implement this factory method to create BDDDomain objects
	 * of the correct type.
	 * </p>
	 */
	protected BDDDomain createDomain(int a, BigInteger b) {
		return new BDDDomain(a, b) {
			public BDDFactory getFactory() {
				return BDDFactory.this;
			}
		};
	}

	/**
	 * <p>
	 * Creates a new finite domain block of the given size. Allocates log 2
	 * (|domainSize|) BDD variables for the domain.
	 * </p>
	 */
	public BDDDomain extDomain(long domainSize) {
		return extDomain(BigInteger.valueOf(domainSize));
	}

	public BDDDomain extDomain(BigInteger domainSize) {
		return extDomain(new BigInteger[] { domainSize })[0];
	}

	/**
	 * <p>
	 * Extends the set of finite domain blocks with domains of the given sizes. Each
	 * entry in domainSizes is the size of a new finite domain which later on can be
	 * used for finite state machine traversal and other operations on finite
	 * domains. Each domain allocates log 2 (|domainSizes[i]|) BDD variables to be
	 * used later. The ordering is interleaved for the domains defined in each call
	 * to extDomain. This means that assuming domain D0 needs 2 BDD variables x1 and
	 * x2 , and another domain D1 needs 4 BDD variables y1, y2, y3 and y4, then the
	 * order then will be x1, y1, x2, y2, y3, y4. The new domains are returned in
	 * order. The BDD variables needed to encode the domain are created for the
	 * purpose and do not interfere with the BDD variables already in use.
	 * </p>
	 * 
	 * <p>
	 * Compare to fdd_extdomain.
	 * </p>
	 */
	public BDDDomain[] extDomain(int[] dom) {
		BigInteger[] a = new BigInteger[dom.length];
		for (int i = 0; i < a.length; ++i) {
			a[i] = BigInteger.valueOf(dom[i]);
		}
		return extDomain(a);
	}

	public BDDDomain[] extDomain(long[] dom) {
		BigInteger[] a = new BigInteger[dom.length];
		for (int i = 0; i < a.length; ++i) {
			a[i] = BigInteger.valueOf(dom[i]);
		}
		return extDomain(a);
	}

	public BDDDomain[] extDomain(BigInteger[] domainSizes) {
		int offset = fdvarnum;
		int binoffset;
		int extravars = 0;
		int n, bn;
		boolean more;
		int num = domainSizes.length;

		/* Build domain table */
		if (domain == null) /* First time */ {
			domain = new BDDDomain[num];
		} else /* Allocated before */ {
			if (fdvarnum + num > domain.length) {
				int fdvaralloc = domain.length + Math.max(num, domain.length);
				BDDDomain[] d2 = new BDDDomain[fdvaralloc];
				System.arraycopy(domain, 0, d2, 0, domain.length);
				domain = d2;
			}
		}

		/* Create bdd variable tables */
		for (n = 0; n < num; n++) {
			domain[n + fdvarnum] = createDomain(n + fdvarnum, domainSizes[n]);
			extravars += domain[n + fdvarnum].varNum();
		}

		binoffset = firstbddvar;
		int bddvarnum = varNum();
		if (firstbddvar + extravars > bddvarnum) {
			setVarNum(firstbddvar + extravars);
		}

		/* Set correct variable sequence (interleaved) */
		for (bn = 0, more = true; more; bn++) {
			more = false;

			for (n = 0; n < num; n++) {
				if (bn < domain[n + fdvarnum].varNum()) {
					more = true;
					domain[n + fdvarnum].ivar[bn] = binoffset++;
				}
			}
		}

		if (isZDD()) {
			// Need to rebuild varsets for existing domains.
			for (n = 0; n < fdvarnum; n++) {
				domain[n].var.free();
				domain[n].var = makeSet(domain[n].ivar);
			}
		}
		for (n = 0; n < num; n++) {
			domain[n + fdvarnum].var = makeSet(domain[n + fdvarnum].ivar);
		}

		fdvarnum += num;
		firstbddvar += extravars;

		BDDDomain[] r = new BDDDomain[num];
		System.arraycopy(domain, offset, r, 0, num);
		return r;
	}

	/**
	 * <p>
	 * This function takes two finite domain blocks and merges them into a new one,
	 * such that the new one is encoded using both sets of BDD variables.
	 * </p>
	 * 
	 * <p>
	 * Compare to fdd_overlapdomain.
	 * </p>
	 */
	public BDDDomain overlapDomain(BDDDomain d1, BDDDomain d2) {
		BDDDomain d;
		int n;

		int fdvaralloc = domain.length;
		if (fdvarnum + 1 > fdvaralloc) {
			fdvaralloc += fdvaralloc;
			BDDDomain[] domain2 = new BDDDomain[fdvaralloc];
			System.arraycopy(domain, 0, domain2, 0, domain.length);
			domain = domain2;
		}

		d = domain[fdvarnum];
		d.realsize = d1.realsize.multiply(d2.realsize);
		d.ivar = new int[d1.varNum() + d2.varNum()];

		for (n = 0; n < d1.varNum(); n++)
			d.ivar[n] = d1.ivar[n];
		for (n = 0; n < d2.varNum(); n++)
			d.ivar[d1.varNum() + n] = d2.ivar[n];

		d.var = makeSet(d.ivar);
		// bdd_addref(d.var);

		fdvarnum++;
		return d;
	}

	/**
	 * <p>
	 * Returns a BDD defining all the variable sets used to define the variable
	 * blocks in the given array.
	 * </p>
	 * 
	 * <p>
	 * Compare to fdd_makeset.
	 * </p>
	 */
	public BDDVarSet makeSet(BDDDomain[] v) {
		BDDVarSet res = emptySet();
		int n;

		for (n = 0; n < v.length; n++) {
			res.unionWith(v[n].set());
		}

		return res;
	}

	/**
	 * <p>
	 * Clear all allocated finite domain blocks that were defined by extDomain() or
	 * overlapDomain().
	 * </p>
	 * 
	 * <p>
	 * Compare to fdd_clearall.
	 * </p>
	 */
	public void clearAllDomains() {
		domain = null;
		fdvarnum = 0;
		firstbddvar = 0;
	}

	/**
	 * <p>
	 * Returns the number of finite domain blocks defined by calls to extDomain().
	 * </p>
	 * 
	 * <p>
	 * Compare to fdd_domainnum.
	 * </p>
	 */
	public int numberOfDomains() {
		return fdvarnum;
	}

	/**
	 * <p>
	 * Returns the ith finite domain block, as defined by calls to extDomain().
	 * </p>
	 */
	public BDDDomain getDomain(int i) {
		if (i < 0 || i >= fdvarnum)
			throw new IndexOutOfBoundsException();
		return domain[i];
	}

	// TODO: fdd_file_hook, fdd_strm_hook

	/**
	 * <p>
	 * Creates a variable ordering from a string. The resulting order can be passed
	 * into <tt>setVarOrder()</tt>. Example: in the order "A_BxC_DxExF", the bits
	 * for A are first, followed by the bits for B and C interleaved, followed by
	 * the bits for D, E, and F interleaved.
	 * </p>
	 * 
	 * <p>
	 * Obviously, domain names cannot contain the 'x' or '_' characters.
	 * </p>
	 * 
	 * @param reverseLocal
	 *            whether to reverse the bits of each domain
	 * @param ordering
	 *            string representation of ordering
	 * @return int[] of ordering
	 * @see net.sf.javabdd.BDDFactory#setVarOrder(int[])
	 */
	public int[] makeVarOrdering(boolean reverseLocal, String ordering) {

		int varnum = varNum();

		int nDomains = numberOfDomains();
		int[][] localOrders = new int[nDomains][];
		for (int i = 0; i < localOrders.length; ++i) {
			localOrders[i] = new int[getDomain(i).varNum()];
		}

		for (int i = 0; i < nDomains; ++i) {
			BDDDomain d = getDomain(i);
			int nVars = d.varNum();
			for (int j = 0; j < nVars; ++j) {
				if (reverseLocal) {
					localOrders[i][j] = nVars - j - 1;
				} else {
					localOrders[i][j] = j;
				}
			}
		}

		BDDDomain[] doms = new BDDDomain[nDomains];

		int[] varorder = new int[varnum];

		// System.out.println("Ordering: "+ordering);
		StringTokenizer st = new StringTokenizer(ordering, "x_", true);
		int numberOfDomains = 0, bitIndex = 0;
		boolean[] done = new boolean[nDomains];
		for (int i = 0;; ++i) {
			String s = st.nextToken();
			BDDDomain d;
			for (int j = 0;; ++j) {
				if (j == numberOfDomains())
					throw new BDDException("bad domain: " + s);
				d = getDomain(j);
				if (s.equals(d.getName()))
					break;
			}
			if (done[d.getIndex()])
				throw new BDDException("duplicate domain: " + s);
			done[d.getIndex()] = true;
			doms[i] = d;
			if (st.hasMoreTokens()) {
				s = st.nextToken();
				if (s.equals("x")) {
					++numberOfDomains;
					continue;
				}
			}
			bitIndex = fillInVarIndices(doms, i - numberOfDomains, numberOfDomains + 1, localOrders, bitIndex,
					varorder);
			if (!st.hasMoreTokens()) {
				break;
			}
			if (s.equals("_"))
				numberOfDomains = 0;
			else
				throw new BDDException("bad token: " + s);
		}

		for (int i = 0; i < doms.length; ++i) {
			if (!done[i]) {
				throw new BDDException("missing domain #" + i + ": " + getDomain(i));
			}
		}

		while (bitIndex < varorder.length) {
			varorder[bitIndex] = bitIndex;
			++bitIndex;
		}

		int[] test = new int[varorder.length];
		System.arraycopy(varorder, 0, test, 0, varorder.length);
		Arrays.sort(test);
		for (int i = 0; i < test.length; ++i) {
			if (test[i] != i)
				throw new BDDException(test[i] + " != " + i);
		}

		return varorder;
	}

	/**
	 * Helper function for makeVarOrder().
	 */
	static int fillInVarIndices(BDDDomain[] doms, int domainIndex, int numDomains, int[][] localOrders, int bitIndex,
			int[] varorder) {
		// calculate size of largest domain to interleave
		int maxBits = 0;
		for (int i = 0; i < numDomains; ++i) {
			BDDDomain d = doms[domainIndex + i];
			maxBits = Math.max(maxBits, d.varNum());
		}
		// interleave the domains
		for (int bitNumber = 0; bitNumber < maxBits; ++bitNumber) {
			for (int i = 0; i < numDomains; ++i) {
				BDDDomain d = doms[domainIndex + i];
				if (bitNumber < d.varNum()) {
					int di = d.getIndex();
					int local = localOrders[di][bitNumber];
					if (local >= d.vars().length) {
						System.out.println("bug!");
					}
					if (bitIndex >= varorder.length) {
						System.out.println("bug2!");
					}
					varorder[bitIndex++] = d.vars()[local];
				}
			}
		}
		return bitIndex;
	}

	/**** BIT VECTORS ****/

	/**
	 * <p>
	 * Implementors must implement this factory method to create BDDBitVector
	 * objects of the correct type.
	 * </p>
	 */
	protected BDDBitVector createBitVector(int a) {
		return new BDDBitVector(a) {
			public BDDFactory getFactory() {
				return BDDFactory.this;
			}
		};
	}

	/**
	 * <p>
	 * Implementors must implement this factory method to create BDDBitVector
	 * objects of the correct type.
	 * </p>
	 */
	protected BDDBitVector createBitVector(BigInteger i) {
		return new BDDBitVector(i) {
			public BDDFactory getFactory() {
				return BDDFactory.this;
			}
		};
	}

	/**
	 * <p>
	 * Build a bit vector that is constant true or constant false.
	 * </p>
	 * 
	 * <p>
	 * Compare to bvec_true, bvec_false.
	 * </p>
	 */
	public BDDBitVector buildVector(int bitnum, boolean b) {
		BDDBitVector v = createBitVector(bitnum);
		v.initialize(b);
		return v;
	}

	/**
	 * <p>
	 * Build a bit vector that corresponds to a constant value.
	 * </p>
	 * 
	 * <p>
	 * Compare to bvec_con.
	 * </p>
	 */
	public BDDBitVector constantVector(int bitnum, long val) {
		BDDBitVector v = createBitVector(bitnum);
		v.initialize(val);
		return v;
	}

	/**
	 * Build a bit vector that corresponds to a constant value. The size of the
	 * vector is determined such that it suffices for holding the value.
	 * 
	 * @param val
	 * @return
	 */
	public BDDBitVector constantVector(BigInteger val) {
		BDDBitVector v = createBitVector(val);
		return v;
	}

	public BDDBitVector constantVector(int bitnum, BigInteger val) {
		BDDBitVector v = createBitVector(bitnum);
		v.initialize(val);
		return v;
	}

	/**
	 * <p>
	 * Build a bit vector using variables offset, offset+step, offset+2*step, ... ,
	 * offset+(bitnum-1)*step.
	 * </p>
	 * 
	 * <p>
	 * Compare to bvec_var.
	 * </p>
	 */
	public BDDBitVector buildVector(int bitnum, int offset, int step) {
		BDDBitVector v = createBitVector(bitnum);
		v.initialize(offset, step);
		return v;
	}

	/**
	 * <p>
	 * Build a bit vector using variables from the given BDD domain.
	 * </p>
	 * 
	 * <p>
	 * Compare to bvec_varfdd.
	 * </p>
	 */
	public BDDBitVector buildVector(BDDDomain d) {
		BDDBitVector v = createBitVector(d.varNum());
		v.initialize(d);
		return v;
	}

	/**
	 * <p>
	 * Build a bit vector using the given variables.
	 * </p>
	 * 
	 * <p>
	 * compare to bvec_varvec.
	 * </p>
	 */
	public BDDBitVector buildVector(int[] var) {
		BDDBitVector v = createBitVector(var.length);
		v.initialize(var);
		return v;
	}

	/**** CALLBACKS ****/

	protected List<Object[]> gc_callbacks, reorder_callbacks, resize_callbacks;

	/**
	 * <p>
	 * Register a callback that is called when garbage collection is about to occur.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void registerGCCallback(Object o, Method m) {
		if (gc_callbacks == null)
			gc_callbacks = new LinkedList<Object[]>();
		registerCallback(gc_callbacks, o, m);
	}

	/**
	 * <p>
	 * Unregister a garbage collection callback that was previously registered.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void unregisterGCCallback(Object o, Method m) {
		if (gc_callbacks == null)
			throw new BDDException();
		if (!unregisterCallback(gc_callbacks, o, m))
			throw new BDDException();
	}

	/**
	 * <p>
	 * Register a callback that is called when reordering is about to occur.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void registerReorderCallback(Object o, Method m) {
		if (reorder_callbacks == null)
			reorder_callbacks = new LinkedList<Object[]>();
		registerCallback(reorder_callbacks, o, m);
	}

	/**
	 * <p>
	 * Unregister a reorder callback that was previously registered.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void unregisterReorderCallback(Object o, Method m) {
		if (reorder_callbacks == null)
			throw new BDDException();
		if (!unregisterCallback(reorder_callbacks, o, m))
			throw new BDDException();
	}

	/**
	 * <p>
	 * Register a callback that is called when node table resizing is about to
	 * occur.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void registerResizeCallback(Object o, Method m) {
		if (resize_callbacks == null)
			resize_callbacks = new LinkedList<Object[]>();
		registerCallback(resize_callbacks, o, m);
	}

	/**
	 * <p>
	 * Unregister a reorder callback that was previously registered.
	 * </p>
	 * 
	 * @param o
	 *            base object
	 * @param m
	 *            method
	 */
	public void unregisterResizeCallback(Object o, Method m) {
		if (resize_callbacks == null)
			throw new BDDException();
		if (!unregisterCallback(resize_callbacks, o, m))
			throw new BDDException();
	}

	protected void gbc_handler(boolean pre, GCStats s) {
		if (gc_callbacks == null) {
			bdd_default_gbchandler(pre, s);
		} else {
			doCallbacks(gc_callbacks, new Integer(pre ? 1 : 0), s);
		}
	}

	protected static void bdd_default_gbchandler(boolean pre, GCStats s) {
		if (pre) {
			if (s.freenodes != 0)
				System.err.println(
						"Starting GC cycle  #" + (s.num + 1) + ": " + s.nodes + " nodes / " + s.freenodes + " free");
		} else {
			System.err.println(s.toString());
		}
	}

	void reorder_handler(boolean b, ReorderStats s) {
		if (b) {
			s.usednum_before = getNodeNum();
			s.time = System.currentTimeMillis();
		} else {
			s.time = System.currentTimeMillis() - s.time;
			s.usednum_after = getNodeNum();
		}
		if (reorder_callbacks == null) {
			bdd_default_reohandler(b, s);
		} else {
			doCallbacks(reorder_callbacks, new Boolean(b), s);
		}
	}

	protected void bdd_default_reohandler(boolean prestate, ReorderStats s) {
		int verbose = 1;
		if (verbose > 0) {
			if (prestate) {
				System.out.println("Start reordering");
			} else {
				System.out.println("End reordering. " + s);
			}
		}
	}

	protected void resize_handler(int oldsize, int newsize) {
		if (resize_callbacks == null) {
			bdd_default_reshandler(oldsize, newsize);
		} else {
			doCallbacks(resize_callbacks, new Integer(oldsize), new Integer(newsize));
		}
	}

	protected static void bdd_default_reshandler(int oldsize, int newsize) {
		int verbose = 1;
		if (verbose > 0) {
			System.out.println("Resizing node table from " + oldsize + " to " + newsize);
		}
	}

	protected void registerCallback(List<Object[]> callbacks, Object o, Method m) {
		if (!Modifier.isPublic(m.getModifiers()) && !m.isAccessible()) {
			throw new BDDException("Callback method not accessible");
		}
		if (!Modifier.isStatic(m.getModifiers())) {
			if (o == null) {
				throw new BDDException("Base object for callback method is null");
			}
			if (!m.getDeclaringClass().isAssignableFrom(o.getClass())) {
				throw new BDDException("Base object for callback method is the wrong type");
			}
		}
		callbacks.add(new Object[] { o, m });
	}

	protected boolean unregisterCallback(List<Object[]> callbacks, Object o, Method m) {
		if (callbacks != null) {
			for (Iterator<Object[]> i = callbacks.iterator(); i.hasNext();) {
				Object[] cb = i.next();
				if (o == cb[0] && m.equals(cb[1])) {
					i.remove();
					return true;
				}
			}
		}
		return false;
	}

	protected void doCallbacks(List<Object[]> callbacks, Object arg1, Object arg2) {
		if (callbacks != null) {
			for (Iterator<Object[]> i = callbacks.iterator(); i.hasNext();) {
				Object[] cb = i.next();
				Object o = cb[0];
				Method m = (Method) cb[1];
				try {
					switch (m.getParameterTypes().length) {
					case 0:
						m.invoke(o, new Object[] {});
						break;
					case 1:
						m.invoke(o, new Object[] { arg1 });
						break;
					case 2:
						m.invoke(o, new Object[] { arg1, arg2 });
						break;
					default:
						throw new BDDException("Wrong number of arguments for " + m);
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					if (e.getTargetException() instanceof RuntimeException)
						throw (RuntimeException) e.getTargetException();
					if (e.getTargetException() instanceof Error)
						throw (Error) e.getTargetException();
					e.printStackTrace();
				}
			}
		}
	}

	public int[] getAttrSizes() {
		System.out.println("getAttrSizes() not implemented");
		return null;
	}

	public BDD[] getXMem() {
		System.out.println("getXMem() not implemented");
		return null;
	}

	public BDD[] getYMem() {
		System.out.println("getYMem() not implemented");
		return null;
	}

	public BDD[] getZMem() {
		System.out.println("getZMem() not implemented");
		return null;
	}

	public BDD[] getZMemFirstItr() {
		System.out.println("getZMemFirstItr() not implemented");
		return null;
	}
	
	public BDD getFulfillBDD(int[] exjindices, int[] findices) {
		System.out.println("getFulfillBDD not implemented");
		return null;
	}
	
	public BDD getTowardsBDD(int[] exjindices, int[] tindices) {
		System.out.println("getTowardsBDD not implemented");
		return null;
	}
	
	public BDD getEnvViolationBDD(int[] iindices, int[] kindices) {
		System.out.println("getEnvViolationBDD not implemented");
		return null;
	}
	
	public BDD getGr1StarWinningStates() {
		System.out.println("getGr1StarWinningStates() not implemented");
		return null;
	}

	public boolean gr1StarGame(BDD[] sysJ, BDD[] envJ,
			BDD[] sfaIni, BDD[] sfaTrans, BDD[] sfaTransToAcc, BDDVarSet[] sfaUnprimeStateVars, BDDVarSet[] sfaPrimeStateVars,
			BDD sysIni, BDD envIni, BDD sysTrans,
			BDD envTrans, BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars,
			BDDVarSet envPrimeVars, BDDPairing pairs, BDD[] sysTransList, BDD[] envTransList,
			BDDVarSet[] sysQuantSets, BDDVarSet[] envQuantSets, boolean efp,
			boolean eun, boolean fpr, boolean sca, boolean mem) {
		System.out.println("gr1 star game not implemented");
		return false;
	}
	
	public boolean gr1Game(BDD[] sysJ, BDD[] envJ, BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans,
			BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars, BDDVarSet envPrimeVars,
			BDDPairing pairs, BDD[] sysTransList, BDD[] envTransList, BDDVarSet[] sysQuantSets,
			BDDVarSet[] envQuantSets, boolean efp, boolean eun, boolean fpr, boolean sca) {
		System.out.println("gr1 game not implemented");
		return false;
	}
	
	public boolean gr1SeparatedGame(BDD[] sysJ, BDD[] envJ, BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans,
			BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars, BDDVarSet envPrimeVars,
			BDDPairing pairs, BDD[] sysTransList, BDD[] envTransList, BDDVarSet[] sysQuantSets,
			BDDVarSet[] envQuantSets, boolean efp, boolean eun, boolean fpr, boolean sca) {
		System.out.println("gr1 game not implemented");
		return false;
	}
	
	public boolean vacuityC(BDD[] justices, BDD ini, BDD trans, BDDVarSet primeVars, BDDPairing pairs, BDD targetJustice) {
		System.out.println("vacuity in c not implemented");
		return false;
	}

	public boolean gr1GameWithIncData(BDD[] sysJ, BDD[] envJ, BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans,
			BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars, BDDVarSet envPrimeVars,
			BDDPairing pairs, boolean efp, boolean eun, boolean fpr, boolean sca, int incBitmap, BDD incStartZ,
			BDD[] incZMem, BDD[] incZMemFirstItr, BDD[] incXMem, int jIdx, int incSizeD1, int incSizeD2,
			int[] incSizeD3) {
		System.out.println("gr1GameWithIncData not implemented");
		return false;
	}

	public int getRabinZSize() {
		System.out.println("getRabinZSize() not implemented");
		return 0;
	}

	public int[] getRabinXSizes() {
		System.out.println("getRabinXSizes() not implemented");
		return null;
	}

	public BDD[] getRabinXMem() {
		System.out.println("getRabinXMem() not implemented");
		return null;
	}

	public BDD[] getRabinZMem() {
		System.out.println("getRabinZMem() not implemented");
		return null;
	}

	public boolean rabinGame(BDD[] sysJ, BDD[] envJ, BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans,
			BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars, BDDVarSet envPrimeVars,
			BDDPairing pairs, BDD[] sysTransList, BDD[] envTransList, BDDVarSet[] sysQuantSets,
			BDDVarSet[] envQuantSets, boolean efp, boolean eun, boolean fpr, boolean sca) {
		System.out.println("rabin game not implemented");
		return false;
	}

	public boolean rabinGameWithIncData(BDD[] sysJ, BDD[] envJ, BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans,
			BDDVarSet sysUnprimeVars, BDDVarSet envUnprimeVars, BDDVarSet sysPrimeVars, BDDVarSet envPrimeVars,
			BDDPairing pairs, boolean efp, boolean eun, boolean fpr, boolean sca, int incBitmap, BDD incStartZ,
			BDD[] incZMem, BDD[] incXMem, int jIdx, int incSizeD1, int incSizeD2, int[] incSizeD3) {
		System.out.println("rabinGameWithIncData not implemented");
		return false;
	}
	
	public BDD getJusticesBDD(BDD[] sysJ, BDD[] envJ, int[] jindices, int[] iindices, int utilindex) {
		System.out.println("getJusticesBDD not implemented");
		return null;
	}
	
	public BDD getTransBDD(BDD sysIni, BDD envIni, BDD sysTrans, BDD envTrans, int[] jindices, int[] iindices, int utilindex) {
		System.out.println("getTransBDD not implemented");
		return null;
	}
	
	public BDD getFixpointsBDD(int[] jindices, int[] iindices, int[] kindices) {
		System.out.println("getFixpointsBDD not implemented");
		return null;
	}
	
	public BDD getFixpointsStarBDD(int[] jindices, int[] iindices, int[] kindices) {
		System.out.println("getFixpointsStarBDD not implemented");
		return null;
	}
	
	public BDD getJusticesStarBDD(BDD[] sysJ, BDD[] envJ, int[] jindices, int[] iindices, int utilindex) {
		System.out.println("getJusticesStarBDD not implemented");
		return null;
	}
	
	
	
	
	// GR(1) controller execution funcions
	
	public void loadFixpointsJits(BDD fixpoints, int[] jindices, int[] iindices, int[] kindices, int[] ranks, BDDPairing pairs, BDDVarSet primeVars) {
		System.out.println("loadFixpointsJits not implemented");
	}
	
	public void loadTransJits(BDD trans, int[] jindices, int[] iindices, int utilindex) {
		System.out.println("loadTransJits not implemented");
	}
	
	public void loadJusticesJits(BDD justices, int[] jindices, int[] iindices, int utilindex, int n, int m) {
		System.out.println("loadJusticesJits not implemented");
	}
	
	public BDD nextStatesJits(BDD current, BDD inputs, BDDPairing pairs, BDDVarSet unprimeVars) {
		System.out.println("nextStatesJits not implemented");
		return null;
	}
	
	public int initControllerJits(BDD inputs, BDDPairing pairs) {
		System.out.println("initControllerJits not implemented");
		return 0;
	}
	
	public void freeControllerJits() {
		System.out.println("freeControllerJits not implemented");
	}
	
	public BDD getTransitionsJits() {
		System.out.println("getTransitionsJits not implemented");
		return null;
	}
	
	public BDD getInitialJits() {
		System.out.println("getInitialJits not implemented");
		return null;
	}
	
	
	
	

	public BDD[] getGr1StarXMem() {
		System.out.println("getGr1StarXMem() game not implemented");
		return null;
	}

	public BDD[] getGr1StarYMem() {
		System.out.println("getGr1StarYMem() game not implemented");
		return null;
	}

	public int[] getGr1StarTowardsExistIterNum() {
		System.out.println("getGr1StarTowardsExistIterNum() game not implemented");
		return null;
	}

	public int[] getGr1StarFulfillExistIterNum() {
		System.out.println("getGr1StarFulfillExistIterNum() game not implemented");
		return null;
	}

	public int getGr1StarEnvJViolationIterNum() {
		System.out.println("getGr1StarEnvJViolationIterNum() game not implemented");
		return 0;
	}

	public BDD[] getGr1StarFulfillExistMem() {
		System.out.println("getGr1StarFulfillExistMem() game not implemented");
		return null;
	}

	public BDD[] getGr1StarTowardsExistMem() {
		System.out.println("getGr1StarTowardsExistMem() game not implemented");
		return null;
	}

	public BDD[] getGR1StarEnvJViolationMem() {
		System.out.println("getGR1StarEnvJViolationMem() game not implemented");
		return null;
	}

	public int[] getGr1StarJusticeIterNum() {
		System.out.println("getGr1StarJusticeIterNum() game not implemented");
		return null;
	}



}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.checks;

import java.util.ArrayList;
import java.util.List;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDDomain;
import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.jtlv.Env;

/**
 * Compute and keep popular BDDs for reuse
 * 
 * @author shalom
 *
 */

public class BDDBuilder {
	private static BDD keptWinRegion = null;
	private static BDD keptTrans = null;
	private static BDD keptIni = null;
	private static List<BehaviorInfo> justBehaviors = null;	
	private static List<BehaviorInfo> transBehaviors = null;
	private static List<BehaviorInfo> iniBehaviors = null;
	private static boolean keepBDDs = false;
	
	private enum bType {INI, TRANS, JUST};
	
	/**
	 * Set behaviors and activate the keepBDDs option
	 * @param behaviors
	 */
	public static void setBehaviors(List<BehaviorInfo> behaviors) {
		justBehaviors = new ArrayList<BehaviorInfo>();	
		transBehaviors = new ArrayList<BehaviorInfo>();	
		iniBehaviors = new ArrayList<BehaviorInfo>();	

		iniBehaviors = allOfType(behaviors, bType.INI);
		transBehaviors = allOfType(behaviors, bType.TRANS);
		justBehaviors = allOfType(behaviors, bType.JUST);

		keptWinRegion = null;
		keptTrans = null;
		keptIni = null;
		keepBDDs = true;
	}
	
	/**
	 * get a copy of the win region when possible
	 * 
	 * @param behaviors
	 * @return
	 */
	public static BDD getWinRegion(List<BehaviorInfo> behaviors) {
		if (keepBDDs && 
				eq(allOfType(behaviors, bType.TRANS), transBehaviors) && 
				eq(allOfType(behaviors, bType.JUST), justBehaviors)) {
			if (keptWinRegion==null) {
				keptWinRegion = GR1Implication.computeWinRegion(behaviors);
			}
			return keptWinRegion.id();
		} else {
			return GR1Implication.computeWinRegion(behaviors);
		}
	}

	/**
	 * get a copy of the transition relation when possible

	 * @param behaviors
	 * @return
	 */
	public static BDD getTrans(List<BehaviorInfo> behaviors) {
		if (keepBDDs && eq(allOfType(behaviors, bType.TRANS), transBehaviors)) {
			if (keptTrans==null) {
				keptTrans = computeTrans(behaviors);
			}
			return keptTrans.id();
		} else {
			return computeTrans(behaviors);
		}
	}
	
	/**
	 * get a copy of the initial states when possible

	 * @param behaviors
	 * @return
	 */
	public static BDD getIni(List<BehaviorInfo> behaviors) {
		if (keepBDDs && eq(allOfType(behaviors, bType.INI), iniBehaviors)) {
			if (keptIni==null) {
				keptIni = computeIni(behaviors);
			}
			return keptIni.id();
		} else {
			return computeIni(behaviors);
		}
	}
	
	/**
	 * Remove all behaviors and BDDs and lower the keepBDDs flag
	 */
	public static void release() {
		if (keptWinRegion!=null) {
			keptWinRegion.free();
		}
		if (keptTrans!=null) {
			keptTrans.free();
		}
		if (keptIni!=null) {
			keptIni.free();
		}
		keptWinRegion = null;
		keptTrans = null;
		keptIni = null;
		justBehaviors = null;
		transBehaviors = null;
		iniBehaviors = null;
		keepBDDs = false;
	}
	
	private static boolean eq(List<BehaviorInfo> a, List<BehaviorInfo> b) {
		return a.containsAll(b) && b.containsAll(a);
	}
	
	/** 
	 * get the initial states of the prefix
	 * @param pref
	 * @return init states
	 */
	private static BDD computeIni(List<BehaviorInfo> pref) {
		BDD result = Env.TRUE();
		for (BehaviorInfo b : pref) {
			if (b.isInitial()) {
				result.andWith(b.initial.id());
			}
		}
		return clear(result);
	}
	/**
	 * compute transitions of the prefix
	 * @param pref
	 * @return Transition function
	 */
	private static BDD computeTrans(List<BehaviorInfo> pref) {
		BDD result = Env.TRUE();
		for (BehaviorInfo b : pref) {
			if (b.isSafety()) {
				result.andWith(b.safety.id());
			}
		}
		return clear(result);
	}

	private static List<BehaviorInfo> allOfType(List<BehaviorInfo> pref, bType t) {
	    List<BehaviorInfo> all = new ArrayList<BehaviorInfo>();
		for (BehaviorInfo b : pref) {
			if (b.isJustice() && t==bType.JUST) {
				all.add(b);
			}
			if (b.isSafety() && t==bType.TRANS) {
				all.add(b);
			}
			if (b.isInitial() && t==bType.INI) {
				all.add(b);
			}
	    }
		return all;
	}
	
	/**
	 * clear BDD from irrelevant domain values caused by domains which are not a power of 2
	 * 
	 * @param b
	 * @return
	 */
	private static BDD clear(BDD b) {
		for (BDDDomain d : b.support().getDomains()) {
			b.andWith(d.domain());
		}
		return b;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.enumerate.printers;

import java.io.PrintStream;
import java.util.Vector;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.games.controller.enumerate.EnumStateI;
import tau.smlab.syntech.games.controller.enumerate.EnumStrategyI;
import tau.smlab.syntech.jtlv.Env;

public class SimpleTextPrinter implements EnumStrategyPrinter {

  @Override
  public void printController(PrintStream out, EnumStrategyI c) {
    for (int i = 0; i < c.numOfStates(); i++) {
      EnumStateI s = c.getState(i);
      if (s.isInitial())
        out.print("Initial ");
      BDD prn = s.getData();
      out.print("State " + i + " "
          + prn.toStringWithDomains(Env.stringer) + "\n");
      Vector<EnumStateI> succ = s.getSuccessors();
      if (succ.isEmpty()) {
        out.print("\tWith no successors.");
      } else {
        EnumStateI[] all_succ = new EnumStateI[succ.size()];
        succ.toArray(all_succ);
        out.print("\tWith successors : " + all_succ[0].getStateId());
        for (int j = 1; j < all_succ.length; j++)
          out.print(", " + all_succ[j].getStateId());
      }
      if (c.isCalcStats()) {
        out.print("\tDist From Ini: " + s.getDistFromIni());
      }
      out.println();
    }
  }

}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel.util;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import tau.smlab.syntech.gamemodel.BehaviorInfo;
import tau.smlab.syntech.gamemodel.GameModel;
import tau.smlab.syntech.spectragameinput.translator.Tracer;

/**
 * This class allows identification of model elements according to traces
 * 
 * Their respective module (parts of monitors and counters are built into the system but their module label is AUX)
 * Their type (pattrens and triggers are considered justices according to their non-aux behaviors)
 * Their kind (pattrens and triggers are considered COMPLEX because they are env or sys with supporting aux,
 * 				parts of monitors and counters are AUX, because they are listed as only aux behaviors)
 * 
 * @author shalom
 *
 */

public class TraceIdentifier {
	GameModel gm = null;
	protected List<BehaviorInfo> env = null;
	protected List<BehaviorInfo> sys = null;
	protected List<BehaviorInfo> aux = null;
	
	public enum Module {SYS, ENV, AUX};	
	public enum Type { INI, SAFE, JUST;
		
		public String toString() {
			switch (this) {
			case INI:
				return "<Initial>";
			case SAFE:
				return "<Safety>";
			case JUST:
				return "<Justice>";
			default:
				return "*error*";
			}	
		}
	}
	
	public enum Kind { COMPLEX, SIMPLE;
		
		public String toString() {
			switch (this) {
			case COMPLEX:
				return "<Complex>";
			case SIMPLE:
				return "<Simple GR(1)>";
			default:
				return "error";
			}
		}
	}
	
	public TraceIdentifier(GameModel gm) {
		this.gm = gm;
		env = new ArrayList<BehaviorInfo>(gm.getEnvBehaviorInfo());
		sys = new ArrayList<BehaviorInfo>(gm.getSysBehaviorInfo());
		aux = new ArrayList<BehaviorInfo>(gm.getAuxBehaviorInfo());
	}
	
	/**
	 * get all traces that build the system, including auxiliary behaviors
	 * 
	 * @return list of traces
	 */
	public List<Integer> getSysTraces() {
		List<Integer> envTraces = new ArrayList<Integer>();
		List<Integer> traceList = new ArrayList<Integer>();
		
		for (BehaviorInfo bi : env) {
			singularAdd(envTraces, bi.traceId);
		}
		
		for (BehaviorInfo bi : sys) {
			if (!envTraces.contains(bi.traceId)) {
				singularAdd(traceList, bi.traceId);
			}
		}
		
		for (BehaviorInfo bi : aux) {
			if (!envTraces.contains(bi.traceId)) {
				singularAdd(traceList, bi.traceId);
			}			
		}
		return traceList;
	}
	
	/**
	 * get all traces that build the environment
	 * @return list of traces
	 */
	public List<Integer> getEnvTraces() {
		List<Integer> traceList = new ArrayList<Integer>();
		for (BehaviorInfo bi : env) {
			singularAdd(traceList, bi.traceId);
		}
		return traceList;
	}	
	
	/**
	 * A trace is identified as ENV or SYS if at least one of its behaviors has it.
	 * 
	 * @param t
	 * @return
	 */
	public Module getModule(Integer t) {
		return in(env, t) ? Module.ENV : (in(sys, t) ? Module.SYS : Module.AUX);
	}
	
	/**
	 * This is the type in the sys or env module. 
	 * Note !! Ones in aux pick the first one they see (for example there could be a ONCE in a monitor safety)
	 * 
	 * @param t
	 * @return
	 */
	public Type getType(Integer t)	{
		List<BehaviorInfo> lookin = null;
		Type ret = null;
		
		switch (getModule(t)) {
		case SYS:
			lookin = sys;
			break;
		case ENV:
			lookin = env;
			break;
		case AUX:
			lookin = aux;
			break;
		}
		for (BehaviorInfo bi : lookin) {
			if (bi.traceId == t) {
				ret = bi.isInitial() ? Type.INI : (bi.isSafety() ? Type.SAFE : Type.JUST);
				break;
			}
		}
		return ret;
	}
	
	/**
	 * Traces both in sys or env but not in aux are simple GR(1) elements
	 * Traces both in sys or env yet also in aux are complex (patterns, triggers, containing ONCE)
	 * Traces only in aux are auxiliary behaviors (monitors, counters), and are simple if they have just one behavior
	 * 
	 * @param t
	 * @return
	 */
	public Kind getKind(Integer t) {
		boolean inSys = in(sys, t);
		boolean inEnv = in(env, t);
		int countAux = countin(aux, t);
		int countSys = countin(sys, t);
		int countEnv = countin(env, t);
		
		return ((inSys | inEnv) && (countAux>0 || countSys>1 || countEnv>1)) || countAux>1 ? Kind.COMPLEX : Kind.SIMPLE;
	}
	
	/**
	 * How many of specified type ate in the list
	 * 
	 * @param lst
	 * @param t
	 * @return
	 */
	public int countType(List<Integer> lst, Type t) {
		int ret = 0;
		for (Integer trace : lst) {
			if (getType(trace)==t) {
				ret++;
			}
		}
		return ret;
	}
	
	/** get a list of lines according to traces
	 * 
	 * @param list
	 * @return
	 */
	public static String formatLines(List<Integer> list) {
		String formatted = "< ";
		for (Integer p : list) {
			EObject obj=Tracer.getTarget(p);
			formatted+= obj==null ? "untraced" : NodeModelUtils.getNode(Tracer.getTarget(p)).getStartLine() + " ";
		}
		return formatted + ">";
	}
	
	/**
	 * get a message about the line number
	 * 
	 * @param b
	 * @return
	 */
	public static String getLine(Integer b) {
		EObject obj=Tracer.getTarget(b);
		return obj==null ? "<line cannot be traced>" : "At line " + NodeModelUtils.getNode(Tracer.getTarget(b)).getStartLine();
	}
	
	/**
	 * Format a message about a marked element
	 * 
	 * @param b
	 * @return
	 */
	public String formatMarked(Integer b) {
		return TraceIdentifier.getLine(b) + (getModule(b)==TraceIdentifier.Module.AUX ? " is an auxiliary" : " is a")
				+ " behavior of kind " + getKind(b) +
				(getKind(b)==TraceIdentifier.Kind.SIMPLE ? " and type " + getType(b) : "");
	}
	
	/**
	 * get the correct traces according to start line numbers
	 * 
	 * @param traces
	 * @param lines
	 * @return
	 */
	public List<Integer> locateSysTraces(List<Integer> lines) {
		List<Integer> traces = getSysTraces();
		List<Integer> subTraces = new ArrayList<Integer>();
		for (Integer l : lines) {
			for (Integer t : traces) {
				if (Tracer.getTarget(t)!=null & l==NodeModelUtils.getNode(Tracer.getTarget(t)).getStartLine()) {
					singularAdd(subTraces, t);
					continue;
				}
			}
		}
		return subTraces;
	}

	/**
	 * add making sure the is the only instance in list
	 * 
	 * @param lst	the list
	 * @param x		the item
	 */
	private void singularAdd(List<Integer> lst, Integer x) {
		if (!lst.contains(x)) {
			lst.add(x);
		}
	}
	
	/**
	 * Is the trace in one of the behaviors?
	 * 
	 * @param lst
	 * @param who
	 * @return
	 */
	private boolean in(List<BehaviorInfo> lst, Integer who) {
		return countin(lst, who) > 0;
	}
	
	/**
	 * How many of the trace is in one of the behaviors?
	 * 
	 * @param lst
	 * @param who
	 * @return
	 */
	private int countin(List<BehaviorInfo> lst, Integer who) {
		int num = 0;
		for (BehaviorInfo bi : lst) {
			if (bi.traceId == who) {
				num++;
			}
		}
		return num;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.time.Instant;
import java.util.HashMap;
import java.util.logging.FileHandler;
import java.util.logging.Logger;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;

import tau.smlab.syntech.ui.preferences.PreferencePage;

public class SpectraLogger {
	public static void logOperationStart(IFile specFile, String actionID) {
		if (PreferencePage.isLoggerActive()) {
			long timeStamp = Instant.now().getEpochSecond();
			SpectraLogger.log(specFile, "TimeStamp-" + timeStamp + "-Start-" + actionID, timeStamp);
		}
	}

	public static void logOperationDone(IFile specFile, String actionID, long time, boolean status) {
		if (PreferencePage.isLoggerActive()) {
			long timeStamp = Instant.now().getEpochSecond();
			SpectraLogger.log(specFile,
					"TimeStamp-" + timeStamp + "-Done-" + actionID + "-Took-" + time + "ms-Status-" + status,
					timeStamp);
		}
	}

	public static void logBuffer(IFile specFile, String actionID, String buffer) {
		if (PreferencePage.isLoggerActive()) {
			long timeStamp = Instant.now().getEpochSecond();
			SpectraLogger.log(specFile, "TimeStamp-" + timeStamp + "-Operation-" + actionID + "-Buffer-" + buffer,
					timeStamp);
		}
	}

	public static void log(IFile specFile, String str, long timeStamp) {
		IPath log_dir_path = specFile.getLocation().removeLastSegments(1).append("/spectra-logs");
		File log_dir = log_dir_path.toFile();
		if (!log_dir.exists()) {
			log_dir.mkdir();
		}

		IPath spec_log_dir_path = log_dir_path.append("/" + specFile.getFullPath().removeFileExtension().lastSegment());
		File dir = spec_log_dir_path.toFile();
		if (!dir.exists()) {
			dir.mkdir();
		}

		FileHandler handler = null;
		try {
			handler = new FileHandler(dir.getAbsolutePath().concat("/" + timeStamp + ".spectraXML"), true);
			handler.setFormatter(new SpectraLoggerFormatter());
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Logger logger = Logger.getLogger(specFile.getLocation().toString());
		logger.addHandler(handler);

		saveNewSpecificationCopy(specFile, timeStamp, spec_log_dir_path);
		logger.info(str);
		handler.close();
	}

	private static void saveNewSpecificationCopy(IFile specFile, long timeStamp, IPath spec_log_dir_path) {
		FileInputStream in = null;
		FileOutputStream out = null;
		try {
			File myObj = spec_log_dir_path.append(timeStamp + ".spectraArxived").toFile();

			myObj.createNewFile();
			FileWriter myWriter = null;
			in = new FileInputStream(specFile.getLocation().toFile());
			out = new FileOutputStream(myObj);

			int n;

			while ((n = in.read()) != -1) {
				out.write(n);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.games.controller.symbolic;

import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDVarSet;
import tau.smlab.syntech.gamemodel.PlayerModule;
import tau.smlab.syntech.jtlv.Env;

public class SymbolicControllerDeterminizer {

  /**
   * Creates a deterministic version of the specified symbolic controller {@code ctrl}, such that
   * for any (initial) state there is at most one assignment to the (non primed) variables controlled by
   * {@code detPlayer} module.
   * 
   * @param ctrl non-deterministic symbolic controller
   * @param detPlayer the player module by which the controller would become deterministic
   * @param responderModule whether {@code detPlayer} is the system (responder) player or the environment player
   * @return A deterministic version of the specified symbolic controller relative to the given player module.
   */
  public static SymbolicController determinize(SymbolicController ctrl, PlayerModule detPlayer, boolean responderModule) {
    if(responderModule) {
      return determinize(ctrl, Env.union(detPlayer.getAllFields()), Env.unionPrime(detPlayer.getAllFields()));
    }
    
    //remove variables of the responder module from the controller
    BDD transEx = ctrl.trans().exist(Env.globalPrimeVars().minus(Env.unionPrime(detPlayer.getAllFields())));
    BDD iniEx = ctrl.initial().exist(Env.globalUnprimeVars().minus(Env.union(detPlayer.getAllFields())));
    
    SymbolicController ctrlEx = new SymbolicController(iniEx, transEx);
    
    //create a deterministic version of the controller with the removed variables of the responder module
    SymbolicController detCtrl = determinize(ctrlEx, Env.union(detPlayer.getAllFields()), Env.unionPrime(detPlayer.getAllFields()));
    
    ctrlEx.free();
    
    SymbolicController resCtrl = new SymbolicController();
    
    //add valid choices of the responder module to the new deterministic controller
    resCtrl.setInit(ctrl.initial().and(detCtrl.initial()));
    resCtrl.setTrans(ctrl.trans().and(detCtrl.trans()));
    
    detCtrl.free();
    
    return resCtrl;
  }
  /**
   * Creates a deterministic version of the specified symbolic controller {@code ctrl}, such that
   * for any (initial) state there is at most one assignment to the variables (iniDetVars) transDetVars that
   * evaluates to true.
   * 
   * @param ctrl non-deterministic symbolic controller
   * @param transDetVars the variables set according to which the transition relation would be deterministic
   * @param iniDetVars   the variables set according to which the initial states would be deterministic
   * @return A deterministic version of the specified symbolic controller relative to the two given variables sets.
   */
  public static SymbolicController determinize(SymbolicController ctrl, BDDVarSet transDetVars, BDDVarSet iniDetVars) {
    BDD detTrans, trans = ctrl.trans();
    BDD detIni, ini = ctrl.initial();
    
    detTrans = trans.determinizeController(transDetVars);
    detIni = ini.determinizeController(iniDetVars);
    
    return new SymbolicController(detIni, detTrans);
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.ui.preferences;

import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

import tau.smlab.syntech.gamemodel.PlayerModule.TransFuncType;
import tau.smlab.syntech.games.gr1.GR1GameExperiments;
import tau.smlab.syntech.games.rabin.RabinGame;
import tau.smlab.syntech.jtlv.BDDPackage;
import tau.smlab.syntech.jtlv.BDDPackage.BBDPackageVersion;
import tau.smlab.syntech.ui.Activator;

/**
 * This class represents a preference page that is contributed to the
 * Preferences dialog. By subclassing <samp>FieldEditorPreferencePage</samp>, we
 * can use the field support built into JFace that allows us to create a page
 * that is small and knows how to save, restore and apply itself.
 * <p>
 * This page is used to modify preferences only. They are stored in the
 * preference store that belongs to the main plug-in class. That way,
 * preferences can be accessed directly via the preference store.
 */

public class PreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {

	public PreferencePage() {
		super(GRID);
		setPreferenceStore(Activator.getDefault().getPreferenceStore());
		setDescription("General SYNTECH preferences:");
	}

	/**
	 * Creates the field editors. Field editors are abstractions of the common GUI
	 * blocks needed to manipulate various types of preferences. Each field editor
	 * knows how to save and restore itself.
	 */

	private RadioGroupFieldEditor engine;
	private RadioGroupFieldEditor concCont;
	private RadioGroupFieldEditor opts;
	private RadioGroupFieldEditor reorder;
	private RadioGroupFieldEditor synthesisMethod;
	private BooleanFieldEditor determinize;
	private BooleanFieldEditor reorderBeforeSave;
	private BooleanFieldEditor isLoggerActive;

	public void createFieldEditors() {
		engine = new RadioGroupFieldEditor(PreferenceConstants.BDD_ENGINE_CHOICE, "BDD engine", 1,
				new String[][] { { "&JTLV package -- pure Java implementation", "JTLV" },
						{ "&CUDD package -- JNI access to C implementation", "CUDD" },
						{ "CUDD package using &ADDs -- JNI access to C implementation", "CUDD_ADD" } },
				getFieldEditorParent(), true);

		opts = new RadioGroupFieldEditor(PreferenceConstants.OPT_CHOICE, "Optimization options", 1,
				new String[][] { { "Disable optimizations", "none" }, { "All optimizations", "all" },
						{ "Algorithms optimizations", "fp_opts" }, { "Symmetry detection", "sym" },
						{ "Controlled predecessors optimizations", "cp_opts" } },
				getFieldEditorParent(), true);

		reorder = new RadioGroupFieldEditor(PreferenceConstants.REORDER_CHOICE, "Reorder strategy", 1,
				new String[][] { { "Disable reorder (not recommended)", "none" }, { "Enable reorder", "reorder" },
						{ "Enable reorder with grouping (variables and their next state copies)", "group" },
				// { "Special reorder strategy", "special"}
				}, getFieldEditorParent(), true);
		
		synthesisMethod = new RadioGroupFieldEditor(PreferenceConstants.SYNTHESIS_METHOD, "Realizability checking method", 1, 
				new String[][] {{"Original GR(1) (3-fixed-points)", PreferenceConstants.SYNTHESIS_METHOD_GR1}, 
					{"Do not force justice assumption violations (4 fixed-points)", PreferenceConstants.SYNTHESIS_METHOD_PITERMAN},
					{"Kind realizability: do not force any assumption violations (reduction plus 4 fixed-points)", PreferenceConstants.SYNTHESIS_METHOD_PITERMAN_REDUCTION}
				},
				getFieldEditorParent(), true);

		determinize = new BooleanFieldEditor(PreferenceConstants.DETERMINIZE,
				"Determinize static symbolic controllers (can be slow)", getFieldEditorParent());
		
		reorderBeforeSave = new BooleanFieldEditor(PreferenceConstants.REORDER_BEFORE_SAVE,
				"Reorder BDD before save to reduce size", getFieldEditorParent());

		isLoggerActive = new BooleanFieldEditor(PreferenceConstants.IS_LOGGER_ACTIVE,
				"Use Spectra Logger", getFieldEditorParent());
				
		concCont = new RadioGroupFieldEditor(PreferenceConstants.CONC_CONT_FORMAT, "Concrete Controller Format", 1,
				new String[][] { { "CMP automaton (Mealy)", "CMP" }, { "JTLV text format", "JTLV" } },
				getFieldEditorParent(), true);

		addField(engine);
		addField(opts);
		addField(reorder);
		addField(determinize);
		addField(reorderBeforeSave);
		addField(concCont);
		addField(isLoggerActive);
		addField(synthesisMethod);

		// String engineChoice =
		// this.getPreferenceStore().getString(PreferenceConstants.BDD_ENGINE_CHOICE);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
	 */
	public void init(IWorkbench workbench) {
	}

	public static boolean isReorderEnabled() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.REORDER_CHOICE);
		return val.equals("reorder");
	}

	// public static boolean isSpecialReorderStrategy() {
	// String val = Activator.getDefault().getPreferenceStore()
	// .getString(PreferenceConstants.REORDER_CHOICE);
	// return val.equals("special");
	// }

	public static boolean isGroupVarSelection() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.REORDER_CHOICE);
		return val.equals("group");
	}

	public static boolean isDeterminize() {
		return Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.DETERMINIZE);
	}
	
	public static boolean isReorderBeforeSave() {
		return Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.REORDER_BEFORE_SAVE);
	}

	public static boolean isLoggerActive() {
		return Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.IS_LOGGER_ACTIVE);
	}

	public static BDDPackage getBDDPackageSelection() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.BDD_ENGINE_CHOICE);
		
		if (val.equals("JTLV")) {
			return BDDPackage.JTLV;
		} else if (val.equals("CUDD")) {
			return BDDPackage.CUDD;
		} else if (val.equals("CUDD_ADD")) {
			return BDDPackage.CUDD_ADD;
		}

		System.out.println("No preference for BDD engine choice was found. Using as default the CUDD library");
		return BDDPackage.CUDD;
	}

	public static BBDPackageVersion getBDDPackageVersionSelection() {
		BDDPackage engineSelection = getBDDPackageSelection();
		if (engineSelection.equals(BDDPackage.JTLV)) {
			return BBDPackageVersion.DEFAULT;
		}

		// CUDD BDD package has been selected
		return BBDPackageVersion.CUDD_3_0;
	}
	
	public static boolean hasSymmetryDetection() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.OPT_CHOICE);
		return val.equals("sym");
	}

	public static boolean hasOptSelection() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.OPT_CHOICE);
		return !val.equals("none");
	}

	public static void setOptSelection() {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.OPT_CHOICE);

		boolean fp_opts = val.equals("all") || val.equals("fp_opts");
		boolean cp_opts = val.equals("all") || val.equals("cp_opts");

		GR1GameExperiments.DETECT_FIX_POINT_EARLY = fp_opts;
		GR1GameExperiments.USE_FIXPOINT_RECYCLE = fp_opts;
		GR1GameExperiments.STOP_WHEN_INITIALS_LOST = fp_opts;
		GR1GameExperiments.SIMULTANEOUS_CONJUNCTION_ABSTRACTION = cp_opts;

		RabinGame.DETECT_FIX_POINT_EARLY = fp_opts;
		RabinGame.USE_FIXPOINT_RECYCLE = fp_opts;
		RabinGame.STOP_WHEN_WIN_FROM_SOME_INITIALS = fp_opts;
		RabinGame.SIMULTANEOUS_CONJUNCTION_ABSTRACTION = cp_opts;

		// TMP - NOTE: the function relprod needed for this optimization is not
		// implemented for ADDs
		if (PreferencePage.getBDDPackageSelection().equals(BDDPackage.CUDD_ADD)) {
			GR1GameExperiments.SIMULTANEOUS_CONJUNCTION_ABSTRACTION = false;
			RabinGame.SIMULTANEOUS_CONJUNCTION_ABSTRACTION = false;
		}
	}

	public static TransFuncType getTransFuncSelection(boolean isDDMin) {
		String val = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.OPT_CHOICE);
		if (val.equals("all") || val.equals("cp_opts")) {
			return isDDMin ? TransFuncType.PARTIAL_DECOMPOSED_FUNC : TransFuncType.DECOMPOSED_FUNC;
		}

		return TransFuncType.SINGLE_FUNC;
	}

	// public static boolean getWellSepIncludeSys() {
	// return
	// "SYS".equals(Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.WELL_SEP_SYS));
	// }

	public static String getConcreteControllerFormat() {
		return Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.CONC_CONT_FORMAT);
	}
	
	public static String getSynthesisMethod() {
		return Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.SYNTHESIS_METHOD);
	}
}<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.logs;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

/**
 * iterator over BDDs of a log
 *
 */
public class BDDLogReader implements Iterable<BDD> {

  private String fileName;

  public BDDLogReader(String fileName) {
    this.fileName = fileName;
  }

  /**
   * translate a log entry to a BDD
   * 
   * @param text
   * @return
   */
  private BDD toBDD(String text) {
    if ("FALSE".equals(text)) {
      return Env.FALSE();
    }
    if ("TRUE".equals(text)) {
      return Env.TRUE();
    }

    String[] stateVals = text.replace("<", "").replace(">", "").replace(" ", "").split(",");
    BDD res = Env.TRUE();
    // iterate over all assignments
    for (String asgmt : stateVals) {
      String[] asgm = asgmt.split(":");
      // check if variable exists
      if (Env.getVar(asgm[0]) != null) {
        BDD val = Env.getBDDValue(asgm[0], asgm[1]);
        // check if value exists
        if (val == null) {
          throw new RuntimeException("Value " + asgm[1] + " undefined for variable " + asgm[0]);
        } else {
          res.andWith(val.id());
        }
      } else {
        System.err.println("Warning:  Variable " + asgm[0] + " from log does not exist and is ignored!");
      }
    }
    return res;
  }

  @Override
  public Iterator<BDD> iterator() {
    try {
      return new Iterator<BDD>() {
        String line = null;
        boolean isNext = false;
        BufferedReader br = new BufferedReader(new FileReader(fileName));

        /**
         * check if we can read another line from the file
         */
        @Override
        public boolean hasNext() {
          if (!isNext) {
            try {
              line = br.readLine();
            } catch (IOException e) {
            }
            isNext = true;
          }
          return line != null;
        }

        /**
         * convert next line to BDD
         */
        @Override
        public BDD next() {
          if (!hasNext()) {
            return null;
          }
          isNext = false;
          return toBDD(line);
        }

        @Override
        public void remove() {
        }

      };
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gameinput.model;

import java.io.Serializable;

import tau.smlab.syntech.gameinput.spec.SpecTraceable;

public class Counter implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 2420031291078508480L;

	public enum OverFlowMethod {
		FALSE, KEEP, MODULO
	};

	// FALSE = Assumption to not exceed bounds.
	// KEEP = Keep Min/ Max value when trying to exceed bounds.
	// MODULO = Modulo(Max value)

	private int traceId;

	private String name;
	private SpecTraceable iniPred;
	private SpecTraceable incPred;
	private SpecTraceable decPred;
	private SpecTraceable resetPred;
	private OverFlowMethod overFlowMethod;
	private OverFlowMethod underFlowMethod;
	private int lower;
	private int upper;

	/**
	 * @param traceId
	 * @param name
	 * @param incPred
	 * @param decPred
	 * @param resetPred
	 * @param overFlowMethod
	 * @param range
	 * @param iniPred
	 */
	public Counter(int traceId, String name, SpecTraceable incPred, SpecTraceable decPred,
			SpecTraceable resetPred, OverFlowMethod overFlowMethod, OverFlowMethod underFlowMethod,
			int lower, int upper, SpecTraceable iniPred) {
		super();
		this.traceId = traceId;
		this.name = name;
		this.iniPred = iniPred;
		this.incPred = incPred;
		this.decPred = decPred;
		this.resetPred = resetPred;
		this.overFlowMethod = overFlowMethod;
		this.underFlowMethod = underFlowMethod;
		this.lower = lower;
		this.upper = upper;
	}

	public Counter(int traceId, String name) {
		this.name = name;
		this.traceId = traceId;
	}

	public void setTraceId(int traceId) {
		this.traceId = traceId;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setIncPred(SpecTraceable incPredicate) {
		this.incPred = incPredicate;
	}

	public void setDecPred(SpecTraceable decPredicate) {
		this.decPred = decPredicate;
	}

	public void setResetPred(SpecTraceable resetPredicate) {
		this.resetPred = resetPredicate;
	}

	public void setOverFlowMethod(OverFlowMethod overFlowMethod) {
		this.overFlowMethod = overFlowMethod;
	}

	public void setUnderFlowMethod(OverFlowMethod underFlowMethod) {
		this.underFlowMethod = underFlowMethod;
	}

	public void setLower(int lower) {
		this.lower = lower;
	}

	public void setUpper(int upper) {
		this.upper = upper;
	}

	public void setIniPred(SpecTraceable initialConstraint) {
		this.iniPred = initialConstraint;
	}

	public int getTraceId() {
		return traceId;
	}

	public String getName() {
		return name;
	}

	public SpecTraceable getIncPred() {
		return incPred;
	}

	public SpecTraceable getResetPred() {
		return resetPred;
	}

	public SpecTraceable getDecPred() {
		return decPred;
	}

	public int getLower() {
		return lower;
	}

	public int getUpper() {
		return upper;
	}

	public OverFlowMethod getOverFlowMethod() {
		return overFlowMethod;
	}

	public OverFlowMethod getUnderFlowMethod() {
		return underFlowMethod;
	}

	public SpecTraceable getIniPred() {
		return iniPred;
	}
}
<file_sep>/*
Copyright (c) since 2015, Tel Aviv University and Software Modeling Lab

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Tel Aviv University and Software Modeling Lab nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Tel Aviv University and Software Modeling Lab 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/

package tau.smlab.syntech.gamemodel;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.sf.javabdd.BDD;
import tau.smlab.syntech.jtlv.Env;

public class GameModel {

	private PlayerModule sys;
	private PlayerModule env;

	private Map<Integer, BDD> weights;

	private List<BehaviorInfo> auxBehaviorInfo = new ArrayList<BehaviorInfo>();
	private List<BehaviorInfo> sysBehaviorInfo = new ArrayList<BehaviorInfo>();
	private List<BehaviorInfo> envBehaviorInfo = new ArrayList<BehaviorInfo>();

	public PlayerModule getSys() {
		return sys;
	}

	public void setSys(PlayerModule sys) {
		this.sys = sys;
	}

	public PlayerModule getEnv() {
		return env;
	}

	public void setEnv(PlayerModule env) {
		this.env = env;
	}

	public Map<Integer, BDD> getWeights() {
		return weights;
	}

	public void setWeights(Map<Integer, BDD> weights) {
		this.weights = weights;
	}

	public List<BehaviorInfo> getEnvBehaviorInfo() {
		return envBehaviorInfo;
	}

	public void addEnvBehaviorInfo(BehaviorInfo envBehaviorInfo) {
		this.envBehaviorInfo.add(envBehaviorInfo);
	}

	public List<BehaviorInfo> getSysBehaviorInfo() {
		return sysBehaviorInfo;
	}

	public void addSysBehaviorInfo(BehaviorInfo sysBehaviorInfo) {
		this.sysBehaviorInfo.add(sysBehaviorInfo);
	}

	public List<BehaviorInfo> getAuxBehaviorInfo() {
		return auxBehaviorInfo;
	}

	public void addAuxBehaviorInfo(BehaviorInfo auxBehaviorInfo) {
		this.auxBehaviorInfo.add(auxBehaviorInfo);
	}

	public void updateSingleTransFunc() {
		sys.createTransFromPartTrans();
		env.createTransFromPartTrans();
	}

	public void resetSingleTransFunc() {
		sys.resetSingleTrans();
		env.resetSingleTrans();
	}

	public void free() {
		Env.free(auxBehaviorInfo);
		Env.free(sysBehaviorInfo);
		Env.free(envBehaviorInfo);
		if(this.weights != null) {
			Env.free(this.weights);
		}
		sys.free();
		env.free();
	}

}
