package org.jactr.core.module.procedural.six; /* * default logging */ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import javolution.util.FastCollection; import javolution.util.FastList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.chunk.IChunk; import org.jactr.core.logging.Logger; import org.jactr.core.model.IModel; import org.jactr.core.module.procedural.IProductionInstantiator; import org.jactr.core.module.random.IRandomModule; import org.jactr.core.production.CannotInstantiateException; import org.jactr.core.production.IInstantiation; import org.jactr.core.production.IProduction; import org.jactr.core.production.VariableBindings; import org.jactr.core.production.bindings.VariableBindingsFactory; import org.jactr.core.production.condition.IBufferCondition; import org.jactr.core.production.condition.ICondition; import org.jactr.core.production.condition.QueryCondition; import org.jactr.core.production.six.ISubsymbolicProduction6; import org.jactr.core.utils.collections.FastCollectionFactory; /** * delegate task to actually do the instantiation and evaluation of the * instantiations. This is delegated out to make parallization easier since this * chunk of code takes the longest, in general. * * @author harrison */ public class InstantiationTask implements Callable<Collection<IInstantiation>> { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(InstantiationTask.class); private final FastList<IProduction> _productionsToInstantiate; private final IProductionInstantiator _instantiator; private final IRandomModule _randomModule; private final IModel _model; private final double _expectedUtilityNoise; public InstantiationTask(Collection<IProduction> productions, IProductionInstantiator instantiator, IModel model, IRandomModule random, double utilityNoise) { _productionsToInstantiate = FastList.newInstance(); _productionsToInstantiate.addAll(productions); _instantiator = instantiator; _randomModule = random; _expectedUtilityNoise = utilityNoise; _model = model; } public Collection<IInstantiation> call() throws Exception { List<IInstantiation> keepers = new ArrayList<IInstantiation>(); boolean debugEnabled = LOGGER.isDebugEnabled(); boolean hasLoggers = Logger.hasLoggers(_model); // this can be relatively // costly to repeat @SuppressWarnings("unchecked") FastCollection<VariableBindings> provisionalBindings = FastCollectionFactory .newInstance(); StringBuilder message = new StringBuilder(); if (debugEnabled) LOGGER.debug(String.format("Attempting to instantiatie %s", _productionsToInstantiate)); for (IProduction production : _productionsToInstantiate) try { provisionalBindings.clear(); // clear the recycled container computeProvisionalBindings(production, provisionalBindings); if (debugEnabled) LOGGER.debug("Instantiating " + production); Collection<IInstantiation> instantiations = _instantiator.instantiate( production, provisionalBindings); for (IInstantiation instantiation : instantiations) { double noise = _randomModule.logisticNoise(_expectedUtilityNoise); ISubsymbolicProduction6 p = (ISubsymbolicProduction6) instantiation .getSubsymbolicProduction(); double utility = p.getExpectedUtility(); if (Double.isNaN(utility)) utility = p.getUtility(); if (debugEnabled) LOGGER.debug(production + " utility: " + utility + " noise:" + noise + " expected utility: " + (utility + noise)); p.setExpectedUtility(utility + noise); if (debugEnabled || hasLoggers) { message.delete(0, message.length()); message.append("Instantiated ").append(production) .append(" expected utility "); message.append(utility + noise).append(" (").append(noise) .append(" noise)"); String msg = message.toString(); if (debugEnabled) LOGGER.debug(msg); if (hasLoggers) Logger.log(_model, Logger.Stream.PROCEDURAL, msg); } keepers.add(instantiation); } } catch (CannotInstantiateException cie) { if (debugEnabled || hasLoggers) { String msg = cie.getMessage(); if (debugEnabled) LOGGER.debug(msg); if (hasLoggers) Logger.log(_model, Logger.Stream.PROCEDURAL, msg); } } catch (Exception e) { LOGGER.error(String.format("Could not instanitate %s ", production), e); } /* * before recycling provisionalBinding collection, let's recycle the * bindings */ for (VariableBindings bindings : provisionalBindings) VariableBindingsFactory.recycle(bindings); FastCollectionFactory.recycle(provisionalBindings); FastList.recycle(_productionsToInstantiate); return keepers; } /** * in order to handle the iterative nature of the instantiation process in * addition to the possibility for multiple sources chunks, provisional * bindings must be created for all the chunk permutations. Ugh. */ private Collection<VariableBindings> computeProvisionalBindings( IProduction production, Collection<VariableBindings> bindingsContainer) { @SuppressWarnings("unchecked") FastCollection<VariableBindings> provisionalBindings = FastCollectionFactory .newInstance(); VariableBindings initialBinding = VariableBindingsFactory.newInstance(); initialBinding.bind("=model", _model); provisionalBindings.add(initialBinding); /* * reusbale map collection. */ Map<IChunk, FastCollection<VariableBindings>> keyedProvisionalBindings = new HashMap<IChunk, FastCollection<VariableBindings>>(); /* * with all the buffers this production should match against, we snag their * source chunks, these will be the values bound to =bufferName. for each * source chunk in a given buffer, we have to create an additional set of * provisional bindings */ FastCollection<IChunk> sourceChunks = FastCollectionFactory.newInstance(); for (ICondition condition : production.getSymbolicProduction() .getConditions()) if (condition instanceof IBufferCondition && !(condition instanceof QueryCondition)) { IActivationBuffer buffer = _model .getActivationBuffer(((IBufferCondition) condition).getBufferName()); sourceChunks.clear(); buffer.getSourceChunks(sourceChunks); /* * nothing there? nothing to bind. */ if (sourceChunks.size() == 0) continue; /* * if there are more than one source chunk, we need to duplicate all the * provisional bindings, add the binding for the source chunk and then * merge the duplicates back into the provisional set */ for (IChunk source : sourceChunks) { FastCollection<VariableBindings> bindings = provisionalBindings; // we've already processed at least 1 source chunk // we need to copy ALL the existing bindings, since we are doing // full permutations. As we do so, we bind =bufferName to source if (keyedProvisionalBindings.size() != 0) bindings = copyAndBinding(provisionalBindings, buffer, source); else // otherwise, we just add the binding (bindings.size =1) for (VariableBindings binding : bindings) binding.bind("=" + buffer.getName(), source, buffer); // store keyedProvisionalBindings.put(source, bindings); } /* * merge these provisionals back into the full set. if there was only * one source chunk, it was already added to the provisional binding, so * we ignore it. If multi, we add all */ for (FastCollection<VariableBindings> bindings : keyedProvisionalBindings .values()) if (bindings != provisionalBindings) { /* * since there was more than one source chunk, we grab those * bindings, and then free up the collection backing it. */ provisionalBindings.addAll(bindings); FastCollectionFactory.recycle(bindings); } keyedProvisionalBindings.clear(); // cleanup for reuse } bindingsContainer.addAll(provisionalBindings); FastCollectionFactory.recycle(sourceChunks); FastCollectionFactory.recycle(provisionalBindings); return bindingsContainer; } /** * we make a full copy of this collection, deeply including the bindings, and * while we are at it, we will add this binding * * @param src * @return */ private FastCollection<VariableBindings> copyAndBinding( Collection<VariableBindings> src, IActivationBuffer buffer, IChunk source) { @SuppressWarnings("unchecked") FastCollection<VariableBindings> rtn = FastCollectionFactory.newInstance(); for (VariableBindings map : src) { VariableBindings clone = VariableBindingsFactory.newInstance(); clone.copy(map); clone.bind("=" + buffer.getName(), clone, source); rtn.add(clone); } return rtn; } }