/*
* Created on Oct 25, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
* (jactr.org) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version. This library is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details. You should have
* received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jactr.core.module.declarative.four.learning;
import java.util.Map;
import java.util.TreeMap;
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.chunk.four.ISubsymbolicChunk4;
import org.jactr.core.chunk.four.Link;
import org.jactr.core.event.IParameterEvent;
import org.jactr.core.module.procedural.event.IProceduralModuleListener;
import org.jactr.core.module.procedural.event.ProceduralModuleEvent;
import org.jactr.core.production.IInstantiation;
import org.jactr.core.production.condition.IBufferCondition;
import org.jactr.core.production.condition.ICondition;
import org.jactr.core.slot.ISlot;
/**
* we use a proceduralmodule listener to track the chunks that are accessed in
* service of firing a production. We listen to two methods:
* productionWillFire() to snag all the chunks that the production requires to
* fire, and productionFired() to call the various parameter update methods on
* the chunks
*
* @author developer
*/
public class ProceduralModuleListener implements IProceduralModuleListener
{
/**
* logger definition
*/
static private final Log LOGGER = LogFactory
.getLog(ProceduralModuleListener.class);
/*
* all the chunks that a production matches against, keyed on buffer name
*/
private Map<String, IChunk> _matchedChunks;
public ProceduralModuleListener(DefaultDeclarativeLearningModule4 learning)
{
_matchedChunks = new TreeMap<String, IChunk>();
}
public void conflictSetAssembled(ProceduralModuleEvent pme)
{
}
public void productionAdded(ProceduralModuleEvent pme)
{
}
/**
* if goals are special, then only the goal chunk's slot values will have
* their times in context incremented. if false, all buffer chunk slot values
* will be incremented
*
* @return
*/
protected boolean goalsAreSpecial()
{
return true;
}
/**
* if true, associative links will be established between the chunks in each
* of the buffers (or just the goal buffer if {@link #goalsAreSpecial()} )
*
* @return
*/
protected boolean associateConcurrentChunks()
{
return true;
}
/**
* snag the chunks that the production that is about to fire is matched
* against
*
* @see org.jactr.core.module.procedural.event.IProceduralModuleListener#productionWillFire(org.jactr.core.module.procedural.event.ProceduralModuleEvent)
*/
public void productionWillFire(ProceduralModuleEvent pme)
{
/*
* snag all the chunks that will be matched against
*/
_matchedChunks.clear();
IInstantiation instantiation = (IInstantiation) pme.getProduction();
for (ICondition condition : instantiation.getSymbolicProduction()
.getConditions())
if (condition instanceof IBufferCondition)
{
IBufferCondition bufferCondition = (IBufferCondition) condition;
Object boundVariable = instantiation.getVariableBindings().get(
"=" + bufferCondition.getBufferName());
if (boundVariable instanceof IChunk)
_matchedChunks.put(bufferCondition.getBufferName(),
(IChunk) boundVariable);
}
}
public void productionCreated(ProceduralModuleEvent pme)
{
}
/**
* adjust the parameter values for the chunks that enabled this production to
* fire
*
* @see org.jactr.core.module.procedural.event.IProceduralModuleListener#productionFired(org.jactr.core.module.procedural.event.ProceduralModuleEvent)
*/
public void productionFired(ProceduralModuleEvent pme)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Adjusting chunk parameter values");
/*
* adjust timesInContext and timesNeeded
*/
for (Map.Entry<String, IChunk> entry : _matchedChunks.entrySet())
{
String bufferName = entry.getKey();
IChunk iChunk = entry.getValue();
ISubsymbolicChunk4 sscI = (ISubsymbolicChunk4) iChunk
.getSubsymbolicChunk();
/*
* everyone who was matched against, was needed
*/
if (LOGGER.isDebugEnabled())
LOGGER.debug("Incrementing times needed for " + iChunk);
sscI.incrementTimesNeeded();
/*
* all the slots of the goal chunk get their timesInContext incremented.
* arguably, this should apply to all the bound chunks in all the buffers
*/
if (IActivationBuffer.GOAL.equals(bufferName) || !goalsAreSpecial())
{
for (ISlot slot : iChunk.getSymbolicChunk().getSlots())
if (slot.getValue() instanceof IChunk)
{
IChunk jChunk = (IChunk) slot.getValue();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Incrementing times in context " + jChunk
+ " value of " + iChunk + "." + slot.getName());
jChunk.getSubsymbolicChunk().incrementTimesInContext();
}
/*
* now we link the chunk to all the other chunks. This is where the
* runtime context comes into play. we are linking all the other chunks
* (J) to this one (I) so that they (J) can spread activation to I.
*/
if (associateConcurrentChunks())
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Updating associative links for " + iChunk);
for (IChunk jChunk : _matchedChunks.values())
{
if (iChunk.equals(jChunk)) continue; // ignore
ISubsymbolicChunk4 sscJ = (ISubsymbolicChunk4) jChunk
.getSubsymbolicChunk();
Link sJI = sscI.getJAssociation(jChunk);
if (sJI != null)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("Incrementing " + sJI);
sJI.incrementFNICJ();
}
else
{
sJI = new Link(iChunk, jChunk);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Adding new link " + sJI);
sscI.addLink(sJI);
sscJ.addLink(sJI);
}
}
}
}
}
}
public void productionsMerged(ProceduralModuleEvent pme)
{
}
@SuppressWarnings("unchecked")
public void parameterChanged(IParameterEvent pe)
{
}
}