public static Cons specializeRule(Cons rule, Vector propositions, List positive, List negative) {
    System.out.println("Specializing ");
    { List candidates = List.newList();
      List coveredNegs = List.newList();
      List coveredPos = List.newList();
      double current_utility = 0.0;
      int featureIndex = 0;
      Cons newClause = Stella.NIL;
      List vars = Logic.getVariablesFromConsPropositions(rule);
      Vector variableTable = null;
      double gain = 0.0;
      double max = 0.0;

      { TrainingExample example = null;
        Cons iter000 = negative.theConsList;

        for (;!(iter000 == Stella.NIL); iter000 = iter000.rest) {
          example = ((TrainingExample)(iter000.value));
          if (Logic.ruleCoversExampleP(rule, example)) {
            coveredNegs.push(example);
          }
        }
      }
      { TrainingExample example = null;
        Cons iter001 = positive.theConsList;

        for (;!(iter001 == Stella.NIL); iter001 = iter001.rest) {
          example = ((TrainingExample)(iter001.value));
          if (Logic.ruleCoversExampleP(rule, example)) {
            coveredPos.push(example);
          }
        }
      }
      if (coveredNegs.emptyP()) {
        System.out.println(" No covered negatives");
        return (rule);
      }
      if (!vars.memberP(Logic.SYM_LOGIC_pY)) {
        vars.push(Logic.SYM_LOGIC_pY);
      }
      variableTable = Vector.newVector(propositions.length() + 1);
      { int i = Stella.NULL_INTEGER;
        int iter002 = 1;
        int upperBound000 = propositions.length();

        for (;iter002 <= upperBound000; iter002 = iter002 + 1) {
          i = iter002;
          (variableTable.theArray)[i] = (Logic.getVariablesFromConsPropositions(Cons.consList(Cons.cons(((Cons)((propositions.theArray)[(i - 1)])), Stella.NIL))));
        }
      }
      { int i = Stella.NULL_INTEGER;
        int iter003 = 1;
        int upperBound001 = propositions.length();

        for (;iter003 <= upperBound001; iter003 = iter003 + 1) {
          i = iter003;
          candidates.push(IntegerWrapper.wrapInteger(i));
          candidates.push(IntegerWrapper.wrapInteger(0 - i));
        }
      }
      { Cons clause = null;
        Cons iter004 = rule;

        for (;!(iter004 == Stella.NIL); iter004 = iter004.rest) {
          clause = ((Cons)(iter004.value));
          { Cons prop = null;
            Vector vector000 = propositions;
            int index000 = 0;
            int length000 = vector000.length();
            int i = Stella.NULL_INTEGER;
            int iter005 = 1;

            loop005 : for (;index000 < length000; index000 = index000 + 1, iter005 = iter005 + 1) {
              prop = ((Cons)((vector000.theArray)[index000]));
              i = iter005;
              if (Stella_Object.equalConsTreesP(prop, clause)) {
                candidates = ((List)(candidates.remove(IntegerWrapper.wrapInteger(i))));
                break loop005;
              }
              if (Stella_Object.equalConsTreesP(Cons.list$(Cons.cons(Logic.SYM_LOGIC_FAIL, Cons.cons(prop, Cons.cons(Stella.NIL, Stella.NIL)))), clause)) {
                candidates = ((List)(candidates.remove(IntegerWrapper.wrapInteger(0 - i))));
                break loop005;
              }
            }
          }
        }
      }
      while (!coveredNegs.emptyP()) {
        System.out.println("   Covers " + coveredNegs.length() + " negs, and " + coveredPos.length() + " pos");
        current_utility = Logic.foilUtility(coveredPos.length(), coveredNegs.length());
        max = 0.0;
        { IntegerWrapper i = null;
          Cons iter006 = candidates.copy().theConsList;

          for (;!(iter006 == Stella.NIL); iter006 = iter006.rest) {
            i = ((IntegerWrapper)(iter006.value));
            { boolean foundP000 = false;

              { Symbol ele = null;
                Cons iter007 = ((List)((variableTable.theArray)[(Stella.integer_abs(i.wrapperValue))])).theConsList;

                loop008 : for (;!(iter007 == Stella.NIL); iter007 = iter007.rest) {
                  ele = ((Symbol)(iter007.value));
                  if (vars.memberP(ele)) {
                    foundP000 = true;
                    break loop008;
                  }
                }
              }
              if (foundP000) {
                if (i.wrapperValue > 0) {
                  gain = Logic.queryFoilGain(Cons.cons(((Cons)((propositions.theArray)[(i.wrapperValue - 1)])), rule), current_utility, coveredPos, coveredNegs);
                }
                else {
                  gain = Logic.queryFoilGain(Cons.cons(Cons.list$(Cons.cons(Logic.SYM_LOGIC_FAIL, Cons.cons(((Cons)((propositions.theArray)[((0 - i.wrapperValue) - 1)])), Cons.cons(Stella.NIL, Stella.NIL)))), rule), current_utility, coveredPos, coveredNegs);
                }
                if (gain > max) {
                  System.out.print("    Current: " + ((Cons)((propositions.theArray)[(Stella.integer_abs(i.wrapperValue) - 1)])) + ": " + gain);
                  if (i.wrapperValue < 0) {
                    System.out.println(" Negated");
                  }
                  else {
                    System.out.println();
                  }
                  featureIndex = i.wrapperValue;
                  max = gain;
                }
              }
            }
          }
        }
        if (max == 0.0) {
          System.out.println("   No features provide any gain");
          System.out.println("   Can't separate ");
          { TrainingExample pos = null;
            Cons iter008 = coveredPos.theConsList;

            for (;!(iter008 == Stella.NIL); iter008 = iter008.rest) {
              pos = ((TrainingExample)(iter008.value));
              System.out.println("     " + pos.name);
            }
          }
          System.out.println("   From ");
          { TrainingExample neg = null;
            Cons iter009 = coveredNegs.theConsList;

            for (;!(iter009 == Stella.NIL); iter009 = iter009.rest) {
              neg = ((TrainingExample)(iter009.value));
              System.out.println("     " + neg.name);
            }
          }
          return (Stella.NIL);
        }
        { Symbol var = null;
          Cons iter010 = ((List)((variableTable.theArray)[(((featureIndex < 0) ? (0 - featureIndex) : featureIndex))])).theConsList;

          for (;!(iter010 == Stella.NIL); iter010 = iter010.rest) {
            var = ((Symbol)(iter010.value));
            if (!vars.memberP(var)) {
              vars.push(var);
            }
          }
        }
        candidates = ((List)(candidates.remove(IntegerWrapper.wrapInteger(featureIndex))));
        newClause = ((Cons)(Stella_Object.copyConsTree(((Cons)((propositions.theArray)[((((featureIndex < 0) ? (0 - featureIndex) : featureIndex)) - 1)])))));
        if (featureIndex < 0) {
          newClause = Cons.list$(Cons.cons(Logic.SYM_LOGIC_FAIL, Cons.cons(newClause, Cons.cons(Stella.NIL, Stella.NIL))));
        }
        System.out.println("   Adding clause " + newClause);
        rule = Cons.cons(newClause, rule);
        Logic.removeExcludedExamples(rule, coveredPos, coveredNegs);
      }
      return (rule);
    }
  }