Skip to content
Snippets Groups Projects
Nloc.java 23 KiB
Newer Older
package nloc;

import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.concurrent.ThreadLocalRandom;

public class Nloc {
Peter Wagenhuber's avatar
Peter Wagenhuber committed
  public static final int MIN_TIMEDIFF = 0;
  private List<Channel> chanlist;
  private List<Droplet> dropletList;

  public Nloc (List<Channel> chanlist) {
    this.chanlist = chanlist;
    this.dropletList = new ArrayList<Droplet>();
  }

  public List<Droplet> 
    getShortestSequenceOnlyDefaultPathHeader(String [] modulesToVisit) {
    
    // start at last bifrucation of payload droplet and move up all bifurcatons
    // while adding header droplets that only have paths with default channels 
    // at bifurcations

    // the list representing the sequence //
    List<Droplet> dropletSequence = null;
    Pump pump = this.getPump();
    List<List<Channel>> pathlist = this.getAllPaths();
    List<Channel> moduleChanList = null; 
    List<Channel> payloadPath = null;

    try {
      moduleChanList = this.getModulesByName(Arrays.asList(modulesToVisit));
      payloadPath = this.getDesiredPath(moduleChanList, pathlist);
    } catch (Exception e) {
      System.out.println(e.getMessage());
      System.exit(1);
    }
    
    // set up initial list of sequence tuples
    Droplet payloadDroplet = new Droplet(DropletType.PAYLOAD,"p");
    SequenceTuple payldTuple = new SequenceTuple(payloadDroplet,payloadPath,0,0);
    Channel previousBifurcation = payldTuple.getPreviousBifurcation();
    payldTuple.setCurrentBifurcation(previousBifurcation);
    List<SequenceTuple> s1 = new ArrayList<SequenceTuple>();
    s1.add(payldTuple);

    /* while still bifurcatins to cover (bifurcation not pump) ascend along 
     * the path of bifurcations of payload droplet and add header droplets 
     * that only take default paths at bifurcations
     * if no header droplet found that only takes default paths stop and 
     * return empty list droplets indicating no suitable sequence found
     */

    boolean suitableHeaderFound = true;
    do {
      Channel currentBifurcation = payldTuple.getCurrentBifurcation();
      // check if header droplet needed
      Channel bifurcSuccessor  = 
        payloadPath.get(payloadPath.indexOf(currentBifurcation) + 1);

      Channel bifurcationDefaultPath = 
        currentBifurcation.getChildrenList().get(0);

      // bifurcation priority: prio = 0 if default channel; prio >= 1 if not 
      // default and threrfore header droplet needed
      int prio = currentBifurcation.getChildrenList().indexOf(bifurcSuccessor);

      if (prio > 0) {
        // we need a header droplet

        // get list of all possible header paths
        List<List<Channel>> possibleHeaderPathlist = this.getAllPathsFromTo(
            pump,bifurcationDefaultPath);

        // find header droplets with only default pahts
        List<SequenceTuple> headersWithDefaultPaths = 
          new ArrayList<SequenceTuple>();

        for (List<Channel> path: possibleHeaderPathlist) {

          if (this.pathOnlyContainsDefaults(path)) {
            String randHeaderName = 
              "h-" + ThreadLocalRandom.current().nextInt(1000, 10000);
            SequenceTuple tmpTuple = 
              new SequenceTuple(new Droplet(DropletType.HEADER,randHeaderName),
                  path, currentBifurcation);
            headersWithDefaultPaths.add(tmpTuple);

            // calculate and set pump offsets

            List<Channel> payloadPathToCurrentBifurcation = 
              payloadPath.subList(0,payloadPath.indexOf(currentBifurcation) + 1);
            int pathLenPayloadDroplet = this.getPayloadPathlength(
                payloadPathToCurrentBifurcation);

            int maxPathLenNewDroplet = getHeaderPathlength(path);
            int minPathLenNewDroplet = 
              maxPathLenNewDroplet - bifurcationDefaultPath.getHSteps() + 1;

            int newTupleMinPos = minPathLenNewDroplet - pathLenPayloadDroplet;
            int newTupleMaxPos = maxPathLenNewDroplet - pathLenPayloadDroplet;

            tmpTuple.setMinPos(newTupleMinPos);
            tmpTuple.setMaxPos(newTupleMaxPos);
          }
        }
        if (headersWithDefaultPaths.isEmpty()) {
          // if no header with default path is found empty sequencetuple list
          // and stop the search
          s1.clear();
          suitableHeaderFound = false;
        } else {
          int oldSeqTupListLen = s1.size();
          for (SequenceTuple hstup: headersWithDefaultPaths) {
            if (!SequenceTuple.conflictingOffsets(hstup, s1)) {
              s1.add(hstup);
              break;
          if ( !(payldTuple.getCurrentBifurcation() instanceof Pump) &&
              oldSeqTupListLen >= s1.size()) {
            s1.clear();
            suitableHeaderFound = false;
          }
        payldTuple.setCurrentBifurcation(payldTuple.getPreviousBifurcation());
      } else {
        // no header needed just ascend to next bifurcation
        payldTuple.setCurrentBifurcation(payldTuple.getPreviousBifurcation());
      }
    } while (suitableHeaderFound && 
        !(payldTuple.getCurrentBifurcation() instanceof Pump));


    if (!s1.isEmpty()) {

      int min = 0, max = 0;
      for (SequenceTuple stl: s1) {
        int tmp = stl.getMinPos();
        if (tmp > max) max = tmp;
        if (tmp < min) min = tmp;
      }
      int span = max - min;
      pump.setSteps(span);

      s1 = setTuplePumpoffsetToPumpPosition(s1, min);

      dropletSequence = generateDropletListRecursive(new ArrayList<Droplet>(), 
          s1, s1.get(0).getMinPos());
    }
    return dropletSequence;
  public List<Droplet> getShortestSequence(String[] modulesToVisit,
      SequenceGenerationMode mode) {
    List<Droplet> dropletSequence = null;
    if (mode == SequenceGenerationMode.ONLYDEFAULT) {
      dropletSequence = getShortestSequenceOnlyDefaultPathHeader(modulesToVisit);
    } else {
      Pump pump = this.getPump();
      List<List<SequenceTuple>> possibleSequences;
      List<SequenceTuple> currentSeq;
      List<List<Channel>> pathlist = this.getAllPaths();
      List<Channel> moduleChanList; 
      List<Channel> payloadPath; 
      try {
        moduleChanList =  this.getModulesByName(Arrays.asList(modulesToVisit));
        payloadPath = this.getDesiredPath(moduleChanList, pathlist);
        possibleSequences = getPossibleSequences(modulesToVisit, mode);
        // sort the list of possible sequences according to the sequences length
        possibleSequences.sort((a,b) -> a.size() - b.size());
          pump.removeAllDroplets();
          currentSeq = possibleSequences.remove(0);
          int min = 0, max = 0;
          for (SequenceTuple stl: currentSeq) {
            int tmp = stl.getMinPos();
            if (tmp > max) max = tmp;
            if (tmp < min) min = tmp;
          }
          int span = max - min;
          pump.setSteps(span);
          currentSeq = setTuplePumpoffsetToPumpPosition(currentSeq, min);
          dropletSequence = generateDropletListRecursive(new ArrayList<Droplet>(), currentSeq, currentSeq.get(0).getMinPos());
          currentSeq = resetPayloadDropletPosition(currentSeq);
        } while (!possibleSequences.isEmpty() && 
            !(dropletSequence.size() == currentSeq.size() &&
              this.sequenceFunctional(payloadPath)));

        if (dropletSequence.size() != currentSeq.size()) {
          dropletSequence.clear();
        }
      } catch(NoSuchModuleException nsme) {
        System.out.println(nsme.getMessage());
        System.exit(1);
      } catch(NlocStructureException nse) {
        System.out.println(nse.getMessage());
        System.exit(1);
      }

    }
  public boolean pathOnlyContainsDefaults(List<Channel> path) {
    boolean onlyDefaults = true;
    for (Channel ch: path) {
      if (ch.isBifurcation()) {
        onlyDefaults &= path.contains(ch.getChildrenList().get(0));
      }
    }
    return onlyDefaults;
  }

  public void setDropletList(List<Droplet> dropletList) {
    this.dropletList = dropletList;
  }

  public List<SequenceTuple> resetPayloadDropletPosition(
      List<SequenceTuple> currentSequence) {

    for (SequenceTuple stup: currentSequence) {
      if (stup.getDroplet().getType() == DropletType.PAYLOAD) {
        stup.setMinPos(0);
        stup.setMaxPos(0);
      }
    }
    return currentSequence;
  }

  public List<SequenceTuple> setTuplePumpoffsetToPumpPosition(
      List<SequenceTuple> currentSequence, int minOffset) {

    for (SequenceTuple stup: currentSequence) {
      int pumpOffsetMin = stup.getMinPos();
      stup.setMinPos(pumpOffsetMin + Math.abs(minOffset));

      int pumpOffsetMax = stup.getMaxPos();
      stup.setMaxPos(pumpOffsetMax + Math.abs(minOffset));
    }
  public List<Droplet> generateDropletListRecursive(
      List<Droplet> dropletList, List<SequenceTuple> currentSequence, 
      int currentPos) {

    if (dropletList.size() == currentSequence.size()) {
      return dropletList;
    } else {

      if (dropletList.isEmpty() || 
          !Position.isOccupied(dropletList, currentPos)) {

        SequenceTuple tmpTup = currentSequence.get(dropletList.size());
        Droplet tmpDr = tmpTup.getDroplet();

        tmpDr.setPosition(new Position(this.getPump(), currentPos));
        Channel pumpOutlet = tmpTup.getPumpOutlet();
        tmpDr.setPumpOutlet(pumpOutlet);

        dropletList.add(tmpDr);
        // set current pos to minimum of the following sequence tuple
        if (dropletList.size() < currentSequence.size()) {
          currentPos = 
            currentSequence.get(dropletList.size()).getMinPos();
        }

        return generateDropletListRecursive(dropletList, currentSequence,
            currentPos);
      } else {
        SequenceTuple tmpTup = currentSequence.get(dropletList.size());
        if (currentPos < tmpTup.getMaxPos()) {
          currentPos++;
          return generateDropletListRecursive(dropletList, currentSequence,
              currentPos);
        } else {
          ListIterator<Droplet> revIter = dropletList.listIterator(
              dropletList.size());

          boolean found = false;
          while (!found && revIter.hasPrevious()) {
            Droplet tmpDr = revIter.previous();
            SequenceTuple tmpTup1 = currentSequence.get(dropletList.size() - 1);

            if (tmpDr.getPosition().getSteps() == currentPos &&
                currentPos < tmpTup1.getMaxPos()) {
              found = true;
            }
          }
          if (found) {
            currentPos++;
            return generateDropletListRecursive(dropletList, currentSequence,
                currentPos);
          } else {
            return dropletList;
          }
  public List<List<SequenceTuple>> getPossibleSequences(
    String[] modulesToVisit, SequenceGenerationMode mode) throws NoSuchModuleException {

    Droplet payloadDroplet = new Droplet(DropletType.PAYLOAD,"p");

    List<List<SequenceTuple>> sequences = new ArrayList<List<SequenceTuple>>();

    List<List<Channel>> pathlist = this.getAllPaths();
    try {
      // Create initial list of possilbe sequences
      List<Channel> moduleChanList = 
        this.getModulesByName(Arrays.asList(modulesToVisit));
      List<Channel> payloadPath = this.getDesiredPath(moduleChanList, pathlist);

      SequenceTuple plt = new SequenceTuple(payloadDroplet,payloadPath,0,0);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
      Channel previousBifurcation = plt.getPreviousBifurcation();
      plt.setCurrentBifurcation(previousBifurcation);
      List<SequenceTuple> s1 = new ArrayList<SequenceTuple>();
      s1.add(plt);

      sequences.add(s1);

Peter Wagenhuber's avatar
Peter Wagenhuber committed
      List<List<SequenceTuple>> oldsequences;
      do {
        oldsequences = new ArrayList<List<SequenceTuple>>(sequences);
        List<List<SequenceTuple>> tmpSeqs = new ArrayList<List<SequenceTuple>>();
        for (List<SequenceTuple> stl: sequences) {
          tmpSeqs.addAll(
              this.computeSequences(stl, mode));
Peter Wagenhuber's avatar
Peter Wagenhuber committed
      } while (sequences.size() != oldsequences.size());
    } catch (Exception e) {
      System.out.println( e.getMessage());
    }
  public void addChannel(Channel chan) {
    chanlist.add(chan);
  }

  public Sink getSink() {
    Sink sink = null;
    for (Channel chan : chanlist) {
      if (chan instanceof Sink) sink = (Sink)chan;
    }
    return sink;
  }

  public Pump getPump() {
    Pump pump = null;
    for (Channel chan : chanlist) {
      if (chan instanceof Pump) pump = (Pump)chan;
    }
    return pump;
  }

  public boolean sequenceFunctional(List<Channel> payloadPath) {
        this.moveDroplets(payloadPath);
      } catch (CoalescedDropletException e) {
        works = false;
        //System.out.println("Coalesce! Droplet: " + e.getDroplet().getName() + " Position: " + e.getDroplet().getPosition().getChannel().getName());
      } catch (PayloadPathIncorrectException exc) {
        works = false;
        System.out.println("Payload path not correct");
        break;
  public List<Droplet> getDropletList() {
    return dropletList;
  }

  public void moveDroplets(List<Channel> payloadPath) 
    throws CoalescedDropletException, PayloadPathIncorrectException {

    Droplet[] drArr = this.dropletList.toArray(new Droplet[dropletList.size()]);
    for (Droplet dr : drArr) {
      if (dr.getType() == DropletType.PAYLOAD) {
        if (payloadPath.contains(dr.getPosition().getChannel())) {
          throw new PayloadPathIncorrectException();
        }
      }
    for (Droplet dr: drArr) {
      if (dr.coalesce()) {
        throw new CoalescedDropletException(dr);
      }
  public List<Channel> getBifurcationList(List<Channel> desiredPath) {
    List<Channel> bfList = new ArrayList<Channel>();

    for (Channel ch: desiredPath) {
      if (ch.isBifurcation()) {
  public static int getPayloadPathlength(List<Channel> path) {
    int len = 0;
    for (Channel ch: path) {
      len += ch.getPSteps(); 
    }
    return len;
  }

  public static int getHeaderPathlength(List<Channel> path) {
    int len = 0;
    for (Channel ch: path) {
      len += ch.getHSteps(); 
    }
    return len;
  }

  public boolean allDropletsInSink() {
    boolean allInSink = true;
    for (Droplet dr : dropletList) {
      allInSink &= dr.isInSink();
    }
    return allInSink;
  public List<Channel> getDesiredPath(List<Channel> modules,
      List<List<Channel>> pathlist) throws NlocStructureException {

    List<Channel> found = new ArrayList<Channel>();

    for (List<Channel> path : pathlist) {

      List<Channel> modlist = new ArrayList<Channel>();

      for (Channel ch: path) {
        if (ch instanceof Module) {
          modlist.add(ch);
        }
      }

      if (modules.equals(modlist) && found.isEmpty()) {
        found = path;
      } else if (modules.equals(modlist) && !found.isEmpty()) {
        throw new NlocStructureException("Paths are not unique!");
      }
      
    if (found.isEmpty()) {
      throw new NlocStructureException("No path found that covers all given Modules");
  public Channel getModuleByName(String name) throws NoSuchModuleException {
    Channel found = null;
    for (Channel ch: chanlist) {
      if (ch.getName().equals(name)) {
        found = ch;
      } 
    }
    if (found == null) throw new NoSuchModuleException(name);
  public List<Channel> getModulesByName(List<String> names) 
    throws NoSuchModuleException {

    List<Channel> ret = new ArrayList<Channel>();
    for (String name : names) {
      Channel ch = getModuleByName(name);
      if (name != null) {
        ret.add(ch);
  public List<List<Channel>> getAllPathsFromTo(Channel from, Channel to) {
    List<List<Channel>> pl = new ArrayList<List<Channel>>();
    List<Channel> path = new ArrayList<Channel>();
    getAllPathsRecursive(from, to, path, pl);
    return pl;
  }

  public List<List<Channel>> getAllPaths() {
    List<List<Channel>> pl = new ArrayList<List<Channel>>();
    List<Channel> path = new ArrayList<Channel>();
    getAllPathsRecursive(this.getPump(), this.getSink(), path, pl);
  private void getAllPathsRecursive(Channel chan, Channel end, List<Channel> path, List<List<Channel>> pathlist) {
      pathlist.add(path);
    } else {
      for (Channel ch : chan.getChildrenList()) {
        getAllPathsRecursive(ch, end, new ArrayList<Channel>(path), pathlist);
  public List<List<SequenceTuple>> computeSequences(List<SequenceTuple> seqTup, 
      SequenceGenerationMode mode){
    List<List<SequenceTuple>> seqTupList = new ArrayList<List<SequenceTuple>>();
    getSequencesAtBifurcationRecursive(seqTup, 0, seqTupList, mode);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
  }

  private void getSequencesAtBifurcationRecursive(
      List<SequenceTuple> seqTupList, int currentSeqTupIndex, 
      List<List<SequenceTuple>> possibleSequences, 
      SequenceGenerationMode mode) {
    SequenceTuple currentSeqTup = seqTupList.get(currentSeqTupIndex);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
    Channel currentBifurcation = currentSeqTup.getCurrentBifurcation();

    List<Channel> dropletPath = currentSeqTup.getPath();
    Channel bifurcSuccessor  = 
      dropletPath.get(dropletPath.indexOf(currentBifurcation) + 1);

    // bifurcation priority: prio = 0 if default channel; prio >= 1 if not 
    // default and threrfore header droplet needed
    int prio = currentBifurcation.getChildrenList().indexOf(bifurcSuccessor);

    if (currentSeqTup.equals(seqTupList.get(seqTupList.size() - 1))) {

      // if at last sequence tuple add another header droplet tuple if needed
      // and add the list of sequence tuples to the possible sequences list

      if (dropletPath.contains(currentBifurcation) && prio > 0 &&
          !(currentBifurcation instanceof Pump)) {

        // cirst check all possible paths of header droplets
        Channel defaultChan = currentBifurcation.getChildrenList().get(0);
          this.getAllPathsFromTo(dropletPath.get(0), defaultChan);
        currentSeqTup.
          setCurrentBifurcation(currentSeqTup.getPreviousBifurcation());
        if (mode == SequenceGenerationMode.EXHAUSTIVE) {
          for (List<Channel> path: pathList) {
            List<SequenceTuple> tmp = 
              generateNewListOfSequenceTuples(seqTupList,
                  path, currentBifurcation,  currentSeqTup, dropletPath, 
                  defaultChan);
            possibleSequences.add(tmp);
        } else if (mode == SequenceGenerationMode.RANDOMHEADER) {

          List<Channel> path =  
            pathList.get(ThreadLocalRandom.current().nextInt(0,pathList.size()));
          List<SequenceTuple> tmp = 
            generateNewListOfSequenceTuples(seqTupList,
                path, currentBifurcation,  currentSeqTup, dropletPath, 
                defaultChan);
      } else if ( !(currentBifurcation instanceof Pump)) {
        // we still have some bifurcations to check
        currentSeqTup.
          setCurrentBifurcation(currentSeqTup.getPreviousBifurcation());
        getSequencesAtBifurcationRecursive(seqTupList, currentSeqTupIndex,
            possibleSequences, mode);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
    } else {
        //possibleSequences.add(seqTupList);
      if (dropletPath.contains(currentBifurcation) && prio > 0 &&
          !(currentBifurcation instanceof Pump)) {
        // we need header droplet 

        // cirst check all possible paths of header droplets
        Channel defaultChan = currentBifurcation.getChildrenList().get(0);
        List<List<Channel>> pathList = 
          this.getAllPathsFromTo(dropletPath.get(0), defaultChan);
        currentSeqTup.
          setCurrentBifurcation(currentSeqTup.getPreviousBifurcation());
        if (mode == SequenceGenerationMode.EXHAUSTIVE) {
          for (List<Channel> path: pathList) {
            List<SequenceTuple> tmp = generateNewListOfSequenceTuples(seqTupList,
                path, currentBifurcation,  currentSeqTup, dropletPath, 
                defaultChan);
            getSequencesAtBifurcationRecursive(tmp, currentSeqTupIndex + 1, 
                possibleSequences, mode); 
        } else if (mode == SequenceGenerationMode.RANDOMHEADER) {
          List<Channel> path =  pathList.get(
              ThreadLocalRandom.current().nextInt(0,pathList.size()));
          List<SequenceTuple> tmp = generateNewListOfSequenceTuples(seqTupList,
              path, currentBifurcation,  currentSeqTup, dropletPath, 
              defaultChan);

          getSequencesAtBifurcationRecursive(tmp, currentSeqTupIndex + 1, 
              possibleSequences, mode); 
      } else if (!(currentBifurcation instanceof Pump)) {
        // we still have some bifurcations to check
        currentSeqTup.
          setCurrentBifurcation(currentSeqTup.getPreviousBifurcation());
        getSequencesAtBifurcationRecursive(seqTupList, currentSeqTupIndex,
            possibleSequences, mode);
      } else {
        getSequencesAtBifurcationRecursive(seqTupList, currentSeqTupIndex + 1, 
            possibleSequences, mode); 

  private List<SequenceTuple> generateNewListOfSequenceTuples(
      List<SequenceTuple> seqTupList, List<Channel> path, 
      Channel currentBifurcation, SequenceTuple currentSeqTup, 
      List<Channel> dropletPath, Channel defaultChan) {

    List<SequenceTuple> tmp = new ArrayList<SequenceTuple>();
    for (SequenceTuple stup: seqTupList) {
      tmp.add(new SequenceTuple(stup));
    }
    String randHeaderName = 
      "h-" + ThreadLocalRandom.current().nextInt(1000, 10000);
    SequenceTuple tmpTuple = 
      new SequenceTuple(new Droplet(DropletType.HEADER,randHeaderName),
          path, currentBifurcation);

    tmpTuple.setCurrentBifurcation(tmpTuple.getPreviousBifurcation());
    tmp.add(tmpTuple);

    // calculate and set pump offsets
    int minPos = currentSeqTup.getMinPos();
    int maxPos = currentSeqTup.getMaxPos();

    List<Channel> pathToCurrentBifurcation =
      dropletPath.subList(0,dropletPath.indexOf(currentBifurcation) + 1);

    int pathLenCurrDroplet = 0;
    if (currentSeqTup.getDroplet().getType() == DropletType.HEADER) {
      pathLenCurrDroplet = getHeaderPathlength(pathToCurrentBifurcation);
    } else {
      pathLenCurrDroplet = getPayloadPathlength(pathToCurrentBifurcation);
    }

    int maxPathLenNewDroplet = getHeaderPathlength(path);
    int minPathLenNewDroplet = 
      maxPathLenNewDroplet - defaultChan.getHSteps() + 1;

    int newTupleMinPos = 
      minPos - (pathLenCurrDroplet - minPathLenNewDroplet);
    int newTupleMaxPos = 
      maxPos - (pathLenCurrDroplet - maxPathLenNewDroplet);

    tmpTuple.setMinPos(newTupleMinPos);
    tmpTuple.setMaxPos(newTupleMaxPos);

    return tmp;
  }