public static Cons learnOneRuleTopDownFromSignatures(List positive, List negative, List covered_pos, Vector consProps) {
    { double current_utility = 0.0;
      List rule = List.newList();
      double gain = 0.0;
      double max_gain = 0.0;
      List used_features = List.newList();
      int num_features = 0;
      List vars = List.newList();
      Vector variableTable = null;
      int feature_index = 0;
      List covered_neg = List.newList();

      System.out.println("Learning rule top down from signatures over " + positive.length() + " positives");
      if (positive.emptyP()) {
        return (Stella.NIL);
      }
      num_features = ((TrainingExample)(positive.first())).input.length();
      variableTable = Vector.newVector(num_features + 1);
      { int i = Stella.NULL_INTEGER;
        int iter000 = 1;
        int upperBound000 = num_features;
        boolean unboundedP000 = upperBound000 == Stella.NULL_INTEGER;

        for (;unboundedP000 ||
                  (iter000 <= upperBound000); iter000 = iter000 + 1) {
          i = iter000;
          (variableTable.theArray)[i] = (Logic.getVariablesFromConsPropositions(Cons.consList(Cons.cons(((Cons)((consProps.theArray)[(i - 1)])), Stella.NIL))));
        }
      }
      vars.push(Logic.SYM_LOGIC_pY);
      { TrainingExample example = null;
        Cons iter001 = negative.theConsList;
        Cons collect000 = null;

        for (;!(iter001 == Stella.NIL); iter001 = iter001.rest) {
          example = ((TrainingExample)(iter001.value));
          if (collect000 == null) {
            {
              collect000 = Cons.cons(example, Stella.NIL);
              if (covered_neg.theConsList == Stella.NIL) {
                covered_neg.theConsList = collect000;
              }
              else {
                Cons.addConsToEndOfConsList(covered_neg.theConsList, collect000);
              }
            }
          }
          else {
            {
              collect000.rest = Cons.cons(example, Stella.NIL);
              collect000 = collect000.rest;
            }
          }
        }
      }
      { TrainingExample example = null;
        Cons iter002 = positive.theConsList;
        Cons collect001 = null;

        for (;!(iter002 == Stella.NIL); iter002 = iter002.rest) {
          example = ((TrainingExample)(iter002.value));
          if (collect001 == null) {
            {
              collect001 = Cons.cons(example, Stella.NIL);
              if (covered_pos.theConsList == Stella.NIL) {
                covered_pos.theConsList = collect001;
              }
              else {
                Cons.addConsToEndOfConsList(covered_pos.theConsList, collect001);
              }
            }
          }
          else {
            {
              collect001.rest = Cons.cons(example, Stella.NIL);
              collect001 = collect001.rest;
            }
          }
        }
      }
      while (!covered_neg.emptyP()) {
        current_utility = Logic.foilUtility(covered_pos.length(), covered_neg.length());
        max_gain = 0.0;
        { int i = Stella.NULL_INTEGER;
          int iter003 = 1;
          int upperBound001 = num_features;
          boolean unboundedP001 = upperBound001 == Stella.NULL_INTEGER;

          for (;unboundedP001 ||
                    (iter003 <= upperBound001); iter003 = iter003 + 1) {
            i = iter003;
            if (!used_features.memberP(IntegerWrapper.wrapInteger(i))) {
              { boolean testValue000 = false;

                testValue000 = Logic.$ENFORCE_LINKED_VARIABLES$;
                if (testValue000) {
                  { boolean foundP000 = false;

                    { Symbol ele = null;
                      Cons iter004 = ((List)((variableTable.theArray)[i])).theConsList;

                      loop005 : for (;!(iter004 == Stella.NIL); iter004 = iter004.rest) {
                        ele = ((Symbol)(iter004.value));
                        if (vars.memberP(ele)) {
                          foundP000 = true;
                          break loop005;
                        }
                      }
                    }
                    testValue000 = foundP000;
                  }
                  testValue000 = !testValue000;
                }
                if (testValue000) {
                  gain = -9999.0;
                }
                else {
                  gain = Logic.foilGain(i, current_utility, covered_pos, covered_neg);
                }
              }
              if (Logic.$TRACE_FOIL$) {
                System.out.println("Foil gain on feature " + i + ": " + gain);
              }
              if (gain > max_gain) {
                feature_index = i;
                max_gain = gain;
              }
              { boolean testValue001 = false;

                testValue001 = Logic.$ENFORCE_LINKED_VARIABLES$;
                if (testValue001) {
                  { boolean foundP001 = false;

                    { Symbol ele = null;
                      Cons iter005 = ((List)((variableTable.theArray)[i])).theConsList;

                      loop006 : for (;!(iter005 == Stella.NIL); iter005 = iter005.rest) {
                        ele = ((Symbol)(iter005.value));
                        if (vars.memberP(ele)) {
                          foundP001 = true;
                          break loop006;
                        }
                      }
                    }
                    testValue001 = foundP001;
                  }
                  testValue001 = !testValue001;
                }
                if (testValue001) {
                  gain = -9999.0;
                }
                else {
                  gain = Logic.foilGain(0 - i, current_utility, covered_pos, covered_neg);
                }
              }
              if (Logic.$TRACE_FOIL$) {
                System.out.println("Foil gain on feature " + i + ": " + gain);
              }
              if (gain > max_gain) {
                feature_index = 0 - i;
                max_gain = gain;
              }
            }
          }
        }
        if (max_gain == 0.0) {
          covered_pos = List.newList();
          System.out.println("   Darn, nothing we can do here, returning nil.");
          return (Stella.NIL);
        }
        if (Logic.$TRACE_FOIL$) {
          System.out.println("** Choosing feature " + ((Cons)((consProps.theArray)[(Stella.integer_abs(feature_index - 1))])));
        }
        if (Logic.$ENFORCE_LINKED_VARIABLES$) {
          { Symbol var = null;
            Cons iter006 = ((List)((variableTable.theArray)[(((feature_index < 0) ? (0 - feature_index) : feature_index))])).theConsList;

            for (;!(iter006 == Stella.NIL); iter006 = iter006.rest) {
              var = ((Symbol)(iter006.value));
              if (!vars.memberP(var)) {
                vars.push(var);
              }
            }
          }
        }
        Logic.updateCoveredExamples(feature_index, covered_pos, covered_neg);
        used_features.push(IntegerWrapper.wrapInteger(((feature_index < 0) ? (0 - feature_index) : feature_index)));
        rule.push(IntegerWrapper.wrapInteger(feature_index));
      }
      System.out.println("   Returning with " + covered_pos.length() + " positives and " + covered_neg.length() + " negatives covered");
      return (Logic.buildAntecedentFromRuleIndex(consProps, rule));
    }
  }