/* * 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.Collection; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunk.event.ChunkEvent; import org.jactr.core.chunk.event.ChunkListenerAdaptor; import org.jactr.core.chunk.four.ISubsymbolicChunk4; import org.jactr.core.chunk.four.Link; import org.jactr.core.utils.references.IReferences; /** * we just listen for slot value changes so that Links can be created correctly. * * @author developer */ public class ChunkListener extends ChunkListenerAdaptor { /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(ChunkListener.class); public ChunkListener() { } @Override public void chunkEncoded(ChunkEvent ce) { /* * add that first reference time */ ce.getSource().getSubsymbolicChunk().accessed(ce.getSimulationTime()); } /** * handles the updating of associative links, references times, and context/needed * tallies. should also handle similarities, but that is not implemented yet and will * be by the six version of this.<br> * The updating is done here since the listener is removed after encoding, so * the master chunk will not have this listener attached * * @param event * @see org.jactr.core.chunk.event.ChunkListenerAdaptor#mergingInto(org.jactr.core.chunk.event.ChunkEvent) */ @Override public void mergingInto(ChunkEvent event) { IChunk self = event.getSource(); IChunk master = event.getChunk(); ISubsymbolicChunk4 selfSSC = (ISubsymbolicChunk4) self .getSubsymbolicChunk(); ISubsymbolicChunk4 masterSSC = (ISubsymbolicChunk4) master .getSubsymbolicChunk(); //update the references for master masterSSC.accessed(event.getSimulationTime()); masterSSC.setTimesInContext(masterSSC.getTimesInContext() + selfSSC.getTimesInContext()); masterSSC.setTimesNeeded(masterSSC.getTimesNeeded() + selfSSC.getTimesNeeded()); /* * and refs */ IReferences refs = masterSSC.getReferences(); for(double refTime : selfSSC.getReferences().getTimes()) refs.addReferenceTime(refTime); // will allocate Collection<Link> links = selfSSC.getIAssociations(null); for (Link iLink : links) { IChunk iChunk = iLink.getIChunk(); Link masterLink = masterSSC.getIAssociation(iChunk); if (masterLink != null) { /** * need to merge the links */ if (LOGGER.isDebugEnabled()) LOGGER.debug(master + " already linked to " + iChunk + ", merging"); masterLink.setCount(Math.max(masterLink.getCount(), iLink.getCount())); masterLink.setStrength(Math.max(masterLink.getStrength(), iLink .getStrength())); } else { /** * add the link to master */ if (LOGGER.isDebugEnabled()) LOGGER.debug(master + " not already linked to " + iChunk + ", linking."); Link newLink = new Link(master, iChunk, iLink.getCount(), iLink .getStrength()); masterSSC.addLink(newLink); ((ISubsymbolicChunk4) iChunk.getSubsymbolicChunk()).addLink(newLink); } /* * reduce the count so that we are sure we're removing the link */ iLink.setCount(1); selfSSC.removeLink(iLink); ((ISubsymbolicChunk4) iChunk.getSubsymbolicChunk()).removeLink(iLink); } links.clear(); links = selfSSC.getJAssociations(links); for (Link jLink : links) { IChunk jChunk = jLink.getJChunk(); Link masterLink = masterSSC.getIAssociation(jChunk); if (masterLink != null) { /** * need to merge the links */ if (LOGGER.isDebugEnabled()) LOGGER.debug(jChunk + " already linked to " + master + ", merging"); masterLink.setCount(Math.max(masterLink.getCount(), jLink.getCount())); masterLink.setStrength(Math.max(masterLink.getStrength(), jLink .getStrength())); } else { /** * add the link to master */ if (LOGGER.isDebugEnabled()) LOGGER.debug(jChunk + " not already linked to " + master + ", linking."); Link newLink = new Link(jChunk, master, jLink.getCount(), jLink .getStrength()); masterSSC.addLink(newLink); ((ISubsymbolicChunk4) jChunk.getSubsymbolicChunk()).addLink(newLink); } /* * reduce the count so that we are sure we're removing the link */ jLink.setCount(1); selfSSC.removeLink(jLink); ((ISubsymbolicChunk4) jChunk.getSubsymbolicChunk()).removeLink(jLink); } } @Override public void slotChanged(ChunkEvent ce) { IChunk iChunk = ce.getSource(); Object oldValue = ce.getOldSlotValue(); Object newValue = ce.getNewSlotValue(); if (LOGGER.isDebugEnabled()) LOGGER.debug(iChunk + "." + ce.getSlotName() + "=" + newValue + " (was " + oldValue + ")"); /* * we can only do this if ISubsymbolicChunk is ISubsymbolicChunk4 */ if (!(iChunk.getSubsymbolicChunk() instanceof ISubsymbolicChunk4)) { if (LOGGER.isWarnEnabled()) LOGGER .warn("Can only adjust associative links if the chunk's subsymbolic is derived from ISubsymbolicChunk4"); return; } /* * I chunk is the owner that references J */ ISubsymbolicChunk4 sscI = (ISubsymbolicChunk4) iChunk.getSubsymbolicChunk(); /* * first the old chunk value.. */ if (oldValue instanceof IChunk) { IChunk jChunk = (IChunk) oldValue; if (jChunk.getSubsymbolicChunk() instanceof ISubsymbolicChunk4) { ISubsymbolicChunk4 sscJ = (ISubsymbolicChunk4) jChunk .getSubsymbolicChunk(); Link sJI = sscJ.getIAssociation(iChunk); if (sJI != null) { sJI.decrement(); if (sJI.getCount() == 0) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Removing link between " + iChunk + " and " + jChunk + " : " + sJI); sscI.removeLink(sJI); sscJ.removeLink(sJI); } else if (LOGGER.isDebugEnabled()) LOGGER.debug("Multiple links established between " + iChunk + " and " + jChunk + " decrementing : " + sJI); } } else if (LOGGER.isWarnEnabled()) LOGGER.warn("old value " + jChunk + " doesn't have a ISubsymbolicChunk4, nothing to be done"); } /* * now for the new one */ if (newValue instanceof IChunk) { IChunk jChunk = (IChunk) newValue; if (jChunk.getSubsymbolicChunk() instanceof ISubsymbolicChunk4) { ISubsymbolicChunk4 sscJ = (ISubsymbolicChunk4) jChunk .getSubsymbolicChunk(); Link sJI = sscJ.getIAssociation(iChunk); /* * is this a new linkage? */ if (sJI == null) { sJI = new Link(jChunk, iChunk); if (LOGGER.isDebugEnabled()) LOGGER.debug("Adding link between " + iChunk + " and " + jChunk + " : " + sJI); sscI.addLink(sJI); sscJ.addLink(sJI); } else { sJI.increment(); // not new, but we need to increment the link if (LOGGER.isDebugEnabled()) LOGGER.debug("Link already established between " + iChunk + " and " + jChunk + " incrementing : " + sJI); } } else if (LOGGER.isWarnEnabled()) LOGGER.warn("new value " + jChunk + " doesn't have a ISubsymbolicChunk4, nothing to be done"); } } }