de.uni_potsdam.hpi.asg.logictool.mapping.SequenceBasedAndGateDecomposer.java Source code

Java tutorial

Introduction

Here is the source code for de.uni_potsdam.hpi.asg.logictool.mapping.SequenceBasedAndGateDecomposer.java

Source

package de.uni_potsdam.hpi.asg.logictool.mapping;

/*
 * Copyright (C) 2015 Norman Kluge
 * 
 * This file is part of ASGlogic.
 * 
 * ASGlogic is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ASGlogic is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ASGlogic.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;

import de.uni_potsdam.hpi.asg.common.stg.model.Signal;
import de.uni_potsdam.hpi.asg.common.stg.model.Transition;
import de.uni_potsdam.hpi.asg.common.stggraph.AbstractState.Value;
import de.uni_potsdam.hpi.asg.logictool.helper.BDDHelper;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.AndDecoSGHelper;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.IOBehaviour;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.IOBehaviourSimulationStep;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.IOBehaviourSimulationStepFactory;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.IOBehaviourSimulationStepPool;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.Partition;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.PartitionPart;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.QuasiSignal;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.SequenceBackCmp;
import de.uni_potsdam.hpi.asg.logictool.mapping.seqanddeco.SequenceFrontCmp;
import de.uni_potsdam.hpi.asg.logictool.netlist.Netlist;
import de.uni_potsdam.hpi.asg.logictool.netlist.NetlistCelem;
import de.uni_potsdam.hpi.asg.logictool.netlist.NetlistTerm;
import de.uni_potsdam.hpi.asg.logictool.netlist.NetlistTerm.NetlistTermAnnotation;
import de.uni_potsdam.hpi.asg.logictool.netlist.NetlistVariable;
import de.uni_potsdam.hpi.asg.logictool.srgraph.State;
import de.uni_potsdam.hpi.asg.logictool.srgraph.StateGraph;
import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDFactory;
import net.sf.javabdd.JFactory;

public class SequenceBasedAndGateDecomposer {
    private static final Logger logger = LogManager.getLogger();

    private Netlist netlist;
    private BDDFactory factory;
    private Map<Signal, Integer> sigidmap;
    private BiMap<NetlistVariable, QuasiSignal> quasimap;
    private AndDecoSGHelper sghelper;
    private StateGraph origsg;

    private IOBehaviourSimulationStepPool pool;
    private long rmSub = 0;
    private long rmFall = 0;
    private IOBehaviourSimulationStep root;

    public SequenceBasedAndGateDecomposer(StateGraph stategraph, Netlist netlist) {
        this.netlist = netlist;
        this.factory = JFactory.init(1000, 250);
        this.sigidmap = new HashMap<>();
        this.quasimap = HashBiMap.create();
        this.origsg = stategraph;
        this.sghelper = new AndDecoSGHelper(stategraph.getSTG().getFile());
    }

    public boolean decomposeAND(NetlistTerm term) {

        logger.info("Decomposition of " + term.toString());

        Set<Signal> signals = netlist.getDrivenSignalsTransitive(term);
        if (signals.isEmpty()) {
            logger.warn("No signal(s) for term " + term + " found");
            return false;
        } else if (signals.size() > 1) {
            logger.warn("Term " + term + " drives more than one signal. This is not supported yet");
            return false;
        }
        Signal origsig = signals.iterator().next();
        if (!isAOC(term, origsig)) {
            logger.warn("Algorithm not applicable for non-AOC architectures");
            return false;
        }

        int startgatesize = BDDHelper.numberOfVars(term.getBdd());

        BDD bdd = term.getBdd();
        Set<Signal> origrelevant = findRelevantSigs(bdd);
        if (origrelevant == null) {
            return false;
        }

        StateGraph sg2 = sghelper.getNewStateGraph(origrelevant, origsig);
        if (sg2 == null) {
            logger.warn("Failed to generate new SG. Using the original one.");
            sg2 = origsg;
        }

        BiMap<Signal, Signal> sigmap = HashBiMap.create();
        Set<Signal> relevant = new HashSet<>();
        boolean found;
        for (Signal oldSig : origrelevant) {
            found = false;
            for (Signal newSig : sg2.getAllSignals()) {
                if (oldSig.getName().equals(newSig.getName())) {
                    sigmap.put(oldSig, newSig);
                    found = true;
                    break;
                }
            }
            if (!found) {
                logger.error("Signal " + oldSig.getName() + " not found");
                return false;
            }
            relevant.add(sigmap.get(oldSig));
        }
        found = false;
        for (Signal newSig : sg2.getAllSignals()) {
            if (origsig.getName().equals(newSig.getName())) {
                sigmap.put(origsig, newSig);
                found = true;
                break;
            }
        }
        if (!found) {
            logger.error("Signal " + origsig.getName() + " not found");
            return false;
        }
        Signal sig = sigmap.get(origsig);

        Map<Signal, Boolean> posnegmap = getInputsPosOrNeg(term, sigmap);
        BDD newbdd = factory.one();
        for (Entry<Signal, Boolean> entry : posnegmap.entrySet()) {
            if (entry.getValue()) {
                newbdd = newbdd.andWith(getPosBDD(entry.getKey()));
            } else {
                newbdd = newbdd.andWith(getNegBDD(entry.getKey()));
            }
            if (entry.getKey() instanceof QuasiSignal) {
                relevant.add(entry.getKey());
            }
        }

        Set<State> startStates = new HashSet<>();
        for (State s : sg2.getStates()) {
            for (Entry<Transition, State> entry2 : s.getNextStates().entrySet()) {
                if (entry2.getKey().getSignal() == sig) {
                    startStates.add(entry2.getValue());
                }
            }
        }

        List<List<Signal>> fallingPartitions = new ArrayList<>();
        for (Signal sig2 : relevant) {
            List<Signal> tmp = new ArrayList<>();
            tmp.add(sig2);
            fallingPartitions.add(tmp);
        }

        SortedSet<IOBehaviour> sequencesFront = new TreeSet<>(new SequenceFrontCmp());
        SortedSet<IOBehaviour> sequencesBack = new TreeSet<>(new SequenceBackCmp());
        Set<IOBehaviour> newSequences = new HashSet<>();
        Set<IOBehaviour> rmSequences = new HashSet<>();
        Deque<IOBehaviourSimulationStep> steps = new ArrayDeque<>();

        pool = new IOBehaviourSimulationStepPool(new IOBehaviourSimulationStepFactory());
        pool.setMaxTotal(-1);

        try {
            root = pool.borrowObject();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Could not borrow object");
            return false;
        }

        IOBehaviourSimulationStep newStep;
        for (State s : startStates) {
            try {
                newStep = pool.borrowObject();
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("Could not borrow object");
                return false;
            }
            root.getNextSteps().add(newStep);
            newStep.setPrevStep(root);
            newStep.setStart(s);
            newStep.setNextState(s);
            steps.add(newStep);
        }

        if (steps.isEmpty()) {
            return false;
        }

        final long checkThreshold = 100;

        long stepsEvaledTotal = 0;
        IOBehaviourSimulationStep step = null;
        while (!steps.isEmpty()) {
            step = steps.removeLast();
            //         System.out.println("#Step: " + step.toString());
            getNewSteps(step, sig, newSequences, steps, relevant);
            stepsEvaledTotal++;
            if (newSequences.size() >= checkThreshold) {
                removeCandidates(sequencesFront, sequencesBack, newSequences, rmSequences);
            }
        }
        removeCandidates(sequencesFront, sequencesBack, newSequences, rmSequences);
        logger.debug("Sequences: " + sequencesFront.size() + " - Tmp Sequences: " + newSequences.size()
                + " - Steps to evaluate: " + steps.size() + " - Steps evaluated: " + stepsEvaledTotal);
        logger.debug("Pool: " + "Created: " + pool.getCreatedCount() + ", Borrowed: " + pool.getBorrowedCount()
                + ", Returned: " + pool.getReturnedCount() + ", Active: " + pool.getNumActive() + ", Idle: "
                + pool.getNumIdle());
        logger.debug("RmSub: " + rmSub + " // RmFall: " + rmFall);

        SortedSet<IOBehaviour> sequences = new TreeSet<>(sequencesFront);
        sequencesFront.clear();
        sequencesBack.clear();
        //      System.out.println(sequences.toString());

        List<IOBehaviour> falling = new ArrayList<>();
        List<IOBehaviour> rising = new ArrayList<>();
        List<IOBehaviour> constant = new ArrayList<>();
        if (!categoriseSequences(newbdd, sequences, falling, rising, constant)) {
            return false;
        }
        //      System.out.println("Falling:");
        //      for(IOBehaviour beh : falling) {
        //         System.out.println(beh.toString());
        //      }
        //      System.out.println("Rising:");
        //      for(IOBehaviour beh : rising) {
        //         System.out.println(beh.toString());
        //      }
        //      System.out.println("Constant:");
        //      for(IOBehaviour beh : constant) {
        //         System.out.println(beh.toString());
        //      }

        fallingPartitions = getPossiblePartitionsFromFalling(falling, relevant);
        //      System.out.println("FallingPartitions: " + fallingPartitions.toString());

        Map<Integer, List<Partition>> partitions = getPartitions(relevant, startgatesize);
        if (partitions == null) {
            logger.error("There was a problem while creating partions for signal " + sig.getName());
            return false;
        }

        //      System.out.println("Init:");
        //      for(Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
        //         System.out.println(entry.getKey());
        //         for(Partition p : entry.getValue()) {
        //            System.out.println("\t" + p.toString());
        //         }
        //      }

        filterPartitions(partitions, fallingPartitions);
        if (partitions.isEmpty()) {
            logger.error("No suitable partions found");
            return false;
        }

        //      System.out.println("After filter Falling:");
        //      for(Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
        //         System.out.println(entry.getKey());
        //         for(Partition p : entry.getValue()) {
        //            System.out.println("\t" + p.toString());
        //         }
        //      }

        //      System.out.println("posneg: " + posnegmap.toString());

        setPartitionBDDs(partitions, posnegmap);

        if (!checkRising(rising, partitions)) {
            logger.error("Check rising failed");
            return false;
        }
        if (partitions.isEmpty()) {
            logger.error("No suitable partions found");
            return false;
        }

        //      System.out.println("After filter Rising:");
        //      for(Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
        //         System.out.println(entry.getKey());
        //         for(Partition p : entry.getValue()) {
        //            System.out.println("\t" + p.toString());
        //         }
        //      }

        if (!checkConstant(constant, partitions)) {
            logger.error("Check constant failed");
            return false;
        }
        if (partitions.isEmpty()) {
            logger.error("No suitable partions found");
            return false;
        }

        //      System.out.println("After filter Constant:");
        //      for(Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
        //         System.out.println(entry.getKey());
        //         for(Partition p : entry.getValue()) {
        //            System.out.println("\t" + p.toString());
        //         }
        //      }

        applyDecoResult(term, partitions, posnegmap, sigmap);
        return true;
    }

    private boolean isAOC(NetlistTerm origterm, Signal sig) {
        // is AND?
        if (!BDDHelper.isAndGate(origterm.getBdd())) {
            return false;
        }
        NetlistVariable var = origterm.getDrivee();
        while (true) {
            if (var.getReader().size() != 1) {
                return false;
            }
            NetlistTerm term = var.getReader().iterator().next();
            // any numbers of orgates and explicit reset gates allowed
            // ending with the celem for this signal
            if (BDDHelper.isOrGate(term.getBdd())) {
                var = term.getDrivee();
            } else if (term.containsAnnotation(NetlistTermAnnotation.rstNew)) {
                var = term.getDrivee();
            } else if (term instanceof NetlistCelem) {
                NetlistCelem celem = (NetlistCelem) term;
                if (celem.getLoopVar() == netlist.getNetlistVariableBySignal(sig)) {
                    return true;
                }
                return false;
            } else {
                return false;
            }
        }
    }

    private void filterPartitions(Map<Integer, List<Partition>> partitions, List<List<Signal>> fallingPartitions) {
        List<Partition> rmPart = new ArrayList<>();
        List<Integer> rmKey = new ArrayList<>();
        for (Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
            rmPart.clear();
            for (Partition part : entry.getValue()) {
                boolean forcebreak = false;
                for (PartitionPart partpart : part.getPartition()) {
                    for (List<Signal> fallpartpart : fallingPartitions) {
                        boolean containsone = false;
                        for (Signal sig : fallpartpart) {
                            if (partpart.getPart().contains(sig)) {
                                containsone = true;
                                break;
                            }
                        }
                        if (containsone) {
                            if (!partpart.getPart().containsAll(fallpartpart)) {
                                rmPart.add(part);
                                forcebreak = true;
                                break;
                            }
                        }

                    }
                    if (forcebreak) {
                        break;
                    }
                }
            }
            entry.getValue().removeAll(rmPart);
            if (entry.getValue().isEmpty()) {
                rmKey.add(entry.getKey());
            }
        }
        for (int i : rmKey) {
            partitions.remove(i);
        }
    }

    private void removeCandidates(SortedSet<IOBehaviour> sequencesFront, SortedSet<IOBehaviour> sequencesBack,
            Set<IOBehaviour> newSequences, Set<IOBehaviour> rmSequences) {
        removeSubSequences(sequencesFront, sequencesBack, newSequences, rmSequences); //new->front,back ; set rm
        sequencesBack.removeAll(rmSequences);
        sequencesFront.removeAll(rmSequences);
        newSequences.removeAll(rmSequences);
        if (rmSequences.size() > 0) {
            rmSub += rmSequences.size();
            logger.debug("rmSub removed " + rmSequences.size() + " candidates");
        }
        //      checkFalling(newSequences, rmSequences, term, relevant, partitions); //set rm
        //      sequencesBack.removeAll(rmSequences);
        //      sequencesFront.removeAll(rmSequences);
        newSequences.clear();
        //      if(rmSequences.size() > 0) {
        //         rmFall += rmSequences.size();
        //         logger.debug("chkFall removed " + rmSequences.size() + " candidates");
        //      }
    }

    private void applyDecoResult(NetlistTerm term, Map<Integer, List<Partition>> partitions,
            Map<Signal, Boolean> posnegmap, BiMap<Signal, Signal> sigmap) {
        BiMap<Signal, Signal> sigmapinv = sigmap.inverse();
        if (partitions.isEmpty()) {
            return;
        }
        Entry<Integer, List<Partition>> entry = partitions.entrySet().iterator().next();
        if (entry.getValue().isEmpty()) {
            return;
        }
        Partition p = entry.getValue().get(0);
        //      System.out.println(partitions);
        logger.debug("Used Partition: " + p.getPartition().toString());

        Set<NetlistVariable> firstlevelands = new HashSet<>();
        for (PartitionPart part : p.getPartition()) {
            if (part.getPart().size() == 1) {
                Signal s = part.getPart().iterator().next();
                NetlistVariable var = null;
                if (s instanceof QuasiSignal) {
                    var = quasimap.inverse().get((QuasiSignal) s);
                } else {
                    var = netlist.getNetlistVariableBySignal(sigmapinv.get(s));
                }
                firstlevelands.add(var);
                continue;
            }
            BDD tmpBDD = netlist.getFac().one();
            for (Signal sig : part.getPart()) {
                NetlistVariable var = null;
                if (sig instanceof QuasiSignal) {
                    var = quasimap.inverse().get((QuasiSignal) sig);
                } else {
                    Signal netlistsig = sigmapinv.get(sig);
                    var = netlist.getNetlistVariableBySignal(netlistsig);
                }
                if (posnegmap.get(sig)) {
                    tmpBDD = tmpBDD.andWith(var.toBDD());
                } else {
                    tmpBDD = tmpBDD.andWith(var.toNotBDD());
                }
            }
            NetlistTerm tmpterm = netlist.getNetlistTermByBdd(tmpBDD);
            NetlistVariable tmpvar = netlist.getNewTmpVar();
            netlist.addConnection(tmpvar, tmpterm);
            firstlevelands.add(tmpterm.getDrivee());
        }
        BDD newbdd = netlist.getFac().one();
        for (NetlistVariable var : firstlevelands) {
            Signal sig = netlist.getSignalByNetlistVariable(var);
            boolean pos = true;
            if (sig != null) {
                pos = posnegmap.get(sigmap.get(sig));
            }

            if (pos) {
                newbdd = newbdd.and(var.toBDD());
            } else {
                newbdd = newbdd.and(var.toNotBDD());
            }
        }
        netlist.alterTermBDD(term, newbdd);
        //      new NetlistGraph(netlist, Arrays.asList("rD_9"), true);
    }

    private boolean checkConstant(List<IOBehaviour> constant, Map<Integer, List<Partition>> partitions) {

        List<Partition> rmPart = new ArrayList<>();
        List<Integer> rmKey = new ArrayList<>();
        for (Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
            for (Partition part : entry.getValue()) {
                boolean forcebreak = false;
                for (IOBehaviour beh : constant) {
                    for (PartitionPart partpart : part.getPartition()) {
                        BDD partbdd = partpart.getBdd();
                        List<Boolean> result = evaluateBDD(partbdd, beh.getStart(), beh.getSequence());
                        if (result == null) {
                            logger.error("Problem while eval bdd");
                            return false;
                        }
                        boolean curr = result.get(0);
                        int changes = 0;
                        for (boolean r : result) {
                            if (curr != r) {
                                changes++;
                                curr = r;
                            }
                        }
                        if (changes > 0) {
                            rmPart.add(part);
                            //logger.error("Changes in constant");
                            //return false;
                            break;
                        }
                    }
                    if (forcebreak) {
                        break;
                    }
                }
            }
            entry.getValue().removeAll(rmPart);
            if (entry.getValue().isEmpty()) {
                rmKey.add(entry.getKey());
            }
        }
        for (int i : rmKey) {
            partitions.remove(i);
        }
        return true;
    }

    private boolean checkRising(List<IOBehaviour> rising, Map<Integer, List<Partition>> partitions) {

        List<Partition> rmPart = new ArrayList<>();
        List<Integer> rmKey = new ArrayList<>();
        for (Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
            for (Partition part : entry.getValue()) {
                boolean forcebreak = false;
                for (IOBehaviour beh : rising) {
                    for (PartitionPart partpart : part.getPartition()) {
                        BDD partbdd = partpart.getBdd();
                        List<Boolean> result = evaluateBDD(partbdd, beh.getStart(), beh.getSequence());
                        if (result == null) {
                            logger.error("Problem while eval bdd");
                            return false;
                        }
                        //                  System.out.println(beh.getSequence().toString());
                        //                  System.out.println(result.toString());
                        boolean curr = result.get(0);
                        int changes = 0;
                        for (boolean r : result) {
                            if (curr != r) {
                                changes++;
                                curr = r;
                            }
                        }
                        if (changes > 1) {
                            rmPart.add(part);
                            //logger.error("Non monotous changes in rising: " + beh.toString());
                            //return false;
                            break;
                        }
                    }
                    if (forcebreak) {
                        break;
                    }
                }
            }
            entry.getValue().removeAll(rmPart);
            if (entry.getValue().isEmpty()) {
                rmKey.add(entry.getKey());
            }
        }
        for (int i : rmKey) {
            partitions.remove(i);
        }
        return true;
    }

    private void setPartitionBDDs(Map<Integer, List<Partition>> partitions, Map<Signal, Boolean> posnegmap) {
        for (Entry<Integer, List<Partition>> entry : partitions.entrySet()) {
            for (Partition p : entry.getValue()) {
                for (PartitionPart part : p.getPartition()) {
                    BDD partbdd = factory.one();
                    for (Signal sig : part.getPart()) {
                        BDD sig2bdd = null;
                        boolean posneg = posnegmap.get(sig);
                        if (posneg) {
                            sig2bdd = getPosBDD(sig);
                        } else {
                            sig2bdd = getNegBDD(sig);
                        }
                        partbdd = partbdd.andWith(sig2bdd);
                    }
                    part.setBdd(partbdd);
                }
            }
        }
    }

    private BDD getPosBDD(Signal sig) {
        if (!sigidmap.containsKey(sig)) {
            sigidmap.put(sig, factory.extVarNum(1));
        }
        return factory.ithVar(sigidmap.get(sig));
    }

    private BDD getNegBDD(Signal sig) {
        if (!sigidmap.containsKey(sig)) {
            sigidmap.put(sig, factory.extVarNum(1));
        }
        return factory.nithVar(sigidmap.get(sig));
    }

    private Map<Signal, Boolean> getInputsPosOrNeg(NetlistTerm term, Map<Signal, Signal> sigmap) {
        Map<Signal, Boolean> posnegmap = new HashMap<>();
        for (NetlistVariable var : BDDHelper.getVars(term.getBdd(), netlist)) {
            Boolean b = BDDHelper.isPos(term.getBdd(), var);
            if (b == null) {
                logger.error("PosNeg error");
                return null;
            }
            Signal tmpsig = netlist.getSignalByNetlistVariable(var);
            if (tmpsig == null) {
                if (netlist.getQuasiSignals().keySet().contains(var)) {
                    if (!quasimap.containsKey(var)) {
                        quasimap.put(var, new QuasiSignal(var.getName()));
                    }
                    tmpsig = quasimap.get(var);
                    if (!sigmap.containsKey(tmpsig)) {
                        sigmap.put(tmpsig, tmpsig);
                    }
                } else {
                    logger.error("And input is not a Signal");
                    return null;
                }
            }
            posnegmap.put(sigmap.get(tmpsig), b);
        }
        return posnegmap;
    }

    private Map<Integer, List<Partition>> getPartitions(Set<Signal> signals, int startgatesize) {
        // cost function
        SortedMap<Integer, List<Partition>> retVal = new TreeMap<>(Collections.reverseOrder());
        Set<Set<Set<Signal>>> parts = getTailCombinations(signals);
        if (parts == null) {
            return null;
        }
        for (Set<Set<Signal>> partition : parts) {
            int cost = 0;
            Set<PartitionPart> parts2 = new HashSet<>();
            for (Set<Signal> partpart : partition) {
                parts2.add(new PartitionPart(partpart));
                if (partpart.size() != 1) {
                    cost += partpart.size();
                }
            }
            if (partition.size() != 1) {
                cost += partition.size();
            }

            if (!retVal.containsKey(cost)) {
                retVal.put(cost, new ArrayList<Partition>());
            }
            retVal.get(cost).add(new Partition(parts2, cost));
        }

        //      System.out.println("Startgatesize: " + startgatesize);
        // filter too large
        List<Partition> rmPart = new ArrayList<>();
        List<Integer> rmKey = new ArrayList<>();
        for (Entry<Integer, List<Partition>> entry : retVal.entrySet()) {
            //         System.out.println(entry.getKey());
            rmPart.clear();
            for (Partition p : entry.getValue()) {
                //            System.out.println("\t" + p.toString());
                if (p.getPartition().size() >= startgatesize) {
                    //               System.out.println("Rm: " + p);
                    rmPart.add(p);
                    continue;
                }
                for (PartitionPart p2 : p.getPartition()) {
                    if (p2.getPart().size() >= startgatesize) {
                        //                  System.out.println("Rm: " + p);
                        rmPart.add(p);
                        continue;
                    }
                }
            }
            entry.getValue().removeAll(rmPart);
            if (entry.getValue().isEmpty()) {
                rmKey.add(entry.getKey());
            }
        }
        for (int i : rmKey) {
            retVal.remove(i);
        }

        return retVal;
    }

    private Set<Set<Set<Signal>>> getTailCombinations(Set<Signal> sigs) {
        try {
            Set<Set<Set<Signal>>> retVal = new HashSet<>();
            for (Set<Signal> s : Sets.powerSet(sigs)) {
                if (s.isEmpty()) {
                    continue;
                }
                SetView<Signal> diff = Sets.difference(sigs, s);
                if (diff.isEmpty()) {
                    Set<Set<Signal>> tmp = new HashSet<>();
                    tmp.add(s);
                    retVal.add(tmp);
                } else {
                    Set<Set<Set<Signal>>> tail = getTailCombinations(diff);
                    for (Set<Set<Signal>> x : tail) {
                        Set<Set<Signal>> tmp = new HashSet<>();
                        tmp.add(s);
                        for (Set<Signal> s2 : x) {
                            tmp.add(s2);
                        }
                        retVal.add(tmp);
                    }
                }
            }
            return retVal;
        } catch (IllegalArgumentException e) {
            logger.error(e.getLocalizedMessage());
            return null;
        }
    }

    private List<List<Signal>> getPossiblePartitionsFromFalling(List<IOBehaviour> falling, Set<Signal> relevant) {
        List<List<Signal>> partitions = new ArrayList<>();
        for (Signal sig : relevant) {
            List<Signal> tmp = new ArrayList<>();
            tmp.add(sig);
            partitions.add(tmp);
        }
        for (IOBehaviour beh : falling) {
            List<Signal> currlist = null;
            for (Transition t : beh.getSequence()) {
                Signal sig2 = t.getSignal();
                if (relevant.contains(sig2)) {
                    if (currlist == null) {
                        currlist = findInPartions(partitions, sig2);
                    } else {
                        List<Signal> second = findInPartions(partitions, sig2);
                        if (currlist == second) {
                            continue;
                        }
                        currlist.addAll(second);
                        partitions.remove(second);
                    }
                }
            }
        }
        return partitions;
    }

    private Set<Signal> findRelevantSigs(BDD bdd) {
        Set<Signal> relevant = new HashSet<>();
        int id = 0;
        for (int val : bdd.varProfile()) {
            if (val == 1) {
                Signal sig = netlist.getSignalByBddId(id);
                if (sig == null) {
                    NetlistVariable pseudosig = netlist.getNetlistVariableByBddId(id);
                    if (!netlist.getQuasiSignals().keySet().contains(pseudosig)) {
                        logger.error("And Input " + pseudosig.getName() + " is not a Signal");
                        return null;
                    }
                } else {
                    relevant.add(sig);
                }
            } else if (val > 1) {
                logger.warn("BDD var > 1");
            }
            id++;
        }
        return relevant;
    }

    private boolean categoriseSequences(BDD bdd, SortedSet<IOBehaviour> sequences, List<IOBehaviour> falling,
            List<IOBehaviour> rising, List<IOBehaviour> constant) {
        for (IOBehaviour beh : sequences) {
            BDD startBDD = bdd;
            MutableBoolean resultStart = new MutableBoolean();
            if (!evaluateBDD(resultStart, startBDD, beh.getStart())) {
                logger.error("Something went wrong");
                return false;
            }
            BDD endBDD = bdd;
            MutableBoolean resultEnd = new MutableBoolean();
            if (!evaluateBDD(resultEnd, endBDD, beh.getEnd())) {
                logger.error("Something went wrong");
                return false;
            }

            if (resultStart.isTrue() && resultEnd.isFalse()) {
                falling.add(beh);
                //System.out.println("uups? falling?");
            } else if (resultStart.isFalse() && resultEnd.isTrue()) {
                rising.add(beh);
            } else if (resultStart.isFalse() && resultEnd.isFalse()) {
                constant.add(beh);
            } else {
                logger.error("Const 1 should not happen");
                return false;
            }
            //System.out.println(resultStart.booleanValue() + "=>" + resultEnd.booleanValue() + " : " + beh);
        }
        return true;
    }

    private void removeSubSequences(SortedSet<IOBehaviour> sequencesFront, SortedSet<IOBehaviour> sequencesBack,
            Set<IOBehaviour> newSequences, Set<IOBehaviour> rmSequences) {
        rmSequences.clear();
        sequencesFront.addAll(newSequences);
        Iterator<IOBehaviour> it = sequencesFront.iterator();
        if (!it.hasNext()) {
            //TODO: why?
            return;
        }
        IOBehaviour curr = it.next();
        while (it.hasNext()) {
            IOBehaviour next = it.next();
            if (newSequences.contains(curr)) {
                if (curr.getStart().compareTo(next.getStart()) == 0) {
                    int i = 0;
                    while (true) {
                        if (curr.getSequence().size() == i) {
                            rmSequences.add(curr);
                            break;
                        }
                        //System.out.println(curr.toString() + " vs " + next.toString());
                        int cmpT = curr.getSequence().get(i).compareTo(next.getSequence().get(i));
                        if (cmpT != 0) {
                            break;
                        }
                        //gleich, check next trans
                        i++;
                    }
                }
            }
            curr = next;
        }
        newSequences.removeAll(rmSequences);
        sequencesBack.addAll(newSequences);
        it = sequencesBack.iterator();
        curr = it.next();
        while (it.hasNext()) {
            IOBehaviour next = it.next();
            if (newSequences.contains(curr)) {
                if (curr.getEnd().compareTo(next.getEnd()) == 0) {
                    int i = 0;
                    while (true) {
                        if (curr.getSequence().size() == i) {
                            rmSequences.add(curr);
                            break;
                        }
                        int cmpT = curr.getSequence().get(curr.getSequence().size() - i - 1)
                                .compareTo(next.getSequence().get(next.getSequence().size() - i - 1));
                        if (cmpT != 0) {
                            break;
                        }
                        //gleich, check next trans
                        i++;
                    }
                }
            }
            curr = next;
        }
    }

    private List<Signal> findInPartions(List<List<Signal>> partitions, Signal sig) {
        for (List<Signal> list : partitions) {
            if (list.contains(sig)) {
                return list;
            }
        }
        logger.error("Variable " + sig.getName() + " not found");
        return null;
    }

    private List<Boolean> evaluateBDD(BDD bddParam, State startState, List<Transition> sequence) {
        List<Boolean> retVal = new ArrayList<>();
        for (int i = sequence.size() - 1; i >= 0; i--) {
            BDD bdd = bddParam.or(factory.zero());
            ListIterator<Transition> it = sequence.listIterator(sequence.size() - i);
            List<Signal> alreadyset = new ArrayList<>();
            while (it.hasPrevious()) {
                BDD sigbdd = null;
                Transition t = it.previous();
                if (!alreadyset.contains(t.getSignal())) {
                    switch (t.getEdge()) {
                    case falling:
                        sigbdd = getNegBDD(t.getSignal());
                        break;
                    case rising:
                        sigbdd = getPosBDD(t.getSignal());
                        break;
                    }
                    bdd = bdd.restrictWith(sigbdd);
                    alreadyset.add(t.getSignal());
                }
            }

            for (Entry<Signal, Value> entry : startState.getStateValues().entrySet()) {
                if (!alreadyset.contains(entry.getKey())) {
                    BDD sigbdd = null;
                    switch (entry.getValue()) {
                    case falling:
                    case high:
                        sigbdd = getPosBDD(entry.getKey());
                        break;
                    case low:
                    case rising:
                        sigbdd = getNegBDD(entry.getKey());
                        break;
                    }
                    bdd = bdd.restrictWith(sigbdd);
                }
            }
            for (Entry<NetlistVariable, Boolean> entry : netlist.getQuasiSignals().entrySet()) {
                BDD sigbdd = null;
                if (entry.getValue()) {
                    //true => Normally 1
                    sigbdd = getPosBDD(quasimap.get(entry.getKey()));
                } else {
                    sigbdd = getNegBDD(quasimap.get(entry.getKey()));
                }
                bdd = bdd.restrictWith(sigbdd);
            }

            if (bdd.isOne()) {
                retVal.add(true);
            } else if (bdd.isZero()) {
                retVal.add(false);
            } else {
                logger.error("BDD not restricted enough?!");
                return null;
            }
        }

        return retVal;
    }

    private boolean evaluateBDD(MutableBoolean result, BDD bdd, State state) {
        BDD bdd2 = bdd.and(factory.one());
        for (Entry<Signal, Value> entry : state.getStateValues().entrySet()) {
            BDD sigbdd = null;
            switch (entry.getValue()) {
            case falling:
            case high:
                sigbdd = getPosBDD(entry.getKey());
                break;
            case low:
            case rising:
                sigbdd = getNegBDD(entry.getKey());
                break;
            }
            bdd2 = bdd2.restrictWith(sigbdd);
        }
        for (Entry<NetlistVariable, Boolean> entry : netlist.getQuasiSignals().entrySet()) {
            BDD sigbdd = null;
            if (entry.getValue()) {
                //true => Normally 1
                sigbdd = getPosBDD(quasimap.get(entry.getKey()));
            } else {
                sigbdd = getNegBDD(quasimap.get(entry.getKey()));
            }
            bdd2 = bdd2.restrictWith(sigbdd);
        }

        if (bdd2.isOne()) {
            result.setTrue();
        } else if (bdd2.isZero()) {
            result.setFalse();
        } else {
            System.out.println(BDDHelper.getFunctionString(bdd2, netlist));
            logger.error("BDD not restricted enough?!");

            return false;
        }
        return true;
    }

    private void getNewSteps(IOBehaviourSimulationStep step, Signal sig, Set<IOBehaviour> newSequences,
            Deque<IOBehaviourSimulationStep> newSteps, Set<Signal> relevant) {

        int occurrences = Collections.frequency(step.getStates(), step.getNextState());
        if (occurrences >= 2) {
            boolean isLoop = false;
            int[] a = new int[occurrences];
            int index = 0;
            for (int i = step.getStates().size() - 1; i >= 0; i--) {
                if (step.getStates().get(i) == step.getNextState()) {
                    a[index++] = i;
                }
            }

            Map<Integer, List<State>> lists = new HashMap<>();

            int endindex = step.getStates().size();
            List<State> xlist = null;
            for (int startindex : a) {
                xlist = step.getStates().subList(startindex, endindex);
                lists.put(endindex, xlist);
                endindex = startindex;
            }

            boolean finished = false;
            int smallesidloop = -1;
            for (Entry<Integer, List<State>> l1 : lists.entrySet()) {
                for (Entry<Integer, List<State>> l2 : lists.entrySet()) {
                    if (l1.getKey() != l2.getKey()) {
                        if (l1.getValue().equals(l2.getValue())) {
                            //                     System.out.println("loop: listmatch!");
                            isLoop = true;
                            smallesidloop = l1.getKey() < l2.getKey() ? l1.getKey() : l2.getKey();
                            xlist = l1.getValue();
                            finished = true;
                            break;
                        }
                    }
                }
                if (finished) {
                    break;
                }
            }

            if (isLoop) {
                //            System.out.println("Loop: " + xlist + ", listsize: " + lists.size());
                //            System.out.println("Smallestid : " + smallesidloop + ", size: " + step.getStates().size());
                step.findStateAndClean(step.getStates().size() - smallesidloop - 1, pool, newSteps);
                return;
            }
        }

        for (Entry<Transition, State> entry : step.getNextState().getNextStates().entrySet()) {
            //System.out.println(entry.toString());
            if (entry.getKey().getSignal() == sig) {
                List<Transition> seq = new ArrayList<>(step.getSequence());
                IOBehaviour beh = new IOBehaviour(seq, step.getStart(), step.getNextState());
                newSequences.add(beh);
            } else {
                IOBehaviourSimulationStep newStep;
                try {
                    newStep = pool.borrowObject();
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error("Could not borrow object");
                    return;
                }
                newStep.getSequence().addAll(step.getSequence());
                if (relevant.contains(entry.getKey().getSignal())) {
                    newStep.getSequence().add(entry.getKey());
                }
                newStep.setStart(step.getStart());
                newStep.setNextState(entry.getValue());
                newStep.getStates().addAll(step.getStates());
                newStep.getStates().add(step.getNextState());
                newStep.setPrevStep(step);
                step.getNextSteps().add(newStep);
                newSteps.add(newStep);
            }
        }
        step.killIfCan(pool);
    }
}