private void addObjects(Type newObjType, Collection newObjs) {
    if (newObjs.isEmpty()) {
      return;
    }

    List objs = (List) objectsByType.get(newObjType);
    if (objs != null) { // if type serves as an argument to some basic RV

      // Add function app vars with these objects as argument
      for (Iterator fIter = model.getFunctions().iterator(); fIter.hasNext(); ) {
        Function f = (Function) fIter.next();
        if (f instanceof RandomFunction) {
          RandomFunction rf = (RandomFunction) f;
          if (Arrays.asList(f.getArgTypes()).contains(newObjType)) {
            addFuncAppVars(rf, newObjType, newObjs);
          }
        }
      }

      // Add number vars with these object as arguments
      for (Iterator typeIter = model.getTypes().iterator(); typeIter.hasNext(); ) {
        Type generatedType = (Type) typeIter.next();
        for (Iterator popIter = generatedType.getPOPs().iterator(); popIter.hasNext(); ) {
          POP pop = (POP) popIter.next();
          if (Arrays.asList(pop.getArgTypes()).contains(newObjType)) {
            addNumberVars(pop, newObjType, newObjs);
          }
        }
      }

      // Don't need to worry about skolem constant vars because
      // they don't have arguments

      objs.addAll(newObjs);
    }
  }
  /** add all random variables without parents into the uninstantiated variables */
  protected void init() {

    // added number variables for those number statement without origin
    // functions
    for (Type generatedType : model.getTypes()) {
      Collection<POP> pops = generatedType.getPOPs();

      // set initial size of unused number statements for each type
      restPOPs.put(generatedType, new HashSet<POP>(pops));

      for (POP pop : pops) {
        for (int i = 0; i < pop.getArgTypes().length; ++i) {
          objectsByType.put(pop.getArgTypes()[i], new ArrayList());
        }

        if (pop.getArgTypes().length == 0) {
          addNumberVar(new NumberVar(pop, Collections.EMPTY_LIST));
        }
      }
    }

    // Determine what types serve as arguments to basic RVs. Initialize
    // their object lists to be empty. As we're doing this, add any
    // random variables with empty arg lists to the list of uninstantiated
    // RVs.

    for (Function f : model.getFunctions()) {
      if (f instanceof RandomFunction) {
        for (int i = 0; i < f.getArgTypes().length; ++i) {
          objectsByType.put(f.getArgTypes()[i], new ArrayList());
        }

        if (f.getArgTypes().length == 0) {
          uninstVars.add(new RandFuncAppVar((RandomFunction) f, Collections.EMPTY_LIST));
        }
      }
    }

    // add skolem constants defined in symbol evidence
    // already added in step 1
    // for (SkolemConstant c : evidence.getSkolemConstants()) {
    // uninstVars.add(new RandFuncAppVar(c, Collections.EMPTY_LIST));
    // }

    // Create initial object lists for those types. While doing so,
    // add uninstantiated variables that have these objects as arguments.
    for (Type type : objectsByType.keySet()) {
      if (type.isSubtypeOf(BuiltInTypes.INTEGER)) {
        addObjects(type, Collections.singleton(new Integer(0)));
        intsAreArgs = true;
      } else if (type == BuiltInTypes.BOOLEAN) {
        addObjects(type, type.getGuaranteedObjects());
      } else if (type.isBuiltIn()) {
        Util.fatalError("Illegal argument type for random function: " + type, false);
      } else {
        // user-defined type
        addObjects(type, type.getGuaranteedObjects());
      }
    }

    // set the iterator
    lastIter = uninstVars.iterator();
  }