Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

246
LINES

< > BotCompany Repo | #1028249 // LineComp_PairIndex_v2 with bucket list [OK]

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (3332L/21K).

fsclass LineComp_PairIndex_v2 {
  bool verbose;
  new HashMap<IntPair, PairInfo> pairInfos;
  new LinkedHashMap<S, Ch> chains;
  
  // buckets
  Bucket oneBucket = new Bucket(1), highest = oneBucket; // 1-bucket is lowest
  
  // duplicates counting didn't work for some reason...
  //int /*bucketCount = 1,*/duplicates;

  fclass PairInfo {
    IntPair pair;
    Bucket bucket;
    new LinkedHashSet<Node> nodes;
    
    *(IntPair *pair) {}
    
    public bool equals(O o) { if (o cast PairInfo) ret pair.equals(o.pair); false; }
    public int hashCode() { ret pair.hashCode(); }
  }
  
  // a bucket lists all pairs with the same number of duplicates
  // and it also knows its next-highest and next-lowest non-empty bucket
  fclass Bucket {
    Bucket higher, lower;
    int level; // number of duplicates of each IntPair in this bucket
    new LinkedHashSet<PairInfo> pairs;
    
    *(int *level) {}
    
    toString { ret "Bucket " + level + appendBracketed(nPairs(pairs)); }
    
    Bucket oneHigher() {
      if (higher != null && higher.level == level+1) ret higher;
      Bucket b = new(level+1);
      //++bucketCount;
      b.lower = this;
      b.higher = higher;
      if (highest == this) highest = b; else higher.lower = b;
      ret higher = b;
    }
    
    Bucket oneLower() {
      if (level == 1) fail("Can't go lower than oneBucket");
      if (lower.level == level-1) ret lower;
      //print("Making bucket " + (level-1) + " (lower: " + lower + ")");
      if (lower.level < 0) fail("Invalid lower bucket");
      Bucket b = new(level-1);
      //++bucketCount;
      b.higher = this;
      b.lower = lower;
      lower.higher = b;
      ret lower = b;
    }
    
    void add(PairInfo pair) {
      pairs.add(pair);
      pair.bucket = this;
    }
    
    void movePairOneHigher(PairInfo pair) {
      //if (level == 1) ++duplicates;
      
      // shortcut: just lift ourselves if we only contain one pair
      if (pairs.size() == 1 && higher != null && higher.level != level+1) {
        //print("shortcut higher");
        ret with level++;
      }
          
      oneHigher().add(pair);
      remove(pair);
    }
    
    void remove(PairInfo pair) {
      pairs.remove(pair);
      if (empty(pairs) && this != oneBucket)
        dropMe();
    }
    
    void dropMe {
      //print("Dropping " + this);
      if (level == 1) fail("Trying to drop oneBucket");
      if (nempty(pairs)) fail("Bucket still has pairs");
      if (higher != null) higher.lower = lower; else highest = lower;
      lower.higher = higher;
      level = -1; // mark invalid for safety
      //--bucketCount;
    }
    
    void movePairOneLower(PairInfo pair) {
      //if (verbose) print("Moving pair lower: " + pair);
      if (this == oneBucket) {
        remove(pair);
        forgetPair(pair);
      } else {
        //if (level == 2) --duplicates;
        
        // shortcut: just lower ourselves if we only contain one pair
        if (pairs.size() == 1 && lower.level != level-1) {
          //print("shortcut lower");
          ret with level--;
        }
          
        oneLower().add(pair);
        remove(pair);
      }
    }
  }
  
  Bucket oneBucket() { ret oneBucket; }
  
  // a "chain" of nodes (one input file)
  fclass Ch {
    Node tail;
    
    *(L<Int> l) {
      fOr (int i : l) add(i);
    }
    
    L<Int> toList() {
      new L<Int> l;
      Node node = tail;
      while (node != null) {
        l.add(node.value);
        node = node.prev;
      }
      ret reverseInPlace(l);
    }
    
    void add(int i) {
      new Node n;
      n.ch = this;
      n.value = i;
      n.prev = tail;
      if (tail != null) tail.next = n;
      tail = n;
      addToIndex(n.prev);
    }
  }
  
  fclass Node {
    Ch ch;
    int value;
    Node prev, next;
    
    int a() { ret value; }
    int b() { ret next == null ? -1 : next.value; }
    IntPair pair() { ret next == null ? null : IntPair(a(), b()); }
  }
  
  IntPair nodeToPair(Node n) {
    ret n?.pair();
  }
  
  // add node to pair index (add to lowest or move to higher bucket)
  void addToIndex(Node n) {
    IntPair p = nodeToPair(n), ret if null;
    PairInfo pi = getPairInfo(p);
    if (pi == null) {
      pi = new PairInfo(p);
      pairInfos.put(p, pi);
      oneBucket.add(pi);
    } else
      pi.bucket.movePairOneHigher(pi);
    pi.nodes.add(n);
  }
  
  // remove node from pair index (move to lower bucket or drop)
  void removeFromIndex(Node n) {
    IntPair p = nodeToPair(n), ret if null;
    PairInfo pi = getPairInfo(p);
    if (pi == null) fail("Can't remove pair " + p);
    pi.nodes.remove(n);
    pi.bucket.movePairOneLower(pi);
  }
  
  IntPair mostPopularDuplicate() {
    //if (verbose) print("Highest bucket: " + highest);
    if (highest == oneBucket) null; // no more duplicates
    PairInfo pi = first(highest.pairs);
    if (pi == null) fail("Bucket empty! " + highest);
    ret pi.pair;
  }
  
  int getCount(IntPair pair) {
    ret getPairInfo(pair).bucket.level;
  }
  
  int numberOfDuplicates() {
    //ret duplicates;
    ret l(pairInfos)-l(oneBucket.pairs);
  }
  
  void replacePair(int pa, int pb, int replaceWith) {
    IntPair p = IntPair(pa, pb);
    PairInfo pi = getPairInfo(p);
    //print("Have " + nNodes(pi.nodes));
    for (Node n : cloneList(pi.nodes)) {
      //print("Processing node " + n.pair());
      continue if n.a() != pa || n.b() != pb; // nodes might have been deleted or changed
      replacePair(n, replaceWith);
    }
  }
  
  void replacePair(Node node, int replaceWith) {
    removeFromIndex(node.prev);
    removeFromIndex(node);
    removeFromIndex(node.next);
    node.value = replaceWith;
    deleteNode(node.next);
    addToIndex(node.prev);
    addToIndex(node);
  }
  
  void deleteNode(Node node) {
    if (node.next != null) node.next.prev = node.prev; else node.ch.tail = node.prev;
    if (node.prev != null) node.prev.next = node.next;
    node.value = -1; // mark invalid
  }
  
  void newChain(S version, L<Int> encoding) {
    chains.put(version, new Ch(encoding));
  }
  
  PairInfo getPairInfo(IntPair pair) {
    ret pairInfos.get(pair);
  }
  
  void forgetPair(PairInfo pair) {
    pairInfos.remove(pair.pair);
    pair.bucket = null;
  }
  
  void fullCheck {
    assertTrue(oneBucket.lower == null);
    assertTrue(oneBucket.level == 1);
    Bucket b = highest;
    while (b != oneBucket) {
      assertNempty(b.pairs);
      assertSame(b.lower.higher, b);
      assertEquals(b.lower.level, b.level-1);
      b = b.lower;
    }
  }
}

Author comment

Began life as a copy of #1028247

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1028249
Snippet name: LineComp_PairIndex_v2 with bucket list [OK]
Eternal ID of this version: #1028249/50
Text MD5: 6bb19fb4bc37d0394e3549817c072311
Transpilation MD5: 72599c9d5f4b9528ce16913438b02193
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-05-29 12:29:49
Source code size: 6769 bytes / 246 lines
Pitched / IR pitched: No / No
Views / Downloads: 334 / 696
Version history: 49 change(s)
Referenced in: #1028252 - LineCompCompressor 0.3 [dev.]