/* * 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 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.basic.AbstractSubsymbolicChunk; import org.jactr.core.chunk.link.IAssociativeLink; import org.jactr.core.event.ParameterEvent; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.module.declarative.associative.IAssociativeLinkContainer; import org.jactr.core.module.declarative.associative.IAssociativeLinkageSystem; import org.jactr.core.module.declarative.four.IBaseLevelActivationEquation; import org.jactr.core.module.declarative.four.IDeclarativeModule4; import org.jactr.core.module.declarative.four.IRandomActivationEquation; import org.jactr.core.module.declarative.four.ISpreadingActivationEquation; 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, IAssociativeLink> _jAssociations; // keyed // on // jChunk protected Map<IChunk, IAssociativeLink> _iAssociations; // keyed // on // iChunk protected IBaseLevelActivationEquation _baseLevelActivationEquation; protected IRandomActivationEquation _randomActivationEquation; protected ISpreadingActivationEquation _spreadingActivationEquation; public DefaultSubsymbolicChunk4() { super(); /* * the use of hashMap here is a problem if we get into the very large scale. * But concurrent skip map might not be much better. plus, we still need to * handle the encoding/merging of the associated chunks correctly.. */ _jAssociations = new HashMap<IChunk, IAssociativeLink>(); _iAssociations = new HashMap<IChunk, IAssociativeLink>(); } @Override public void encode(double when) { if (!_parentChunk.isEncoded()) try { writeLock().lock(); IDeclarativeModule decMod = _parentChunk.getModel() .getDeclarativeModule(); IDeclarativeModule4 dm = decMod.getAdapter(IDeclarativeModule4.class); if (dm == null) { if (LOGGER.isWarnEnabled()) LOGGER .warn("IDeclarativeModule4 required to get base level constant"); } else setBaseLevelActivation(dm.getBaseLevelConstant()); setCreationCycle(_parentChunk.getModel().getCycle()); } finally { writeLock().unlock(); } super.encode(when); } @Override public void dispose() { super.dispose(); _jAssociations.clear(); _iAssociations.clear(); } 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(); } } public void addLink(IAssociativeLink l) { try { writeLock().lock(); Link4 currentLink = null; IChunk iChunk = l.getIChunk(); IChunk jChunk = l.getJChunk(); if (jChunk.equals(_parentChunk)) { currentLink = (Link4) getIAssociation(iChunk); if (currentLink == null) _iAssociations.put(iChunk, l); else { currentLink.increment(); if (LOGGER.isDebugEnabled()) LOGGER.debug( "Already have a link " + l + ", incrementing instead ", new RuntimeException()); } } if (iChunk.equals(_parentChunk)) { currentLink = (Link4) getJAssociation(jChunk); if (currentLink == null) _jAssociations.put(jChunk, l); else { currentLink.increment(); if (LOGGER.isDebugEnabled()) LOGGER.debug("Already have a link " + l + ", use incrementing instead", new RuntimeException()); } } /* * mark all of the links as dirty. that is, their strengths need to be * relearned */ for (IAssociativeLink link : _iAssociations.values()) ((Link4) link).dirty(); for (IAssociativeLink link : _jAssociations.values()) ((Link4) link).dirty(); } finally { writeLock().unlock(); } if (_parentChunk.hasParameterListeners()) _parentChunk.dispatch(new ParameterEvent(this, _parentChunk.getModel() .getAge(), LINKS, null, null)); } public IAssociativeLink getIAssociation(IChunk iChunk) { try { readLock().lock(); return _iAssociations.get(iChunk); } finally { readLock().unlock(); } } public Collection<IAssociativeLink> getIAssociations( Collection<IAssociativeLink> container) { if (container == null) container = new ArrayList<IAssociativeLink>(); try { readLock().lock(); container.addAll(_iAssociations.values()); return container; } finally { readLock().unlock(); } } public IAssociativeLink getJAssociation(IChunk jChunk) { try { readLock().lock(); return _jAssociations.get(jChunk); } finally { readLock().unlock(); } } public Collection<IAssociativeLink> getJAssociations( Collection<IAssociativeLink> container) { if (container == null) container = new ArrayList<IAssociativeLink>(); 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(IAssociativeLink l) { // Collection<Link> old = getIAssociations(); try { writeLock().lock(); Link4 currentLink = null; if (_parentChunk.equals(l.getIChunk())) { currentLink = (Link4) getJAssociation(l.getJChunk()); if (currentLink != null) { currentLink.decrement(); if (currentLink.getCount() <= 0) _jAssociations.remove(l.getJChunk()); } } if (_parentChunk.equals(l.getJChunk())) { currentLink = (Link4) getIAssociation(l.getIChunk()); if (currentLink != null) { currentLink.decrement(); if (currentLink.getCount() <= 0) _iAssociations.remove(l.getIChunk()); } } /* * mark all of the links as dirty. that is, their strengths need to be * relearned */ for (IAssociativeLink link : _iAssociations.values()) ((Link4) link).dirty(); for (IAssociativeLink link : _jAssociations.values()) ((Link4) link).dirty(); } finally { writeLock().unlock(); } if (_parentChunk.hasParameterListeners()) _parentChunk.dispatch(new ParameterEvent(this, _parentChunk.getModel() .getAge(), LINKS, null, null)); } @Override public Collection<String> getSetableParameters() { Collection<String> str = super.getSetableParameters(); str.add(LINKS); str.add(CREATION_CYCLE); return str; } @Override public String getParameter(String key) { String rtn = null; if (LINKS.equalsIgnoreCase(key)) { /* * here we are using the adapter to get the link container, even though * this class implements directly, we go through the adapter in case * someone has needed to replace the container. Note also, we dont use * this adaptable, but the chunk's. Should probably remove adaptable from * content classes. */ FastList<IAssociativeLink> associations = FastList.newInstance(); try { IAssociativeLinkContainer aslc = getParentChunk().getAdapter( IAssociativeLinkContainer.class); aslc.getOutboundLinks(associations); // everyone we spread to ACTRParameterHandler actrph = new ACTRParameterHandler(getParentChunk() .getModel()); LinkParameterHandler lph = getParentChunk().getModel() .getDeclarativeModule().getAssociativeLinkageSystem() .getParameterHandler(); lph.setDependents(getParentChunk(), actrph); CollectionParameterHandler<IAssociativeLink> aph = new CollectionParameterHandler<IAssociativeLink>( lph); rtn = aph.toString(associations); } finally { FastList.recycle(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()); IAssociativeLinkageSystem ls = getParentChunk().getModel() .getDeclarativeModule().getAssociativeLinkageSystem(); LinkParameterHandler lph = getParentChunk().getModel() .getDeclarativeModule().getAssociativeLinkageSystem() .getParameterHandler(); lph.setDependents(getParentChunk(), actrph); CollectionParameterHandler<IAssociativeLink> aph = new CollectionParameterHandler<IAssociativeLink>( lph, true); for (IAssociativeLink l : aph.coerce(value)) { if (LOGGER.isDebugEnabled()) LOGGER.debug("adding link " + l); Link4 oldLink = (Link4) getIAssociation(l.getIChunk()); if (oldLink != null) oldLink.copy(l); else ls.addLink(l); } } else super.setParameter(key, value); } public void setBaseLevelActivationEquation( IBaseLevelActivationEquation equation) { if (_baseLevelActivationEquation != null) removeActivationParticipant(_baseLevelActivationEquation); _baseLevelActivationEquation = equation; addActivationParticipant(equation); } public void setRandomActivationEquation(IRandomActivationEquation equation) { if (_randomActivationEquation != null) removeActivationParticipant(_randomActivationEquation); _randomActivationEquation = equation; addActivationParticipant(equation); } public void setSpreadingActivationEquation( ISpreadingActivationEquation equation) { if (_spreadingActivationEquation != null) removeActivationParticipant(_spreadingActivationEquation); _spreadingActivationEquation = equation; addActivationParticipant(equation); } // @Override // protected double computeBaseLevelActivation() // { // if (_baseLevelActivationEquation == null) return _baseLevelActivation; // // return _baseLevelActivationEquation.computeBaseLevelActivation( // _parentChunk.getModel(), _parentChunk); // } // // @Override // protected double computeSpreadingActivation() // { // if (_spreadingActivationEquation != null) // return _spreadingActivationEquation.computeSpreadingActivation( // _parentChunk.getModel(), _parentChunk); // // return _spreadingActivation; // // } // // @Override // protected double computeRandomActivation() // { // if (_randomActivationEquation != null) // return _randomActivationEquation.computeRandomActivation( // _parentChunk.getModel(), _parentChunk); // return 0; // } @Override public void getOutboundLinks(Collection<IAssociativeLink> container) { getIAssociations(container); } @Override public long getNumberOfOutboundLinks() { return getNumberOfIAssociations(); } @Override public void getInboundLinks(Collection<IAssociativeLink> container) { getJAssociations(container); } @Override public long getNumberOfInboundLinks() { return getNumberOfJAssociations(); } @Override public void getOutboundLinks(IChunk receiver, Collection<IAssociativeLink> container) { IAssociativeLink link = getIAssociation(receiver); if (link != null) container.add(link); } @Override public void getInboundLinks(IChunk sender, Collection<IAssociativeLink> container) { IAssociativeLink link = getJAssociation(sender); if (link != null) container.add(link); } }