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

216
LINES

< > BotCompany Repo | #1031504 // ProbabilisticList - list ordered by probability [OK!]

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

Libraryless. Click here for Pure Java version (10590L/59K).

// As long as you don't access the by-numeral-index functions,
// you can add and remove elements quickly.
// Upon accessing the list, it is updated once to fit the new data.

// Note: When adding the same element twice, it will be stored only
//       once with the higher probabilities of the two.
//
// class is synchronized
sclass ProbabilisticList<A> extends AbstractRandomAccessList<WithProbability<A>> {
  // these are the 2 main data structures we update
  Map<A, Double> probabilities = hashMap();
  MultiSetMap<Double, A> byProbability
    = multiSetMap_outerDescTreeMap_innerCompactLinkedHashSet();
    // = multiSetMap_outerDescTreeMap_innerBetterLinkedHashSet();
  
  L<WithProbability<A>> list; // this is only updated when requested
  
  // CUSTOMIZATION
  
  // must be >= 0. probability 0 is never added
  double cutoffProbabilityOnAdd = 0;
  
  Cl<ProbabilisticListListener<A>> listeners;
  
  *() {}
  *(Iterable<WithProbability<A>> l) {
    main addAll(this, l);
  }
  
  public synchronized WithProbability<A> get(int idx) {
    if (idx < 0 || idx >= size()) null;
    makeListUpToIndex(idx);
    ret list.get(idx);
  }
  
  public synchronized int size() { ret l(probabilities); }
  
  // assuming the index is within range
  void makeListUpToIndex(int idx) {
    if (idx < l(list)) ret; // index already there
    
    if (list == null) list = new L;
    
    WithProbability<A> lastEntry = main last(list);
    A a = lastEntry?!;
    double probability = lastEntry == null ? 0 : lastEntry.probability();
    
    //print("Making list from " + l(list) + " to " + idx);
    
    while (idx >= l(list)) {
      //printVars_str(+idx, +a, +probability);
      if (a == null) {
        probability = byProbability.firstKey();
        a = first(byProbability.get(probability));
      } else {
        CompactLinkedHashSet<A> setForProbability = cast byProbability.get(probability);
        a = setForProbability.nextElement(a);
        //printVars_str(+probability, +setForProbability, +a);
        if (a == null) {
          probability = byProbability.higherKey(probability);
          a = first(byProbability.get(probability));
        }
      }
      list.add(WithProbability(probability, a));
    }
  }
  
  synchronized bool containsElement(A a) {
    ret probabilities.containsKey(a);
  }
  
  public bool add aka put(A a, double probability) {
    ret add(WithProbability(probability, a));
  }
  
  public bool add(WithProbability<A> wp) {
    A a;
    double newP;
    
    synchronized {
      if (wp == null || wp.probability() <= cutoffProbabilityOnAdd) false;
      a = wp!;
      newP = wp.probability();
      Double oldP = probabilities.get(a);
      if (oldP != null) {
        if (oldP.doubleValue() >= newP)
          false;
        else
          remove(WithProbability<A>(oldP, a));
      }
        
      clearListFrom(newP);
      probabilities.put(a, newP);
      byProbability.add(newP, a);
    }
      
    fireElementAdded(a, newP);
    true;
  }
  
  // will also delete if given probability doesn't match
  @Override
  public bool remove(O wp) {
    if (wp == null) false;
    cast wp to WithProbability<A>;
    ret removeElement(wp!);
  }
  
  public synchronized bool removeElement(A a) {
    if (a == null) false;
    Double oldP = probabilities.get(a);
    if (oldP == null) false;
    clearListFrom(oldP);
    probabilities.remove(a);
    byProbability.remove(oldP, a);
    true;
  }
  
  @Override
  public synchronized WithProbability<A> remove(int idx) {
    var a = get(idx);
    remove(a);
    ret a;
  }
  
  // internal
  void clearListFrom(double p) {
    int idx = generalizedBinarySearch2(list, a -> a.probability() <= p ? 1 : -1);
    idx = -idx-1;
    //printVars clearListFrom(p, idx, before := takeFirst(idx, list), after := main subList(idx, list));
    truncateList(list, idx);
  }
  
  void at(double p, A a) {
    add(WithProbability(p, a));
  }
  
  // faster version of truncateList
  void truncate(int size) {
    if (size < 0) fail();
    while (size() > size)
      removeLast();
  }
  
  double getProbability(A a) {
    ret orZero(probabilities.get(a));
  }

  void truncateBelow(double thresholdProbability) {
    A a;
    while ((a = last()) != null && getProbability(a) < thresholdProbability)
      removeElement(a);
  }
  
  A last() {  
    Double last = byProbability.lastKey();
    if (last == null) null;
    CompactLinkedHashSet<A> set = cast byProbability.getOpt(last);
    ret set.last();
  }
  
  void removeLast {
    removeElement(last());
  }
  
  int indexOfElement(A a) {
    // quickly bail if element is not contained
    double p = getProbability(a);
    if (p == 0) ret -1;
    
    // TODO: binary search and stuff
    int n = size();
    for i to n:
      if (eq(a, get(i)!))
        ret i;
    fail("Internal error");
  }
  
  // elements without probabilities
  L<A> rawList aka elementsOnly() {
    ret lazyMap_noSave(this, a -> a!);
  }
  
  // just the probabilities in the list
  L<Double> probabilities() {
    ret lazyMap_noSave(this, a -> a.probability());
  }
  
  L<ProbabilisticListListener<A>> listenersList() {
    if (listeners == null) null;
    synchronized { ret cloneList(listeners); }
  }
  
  void fireElementAdded(A a, double probability) {
    main forEach(listenersList(), l -> l.elementAdded(a, probability));
  }
  
  synchronized void addListener(ProbabilisticListListener<A> l) {
    listeners = addOrCreate(listeners, l);
  }
  
  synchronized void removeListener(ProbabilisticListListener<A> l) {
    listeners?.remove(l);
  }
  
  void onElementAdded(IVF2<A, Double> f) {
    if (f != null)
      addListener(new ProbabilisticListAdapter<A> {
        @Override
        public void elementAdded(A a, double probability) {
          f.get(a, probability);
        }
      });
  }
  
}

Author comment

Began life as a copy of #1028471

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1031504
Snippet name: ProbabilisticList - list ordered by probability [OK!]
Eternal ID of this version: #1031504/56
Text MD5: e80072181788c6849cd110b70f422091
Transpilation MD5: 4ec8bbcefbe8fbbebb8d855dc21e23d1
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-09-02 20:28:57
Source code size: 6028 bytes / 216 lines
Pitched / IR pitched: No / No
Views / Downloads: 365 / 831
Version history: 55 change(s)
Referenced in: #1034167 - Standard Classes + Interfaces (LIVE, continuation of #1003674)