/* * Created on Aug 14, 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.six; 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.four.ISubsymbolicChunk4; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.module.declarative.basic.DefaultDeclarativeModule; import org.jactr.core.module.declarative.event.DeclarativeModuleEvent; import org.jactr.core.module.declarative.five.IDeclarativeModule5; import org.jactr.core.module.declarative.four.DefaultBaseLevelActivationEquation; import org.jactr.core.module.declarative.four.DefaultRandomActivationEquation; import org.jactr.core.module.declarative.four.DefaultSpreadingActivationEquation; 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.module.declarative.four.learning.IDeclarativeLearningModule4; import org.jactr.core.module.random.IRandomModule; import org.jactr.core.utils.parameter.IParameterized; import org.jactr.core.utils.parameter.ParameterHandler; import org.jactr.core.utils.references.IOptimizedReferences; import org.jactr.core.utils.references.IReferences; /** * Default declarative module for ACT-R 6. <br/> * This module uses the {@link IDeclarativeConfigurator} to set the chunk's * various equations ({@link IBaseLevelActivationEquation}, * {@link ISpreadingActivationEquation}, {@link IRandomActivationEquation}). * Clients extending this should be sure to delegate to the original * configurator as to keep this functionality ( {@link #getConfigurator()}). <h3> * Parameters</h3> * <ul> * <li><b>EnablePartialMatching</b> : Turn on partial matching in searches * (values:true/false. default: false) * <li><b>ActivationNoise</b> : Transient noise added to activations (value: * numeric. default: 0) (note: random module must be present) * <li><b>PermanentActivationNoise</b> : Permanent noise added to activations * (value: numeric. default:0) (note: random module must be present) * <li><b>BaseLevelConstant</b> : Constant added to base level activations * (value: numeric. default: 0) * <li><b>MismatchPenalty</b> : Penalty applied to all partial match scores on a * per mismatch basis (value: numeric. default: 0) (partial matching must be * enabled) * <li><b>MaximumSimilarity</b> : Similarity score between two perfectly matched * slot values (value: numeric. default:0) * <li><b>MaximumDifference</b> : Similarity score between two perfectly * mismatched slot values (value: numeric. default:0) * </ul> * * @see http://jactr.org/node/87 * @author harrison */ public class DefaultDeclarativeModule6 extends DefaultDeclarativeModule implements IDeclarativeModule, IDeclarativeModule4, IDeclarativeModule5, IParameterized { /** * logger definition */ static final Log LOGGER = LogFactory .getLog(DefaultDeclarativeModule6.class); static private boolean _subsymbolicWarning = false; protected double _activationNoise; protected double _permanentActivationNoise; protected boolean _partialMatchingEnabled = false; protected double _mismatchPenalty; protected double _baseLevelConstant; protected double _maximumSimilarity; protected double _maximumDifference; protected Map<Pair, Double> _similarities; private IRandomActivationEquation _randomActivationEquation; private IBaseLevelActivationEquation _baseLevelActivationEquation; private ISpreadingActivationEquation _spreadingActivationEquation; private int _optimizationLevel = 0; public DefaultDeclarativeModule6() { super(); _similarities = new HashMap<Pair, Double>(); } /** * make sure that the appropriate activation equations are configured for the * chunks */ @Override protected void configure(IChunk newChunk) { if (_baseLevelActivationEquation == null) { /* * now let's check for a learning module.. particularly one that has base * level */ IDeclarativeLearningModule4 decLM = (IDeclarativeLearningModule4) getModel() .getModule(IDeclarativeLearningModule4.class); if (decLM != null) { _baseLevelActivationEquation = decLM.getBaseLevelActivationEquation(); _optimizationLevel = decLM.getOptimizationLevel(); } else _baseLevelActivationEquation = new DefaultBaseLevelActivationEquation( DefaultDeclarativeModule6.this); } if (_spreadingActivationEquation == null) _spreadingActivationEquation = new DefaultSpreadingActivationEquation(); if (_randomActivationEquation == null) { IRandomModule random = (IRandomModule) getModel().getModule( IRandomModule.class); _randomActivationEquation = new DefaultRandomActivationEquation(random, DefaultDeclarativeModule6.this); } /* * set the equations to be used */ ISubsymbolicChunk4 ssc = (ISubsymbolicChunk4) newChunk .getSubsymbolicChunk().getAdapter(ISubsymbolicChunk4.class); if (ssc != null) { ssc.setBaseLevelActivationEquation(_baseLevelActivationEquation); ssc.setSpreadingActivationEquation(_spreadingActivationEquation); ssc.setRandomActivationEquation(_randomActivationEquation); IReferences references = ssc.getReferences(); if (references instanceof IOptimizedReferences) ((IOptimizedReferences) references) .setOptimizationLevel(_optimizationLevel); } else if (LOGGER.isWarnEnabled() && !_subsymbolicWarning) { LOGGER .warn(String .format( "%s is designed for chunks with subsymbolics derived from ISubsymbolicChunk4", getClass().getSimpleName())); _subsymbolicWarning = true; } super.configure(newChunk); } @Override synchronized public void dispose() { try { _chunkLock.writeLock().lock(); _similarities.clear(); _similarities = null; } finally { _chunkLock.writeLock().unlock(); } super.dispose(); } public double getActivationNoise() { return _activationNoise; } public double getPermanentActivationNoise() { return _permanentActivationNoise; } public boolean isPartialMatchingEnabled() { return _partialMatchingEnabled; } public void setActivationNoise(double noise) { double old = _activationNoise; _activationNoise = noise; if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, ACTIVATION_NOISE, old, noise)); } public void setPartialMatchingEnabled(boolean enable) { boolean old = _partialMatchingEnabled; _partialMatchingEnabled = enable; if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, PARTIAL_MATCHING, old, enable)); } public void setPermanentActivationNoise(double noise) { double old = _permanentActivationNoise; _permanentActivationNoise = noise; if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, PERMANENT_ACTIVATION_NOISE, old, noise)); } public double getMismatchPenalty() { return _mismatchPenalty; } public void setMismatchPenalty(double mismatch) { double old = _mismatchPenalty; _mismatchPenalty = mismatch; if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, MISMATCH_PENALTY, old, mismatch)); } public double getMaximumDifference() { return _maximumDifference; } public double getMaximumSimilarity() { return _maximumSimilarity; } public void setMaximumDifference(double maxDiff) { double old = _maximumDifference; _maximumDifference = maxDiff; if (_maximumDifference > 0) if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("MaximumDifference should be <= 0")); if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, MAXIMUM_DIFFERENCE, old, maxDiff)); } public void setMaximumSimilarity(double maxSim) { double old = _maximumSimilarity; _maximumSimilarity = maxSim; if (_maximumSimilarity < 0) if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("MaximumSimilarity should be >=0")); if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, MAXIMUM_SIMILARITY, old, maxSim)); } public double getBaseLevelConstant() { return _baseLevelConstant; } public void setBaseLevelConstant(double base) { double old = _baseLevelConstant; _baseLevelConstant = base; if (hasListeners()) dispatch(new DeclarativeModuleEvent(this, BASE_LEVEL_CONSTANT, old, _baseLevelConstant)); } public double getSimilarity(Object one, Object two) { Pair tmp = new Pair(one, two); if (_similarities.containsKey(tmp)) return _similarities.get(tmp); return _maximumDifference; } public void setSimilarity(Object one, Object two, double sim) { _similarities.put(new Pair(one, two), sim); } /** * @see org.jactr.core.utils.parameter.IParameterized#getParameter(java.lang.String) */ @Override public String getParameter(String key) { if (PARTIAL_MATCHING.equalsIgnoreCase(key)) return "" + isPartialMatchingEnabled(); if (BASE_LEVEL_CONSTANT.equalsIgnoreCase(key)) return "" + getBaseLevelConstant(); if (ACTIVATION_NOISE.equalsIgnoreCase(key)) return "" + getActivationNoise(); if (PERMANENT_ACTIVATION_NOISE.equalsIgnoreCase(key)) return "" + getPermanentActivationNoise(); if (MISMATCH_PENALTY.equalsIgnoreCase(key)) return "" + getMismatchPenalty(); if (MAXIMUM_DIFFERENCE.equalsIgnoreCase(key)) return "" + getMaximumDifference(); if (MAXIMUM_SIMILARITY.equalsIgnoreCase(key)) return "" + getMaximumSimilarity(); return super.getParameter(key); } /** * @see org.jactr.core.utils.parameter.IParameterized#getSetableParameters() */ @Override public Collection<String> getSetableParameters() { Collection<String> rtn = super.getSetableParameters(); rtn.add(PARTIAL_MATCHING); rtn.add(BASE_LEVEL_CONSTANT); rtn.add(ACTIVATION_NOISE); rtn.add(PERMANENT_ACTIVATION_NOISE); rtn.add(MISMATCH_PENALTY); rtn.add(MAXIMUM_DIFFERENCE); rtn.add(MAXIMUM_SIMILARITY); return rtn; } /** * @see org.jactr.core.utils.parameter.IParameterized#setParameter(java.lang.String, * java.lang.String) */ @Override public void setParameter(String key, String value) { if (PARTIAL_MATCHING.equalsIgnoreCase(key)) setPartialMatchingEnabled(ParameterHandler.booleanInstance() .coerce(value)); else if (BASE_LEVEL_CONSTANT.equalsIgnoreCase(key)) setBaseLevelConstant(ParameterHandler.numberInstance().coerce(value) .doubleValue()); else if (ACTIVATION_NOISE.equalsIgnoreCase(key)) setActivationNoise(ParameterHandler.numberInstance().coerce(value) .doubleValue()); else if (PERMANENT_ACTIVATION_NOISE.equalsIgnoreCase(key)) setPermanentActivationNoise(ParameterHandler.numberInstance() .coerce(value).doubleValue()); else if (MISMATCH_PENALTY.equalsIgnoreCase(key)) setMismatchPenalty(ParameterHandler.numberInstance().coerce(value) .doubleValue()); else if (MAXIMUM_DIFFERENCE.equalsIgnoreCase(key)) setMaximumDifference(ParameterHandler.numberInstance().coerce(value) .doubleValue()); else if (MAXIMUM_SIMILARITY.equalsIgnoreCase(key)) setMaximumSimilarity(ParameterHandler.numberInstance().coerce(value) .doubleValue()); else super.setParameter(key, value); } }