package org.jactr.core.module.declarative.four.associative; /* * default logging */ import java.util.concurrent.Executor; import javolution.util.FastList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunk.event.IChunkListener; import org.jactr.core.chunk.four.AssociativeLinkEquation4; import org.jactr.core.chunk.four.Link4; import org.jactr.core.chunk.link.IAssociativeLink; import org.jactr.core.chunk.link.IAssociativeLinkEquation; import org.jactr.core.model.IModel; import org.jactr.core.module.declarative.associative.IAssociativeLinkContainer; import org.jactr.core.module.declarative.associative.IAssociativeLinkageSystem; import org.jactr.core.module.declarative.basic.DefaultAssociativeLinkageSystem; import org.jactr.core.module.declarative.event.DeclarativeModuleEvent; import org.jactr.core.module.declarative.event.DeclarativeModuleListenerAdaptor; import org.jactr.core.module.declarative.event.IDeclarativeModuleListener; import org.jactr.core.module.declarative.four.learning.IDeclarativeLearningModule4; import org.jactr.core.module.procedural.IProceduralModule; import org.jactr.core.module.procedural.event.IProceduralModuleListener; import org.jactr.core.slot.ISlot; /** * version four associative linkage system. The base class handles the creation * of the links for us. This code installs the procedural, declarative, and * chunk listeners necessary for the establishment and learning of associative * links * * @author harrison */ public class DefaultAssociativeLinkageSystem4 extends DefaultAssociativeLinkageSystem { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(DefaultAssociativeLinkageSystem4.class); private IChunkListener _chunkListener; private IProceduralModuleListener _proceduralListener; private IDeclarativeModuleListener _declarativeListener; private Executor _executor; public DefaultAssociativeLinkageSystem4( IDeclarativeLearningModule4 learningModule, Executor executor) { _executor = executor; _chunkListener = createChunkListener(learningModule, executor); _proceduralListener = createProceduralListener(learningModule, executor); _declarativeListener = createDeclarativeModuleListener(learningModule, executor); setAssociativeLinkEquation(createLinkEquation(learningModule)); } protected IDeclarativeModuleListener createDeclarativeModuleListener( IDeclarativeLearningModule4 learningModule, Executor executor) { return new DeclarativeModuleListenerAdaptor() { @Override public void chunkCreated(DeclarativeModuleEvent dme) { IChunk iChunk = dme.getChunk(); /* * create the initial self-link */ IAssociativeLinkageSystem linkageSystem = dme.getSource() .getAssociativeLinkageSystem(); if (linkageSystem != null) linkageSystem.addLink(linkageSystem.createLink(iChunk, iChunk)); /* * chunks with default slot values will by-pass the normal chain of * event notification (the slot values are assigned before the chunk * listener can be attached). So, we do the containment linking directly */ FastList<ISlot> slots = FastList.newInstance(); try { iChunk.getSymbolicChunk().getSlots(slots); if(slots.size()==0) return; if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Post-linking %s and %s", iChunk, slots)); for (ISlot slot : slots) if(slot.getValue() instanceof IChunk) linkSlotValue(iChunk, (IChunk)slot.getValue(), false); } finally { FastList.recycle(slots); } } }; } /** * allows us to detect slot changes and handle merging & encoding may return * null * * @return */ protected IChunkListener createChunkListener( IDeclarativeLearningModule4 learningModule, Executor executor) { return new ChunkListener(this); } protected IAssociativeLinkEquation createLinkEquation( IDeclarativeLearningModule4 learningModule) { return new AssociativeLinkEquation4(learningModule); } /** * we use the production firing to trigger the learning may return null. * * @return */ protected IProceduralModuleListener createProceduralListener( IDeclarativeLearningModule4 learningModule, Executor executor) { return new ProceduralModuleListener(learningModule); } @Override public IChunkListener getChunkListener() { return _chunkListener; } @Override public void install(IModel model) { model.getDeclarativeModule().addListener(_declarativeListener, _executor); if (_proceduralListener == null) return; /* * attach the procedural listener */ IProceduralModule procMod = model.getProceduralModule(); procMod.addListener(_proceduralListener, _executor); } @Override public void uninstall(IModel model) { model.getDeclarativeModule().removeListener(_declarativeListener); if (_proceduralListener == null) return; IProceduralModule procMod = model.getProceduralModule(); procMod.removeListener(_proceduralListener); } /** * will create (or remove) an associative link from value to iChunk, * establishing the containment link. if valueIsOld, the link will be * decremented until 0 then removed. * * @param iChunk * @param value * @param valueIsOld */ protected void linkSlotValue(IChunk iChunk, IChunk jChunk, boolean valueIsOld) { IAssociativeLinkContainer iContainer = iChunk .getAdapter(IAssociativeLinkContainer.class); IAssociativeLinkContainer jContainer = jChunk .getAdapter(IAssociativeLinkContainer.class); FastList<IAssociativeLink> links = FastList.newInstance(); iContainer.getInboundLinks(jChunk, links); if (!valueIsOld) { // add if (links.size() == 0) { IAssociativeLink sJI = createLink(iChunk, jChunk); if (LOGGER.isDebugEnabled()) LOGGER.debug("Adding link between " + iChunk + " and " + jChunk + " : " + sJI); iContainer.addLink(sJI); jContainer.addLink(sJI); } else { // hopefully just one Link4 sJI = (Link4) links.iterator().next(); sJI.increment(); // not new, but we need to increment the if (LOGGER.isDebugEnabled()) LOGGER.debug("Link already established between " + iChunk + " and " + jChunk + " incrementing : " + sJI); } } else if(links.size()!=0) { /* * remove the old value.. decrement and remove if necessary */ //hopefully just one Link4 sJI = (Link4) links.iterator().next(); sJI.decrement(); if (sJI.getCount() == 0) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Removing link between " + iChunk + " and " + jChunk + " : " + sJI); iContainer.removeLink(sJI); jContainer.removeLink(sJI); } else if (LOGGER.isDebugEnabled()) LOGGER.debug("Multiple links established between " + iChunk + " and " + jChunk + " decrementing : " + sJI); } // ISubsymbolicChunk4 sscI = iChunk.getSubsymbolicChunk() // .getAdapter(ISubsymbolicChunk4.class); // ISubsymbolicChunk4 sscJ = value.getSubsymbolicChunk() // .getAdapter(ISubsymbolicChunk4.class); // IAssociativeLink sJI = sscJ.getIAssociation(iChunk); // // if (!valueIsOld) // { // // add // if (sJI == null) // { // sJI = createLink(iChunk, value); // if (LOGGER.isDebugEnabled()) // LOGGER.debug("Adding link between " + iChunk + " and " + value // + " : " + sJI); // // since we are the linkage system, we can assume this is correct and // // not // // use linkageSystem.addLink // sscI.addLink(sJI); // sscJ.addLink(sJI); // } // else // { // ((Link4) sJI).increment(); // not new, but we need to increment the // // link // if (LOGGER.isDebugEnabled()) // LOGGER.debug("Link already established between " + iChunk + " and " // + value + " incrementing : " + sJI); // } // } // else if (sJI != null) // { // // remove // ((Link4) sJI).decrement(); // if (((Link4) sJI).getCount() == 0) // { // if (LOGGER.isDebugEnabled()) // LOGGER.debug("Removing link between " + iChunk + " and " + value // + " : " + sJI); // sscI.removeLink(sJI); // sscJ.removeLink(sJI); // } // else if (LOGGER.isDebugEnabled()) // LOGGER.debug("Multiple links established between " + iChunk + " and " // + value + " decrementing : " + sJI); // } } }