public static Cons learnOneRuleBottomUp(List positive, List negative) {
    { Cons lgg = Stella.NIL;
      Cons rule = Stella.NIL;
      int score = 0;
      int numPositive = positive.length();
      int index1 = 0;
      int index2 = 0;
      Cons facts1 = Stella.NIL;
      Cons facts2 = Stella.NIL;
      int max = 0;
      int cover = 0;
      int numLggs = positive.length() * 5;
      Cons bestLgg = Stella.NIL;

      System.out.println("Learning rule bottom up over " + positive.length() + " positives");
      max = 0;
      bestLgg = Stella.NIL;
      if (positive.length() == 1) {
        rule = ((TrainingExample)(positive.first())).facts;
        positive.pop();
        return (rule);
      }
      while (positive.nonEmptyP() &&
          ((max > 0) ||
           (rule == Stella.NIL))) {
        cover = max + cover;
        max = 0;
        System.out.println("   Current rule covers " + cover + " positive examples");
        System.out.println("           rule is " + rule);
        if (!(rule == Stella.NIL)) {
          Logic.removeCoveredExamples(rule, positive);
        }
        numLggs = positive.length() * 5;
        { int i = Stella.NULL_INTEGER;
          int iter000 = 1;
          int upperBound000 = numLggs;
          boolean unboundedP000 = upperBound000 == Stella.NULL_INTEGER;

          for (;unboundedP000 ||
                    (iter000 <= upperBound000); iter000 = iter000 + 1) {
            i = iter000;
            i = i;
            index1 = Stella.random(positive.length());
            facts1 = ((TrainingExample)(positive.nth(index1))).facts;
            if (rule == Stella.NIL) {
              {
                index2 = Stella.random(positive.length());
                while (index1 == index2) {
                  index2 = Stella.random(positive.length());
                }
                facts2 = ((TrainingExample)(positive.nth(index2))).facts;
              }
            }
            else {
              facts2 = rule;
            }
            lgg = Logic.leastGeneralGeneralization(facts1, facts2);
            if (!Logic.ruleCoversAnyExampleP(lgg, negative)) {
              score = Logic.numExamplesCovered(lgg, positive);
              if (score > max) {
                System.out.println("   Best covers " + score + " positives");
                bestLgg = lgg;
                if ((cover + score) >= numPositive) {
                  Logic.removeCoveredExamples(lgg, positive);
                  return (Logic.removeRedundantClauses(lgg));
                }
                max = score;
              }
            }
          }
        }
        rule = bestLgg;
      }
      return (Logic.removeRedundantClauses(rule));
    }
  }