sclass PosNeg {
  new MultiSet pos;
  new MultiSet neg;
  
  *() {}
  *(Iterable pos, Iterable neg) {
    this.pos.addAll(pos);
    this.neg.addAll(neg);
  }
  
  *(Iterable> pairs) {
    fOr (Pair p : pairs)
      add(p.a, p.b);
  }
  
  *(Map map) {
    fOr (A a, Bool b : map)
      add(a, b);
  }
  
  void add(A a, int score) {
    if (score > 0)
      pos.add(a, score);
    else if (score < 0)
      neg.add(a, -score);
  }
  
  void add(A a, Bool b) {
    if (isTrue(b))
      pos.add(a);
    else if (isFalse(b))
      neg.add(a);
  }
  
  int get(A a) {
    ret pos.get(a)-neg.get(a);
  }
  
  int score() { ret l(pos)-l(neg); }
  int n() { ret l(pos)+l(neg); }
  int nPos() { ret l(pos); }
  int nNeg() { ret l(neg); }
  bool isEmpty() { ret n() == 0; }
  bool perfect() { ret nPos() != 0 && nNeg() == 0; }
  bool antiPerfect() { ret nPos() == 0 && nNeg() != 0; }
  
  toString {
    ret "+" + nPos() + "/-" + nNeg() + ": " + pos + " / " + neg;
  }
}