/* * 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.chunk.four; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunk.ISubsymbolicChunk; import org.jactr.core.chunk.basic.AbstractSubsymbolicChunk; import org.jactr.core.event.ParameterEvent; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.module.declarative.four.IDeclarativeModule4; import org.jactr.core.runtime.ACTRRuntime; import org.jactr.core.utils.parameter.ACTRParameterHandler; import org.jactr.core.utils.parameter.CollectionParameterHandler; import org.jactr.core.utils.parameter.LinkParameterHandler; import org.jactr.core.utils.parameter.ParameterHandler; public class DefaultSubsymbolicChunk4 extends AbstractSubsymbolicChunk implements ISubsymbolicChunk4 { /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(DefaultSubsymbolicChunk4.class); protected long _creationCycle; protected Map<IChunk, Link> _jAssociations; // keyed // on // jChunk protected Map<IChunk, Link> _iAssociations; // keyed // on // iChunk public DefaultSubsymbolicChunk4(IChunk parent) { super(parent); _jAssociations = new HashMap<IChunk, Link>(); _iAssociations = new HashMap<IChunk, Link>(); } @Override public void encode(double when) { if (!_parentChunk.isEncoded()) try { writeLock().lock(); IDeclarativeModule decMod = _parentChunk.getModel() .getDeclarativeModule(); if (!(decMod instanceof IDeclarativeModule4)) { if (LOGGER.isWarnEnabled()) LOGGER .warn("IDeclarativeModule4 required to get base level constant"); } else setBaseLevelActivation(((IDeclarativeModule4) decMod) .getBaseLevelConstant()); setCreationCycle(_parentChunk.getModel().getCycle()); /* * add a link to ourselves */ addLink(new Link(_parentChunk, _parentChunk)); } finally { writeLock().unlock(); } super.encode(when); } @Override public void dispose() { super.dispose(); try { writeLock().lock(); /* * remove our associations. Why do we bother? a chunk can be disposed * during the normal life cycle of a model. For example, if a visual * object were stashed in the visual-location.objects slot, the * visual-location will have a link to the visual object. When the visual * object is disposed of because it cannot be seen, but was never actually * encoded, we need to remove the associative links */ for (Link l : _jAssociations.values()) if (!l.getJChunk().hasBeenDisposed()) { ((ISubsymbolicChunk4) l.getJChunk().getSubsymbolicChunk()) .removeLink(l); } for (Link l : _iAssociations.values()) if (!l.getIChunk().hasBeenDisposed()) { ((ISubsymbolicChunk4) l.getIChunk().getSubsymbolicChunk()) .removeLink(l); } _jAssociations.clear(); _iAssociations.clear(); } finally { writeLock().unlock(); } } public void setCreationCycle(long cycle) { long old = 0; try { writeLock().lock(); old = _creationCycle; _creationCycle = cycle; } finally { writeLock().unlock(); } if (_parentChunk.hasParameterListeners()) _parentChunk.dispatch(new ParameterEvent(this, ACTRRuntime.getRuntime() .getClock(_parentChunk.getModel()).getTime(), CREATION_CYCLE, old, cycle)); } public long getCreationCycle() { try { readLock().lock(); return _creationCycle; } finally { readLock().unlock(); } } @Override protected double computeSpreadingActivation() { double spread = 0.0; for (Link jLink : getJAssociations(null)) { ISubsymbolicChunk sc = jLink.getJChunk().getSubsymbolicChunk(); spread += sc.getSourceActivation() * jLink.getStrength(); if (LOGGER.isDebugEnabled()) LOGGER.debug(_parentChunk + " Pulling " + spread + " from " + jLink); } if (LOGGER.isDebugEnabled()) LOGGER.debug("SpreadingActivation " + spread); if (Double.isNaN(spread) || Double.isInfinite(spread)) spread = 0; return spread; } public void addLink(Link l) { try { writeLock().lock(); Link currentLink = null; IChunk iChunk = l.getIChunk(); IChunk jChunk = l.getJChunk(); if (jChunk.equals(_parentChunk)) { currentLink = getIAssociation(iChunk); if (currentLink == null) _iAssociations.put(iChunk, l); else if (LOGGER.isDebugEnabled()) LOGGER.debug("Already have a link " + l + ", use increment instead ", new RuntimeException()); } if (iChunk.equals(_parentChunk)) { currentLink = getJAssociation(jChunk); if (currentLink == null) _jAssociations.put(jChunk, l); else if (LOGGER.isDebugEnabled()) LOGGER.debug("Already have a link " + l + ", use increment instead", new RuntimeException()); } } finally { writeLock().unlock(); } // if (_parentChunk.hasParameterListeners() && old != null) // _parentChunk.dispatch(new ParameterEvent(this, ACTRRuntime.getRuntime() // .getClock(_parentChunk.getModel()).getTime(), LINKS, old, // getIAssociations())); } public Link getIAssociation(IChunk iChunk) { try { readLock().lock(); return _iAssociations.get(iChunk); } finally { readLock().unlock(); } } public Collection<Link> getIAssociations(Collection<Link> container) { if (container == null) container = new ArrayList<Link>(); try { readLock().lock(); container.addAll(_iAssociations.values()); return container; } finally { readLock().unlock(); } } public Link getJAssociation(IChunk jChunk) { try { readLock().lock(); return _jAssociations.get(jChunk); } finally { readLock().unlock(); } } public Collection<Link> getJAssociations(Collection<Link> container) { if (container == null) container = new ArrayList<Link>(); try { readLock().lock(); container.addAll(_jAssociations.values()); return container; } finally { readLock().unlock(); } } public int getNumberOfIAssociations() { try { readLock().lock(); return _iAssociations.size(); } finally { readLock().unlock(); } } public int getNumberOfJAssociations() { try { readLock().lock(); return _jAssociations.size(); } finally { readLock().unlock(); } } public void removeLink(Link l) { // Collection<Link> old = getIAssociations(); try { writeLock().lock(); Link currentLink = null; if (_parentChunk.equals(l.getIChunk())) { currentLink = getJAssociation(l.getJChunk()); if (currentLink != null) { currentLink.decrement(); if (currentLink.getCount() <= 0) _jAssociations.remove(l.getJChunk()); } } if (_parentChunk.equals(l.getJChunk())) { currentLink = getIAssociation(l.getIChunk()); if (currentLink != null) { currentLink.decrement(); if (currentLink.getCount() <= 0) _iAssociations.remove(l.getIChunk()); } } } finally { writeLock().unlock(); } // if (_parentChunk.hasParameterListeners()) // _parentChunk.dispatch(new ParameterEvent(this, ACTRRuntime.getRuntime() // .getClock(_parentChunk.getModel()).getTime(), LINKS, old, // getIAssociations())); } @Override public Collection<String> getPossibleParameters() { Collection<String> str = super.getPossibleParameters(); str.add(LINKS); str.add(CREATION_CYCLE); return str; } @Override public String getParameter(String key) { String rtn = null; if (LINKS.equalsIgnoreCase(key)) { Collection<Link> associations = getIAssociations(null); // everyone we // spread // to ACTRParameterHandler actrph = new ACTRParameterHandler(getParentChunk() .getModel()); LinkParameterHandler lph = new LinkParameterHandler(getParentChunk(), actrph); CollectionParameterHandler<Link> aph = new CollectionParameterHandler<Link>( lph); rtn = aph.toString(associations); } else if (CREATION_CYCLE.equalsIgnoreCase(key)) rtn = ParameterHandler.numberInstance().toString(getCreationCycle()); else rtn = super.getParameter(key); return rtn; } @Override public void setParameter(String key, String value) { if (CREATION_CYCLE.equalsIgnoreCase(key)) setCreationCycle(ParameterHandler.numberInstance().coerce(value) .longValue()); else if (LINKS.equalsIgnoreCase(key)) { ACTRParameterHandler actrph = new ACTRParameterHandler(getParentChunk() .getModel()); LinkParameterHandler lph = new LinkParameterHandler(getParentChunk(), actrph); CollectionParameterHandler<Link> aph = new CollectionParameterHandler<Link>( lph); for (Link l : aph.coerce(value)) { if (LOGGER.isDebugEnabled()) LOGGER.debug("adding link " + l); Link oldLink = getIAssociation(l.getIChunk()); if (oldLink != null) { oldLink.setCount(Math.max(oldLink.getCount(), l.getCount())); oldLink.setStrength(Math.max(oldLink.getStrength(), l.getStrength())); } else { addLink(l); /* * we also have to add it to the iChunk */ ((ISubsymbolicChunk4) l.getIChunk().getSubsymbolicChunk()).addLink(l); } } } super.setParameter(key, value); } }