WorldInProgress.java

/*
 * Copyright (c) 2005, 2006, Regents of the University of California
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.  
 *
 * * Neither the name of the University of California, Berkeley nor
 *   the names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior 
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package blog;

import java.util.*;
import common.Util;
import common.ExtensibleLinkedList;
import common.AddedTupleIterator;
import common.DGraph;



PartialWorld implementation that maintains a list of uninstantiated VarWithDistrib objects, and allows variables to be instantiated using a special method of an iterator over this list. This is useful for rejection sampling.

The list of uninstantiated basic variables only includes variables whose arguments necessarily exist in this partial world. Thus, as more number variables are instantiated and more objects necessarily exist, more variables will be added to the list. The list is not represented explicitly -- if integers or natural numbers serve as variable arguments, then the full list is infinite. Thus, the WorldInProgress class does not allow random access to the list. It only allows iteration, and additional variables are added lazily to the explicit list as needed.

The hypothetical "full" list is ordered in such a way that every one of its elements has a finite index. This is achieved by interleaving variables that have integer arguments with variables that have non-guaranteed arguments.


public class WorldInProgress extends DefaultPartialWorld {
    

Creates a new WorldInProgress with no instantiated random variables. numbers) to allow as arguments of RVs that are included in the uninstantiated RV list. To allow unbounded integers, pass -1 for this parameter. as arguments of RVs that are included in the uninstantiated RVs list. Objects generated by the empty tuple have depth 0; other non-guaranteed objects have depth one greater than the maximum depth of their generating objects. To allow unbounded depths, pass -1 for this parameter.

Parameters: 
intBound - maximum absolute value of integers (or natural
depthBound - maximum depth of non-guaranteed objects to allow


    public WorldInProgress(Model model, Evidence evidence, 
			   int intBound, int depthBound) {
	super(Collections.EMPTY_SET);
	this.model = model;
	this.evidence = evidence;
	this.intBound = intBound;
	this.depthBound = depthBound;

	// 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 (Iterator fIter = model.getFunctions().iterator(); 
	     fIter.hasNext(); ) {
	    Function f = (Function) fIter.next();
	    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));
		}
	    }
	}

	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();
		for (int i = 0; i < pop.getArgTypes().length; ++i) {
		    objectsByType.put(pop.getArgTypes()[i], new ArrayList());
		}

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

	for (Iterator skolemIter = evidence.getSkolemConstants().iterator(); 
	     skolemIter.hasNext(); ) {
	    SkolemConstant c = (SkolemConstant) skolemIter.next();
	    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 (Iterator typeIter = objectsByType.keySet().iterator(); 
	     typeIter.hasNext(); ) {
	    Type type = (Type) typeIter.next();
	    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());
	    }
	}
    }

    public void setValue(VarWithDistrib var, Object value) {
	super.setValue(var, value);

	if (var instanceof NumberVar) {
	    int varDepth = getVarDepth(var);
	    if ((depthBound < 0) || (varDepth < depthBound)) {
		if (getVarDepth(var) >= maxInt) {
		    // We're creating non-guaranteed objects of greater depth, 
		    // so increase maxInt as well
		    increaseMaxInt();
		}
		
		// Add objects generated by this number variable
		NumberVar nv = (NumberVar) var;
		addObjects(nv.pop().type(), getSatisfiers(nv));
	    }
	}
    }

    

Returns an iterator over the basic random variables whose arguments necessarily exist in this world, but which are not yet instantiated.


    public UninstVarIterator uninstVarIterator() {
	return new UninstVarIterator();
    }

    

Returns true if every basic random variable whose arguments necessarily exist in this world is instantiated.


    public boolean isComplete() {
	if (uninstVars.isEmpty()) {
	    increaseMaxInt();
	}
	return uninstVars.isEmpty(); // no uninstantiated vars -> complete
    }

    private int getVarDepth(VarWithDistrib var) {
	int maxArgDepth = 0;
	for (int i = 0; i < var.args().length; ++i) {
	    Object arg = var.args()[i];
	    if (arg instanceof NonGuaranteedObject) {
		int d = ((NonGuaranteedObject) arg).getDepth();
		maxArgDepth = Math.max(d, maxArgDepth);
	    }
	}
	return maxArgDepth;
    }

    

Increases the maximum magnitude of integers (and natural numbers) in the object lists by 1. Adds any basic RVs that use the newly added integers to the uninstantiated variables list.

Note that no variables will be added if integers don't serve as arguments to basic RVs in this model, or if they only occur in argument lists along with types that happen to have an empty extension in this world. In either case, if increasing maxInt by 1 doesn't yield new variables, then further increases won't do anything either. So there's no point in calling this method in a loop.


    private void increaseMaxInt() {
	if (intsAreArgs
	    && ((intBound < 0) || (maxInt < intBound))) {

	    ++maxInt;
	    
	    if (objectsByType.containsKey(BuiltInTypes.NATURAL_NUM)) {
		addObjects(BuiltInTypes.NATURAL_NUM, 
			   Collections.singleton(new Integer(maxInt)));
	    }
	    
	    if (objectsByType.containsKey(BuiltInTypes.INTEGER)) {
		List newInts = new ArrayList();
		newInts.add(new Integer(maxInt));
		newInts.add(new Integer(-maxInt));
		addObjects(BuiltInTypes.INTEGER, newInts);
	    }
	}
    }

    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);
	}
    }

    private void addFuncAppVars(RandomFunction f, Type newObjType, 
				Collection newObjs) {
	for (Iterator iter = getAddedTupleIterator
		     (Arrays.asList(f.getArgTypes()), newObjType, newObjs); 
	         iter.hasNext(); ) {
	    List args = (List) iter.next();
	    VarWithDistrib v = new RandFuncAppVar(f, args);
	    if (Util.verbose()) {
		System.out.println("Adding uninstantiated var: " + v);
	    }
	    uninstVars.add(v);
	}   
    }

    private void addNumberVars(POP pop, Type newObjType, 
			       Collection newObjs) {
	for (Iterator iter = getAddedTupleIterator
		     (Arrays.asList(pop.getArgTypes()), newObjType, newObjs); 
                 iter.hasNext(); ) {
	    List genObjs = (List) iter.next();
	    VarWithDistrib v = new NumberVar(pop, genObjs);
	    if (Util.verbose()) {
		System.out.println("Adding uninstantiated var: " + v);
	    }
	    uninstVars.add(v);
	}
    }

    private Iterator getAddedTupleIterator(List argTypes, Type newObjType, 
					   Collection newObjs) {
	List orig = new ArrayList();
	List added = new ArrayList();
	for (Iterator iter = argTypes.iterator(); iter.hasNext(); ) {
	    Type type = (Type) iter.next();
	    orig.add(objectsByType.get(type));
	    if (type == newObjType) {
		added.add(newObjs);
	    } else {
		added.add(Collections.EMPTY_SET);
	    }
	}

	return new AddedTupleIterator(orig, added);
    }

    

Inner class for iterating over the list of uninstantiated variables. It is like an ordinary iterator, but has an extra method setValue for instantiating the variable returned by the last call to next.


    public class UninstVarIterator implements Iterator {
	public boolean hasNext() {
	    ensureListExtended();
	    return listIter.hasNext();
	}

	

Always returns an object of class VarWithDistrib.


	public Object next() {
	    ensureListExtended();
	    lastVar = (VarWithDistrib) listIter.next();
	    return lastVar;
	}

	

The remove method is not supported, because the only way to remove a variable from the list of uninstantiated variables is to instantiate it.


	public void remove() {
	    throw new UnsupportedOperationException
		("Can't remove objects from UninstVarIterator.");
	}

	

Instantiates the last variable returned by next to the given value. The variable must be supported by this partial world, or a fatal error will occur. been called, or if setValue has already been called since the last call to next

Throws:  IllegalStateException if next has not yet


	public void setValue(Object value) {
	    if (lastVar == null) {
		throw new IllegalStateException
		    ("No variable to instantiate.");
	    }
	    
	    WorldInProgress.this.setValue(lastVar, value); 
	    listIter.remove(); // no longer uninstantiated

	    lastVar = null;
	}
	
	private void ensureListExtended() {
	    if (!listIter.hasNext()) {
		// Try extending the list of uninstantiated vars by
		// increasing maxInt.  
		increaseMaxInt();
	    }
	}
		

	private Iterator listIter = uninstVars.iterator();
	VarWithDistrib lastVar = null;
    }

    private Model model;
    private Evidence evidence; 

    private Collection uninstVars = new ExtensibleLinkedList();

    private Map objectsByType = new HashMap(); // from Type to List
    private boolean intsAreArgs = false; 
    private int maxInt = 0; // max int added to object list so far

    private int intBound;
    private int depthBound;
}


This file was generated on Tue Jun 08 17:53:36 PDT 2010 from file WorldInProgress.java
by the ilog.language.tools.Hilite Java tool written by Hassan Aït-Kaci