Skip to content
Snippets Groups Projects
Nloc.java 22.5 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));
            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);
            }
          }
          if (oldSeqTupListLen < s1.size()) {
            s1.clear();
            suitableHeaderFound = false;
          }
        }
      } 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> getShortestSequenceExhaustive(String[] modulesToVisit) {
    List<List<SequenceTuple>> possibleSequences;
    List<Droplet> dropletSequence = null;
      possibleSequences = getPossibleSequencesExhaustive(modulesToVisit);
      // sort the list of possible sequences according to the sequences length
      possibleSequences.sort((a,b) -> a.size() - b.size());

      do {

        pump.removeAllDroplets();
        currentSeq = possibleSequences.remove(0);
        //System.out.println("Working on sequence");
        //for (SequenceTuple stup: currentSeq) {
        //  if (currentSeq.indexOf(stup) == (currentSeq.size() - 1)) {
        //    System.out.print(stup.getDroplet().getName() + ": " + stup.getMinPos() + ":" + stup.getMaxPos() + " : " + stup.getPath().get(1).getName());
        //  } else { 
        //    System.out.print(stup.getDroplet().getName() + ": " + stup.getMinPos() + ":" + stup.getMaxPos() + " : " + stup.getPath().get(1).getName() + " -> ");
        //  }
        //}
        //System.out.println("\n");

        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);
          !(dropletSequence.size() == currentSeq.size() &&
            this.sequenceFunctional()));

      if (dropletSequence.size() != currentSeq.size()) {
    } catch(NoSuchModuleException nsme) {
      System.out.println(nsme.getMessage());
  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>> getPossibleSequencesExhaustive(
    String[] modulesToVisit) 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(
Peter Wagenhuber's avatar
Peter Wagenhuber committed
              this.computeSequences(stl));
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() {
      try {
        this.moveDroplets();
      } catch (CoalescedDropletException e) {
        works = false;
        //System.out.println("Coalesce! Droplet: " + e.getDroplet().getName() + " Position: " + e.getDroplet().getPosition().getChannel().getName());
  public List<Droplet> getDropletList() {
    return dropletList;
  }

  public void moveDroplets() throws CoalescedDropletException {
    Droplet[] drArr = this.dropletList.toArray(new Droplet[dropletList.size()]);
    for (Droplet dr : drArr) {
    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);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
  public List<List<SequenceTuple>> computeSequences(List<SequenceTuple> seqTup){
    List<List<SequenceTuple>> seqTupList = new ArrayList<List<SequenceTuple>>();
    //SequenceTuple currentSeqTup = seqTup.get(0);
    getSequencesAtBifurcationRecursive(seqTup, 0, seqTupList);
    //System.out.println("returning " + seqTupList);
Peter Wagenhuber's avatar
Peter Wagenhuber committed
  }

  private void getSequencesAtBifurcationRecursive(
      List<SequenceTuple> seqTupList, int currentSeqTupIndex, 
Peter Wagenhuber's avatar
Peter Wagenhuber committed
      List<List<SequenceTuple>> possibleSequences) {

    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());
          List<SequenceTuple> tmp = new ArrayList<SequenceTuple>();
          for (SequenceTuple stup: seqTupList) {
            tmp.add(new SequenceTuple(stup));
          }
          String randHeaderName = 
            "h-" + ThreadLocalRandom.current().nextInt(1000, 10000);
            new SequenceTuple(new Droplet(DropletType.HEADER,randHeaderName),
                path, currentBifurcation);
Peter Wagenhuber's avatar
Peter Wagenhuber committed

          tmpTuple.setCurrentBifurcation(tmpTuple.getPreviousBifurcation());
          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);
      } else if (!(currentBifurcation instanceof Pump)) {
        // we still have some bifurcations to check
        currentSeqTup.
          setCurrentBifurcation(currentSeqTup.getPreviousBifurcation());
        getSequencesAtBifurcationRecursive(seqTupList, currentSeqTupIndex,
            possibleSequences);
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());

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

          tmpTuple.setCurrentBifurcation(tmpTuple.getPreviousBifurcation());

          tmp.add(seqTupList.indexOf(currentSeqTup) + 1, 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);

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

      }