├── .travis.yml ├── .gitignore ├── run.bat ├── run.sh ├── src ├── main │ ├── resources │ │ ├── images │ │ │ ├── add.png │ │ │ ├── disk.png │ │ │ ├── play.png │ │ │ ├── step.png │ │ │ ├── stop.png │ │ │ ├── cleanup.png │ │ │ ├── delete.png │ │ │ ├── eraser.png │ │ │ ├── refresh.png │ │ │ ├── book_open.png │ │ │ ├── bullet_go.png │ │ │ ├── cog_edit.png │ │ │ ├── resultset_next.png │ │ │ └── arrow_rotate_clockwise.png │ │ ├── log4j.properties │ │ └── config.xml │ ├── java │ │ └── htm │ │ │ ├── model │ │ │ ├── algorithms │ │ │ │ ├── spatial │ │ │ │ │ ├── NUPICSpatialPooler.java │ │ │ │ │ ├── SpatialPooler.java │ │ │ │ │ └── WhitePaperSpatialPooler.java │ │ │ │ ├── temporal │ │ │ │ │ ├── NUPICTemporalPooler.java │ │ │ │ │ └── TemporalPooler.java │ │ │ │ └── Pooler.java │ │ │ ├── fractal │ │ │ │ ├── Fractal.java │ │ │ │ └── Composite.java │ │ │ ├── Region.java │ │ │ ├── space │ │ │ │ ├── Element.java │ │ │ │ ├── InputSpace.java │ │ │ │ └── BaseSpace.java │ │ │ ├── DistalDendriteSegment.java │ │ │ ├── Synapse.java │ │ │ ├── Layer.java │ │ │ ├── Cell.java │ │ │ └── Column.java │ │ │ ├── utils │ │ │ ├── CollectionUtils.java │ │ │ ├── CircularArrayList.java │ │ │ ├── MathUtils.java │ │ │ └── UIUtils.java │ │ │ └── visualizer │ │ │ ├── surface │ │ │ ├── CellSurface.java │ │ │ ├── ColumnSDRSurface.java │ │ │ ├── SensoryInputSurface.java │ │ │ ├── LayerColumnsVerticalView.java │ │ │ ├── BaseSurface.java │ │ │ └── LayerSlicedHorizontalView.java │ │ │ ├── SpatialInfo.java │ │ │ ├── ParametersEditor.java │ │ │ └── Parameters.java │ ├── groovy │ │ └── htm │ │ │ └── utils │ │ │ └── MathUtilsExt.groovy │ └── assembly │ │ └── distribution.xml └── test │ └── groovy │ └── htm │ ├── AbstractSpockTest.groovy │ └── utils │ └── MathUtilsTest.groovy ├── README.md ├── examples ├── 2-1.xml ├── aaax.xml ├── 2-1-2.xml ├── balls-reflect.xml ├── balls-reflect-with-spatial.xml ├── balls-reflect_overlap-spatial.xml ├── balls-reflect_overlap.xml └── pong.xml ├── License_Numenta.txt └── pom.xml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | cache: 3 | directories: 4 | - $HOME/.m2 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *~ 3 | target/* 4 | *.class 5 | bin/ 6 | build/ 7 | .project 8 | .idea/ 9 | *.iml 10 | *.log -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | java -classpath "lib\commons-logging-1.1.3.jar;lib\log4j-1.2.9.jar;htm-visualizer.jar" htm.visualizer.Viewer 2 | 3 | 4 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java -classpath "lib/commons-logging-1.1.3.jar:lib/log4j-1.2.9.jar:htm-visualizer.jar" htm.visualizer.Viewer 3 | -------------------------------------------------------------------------------- /src/main/resources/images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/add.png -------------------------------------------------------------------------------- /src/main/resources/images/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/disk.png -------------------------------------------------------------------------------- /src/main/resources/images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/play.png -------------------------------------------------------------------------------- /src/main/resources/images/step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/step.png -------------------------------------------------------------------------------- /src/main/resources/images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/stop.png -------------------------------------------------------------------------------- /src/main/resources/images/cleanup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/cleanup.png -------------------------------------------------------------------------------- /src/main/resources/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/delete.png -------------------------------------------------------------------------------- /src/main/resources/images/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/eraser.png -------------------------------------------------------------------------------- /src/main/resources/images/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/refresh.png -------------------------------------------------------------------------------- /src/main/resources/images/book_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/book_open.png -------------------------------------------------------------------------------- /src/main/resources/images/bullet_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/bullet_go.png -------------------------------------------------------------------------------- /src/main/resources/images/cog_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/cog_edit.png -------------------------------------------------------------------------------- /src/main/resources/images/resultset_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/resultset_next.png -------------------------------------------------------------------------------- /src/main/resources/images/arrow_rotate_clockwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solovyevk/htm-cla-visualizer/HEAD/src/main/resources/images/arrow_rotate_clockwise.png -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/spatial/NUPICSpatialPooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms.spatial; 10 | 11 | public class NUPICSpatialPooler { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/groovy/htm/AbstractSpockTest.groovy: -------------------------------------------------------------------------------- 1 | package htm 2 | import org.junit.Ignore 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: miao.lin 6 | * Date: 14-3-12 7 | * Time: 上午11:25 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | import spock.lang.Specification 11 | 12 | @Ignore 13 | class AbstractSpockTest extends Specification { 14 | 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/htm/model/fractal/Fractal.java: -------------------------------------------------------------------------------- 1 | package htm.model.fractal; 2 | 3 | import java.util.List; 4 | 5 | public interface Fractal { 6 | public void reset(); 7 | public P getOwner(); 8 | public E getElementByIndex(int inx); 9 | public List getElements(); 10 | public boolean addElement(E element); 11 | public boolean addAll(List all); 12 | public void removeElement(E element); 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/groovy/htm/utils/MathUtilsExt.groovy: -------------------------------------------------------------------------------- 1 | package htm.utils 2 | 3 | import groovy.transform.CompileStatic 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: miao.lin 8 | * Date: 14-3-12 9 | * Time: 上午11:21 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | @CompileStatic 13 | class MathUtilsExt extends MathUtils{ 14 | static public double findMax(double... values) { 15 | return GroovyCollections.max(values.toList()) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/htm/model/Region.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class Region extends htm.model.fractal.Composite { 15 | public static final int BRAIN_REGION_LAYERS_NUMBER = 6; 16 | 17 | protected final Map layers = new HashMap(BRAIN_REGION_LAYERS_NUMBER); 18 | 19 | public Layer getLayer(String level){ 20 | return layers.get(level); 21 | } 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/test/groovy/htm/utils/MathUtilsTest.groovy: -------------------------------------------------------------------------------- 1 | package htm.utils 2 | 3 | import htm.AbstractSpockTest 4 | import org.junit.Test 5 | 6 | /** 7 | * Created with IntelliJ IDEA. 8 | * User: miao.lin 9 | * Date: 14-3-12 10 | * Time: 上午11:28 11 | * To change this template use File | Settings | File Templates. 12 | */ 13 | class MathUtilsTest extends AbstractSpockTest{ 14 | @Test 15 | void testFindMax(){ 16 | expect: 17 | MathUtilsExt.findMax(a,b,c,d)==c 18 | 19 | where: 20 | a | b | c | d 21 | 1.1 | 2.2 | 10.8 | 9.9 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/temporal/NUPICTemporalPooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms.temporal; 10 | 11 | import htm.model.Cell; 12 | import htm.model.DistalDendriteSegment; 13 | 14 | public class NUPICTemporalPooler extends WhitePaperTemporalPooler { 15 | public NUPICTemporalPooler(Config cfg) { 16 | super(cfg); 17 | } 18 | 19 | @Override 20 | public DistalDendriteSegment getActiveSegment(Cell cell, int time, Cell.State state) { 21 | return super.getActiveSegment(cell, time, state); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | htm-visualizer 2 | ============== 3 | 4 | Visualization of Hierarchical Temporal Memory (HTM) Cortical Learning Algorithms (CLA) in JAVA 5 | 6 | 7 | Implementation is based on Numenta's CLA white paper: 8 | https://www.groksolutions.com/htm-overview/education/HTM_CorticalLearningAlgorithms.pdf 9 | 10 | Videos: 11 | 12 | 1) Introduction: https://www.youtube.com/watch?v=nRgbQhdfL9Q 13 | 14 | 2) Debugging Temporal Pooler segments formation: https://www.youtube.com/watch?v=9twCUKrAqPo 15 | 16 | 17 | Build Steps: 18 | 19 | 1) Download and install Maven: http://maven.apache.org/download.cgi 20 | 21 | 2) Execute "mvn package" command in the project home directory (where pom.xml file located) 22 | -------------------------------------------------------------------------------- /src/main/java/htm/utils/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.utils; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | public class CollectionUtils { 16 | 17 | private CollectionUtils() { 18 | } 19 | 20 | public static List filter(Collection target, Predicate predicate) { 21 | List result = new ArrayList(); 22 | for (T element: target) { 23 | if (predicate.apply(element)) { 24 | result.add(element); 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | public static interface Predicate { boolean apply(T type); } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/assembly/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | dist 3 | false 4 | 5 | zip 6 | 7 | 8 | 9 | target/${project.build.finalName}.jar 10 | htm-visualizer.jar 11 | 0644 12 | 13 | 14 | run.bat 15 | run.bat 16 | true 17 | 0644 18 | 19 | 20 | run.sh 21 | run.sh 22 | true 23 | 0755 24 | 25 | 26 | 27 | 28 | /lib 29 | 30 | htm:htm-visualizer 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/Pooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms; 10 | 11 | import htm.model.Layer; 12 | import htm.model.algorithms.spatial.SpatialPooler; 13 | import htm.model.algorithms.temporal.TemporalPooler; 14 | 15 | public abstract class Pooler { 16 | protected Layer layer; 17 | protected boolean learningMode = true; 18 | 19 | public boolean isLearningMode() { 20 | return learningMode; 21 | } 22 | 23 | public void setLearningMode(boolean learningMode) { 24 | this.learningMode = learningMode; 25 | } 26 | 27 | public Pooler setLayer(Layer layer) { 28 | this.layer = layer; 29 | if(TemporalPooler.class.isAssignableFrom(this.getClass())){ 30 | layer.setTemporalPooler((TemporalPooler)this); 31 | } else { 32 | layer.setSpatialPooler((SpatialPooler)this); 33 | } 34 | return this; 35 | } 36 | 37 | public abstract void execute(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # This is a configuration file for using log4j with Kodo logging. 2 | # For details about log4j configuration, see: 3 | # http://jakarta.apache.org/log4j/docs/index.html 4 | 5 | log4j.rootCategory=WARN, console, testLog 6 | 7 | log4j.category.htm=DEBUG 8 | log4j.category.htm.visualizer.HTMGraphicInterface=INFO 9 | log4j.category.htm.model.Column=INFO 10 | log4j.category.htm.model.Region=INFO 11 | 12 | 13 | # Set appender specific options. 14 | log4j.appender.testLog=org.apache.log4j.RollingFileAppender 15 | log4j.appender.testLog.File=visualizer.log 16 | log4j.appender.testLog.Append=true 17 | log4j.appender.testLog.MaxFileSize=10mb 18 | log4j.appender.testLog.MaxBackupIndex=9 19 | log4j.appender.testLog.layout=org.apache.log4j.PatternLayout 20 | log4j.appender.testLog.layout.ConversionPattern=%-5r %-5p - %m%n 21 | 22 | log4j.appender.console=org.apache.log4j.ConsoleAppender 23 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 24 | log4j.appender.console.layout.ConversionPattern=%-5r %-5p - %m%n 25 | -------------------------------------------------------------------------------- /src/main/java/htm/model/space/Element.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.space; 10 | 11 | 12 | import htm.model.fractal.Composite; 13 | 14 | import java.awt.*; 15 | 16 | public class Element extends Composite { 17 | protected final Point position; 18 | private final int index; 19 | 20 | public Element(P owner, Point position, int index) { 21 | this.owner = owner; 22 | this.position = position; 23 | this.index = index; 24 | } 25 | 26 | public Point getPosition() { 27 | return position; 28 | } 29 | 30 | public int getIndex() { 31 | return index; 32 | } 33 | 34 | /** 35 | * Kind unique identifier for position 36 | */ 37 | public int getLocationSeed() { 38 | int length = position.y == 0 ? 1 : (int)(Math.log10(position.y) + 1); 39 | return (position.x + 1) * (int)Math.pow(10, length) + position.y; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "locationSeed:" + getLocationSeed() + ", X:" + getPosition().x + ", Y:" + getPosition().y + ", index:" + getIndex(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 5.0 6 | 4.0 7 | 3 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 0 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.005 31 | 0.005 32 | 33 | 34 | 0.2 35 | 0.005 36 | 0.005 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/htm/utils/CircularArrayList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.utils; 10 | 11 | import java.util.ArrayList; 12 | 13 | 14 | public class CircularArrayList extends ArrayList { 15 | 16 | protected final int maxCapacity; 17 | 18 | /** 19 | * ArrayList has a capacity, if full, 20 | * remove the oldest element 21 | * 22 | * @param capacity 23 | */ 24 | public CircularArrayList(int capacity) { 25 | super(capacity + 1); 26 | this.maxCapacity = capacity; 27 | } 28 | 29 | /** 30 | * 31 | * if full, remove oldest element 32 | * @param element 33 | */ 34 | 35 | @Override public boolean add(E element) { 36 | boolean result = super.add(element); 37 | removeExcess(); 38 | return result; 39 | } 40 | 41 | /** 42 | * if full, remove oldest element 43 | * 44 | * @param index 45 | * @param element 46 | */ 47 | @Override 48 | public void add(int index, E element) { 49 | super.add(index, element); 50 | removeExcess(); 51 | } 52 | 53 | private void removeExcess() { 54 | if (this.size() > maxCapacity) { 55 | this.remove(maxCapacity); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/htm/model/fractal/Composite.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.fractal; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | public class Composite implements Fractal { 16 | protected final List elementList = new ArrayList(); 17 | protected P owner; 18 | 19 | @Override public void reset() { 20 | //DO NOTHING BY DEFAULT 21 | } 22 | 23 | @Override public List getElements() { 24 | return Collections.unmodifiableList(elementList); 25 | } 26 | 27 | public List getElementsList() { 28 | return elementList; 29 | } 30 | 31 | @Override public boolean addAll(List all) { 32 | return elementList.addAll(all); 33 | } 34 | 35 | @Override 36 | public P getOwner() { 37 | return owner; 38 | } 39 | 40 | @Override public E getElementByIndex(int index) { 41 | return elementList.get(index); 42 | } 43 | 44 | @Override public boolean addElement(E element) { 45 | return elementList.add(element); 46 | } 47 | 48 | @Override public void removeElement(E element) { 49 | elementList.remove(element); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/2-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 8.0 7 | 3 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 1 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/htm/utils/MathUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.utils; 10 | 11 | import java.math.BigDecimal; 12 | import java.util.List; 13 | 14 | public class MathUtils { 15 | // private MathUtils() { 16 | // } 17 | 18 | static public double findMax(Double... values) { 19 | double max = Double.MIN_VALUE; 20 | for (double d : values) { 21 | if (d > max) max = d; 22 | } 23 | return max; 24 | } 25 | 26 | static public double findMax(List values) { 27 | double max = Double.MIN_VALUE; 28 | for (Double d : values) { 29 | if (d > max) max = d; 30 | } 31 | return max; 32 | } 33 | 34 | static public double findMin(Double... values) { 35 | double min = Double.MAX_VALUE; 36 | for (double d : values) { 37 | if (d < min) min = d; 38 | } 39 | return min; 40 | } 41 | 42 | static public double findMin(List values) { 43 | double min = Double.MAX_VALUE; 44 | for (double d : values) { 45 | if (d < min) min = d; 46 | } 47 | return min; 48 | } 49 | 50 | public static boolean inRange(int value, int lowerBound, int upperBound) { 51 | return (lowerBound <= value && value <= upperBound); 52 | } 53 | 54 | public static boolean inRange(double value, double lowerBound, double upperBound) { 55 | return (lowerBound <= value && value <= upperBound); 56 | } 57 | 58 | public static double round(double value, int places) { 59 | if (places < 0) throw new IllegalArgumentException("places should not be negative"); 60 | BigDecimal bd = new BigDecimal(value); 61 | bd = bd.setScale(places, BigDecimal.ROUND_HALF_UP); 62 | return bd.doubleValue(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /examples/aaax.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 23.275 7 | 4 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 7 23 | 4 24 | 0 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.02 37 | 38 | 39 | 000000000000000000000000000001000000000011100000000010100000000111110000000100010000000100010000000000000000000000000000000000000000000000000000 40 | 000000000000000000000000000001000000000011100000000010100000000111110000000100010000000100010000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000000001000000000011100000000010100000000111110000000100010000000100010000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000100010000000010100000000001000000000001000000000010100000000100010000000000000000000000000000000000000000000000000000 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/2-1-2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 8.0 7 | 3 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 1 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000100000000000100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000 43 | 000000000000000000100000000000100000000000100000000000100000000000100000000000100000000000000000000000000000000000000000000000000000000000000000 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/spatial/SpatialPooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms.spatial; 10 | 11 | public abstract class SpatialPooler extends htm.model.algorithms.Pooler { 12 | 13 | private final int minimalOverlap; 14 | 15 | private final double boostRate; 16 | 17 | private final int desiredLocalActivity; 18 | 19 | protected SpatialPooler(Config cfg) { 20 | this.minimalOverlap = cfg.getMinOverlap(); 21 | this.boostRate = cfg.getBoostRate(); 22 | this.desiredLocalActivity = cfg.getDesiredLocalActivity(); 23 | } 24 | 25 | /** 26 | * WP 27 | * A minimum number of inputs that must be active for a 28 | * column to be considered during the inhibition step. 29 | */ 30 | public int getMinimalOverlap() { 31 | return minimalOverlap; 32 | } 33 | 34 | /** 35 | * The amount that is added to a Column's Boost value in a single time step, when it is being boosted. 36 | */ 37 | public double getBoostRate() { 38 | return boostRate; 39 | } 40 | 41 | /** 42 | * WP 43 | * desiredLocalActivity A parameter controlling the number of columns that 44 | * will be winners after the inhibition step. 45 | */ 46 | public int getDesiredLocalActivity() { 47 | return desiredLocalActivity; 48 | } 49 | 50 | public static class Config { 51 | private final int minOverlap; 52 | private final int desiredLocalActivity; 53 | private final double boostRate; 54 | 55 | public Config(int minOverlap, int desiredLocalActivity, 56 | double boostRate) { 57 | this.minOverlap = minOverlap; 58 | this.desiredLocalActivity = desiredLocalActivity; 59 | this.boostRate = boostRate; 60 | } 61 | 62 | 63 | public int getMinOverlap() { 64 | return minOverlap; 65 | } 66 | 67 | public int getDesiredLocalActivity() { 68 | return desiredLocalActivity; 69 | } 70 | 71 | public double getBoostRate() { 72 | return boostRate; 73 | } 74 | } 75 | } 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/main/java/htm/model/space/InputSpace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.space; 10 | 11 | 12 | import java.awt.*; 13 | import java.util.List; 14 | import java.util.NoSuchElementException; 15 | 16 | public class InputSpace extends BaseSpace { 17 | public InputSpace(int xSize, int ySize) { 18 | super(xSize, ySize); 19 | initElementSpace(); 20 | } 21 | 22 | public InputSpace(Dimension dimension) { 23 | super(dimension); 24 | initElementSpace(); 25 | } 26 | 27 | @Override 28 | protected Input createElement(int index, 29 | Point position) { 30 | return new Input(this, position, index, false); 31 | } 32 | 33 | 34 | public void setInputValue(int index, boolean value) { 35 | this.getElementByIndex(index).setValue(value); 36 | } 37 | 38 | public boolean getInputValue(int index) { 39 | return this.getElementByIndex(index).getValue(); 40 | } 41 | 42 | 43 | public static class Input extends Element { 44 | private boolean value; 45 | 46 | public Input(InputSpace space, Point position, int index, boolean value) { 47 | super(space, position, index); 48 | this.value = value; 49 | } 50 | 51 | public boolean getValue() { 52 | return value; 53 | } 54 | 55 | @Override public boolean addAll(List all) { 56 | throw new NoSuchElementException("Not supported for Input. It is a Leaf Element"); 57 | } 58 | 59 | @Override public Input getElementByIndex(int index) { 60 | throw new NoSuchElementException("Not supported for Input. It is a Leaf Element"); 61 | } 62 | 63 | @Override public boolean addElement(Input element) { 64 | throw new NoSuchElementException("Not supported for Input. It is a Leaf Element"); 65 | } 66 | 67 | @Override public void removeElement(Input element) { 68 | throw new NoSuchElementException("Not supported for Input. It is a Leaf Element"); 69 | } 70 | 71 | public void setValue(boolean sourceInput) { 72 | this.value = sourceInput; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/CellSurface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer.surface; 10 | 11 | import htm.model.Cell; 12 | import htm.model.Layer; 13 | import htm.utils.UIUtils; 14 | 15 | import java.awt.*; 16 | 17 | public abstract class CellSurface extends BaseSurface.CircleElementsSurface { 18 | public static final Color PREDICTED_COLOR = Color.BLUE; 19 | public static final Color PREDICTED_IN_STEP_COLOR = UIUtils.LIGHT_BLUE; 20 | public static final Color LEARNING_COLOR = Color.RED; 21 | protected final Layer region; 22 | 23 | public CellSurface(int xSize, int ySize, Layer region) { 24 | super(xSize, ySize); 25 | this.region = region; 26 | } 27 | 28 | protected Layer getRegion() { 29 | return region; 30 | } 31 | 32 | @Override 33 | protected void drawElement(Graphics2D g2d, int columnIndex, int x, int y, int width, int height) { 34 | Cell currentCell = getCell(columnIndex); 35 | drawCell(g2d, x, y, width, height, currentCell, Cell.NOW); 36 | } 37 | 38 | public static void drawCell(Graphics2D g2d, Rectangle rect, Cell cell, int time) { 39 | drawCell(g2d, rect.x, rect.y, rect.width, rect.height, cell, time); 40 | } 41 | 42 | public static void drawCell(Graphics2D g2d, int x, int y, int width, int height, Cell cell, int time) { 43 | int predictInStep = cell.getPredictInStepState(time); 44 | Color predictedColor = predictInStep > 1 ? PREDICTED_IN_STEP_COLOR : PREDICTED_COLOR; 45 | if (cell.getPredictiveState(time) && cell.getActiveState(time)) { 46 | UIUtils.drawStatesInCircle(g2d, x, y, width, height, predictedColor, ACTIVE_COLOR); 47 | } else if (cell.getPredictiveState(time)) { 48 | UIUtils.drawStatesInCircle(g2d, x, y, width, height, predictedColor); 49 | } else if (cell.getActiveState(time)) { 50 | UIUtils.drawStatesInCircle(g2d, x, y, width, height, ACTIVE_COLOR); 51 | } else { 52 | UIUtils.drawStatesInCircle(g2d, x, y, width, height); 53 | } 54 | if (cell.getLearnState(time)) { 55 | //third of cell width 56 | int newWidth = width / 3; 57 | g2d.setColor(LEARNING_COLOR); 58 | g2d.fillRect(x + newWidth + 1, y + newWidth + 1, newWidth, newWidth); 59 | } 60 | if(predictInStep > 1){ 61 | String predictInStepStr = predictInStep+""; 62 | UIUtils.drawTextInCenter(g2d, x, y, width, height, predictInStepStr); 63 | } 64 | } 65 | 66 | public abstract Cell getCell(int index); 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/temporal/TemporalPooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms.temporal; 10 | 11 | import htm.model.Cell; 12 | import htm.model.DistalDendriteSegment; 13 | 14 | public abstract class TemporalPooler extends htm.model.algorithms.Pooler { 15 | 16 | private final int newSynapseCount; 17 | private final int activationThreshold; 18 | private final int minThreshold; 19 | 20 | protected TemporalPooler(Config cfg) { 21 | this.newSynapseCount = cfg.getNewSynapseCount(); 22 | this.activationThreshold = cfg.getActivationThreshold(); 23 | this.minThreshold = cfg.getMinThreshold(); 24 | } 25 | 26 | 27 | /** 28 | * WP 29 | *

30 | * newSynapseCount 31 | * The maximum number of synapses added to a segment during learning. 32 | */ 33 | public int getNewSynapseCount() { 34 | return newSynapseCount; 35 | } 36 | 37 | /** 38 | * WP 39 | * activationThreshold 40 | *

41 | * Activation threshold for a segment. If the number of active connected 42 | * synapses in a segment is greater than activationThreshold, the segment is said to be active. 43 | */ 44 | public int getActivationThreshold() { 45 | return activationThreshold; 46 | } 47 | 48 | /** 49 | * WP 50 | * minThreshold Minimum segment activity for learning. 51 | */ 52 | public int getMinThreshold() { 53 | return minThreshold; 54 | } 55 | 56 | 57 | /** 58 | * WP 59 | * segmentActive(s, t, state) 60 | *

61 | * This routine returns true if the number of connected synapses on segments that are active due to the given 62 | * state at time t is greater than activationThreshold. The parameter state can be activeState, or learnState. 63 | */ 64 | public boolean segmentActive(DistalDendriteSegment segment, int time, Cell.State state) { 65 | return segment.getConnectedWithStateCell(time, state).size() > activationThreshold; 66 | } 67 | 68 | 69 | public static class Config { 70 | private final int newSynapseCount; 71 | private final int activationThreshold; 72 | private final int minThreshold; 73 | 74 | public Config(int newSynapseCount, int activationThreshold, int minThreshold) { 75 | this.newSynapseCount = newSynapseCount; 76 | this.activationThreshold = activationThreshold; 77 | this.minThreshold = minThreshold; 78 | } 79 | 80 | public int getNewSynapseCount() { 81 | return newSynapseCount; 82 | } 83 | 84 | public int getActivationThreshold() { 85 | return activationThreshold; 86 | } 87 | 88 | public int getMinThreshold() { 89 | return minThreshold; 90 | } 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /examples/balls-reflect.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 17.5 7 | 2 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 0 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 43 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 44 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011 45 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 46 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 47 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 48 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/balls-reflect-with-spatial.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 4.41 6 | 17.5 7 | 3 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 2 18 | 1 19 | 0.01 20 | 21 | 22 | 5 23 | 1 24 | 0 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 43 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 44 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011 45 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 46 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 47 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 48 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 49 | 50 | 51 | -------------------------------------------------------------------------------- /License_Numenta.txt: -------------------------------------------------------------------------------- 1 | This software is based upon or includes certain works and algorithms related 2 | to hierarchical temporal memory ("HTM") technology published by Numenta Inc. 3 | 4 | 5 | Numenta holds patent rights related to HTM and the algorithms used in this 6 | software. 7 | 8 | Numenta has agreed not to assert its patent rights against 9 | development or use of independent HTM systems, as long as such development 10 | or use is for research purposes only, and not for any commercial or production 11 | use. 12 | 13 | Any commercial or production use of HTM technology that infringes on 14 | Numenta's patents will require a commercial license from Numenta. 15 | 16 | 17 | 18 | Based on the foregoing, this software is licensed under the terms below, for 19 | research purposes only and not for any commercial or production use. 20 | 21 | Numenta License for Non-Commercial Use: 22 | 23 | For 24 | purposes of this license, "commercial or production use" includes training an 25 | HTM network with the intent of later deploying the trained network or 26 | application for commercial or production purposes, and using or permitting 27 | others to use the output from HTM technology for commercial or production 28 | purposes. 29 | 30 | Redistribution and use in source and binary forms, with or without 31 | modification, are permitted (subject to the limitations in the disclaimer 32 | below) provided that the following conditions are met: 33 | 34 | * Redistributions of source code, including any modifications or derivative 35 | works, must retain the full text of this license and the following disclaimer, 36 | and be subject to the terms and conditions of this license. 37 | 38 | * Redistributions in binary form, including any modifications or derivative 39 | works, must reproduce the full text of this license and the following 40 | disclaimer in the documentation and/or other materials provided with the 41 | distribution, and be subject to the terms and conditions of this license. 42 | 43 | * Neither the name of Numenta, Inc., Barry Maturkanich, nor the names of other 44 | contributors may be used to endorse or promote products derived from this 45 | software without specific prior written permission. 46 | 47 | NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT RIGHTS ARE GRANTED BY THIS 48 | LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 50 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 52 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 54 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 55 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 56 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 57 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/main/java/htm/model/space/BaseSpace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.space; 10 | 11 | 12 | import htm.utils.CollectionUtils; 13 | import org.apache.commons.logging.Log; 14 | import org.apache.commons.logging.LogFactory; 15 | 16 | import java.awt.*; 17 | import java.util.List; 18 | 19 | 20 | public abstract class BaseSpace> extends htm.model.fractal.Composite { 21 | private static final Log LOG = LogFactory.getLog( 22 | BaseSpace.class); 23 | 24 | private final Dimension dimension; 25 | 26 | 27 | protected BaseSpace(int xSize, int ySize) { 28 | this.dimension = new Dimension(xSize, ySize); 29 | } 30 | /*Have to call it after construction and param initialization*/ 31 | protected void initElementSpace() { 32 | int xSize = this.dimension.width; int ySize = this.dimension.height; 33 | int index = 0; 34 | for (int y = 0; y < ySize; y++) { 35 | for (int x = 0; x < xSize; x++) { 36 | elementList.add(index, createElement(index, new Point(x, y))); 37 | index++; 38 | } 39 | } 40 | } 41 | 42 | BaseSpace(Dimension dimension) { 43 | this(dimension.width, dimension.height); 44 | } 45 | 46 | public int getLongSide() { 47 | return Math.max(dimension.width, dimension.height); 48 | } 49 | 50 | public int getShortSide() { 51 | return Math.min(dimension.width, dimension.height); 52 | } 53 | 54 | protected abstract E createElement(int index, Point position); 55 | 56 | public E getElementByPosition(Point position) { 57 | for (E element : elementList) { 58 | if (element.getPosition().x == position.x && element.getPosition().y == position.y) { 59 | return element; 60 | } 61 | } 62 | throw new IllegalArgumentException("There in no element by this position" + position); 63 | } 64 | 65 | 66 | public List getAllWithinRadius(final Point center, final double radius) { 67 | CollectionUtils.Predicate withinRadius = new CollectionUtils.Predicate() { 68 | @Override public boolean apply(E element) { 69 | return Math.pow(center.x - element.getPosition().x, 2) + Math.pow(center.y - element.getPosition().y, 70 | 2) <= Math.pow(radius, 2); 71 | } 72 | }; 73 | return CollectionUtils.filter(elementList, withinRadius); 74 | } 75 | 76 | public Dimension getDimension() { 77 | return dimension; 78 | } 79 | 80 | protected Point convertPositionToOtherSpace(Point srcPosition, Dimension srcDimension, Dimension targetDimension) { 81 | double xScale = targetDimension.getWidth() / srcDimension.getWidth(); 82 | double yScale = targetDimension.getHeight() / srcDimension.getHeight(); 83 | //apply function scale 84 | double xAdj = 0;// xScale/2 - (srcPosition.getX()/srcDimension.getWidth()) * xScale; 85 | double targetX = Math.min(Math.ceil(srcPosition.getX() * xScale + (xScale > 1 ? xAdj : 0)), 86 | targetDimension.width - 1); 87 | //LOG.debug("xAdj:" + xAdj + ", X:" + srcPosition.getX() * xScale + ", adj. targetX :" + targetX); 88 | double yAdj = 0;// yScale/2 - (srcPosition.getY()/srcDimension.getHeight()) * yScale; 89 | //double yAdj = yScale / 2 - srcPosition.getY() / ((yScale + 2) * yScale); 90 | double targetY = Math.min(Math.ceil(srcPosition.getY() * yScale + (yScale > 1 ? yAdj : 0)), 91 | targetDimension.height - 1); 92 | Point result = new Point(); 93 | result.setLocation(targetX, targetY); 94 | return result; 95 | } 96 | 97 | /* 98 | helpers 99 | */ 100 | public static double getDistance(Point pointOne, Point pointTwo) { 101 | int dX = pointOne.x - pointTwo.x; 102 | int dY = pointOne.y - pointTwo.y; 103 | return Math.sqrt(Math.pow(dX, 2) + Math.pow(dY, 2)); 104 | } 105 | 106 | 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/ColumnSDRSurface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer.surface; 10 | 11 | 12 | import htm.model.Cell; 13 | import htm.model.Column; 14 | import htm.model.Layer; 15 | import htm.utils.UIUtils; 16 | 17 | import java.awt.*; 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | public class ColumnSDRSurface extends BaseSurface.CircleElementsSurface { 22 | 23 | 24 | protected final Layer region; 25 | private Column currentColumn; //clicked on 26 | private Integer selectedColumnIndex; //selected from neighbours table 27 | 28 | public ColumnSDRSurface(Layer region) { 29 | super(region.getDimension().width, region.getDimension().height); 30 | this.region = region; 31 | } 32 | 33 | @Override 34 | protected void drawElement(Graphics2D g2d, int index, int x, int y, int width, int height) { 35 | Column column = getColumn(index); 36 | Set cellStates = new HashSet(); 37 | for (Cell cell : column.getElements()) { 38 | int predictInStep = cell.getPredictInStepState(Cell.NOW); 39 | if (predictInStep == 1) { 40 | cellStates.add(CellSurface.PREDICTED_COLOR); 41 | } 42 | if (predictInStep > 1) { 43 | cellStates.add(CellSurface.PREDICTED_IN_STEP_COLOR); 44 | } 45 | } 46 | if (column.isActive()) { 47 | cellStates.add(ACTIVE_COLOR); 48 | } 49 | UIUtils.drawStatesInCircle(g2d, x, y, width, height, cellStates.toArray(new Color[cellStates.size()])); 50 | } 51 | 52 | public Column getColumn(int columnIndex) { 53 | return region.getElementByIndex(columnIndex); 54 | } 55 | 56 | public void setCurrentColumn(Column currentColumn) { 57 | this.currentColumn = this.currentColumn != currentColumn ? currentColumn : null; 58 | this.selectedColumnIndex = null; 59 | this.repaint(); 60 | } 61 | 62 | public void setSelectedColumn(int selectedColumnIndex) { 63 | this.selectedColumnIndex = selectedColumnIndex; 64 | this.repaint(); 65 | } 66 | 67 | public void drawInhibitedColumns(Column currentColumn, Graphics2D g2d) { 68 | java.util.List inhibitedColumn = currentColumn.getNeighbors(region.getAverageReceptiveFieldSize()); 69 | g2d.setColor(Color.LIGHT_GRAY); 70 | Composite original = g2d.getComposite(); 71 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 72 | 0.4f)); 73 | for (Column column : inhibitedColumn) { 74 | Rectangle columnRec = this.getElementArea(column.getPosition()); 75 | g2d.fillOval(columnRec.x, columnRec.y, columnRec.width, columnRec.height); 76 | } 77 | g2d.setComposite(original); 78 | } 79 | 80 | @Override 81 | protected void doDrawing(Graphics2D g2d) { 82 | super.doDrawing(g2d); 83 | if (currentColumn != null) { 84 | drawInhibitedColumns(currentColumn, g2d); 85 | //Current Column selection 86 | Point center = currentColumn.getPosition(); 87 | Rectangle aroundRec = getElementAreaWithScale(center, 88 | 1 / (Math.PI / 4) * 1.1); 89 | g2d.setColor(Color.ORANGE); 90 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 91 | 0.2f)); 92 | g2d.fillOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 93 | } 94 | if (selectedColumnIndex != null) { 95 | Composite original = g2d.getComposite(); 96 | Rectangle aroundRec = getElementAreaWithScale(selectedColumnIndex, 1 / (Math.PI / 4) * 1.5); 97 | g2d.setColor(UIUtils.LIGHT_BLUE); 98 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 99 | 0.5f)); 100 | g2d.fillOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 101 | g2d.setComposite(original); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /examples/balls-reflect_overlap-spatial.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 8.0 6 | 16.48 7 | 4 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 4 19 | 0.01 20 | 21 | 22 | 5 23 | 3 24 | 2 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 111000000000111000000000111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 000000000000011100000000011100000000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000001110000000001110000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000000000000000111000000000111000000000111000000000000000000000000000000000000000000000000000000000000000000000000000000 43 | 000000000000000000000000000000000000000000000000000011100000000011100000000011100000000000000000000000000000000000000000000000000000000000000000 44 | 000000000000000000000000000000000000000000000000000000000000000001110000000001110000000001110000000000000000000000000000000000000000000000000000 45 | 000000000000000000000000000000000000000000000000000000000000000000000000000000111000000000111000000000111000000000000000000000000000000000000000 46 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100000000011100000000011100000000000000000000000000 47 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000001110000000001110000000000000 48 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111000000000111000000000111 49 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000001110000000001110000000000000 50 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100000000011100000000011100000000000000000000000000 51 | 000000000000000000000000000000000000000000000000000000000000000000000000000000111000000000111000000000111000000000000000000000000000000000000000 52 | 000000000000000000000000000000000000000000000000000000000000000001110000000001110000000001110000000000000000000000000000000000000000000000000000 53 | 000000000000000000000000000000000000000000000000000011100000000011100000000011100000000000000000000000000000000000000000000000000000000000000000 54 | 000000000000000000000000000000000000000111000000000111000000000111000000000000000000000000000000000000000000000000000000000000000000000000000000 55 | 000000000000000000000000001110000000001110000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 56 | 000000000000011100000000011100000000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/balls-reflect_overlap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 15.0 7 | 3 8 | 12 9 | 12 10 | 11 | 12 | 12 13 | 12 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 1 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 43 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 44 | 000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000 45 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 46 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000 47 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 48 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000 49 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011 50 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000 51 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 52 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000 53 | 000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000 54 | 000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000 55 | 000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 56 | 000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 57 | 000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 58 | 000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/SensoryInputSurface.java: -------------------------------------------------------------------------------- 1 | package htm.visualizer.surface; 2 | 3 | import htm.model.Column; 4 | import htm.model.Synapse; 5 | import htm.model.space.InputSpace; 6 | import htm.utils.UIUtils; 7 | 8 | import java.awt.*; 9 | import java.util.List; 10 | 11 | /* 12 | This is our Sensory Input Interface, bits activated on mouse enter 13 | */ 14 | public class SensoryInputSurface extends BaseSurface.SquareElementsSurface { 15 | 16 | private final InputSpace sensoryInput; 17 | private Column currentColumn; 18 | private Integer selectedInputIndex; 19 | 20 | public SensoryInputSurface(int xSize, int ySize) { 21 | this(new InputSpace(xSize, ySize)); 22 | } 23 | 24 | public SensoryInputSurface(InputSpace sensoryInput) { 25 | super(sensoryInput.getDimension().width, sensoryInput.getDimension().height); 26 | this.sensoryInput = sensoryInput; 27 | this.addElementMouseEnterListener(new ElementMouseEnterListener() { 28 | @Override public void onElementMouseEnter(ElementMouseEnterEvent e) { 29 | int index = e.getIndex(); 30 | setInputValue(index, !getInputValue(index)); 31 | } 32 | }); 33 | } 34 | 35 | @Override 36 | protected void drawElement(Graphics2D g2d, int index, int x, int y, int width, int height) { 37 | g2d.setColor(getInputValue(index) ? ACTIVE_COLOR : this.getBackground()); 38 | g2d.fillRect(x, y, width, height); 39 | super.drawElement(g2d, index, x, y, width, 40 | height); 41 | } 42 | 43 | private void drawProximalSynapsesForColumn(Column column, Graphics2D g2d) { 44 | List synapsesToDraw = column.getPotentialSynapses(); 45 | Point center = column.getInputSpacePosition(); 46 | Rectangle aroundRec = getElementAreaWithScale(center, 47 | 1 / (Math.PI / 4) * (sensoryInput.getShortSide() / column.getOwner().getShortSide()) * 1.1); 48 | g2d.setColor(Color.ORANGE); 49 | Composite original = g2d.getComposite(); 50 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 51 | 0.2f)); 52 | g2d.fillOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 53 | g2d.setComposite(original); 54 | for (Synapse.ProximalSynapse proximalSynapse : synapsesToDraw) { 55 | Rectangle insideRec = getElementAreaWithScale(this.getElementPositionByIndex( 56 | proximalSynapse.getConnectedSensoryInput().getIndex()), .5); 57 | renderSynapse(g2d, proximalSynapse.getPermanence(), insideRec); 58 | } 59 | g2d.setComposite(original); 60 | } 61 | 62 | public static void renderSynapse(Graphics2D g2d, double permanence, Rectangle insideRec) { 63 | Composite original = g2d.getComposite(); 64 | Color synapseStateColor = permanence >= Synapse.ProximalSynapse.CONNECTED_PERMANENCE ? Color.GREEN : Color.RED; 65 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 66 | Math.min(1.0f, Math.max(0.2f, (float)Math.abs( 67 | permanence - Synapse.ProximalSynapse.CONNECTED_PERMANENCE) * 30)))); 68 | g2d.setColor(synapseStateColor); 69 | g2d.fillRect(insideRec.x, insideRec.y, insideRec.width, insideRec.height); 70 | g2d.setComposite(original); 71 | } 72 | 73 | 74 | public void setInputValue(int index, boolean value) { 75 | sensoryInput.setInputValue(index, value); 76 | repaint(this.getElementAreaByIndex(index)); 77 | } 78 | 79 | public boolean getInputValue(int index) { 80 | return sensoryInput.getInputValue(index); 81 | } 82 | 83 | public void setSensoryInputValues(boolean[] source) { 84 | for (int i = 0; i < source.length; i++) { 85 | sensoryInput.setInputValue(i, source[i]); 86 | 87 | } 88 | repaint(); 89 | } 90 | 91 | public boolean[] getSensoryInputValues() { 92 | boolean[] result = new boolean[dimension.width * dimension.height]; 93 | for (int i = 0; i < result.length; i++) { 94 | result[i] = sensoryInput.getInputValue(i); 95 | 96 | } 97 | return result; 98 | } 99 | 100 | public void reset() { 101 | setSensoryInputValues(new boolean[dimension.width * dimension.height]); 102 | } 103 | 104 | @Override protected void doDrawing(Graphics2D g2d) { 105 | super.doDrawing(g2d); 106 | if (currentColumn != null) { 107 | drawProximalSynapsesForColumn(currentColumn, g2d); 108 | } 109 | if (selectedInputIndex != null) { 110 | Composite original = g2d.getComposite(); 111 | Rectangle aroundRec = getElementAreaWithScale(selectedInputIndex, 1 / (Math.PI / 4) * 1.5); 112 | g2d.setColor(UIUtils.LIGHT_BLUE); 113 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 114 | 0.5f)); 115 | g2d.fillOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 116 | g2d.setComposite(original); 117 | } 118 | } 119 | 120 | public InputSpace getSensoryInput() { 121 | return sensoryInput; 122 | } 123 | 124 | public void setCurrentColumn(Column currentColumn) { 125 | this.currentColumn = this.currentColumn != currentColumn ? currentColumn : null; 126 | selectedInputIndex = null; 127 | this.repaint(); 128 | } 129 | 130 | public void setSelectedInput(Integer inputIndex) { 131 | this.selectedInputIndex = inputIndex; 132 | this.repaint(); 133 | } 134 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | htm 5 | htm-visualizer 6 | jar 7 | 1.1 8 | HTM-CLA Visualizer 9 | 10 | 11 | 2.5.6 12 | 13 | 14 | 15 | 16 | log4j 17 | log4j 18 | 1.2.9 19 | runtime 20 | 21 | 22 | 23 | commons-logging 24 | commons-logging 25 | 1.1.3 26 | 27 | 28 | 29 | junit 30 | junit 31 | 4.10 32 | test 33 | 34 | 35 | 36 | org.codehaus.groovy 37 | groovy-all 38 | 2.2.1 39 | 40 | 41 | 42 | org.spockframework 43 | spock-core 44 | 0.7-groovy-2.0 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 59 | 60 | maven-assembly-plugin 61 | 62 | 63 | jar-assembly 64 | package 65 | 66 | single 67 | 68 | 69 | 70 | 71 | htm.visualizer.Viewer 72 | ${project.description} 73 | ${project.version} 74 | 75 | 76 | 77 | jar-with-dependencies 78 | 79 | 80 | 81 | 82 | distribution-assembly 83 | package 84 | 85 | single 86 | 87 | 88 | 89 | src/main/assembly/distribution.xml 90 | 91 | 92 | 93 | 94 | 95 | 96 | maven-source-plugin 97 | 98 | 99 | 100 | org.codehaus.mojo 101 | build-helper-maven-plugin 102 | 1.8 103 | 104 | 105 | add-source 106 | generate-sources 107 | 108 | add-source 109 | 110 | 111 | 112 | src/main/groovy 113 | 114 | 115 | 116 | 117 | add-test-source 118 | generate-test-sources 119 | 120 | add-test-source 121 | 122 | 123 | 124 | src/test/groovy 125 | 126 | 127 | 128 | 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-compiler-plugin 133 | 3.1 134 | 135 | groovy-eclipse-compiler 136 | 1.6 137 | 1.6 138 | 139 | 140 | 141 | org.codehaus.groovy 142 | groovy-eclipse-compiler 143 | 2.8.0-01 144 | 145 | 146 | org.codehaus.groovy 147 | groovy-eclipse-batch 148 | 2.1.8-01 149 | 150 | 151 | 152 | 153 | org.codehaus.groovy 154 | groovy-eclipse-compiler 155 | 2.8.0-01 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/main/java/htm/model/DistalDendriteSegment.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model; 10 | 11 | import htm.model.fractal.Composite; 12 | import htm.utils.CollectionUtils; 13 | 14 | import java.util.List; 15 | 16 | public class DistalDendriteSegment extends Composite { 17 | 18 | protected final DistalDendriteSegment predictedBy; 19 | 20 | 21 | //We need to check if synapse connected to this cell is already exist before adding new one 22 | @Override public boolean addElement(Synapse.DistalSynapse distalSynapse) { 23 | Cell newSynapseCell = distalSynapse.getFromCell(); 24 | for (Synapse.DistalSynapse existingSynapse : elementList) { 25 | if (existingSynapse.getFromCell() == newSynapseCell) { 26 | return false; 27 | } 28 | } 29 | distalSynapse.setSegment(this); 30 | return super.addElement(distalSynapse); 31 | } 32 | 33 | @Override public String toString() { 34 | StringBuilder result = new StringBuilder().append("Synapses Number:").append(this.elementList.size()); 35 | result = result.append("; sequence Segment:").append(this.isSequenceSegment()); 36 | result.append("; Belongs to Cell:").append(this.owner); 37 | return result.toString(); 38 | } 39 | 40 | 41 | public DistalDendriteSegment(Cell belongsToCell, DistalDendriteSegment predictedBy) { 42 | this.owner = belongsToCell; 43 | this.predictedBy = predictedBy; 44 | attachToCell(); 45 | } 46 | 47 | protected void attachToCell() { 48 | owner.addElement(this); 49 | } 50 | 51 | public boolean isSequenceSegment() { 52 | return predictedBy == null; 53 | } 54 | 55 | public int size(){return elementList.size();} 56 | 57 | public boolean contains(Synapse.DistalSynapse synapse){ 58 | return elementList.contains(synapse); 59 | } 60 | 61 | 62 | 63 | public List getConnectedWithStateCell(int time, Cell.State state) { 64 | return CollectionUtils.filter(this.elementList, new ConnectedCellStateByTimePredicate(time, state)); 65 | } 66 | 67 | public List getActiveCellSynapses(int time) { 68 | return CollectionUtils.filter(this.elementList, new ActiveCellByTimePredicate(time)); 69 | } 70 | 71 | 72 | 73 | public int predictedInStep() { 74 | int result = 1; 75 | DistalDendriteSegment predictedBySegment = this.predictedBy; 76 | while (predictedBySegment != null) { 77 | result = result + 1; 78 | predictedBySegment = predictedBySegment.getPredictedBy(); 79 | } 80 | return result; 81 | } 82 | 83 | public DistalDendriteSegment getPredictedBy() { 84 | return predictedBy; 85 | } 86 | 87 | private static class ActiveCellByTimePredicate implements CollectionUtils.Predicate { 88 | private final int time; 89 | 90 | private ActiveCellByTimePredicate(int time) { 91 | this.time = time; 92 | } 93 | 94 | @Override 95 | public boolean apply(Synapse.DistalSynapse synapse) { 96 | //return synapse.getFromCell().getActiveState(time); 97 | //By Kirill 98 | return synapse.getFromCell().getActiveState(time) && synapse.getFromCell().getLearnState(time); 99 | } 100 | } 101 | 102 | 103 | private static class ConnectedCellStateByTimePredicate implements CollectionUtils.Predicate { 104 | private final int time; 105 | private final Cell.State cellState; 106 | 107 | private ConnectedCellStateByTimePredicate(int time, Cell.State cellState) { 108 | this.time = time; 109 | this.cellState = cellState; 110 | } 111 | 112 | @Override 113 | public boolean apply(Synapse.DistalSynapse synapse) { 114 | boolean result = synapse.isConnected( 115 | Synapse.DistalSynapse.CONNECTED_PERMANENCE); 116 | switch (cellState) { 117 | case ACTIVE: 118 | return result && synapse.getFromCell().getActiveState(time); 119 | case LEARN: 120 | return result && synapse.getFromCell().getLearnState(time); 121 | } 122 | throw new RuntimeException("We shouldn't get here"); 123 | } 124 | } 125 | 126 | public static class Update extends DistalDendriteSegment { 127 | private final DistalDendriteSegment target; 128 | private final int time; 129 | 130 | public Update(Cell belongsToCell, DistalDendriteSegment target, int time, DistalDendriteSegment predictedBy) { 131 | super(belongsToCell, predictedBy); 132 | this.target = target; 133 | this.time = time; 134 | } 135 | 136 | @Override 137 | public int predictedInStep() { 138 | //Segment for this update hasn't been created yet 139 | if (target == null) { 140 | return predictedBy == null ? 1 : predictedBy.predictedInStep() + 1; 141 | } else { 142 | return target.predictedInStep(); 143 | } 144 | } 145 | 146 | @Override public boolean isSequenceSegment() { 147 | if (target == null) { 148 | return predictedBy == null; 149 | } else { 150 | return target.isSequenceSegment(); 151 | } 152 | } 153 | 154 | @Override 155 | protected void attachToCell() { 156 | this.owner.getSegmentUpdates().add(this); 157 | } 158 | 159 | public boolean isNewSegment() { 160 | return target == null; 161 | } 162 | 163 | public DistalDendriteSegment getTarget() { 164 | return target; 165 | } 166 | 167 | public int getTime() { 168 | return time; 169 | } 170 | 171 | @Override 172 | public String toString() { 173 | StringBuilder result = new StringBuilder().append(" New Segment:").append(this.isNewSegment()); 174 | result = result.append("; Time:").append(this.time); 175 | result.append(super.toString()); 176 | return result.toString(); 177 | } 178 | 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/htm/model/Synapse.java: -------------------------------------------------------------------------------- 1 | package htm.model; 2 | 3 | import htm.model.space.BaseSpace; 4 | import htm.model.space.InputSpace; 5 | import htm.utils.CircularArrayList; 6 | import htm.utils.MathUtils; 7 | 8 | public class Synapse { 9 | private double permanence; 10 | 11 | public Synapse(double initPermanence) { 12 | this.permanence = initPermanence; 13 | } 14 | 15 | /** 16 | * synapse is considered connected if its permanence is bigger than 17 | * connectedPermanence 18 | * 19 | * @param connectedPermanence 20 | * @return 21 | */ 22 | public boolean isConnected(double connectedPermanence) { 23 | return this.permanence >= connectedPermanence; 24 | } 25 | 26 | 27 | public double getPermanence() { 28 | return permanence; 29 | } 30 | 31 | public void setPermanence(double d) { 32 | this.permanence = Math.min(Math.max(d, 0), 1); 33 | } 34 | 35 | public static class ProximalSynapse extends Synapse { 36 | /** 37 | * WP 38 | * If the permanence value for a synapse is greater than this 39 | * value, it is said to be connected. 40 | */ 41 | public static double CONNECTED_PERMANENCE = 0.2; 42 | /** 43 | * WP 44 | * Amount permanence values of synapses are incremented 45 | * during learning. 46 | */ 47 | public static double PERMANENCE_INCREASE = 0.005; 48 | /** 49 | * WP 50 | * Amount permanence values of synapses are decremented 51 | * during learning. 52 | */ 53 | public static double PERMANENCE_DECREASE = 0.005; 54 | 55 | public static void updateFromConfig(Config synapseCfg) { 56 | ProximalSynapse.CONNECTED_PERMANENCE = synapseCfg.getConnectedPerm(); 57 | ProximalSynapse.PERMANENCE_INCREASE = synapseCfg.getPermanenceInc(); 58 | ProximalSynapse.PERMANENCE_DECREASE = synapseCfg.getPermanenceDec(); 59 | } 60 | 61 | private final InputSpace.Input connectedSensoryInput; 62 | private final Column belongsTo; 63 | private final double distanceToColumn; 64 | 65 | public ProximalSynapse(double initPermanence, InputSpace.Input connectedSensoryInput, Column belongsTo) { 66 | super(initPermanence); 67 | this.connectedSensoryInput = connectedSensoryInput; 68 | this.belongsTo = belongsTo; 69 | this.distanceToColumn = BaseSpace.getDistance(belongsTo.getOwner().convertInputPositionToColumnSpace( 70 | connectedSensoryInput.getPosition()), 71 | belongsTo.getPosition()); 72 | } 73 | 74 | 75 | public InputSpace.Input getConnectedSensoryInput() { 76 | return connectedSensoryInput; 77 | } 78 | 79 | public double getDistanceToColumn() { 80 | return distanceToColumn; 81 | } 82 | 83 | public Column getBelongsTo() { 84 | return belongsTo; 85 | } 86 | } 87 | 88 | public static class DistalSynapse extends Synapse { 89 | 90 | public static double CONNECTED_PERMANENCE = 0.2; 91 | /** 92 | * WP 93 | * Amount permanence values of synapses are incremented 94 | * during learning. 95 | */ 96 | public static double PERMANENCE_INCREASE = 0.005; 97 | /** 98 | * WP 99 | * Amount permanence values of synapses are decremented 100 | * during learning. 101 | */ 102 | public static double PERMANENCE_DECREASE = 0.005; 103 | 104 | private final Cell fromCell; 105 | private DistalDendriteSegment segment; 106 | 107 | 108 | public static void updateFromConfig(Config synapseCfg) { 109 | DistalSynapse.CONNECTED_PERMANENCE = synapseCfg.getConnectedPerm(); 110 | DistalSynapse.PERMANENCE_INCREASE = synapseCfg.getPermanenceInc(); 111 | DistalSynapse.PERMANENCE_DECREASE = synapseCfg.getPermanenceDec(); 112 | } 113 | 114 | public DistalSynapse(Cell fromCell) { 115 | //NOT sure how to deal with initial permanence, do following for now 116 | this(CONNECTED_PERMANENCE - 3 * PERMANENCE_INCREASE, fromCell); 117 | } 118 | 119 | public DistalSynapse(double initPermanence, Cell fromCell) { 120 | super(initPermanence); 121 | this.fromCell = fromCell; 122 | } 123 | 124 | public Cell getFromCell() { 125 | return fromCell; 126 | } 127 | 128 | public DistalDendriteSegment getSegment() { 129 | return segment; 130 | } 131 | 132 | public void setSegment(DistalDendriteSegment segment) { 133 | this.segment = segment; 134 | } 135 | 136 | /*Added by Kirill to track speed of permanence changes for active cells*/ 137 | 138 | public static final int PERMANENCE_RANGE_BUFFER_SIZE = 20; 139 | private final PermanenceBufferedState permanenceRangeForActiveCell = new PermanenceBufferedState(); 140 | 141 | public void updatePermanenceRangeForActiveCell() { 142 | permanenceRangeForActiveCell.addState(this.getPermanence()); 143 | } 144 | 145 | public double getPermanenceRangeChangeForActive(){ 146 | double currentPermanence = getPermanence(); 147 | if(currentPermanence == 1.0 || permanenceRangeForActiveCell.size() < PERMANENCE_RANGE_BUFFER_SIZE){ 148 | return 1.0; 149 | } else { 150 | return MathUtils.findMax(permanenceRangeForActiveCell) - MathUtils.findMin(permanenceRangeForActiveCell); 151 | } 152 | } 153 | 154 | private static class PermanenceBufferedState extends CircularArrayList { 155 | public PermanenceBufferedState() { 156 | super(PERMANENCE_RANGE_BUFFER_SIZE); 157 | } 158 | 159 | void addState(Double value) { 160 | this.add(0, value); 161 | } 162 | 163 | public Double getLast() { 164 | return this.get(0); 165 | } 166 | } 167 | } 168 | 169 | 170 | public static class Config { 171 | private final double connectedPerm; 172 | private final double permanenceInc; 173 | private final double permanenceDec; 174 | 175 | 176 | public Config(double connectedPerm, double permanenceInc, double permanenceDec) { 177 | this.connectedPerm = connectedPerm; 178 | this.permanenceInc = permanenceInc; 179 | this.permanenceDec = permanenceDec; 180 | } 181 | 182 | public double getConnectedPerm() { 183 | return connectedPerm; 184 | } 185 | 186 | public double getPermanenceInc() { 187 | return permanenceInc; 188 | } 189 | 190 | public double getPermanenceDec() { 191 | return permanenceDec; 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/LayerColumnsVerticalView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer.surface; 10 | 11 | import htm.model.Cell; 12 | import htm.model.Column; 13 | import htm.model.Layer; 14 | import org.apache.commons.logging.Log; 15 | import org.apache.commons.logging.LogFactory; 16 | 17 | import java.awt.*; 18 | import java.awt.font.FontRenderContext; 19 | import java.awt.font.TextLayout; 20 | import java.util.List; 21 | import javax.swing.*; 22 | 23 | public class LayerColumnsVerticalView extends CellSurface implements Scrollable { 24 | private int selectedCellIndex = -1; 25 | private static final Log LOG = LogFactory.getLog(LayerColumnsVerticalView.class); 26 | protected List columns; 27 | private static final int MIN_CELL_SIZE = 28; 28 | private final int columnIndexHeight = 12; 29 | 30 | public LayerColumnsVerticalView(Layer region) { 31 | super(1, region.getCellsInColumn(), region); 32 | this.updateColumns(); 33 | /* this.addElementMouseEnterListener(new ElementMouseEnterListener() { 34 | @Override 35 | public void onElementMouseEnter(ElementMouseEnterEvent e) { 36 | setSelectedCellIndex(e.getIndex()); 37 | } 38 | });*/ 39 | } 40 | 41 | public void updateColumns() { 42 | selectedCellIndex = -1; 43 | columns = region.getActiveColumns(); 44 | this.dimension.width = columns.size(); 45 | resizeAndRepaint(); 46 | } 47 | 48 | @Override 49 | public Dimension getPreferredSize() { 50 | int elementSpaceAllocation = getElementSpaceAllocation(), 51 | prefHeight = super.getPreferredSize().height, 52 | prefWidth = super.getPreferredSize().width, 53 | columnWidthAllocation = elementSpaceAllocation * dimension.width, 54 | columnHeightAllocation = elementSpaceAllocation * dimension.height + columnIndexHeight; 55 | return new Dimension(columnWidthAllocation < prefWidth ? prefWidth : columnWidthAllocation, 56 | columnHeightAllocation < prefHeight ? prefHeight : columnHeightAllocation); 57 | } 58 | 59 | protected void resizeAndRepaint() { 60 | revalidate(); 61 | repaint(); 62 | } 63 | 64 | @Override 65 | protected int getElementSpaceAllocation() { 66 | return Math.max(MIN_CELL_SIZE, (40 - region.getCellsInColumn()* 2)); 67 | 68 | } 69 | 70 | @Override protected Point getElementStartPoint(int elementSpaceAllocation) { 71 | int y = super.getElementStartPoint(elementSpaceAllocation).y + columnIndexHeight; 72 | return new Point(2, y); 73 | } 74 | 75 | 76 | @Override 77 | protected void doDrawing(Graphics2D g2d) { 78 | super.doDrawing(g2d); 79 | //Draw column index 80 | for (int i = 0; i < columns.size(); i++) { 81 | Rectangle area = getElementAreaByIndex(i); 82 | g2d.setColor(ACTIVE_COLOR); 83 | drawColumnIndex(g2d, columns.get(i).getIndex(), area); 84 | } 85 | //Draw selection 86 | Stroke originalStroke = g2d.getStroke(); 87 | g2d.setStroke(new BasicStroke(2)); 88 | if (selectedCellIndex != -1) { 89 | g2d.setColor(Color.RED); 90 | Rectangle aroundRec = getElementAreaWithScale(selectedCellIndex, 1 / (Math.PI / 4) * 0.9); 91 | g2d.drawOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 92 | Column column = getCell(selectedCellIndex).getOwner(); 93 | List columnCells = column.getElements(); 94 | for (Cell columnCell : columnCells) { 95 | int cellInx = indexOf(columnCell); 96 | if (cellInx != selectedCellIndex) { 97 | aroundRec = getElementAreaWithScale(cellInx, 1 / (Math.PI / 4) * 0.9); 98 | g2d.setColor(Color.ORANGE); 99 | g2d.drawOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 100 | } 101 | } 102 | } 103 | g2d.setStroke(originalStroke); 104 | } 105 | 106 | protected int getIndexCaptionYPosShift(){ 107 | return SPACE_BETWEEN_ELEMENTS; 108 | } 109 | 110 | protected void drawColumnIndex(Graphics2D g2, int columnIndex, Rectangle firstCellArea) { 111 | FontRenderContext frc = g2.getFontRenderContext(); 112 | Font indexFont = new Font("Helvetica", Font.BOLD, 12); 113 | TextLayout indexLayout = new TextLayout(columnIndex + "", indexFont, frc); 114 | int drawPosX = (int)(firstCellArea.getX() + (firstCellArea.getWidth() - indexLayout.getAdvance()) / 2); 115 | int drawPosY = firstCellArea.y - getIndexCaptionYPosShift(); 116 | indexLayout.draw(g2, drawPosX, drawPosY); 117 | } 118 | 119 | @Override 120 | public Cell getCell(int index) { 121 | int cellIndex = index / dimension.width, columnIndex = index % dimension.width; 122 | return columns.get(columnIndex).getElementByIndex(cellIndex); 123 | } 124 | 125 | public int indexOf(Cell cell) { 126 | int index = 0; 127 | for (int y = 0; y < dimension.height; y++) { 128 | for (int x = 0; x < dimension.width; x++) { 129 | if (cell == getCell(index)) { 130 | return index; 131 | } 132 | index++; 133 | } 134 | } 135 | return -1; 136 | } 137 | 138 | public void setSelectedCellIndex(int selectedCellIndex) { 139 | this.selectedCellIndex = this.selectedCellIndex != selectedCellIndex ? selectedCellIndex : -1; 140 | repaint(); 141 | } 142 | 143 | public void setSelectedCell(Cell cell) { 144 | setSelectedCellIndex(indexOf(cell)); 145 | } 146 | 147 | @Override public Dimension getPreferredScrollableViewportSize() { 148 | return getParent() instanceof JViewport ? getParent().getSize() : getPreferredSize(); 149 | } 150 | 151 | @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 152 | return getElementSpaceAllocation(); 153 | } 154 | 155 | @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 156 | return getElementSpaceAllocation(); 157 | } 158 | 159 | @Override public boolean getScrollableTracksViewportWidth() { 160 | return getParent() instanceof JViewport 161 | && (getParent().getWidth() > getPreferredSize().width); 162 | } 163 | 164 | @Override public boolean getScrollableTracksViewportHeight() { 165 | return getParent() instanceof JViewport 166 | && (getParent().getHeight() > getPreferredSize().height); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/htm/model/Layer.java: -------------------------------------------------------------------------------- 1 | package htm.model; 2 | 3 | import htm.model.algorithms.spatial.SpatialPooler; 4 | import htm.model.algorithms.temporal.TemporalPooler; 5 | import htm.model.space.BaseSpace; 6 | import htm.model.space.InputSpace; 7 | import htm.utils.CollectionUtils; 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | 11 | import java.awt.*; 12 | import java.util.List; 13 | 14 | 15 | public class Layer extends BaseSpace { 16 | 17 | 18 | private final InputSpace inputSpace; 19 | /** 20 | * inputRadius for this input Space 21 | * The concept of Input Radius is an additional parameter to control how 22 | * far away synapse connections can be made instead of allowing connections anywhere. 23 | */ 24 | private final double inputRadius; 25 | 26 | /** 27 | * Furthest number of columns away (in this Region's Column grid space) to allow new distal 28 | * synapse connections. If set to 0 then there is no restriction and connections 29 | * can form between any two columns in the region. 30 | *

31 | * WP 32 | *

33 | * learningRadius The area around a temporal pooler cell from which it can get lateral connections. 34 | */ 35 | private final double learningRadius; 36 | private final int cellsInColumn; 37 | 38 | private final boolean skipSpatial; 39 | 40 | private static final Log LOG = LogFactory.getLog(Layer.class); 41 | 42 | private static final CollectionUtils.Predicate BOTTOM_UP_WINNING_COLUMNS_PREDICATE = new CollectionUtils.Predicate() { 43 | @Override public boolean apply(Column column) { 44 | return column.isActive(); 45 | } 46 | }; 47 | 48 | //TODO not sure if Layer should directly reference algorithmic classes: Temporal/Spatial Pooler 49 | private TemporalPooler temporalPooler; 50 | private SpatialPooler spatialPooler; 51 | 52 | public TemporalPooler getTemporalPooler() { 53 | return temporalPooler; 54 | } 55 | 56 | public void setTemporalPooler(TemporalPooler temporalPooler) { 57 | this.temporalPooler = temporalPooler; 58 | } 59 | 60 | public SpatialPooler getSpatialPooler() { 61 | return spatialPooler; 62 | } 63 | 64 | public void setSpatialPooler(SpatialPooler spatialPooler) { 65 | this.spatialPooler = spatialPooler; 66 | } 67 | 68 | 69 | public Layer(Config layerCfg) { 70 | super(layerCfg.getRegionDimension().width, layerCfg.getRegionDimension().height); 71 | this.cellsInColumn = layerCfg.getCellsInColumn(); 72 | this.initElementSpace(); 73 | this.inputSpace = new InputSpace(layerCfg.getSensoryInputDimension().width, 74 | layerCfg.getSensoryInputDimension().height); 75 | this.inputRadius = layerCfg.getInputRadius(); 76 | this.learningRadius = layerCfg.getLearningRadius(); 77 | this.skipSpatial = layerCfg.isSkipSpatial(); 78 | if (skipSpatial) { 79 | if (inputSpace.getDimension().height != this.getDimension().height || inputSpace.getDimension().width != this.getDimension().width) { 80 | throw new IllegalArgumentException( 81 | "With \"Skip Spatial Mode \" Sensory Input must be the same size as this Region"); 82 | } 83 | } else { 84 | connectToInputSpace(); 85 | } 86 | } 87 | 88 | @Override 89 | protected Column createElement(int index, Point position) { 90 | return new Column(this, index, position); 91 | } 92 | 93 | public java.util.List getColumns() { 94 | return this.getElements(); 95 | } 96 | 97 | public void connectToInputSpace() { 98 | for (Column column : getColumns()) { 99 | column.createProximalSegment(inputRadius); 100 | } 101 | } 102 | 103 | public Point convertColumnPositionToInputSpace(Point columnPosition) { 104 | return convertPositionToOtherSpace(columnPosition, this.getDimension(), inputSpace.getDimension()); 105 | } 106 | 107 | public Point convertInputPositionToColumnSpace(Point inputPosition) { 108 | return convertPositionToOtherSpace(inputPosition, inputSpace.getDimension(), this.getDimension()); 109 | } 110 | 111 | 112 | /** 113 | * WP 114 | * activeColumns(t) t=0 115 | * List of column indices that are winners due to bottom-up input 116 | * (this is the output of the spatial pooler). 117 | * 118 | * @return 119 | */ 120 | 121 | public List getActiveColumns() { 122 | return CollectionUtils.filter(this.getElements(), BOTTOM_UP_WINNING_COLUMNS_PREDICATE); 123 | } 124 | 125 | /** 126 | * WP 127 | * activeColumns(t) 128 | * List of column indices that are winners due to bottom-up input 129 | * (this is the output of the spatial pooler). 130 | * 131 | * @param time (t - 0) - current step, (t - 1) - previous step, (t- n) - n step 132 | * @return 133 | */ 134 | public List getActiveColumns(final int time) { 135 | return CollectionUtils.filter(this.getElements(), new CollectionUtils.Predicate() { 136 | @Override public boolean apply(Column column) { 137 | return column.isActive(time); 138 | } 139 | }); 140 | } 141 | 142 | 143 | /** 144 | * WP 145 | * averageReceptiveFieldSize() 146 | * The radius of the average connected receptive field size of all the columns. 147 | * The connected receptive field size of a column includes only the connected synapses (those with permanence values >= connectedPerm). 148 | * This is used to determine the extent of lateral inhibition between columns. 149 | */ 150 | 151 | public double getAverageReceptiveFieldSize() { 152 | double sum = 0; 153 | for (Column column : getColumns()) { 154 | java.util.List connectedSynapses = column.getConnectedSynapses(); 155 | double maxDistance = 0; 156 | for (Synapse.ProximalSynapse connectedSynapse : connectedSynapses) { 157 | // Determine the distance of the further proximal synapse. This will be considered the size of the receptive field. 158 | maxDistance = Math.max(maxDistance, connectedSynapse.getDistanceToColumn()); 159 | } 160 | LOG.debug("maxDistance for column:#" + column.getIndex() + " - " + maxDistance); 161 | // Add the current column's receptive field size to the sum. 162 | sum += maxDistance; 163 | } 164 | return sum / getColumns().size(); 165 | } 166 | 167 | public Dimension getInputSpaceDimension() { 168 | return inputSpace.getDimension(); 169 | } 170 | 171 | public InputSpace getInputSpace() { 172 | return inputSpace; 173 | } 174 | 175 | public double getInputRadius() { 176 | return inputRadius; 177 | } 178 | 179 | public double getLearningRadius() { 180 | return learningRadius; 181 | } 182 | 183 | public boolean isSkipSpatial() { 184 | return skipSpatial; 185 | } 186 | 187 | public int getCellsInColumn() { 188 | return cellsInColumn; 189 | } 190 | 191 | public static class Config { 192 | private final Dimension regionDimension; 193 | private final Dimension sensoryInputDimension; 194 | private final double inputRadius; 195 | private final double learningRadius; 196 | private final boolean skipSpatial; 197 | private final int cellsInColumn; 198 | 199 | 200 | public Config(Dimension regionDimension, Dimension sensoryInputDimension, 201 | double inputRadius, double learningRadius, boolean skipSpatial, int cellsInColumn) { 202 | this.regionDimension = regionDimension; 203 | this.sensoryInputDimension = sensoryInputDimension; 204 | this.inputRadius = inputRadius; 205 | this.learningRadius = learningRadius; 206 | this.skipSpatial = skipSpatial; 207 | this.cellsInColumn = cellsInColumn; 208 | } 209 | 210 | public double getLearningRadius() { 211 | return learningRadius; 212 | } 213 | 214 | public double getInputRadius() { 215 | return inputRadius; 216 | } 217 | 218 | public Dimension getRegionDimension() { 219 | return regionDimension; 220 | } 221 | 222 | public Dimension getSensoryInputDimension() { 223 | return sensoryInputDimension; 224 | } 225 | 226 | public boolean isSkipSpatial() { 227 | return skipSpatial; 228 | } 229 | 230 | 231 | public int getCellsInColumn() { 232 | return cellsInColumn; 233 | } 234 | } 235 | } 236 | 237 | -------------------------------------------------------------------------------- /src/main/java/htm/model/algorithms/spatial/WhitePaperSpatialPooler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.model.algorithms.spatial; 10 | 11 | import htm.model.Column; 12 | import htm.model.Synapse; 13 | import org.apache.commons.logging.Log; 14 | import org.apache.commons.logging.LogFactory; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | import java.util.Comparator; 19 | import java.util.List; 20 | 21 | public class WhitePaperSpatialPooler extends SpatialPooler { 22 | 23 | private static final Log LOG = LogFactory.getLog(WhitePaperSpatialPooler.class); 24 | 25 | 26 | private static final Comparator OVERLAP_COMPARATOR = new Comparator() { 27 | @Override public int compare(Column column1, Column column2) { 28 | Double overlap1 = column1.getOverlap(), overlap2 = column2.getOverlap(); 29 | return overlap2.compareTo(overlap1); 30 | } 31 | }; 32 | 33 | public WhitePaperSpatialPooler(Config cfg) { 34 | super(cfg); 35 | } 36 | 37 | /** 38 | * Performs spatial pooling for the current input in this Region. 39 | * The result will be a subset of Columns being set as active as well 40 | * as (proximal) synapses in all Columns having updated permanences and boosts, and 41 | * the Region will update inhibitionRadius. 42 | *

43 | * WP 44 | * Phase 1: 45 | * Compute the overlap with the current input for each column. Given an input 46 | * vector, the first phase calculates the overlap of each column with that 47 | * vector. The overlap for each column is simply the number of connected 48 | * synapses with active inputs, multiplied by its boost. If this value is 49 | * below minOverlap, we set the overlap score to zero. 50 | *

51 | * Phase 2: 52 | * Compute the winning columns after inhibition. The second phase calculates 53 | * which columns remain as winners after the inhibition step. 54 | * desiredLocalActivity is a parameter that controls the number of columns 55 | * that end up winning. For example, if desiredLocalActivity is 10, a column 56 | * will be a winner if its overlap score is greater than the score of the 57 | * 10'th highest column within its inhibition radius. 58 | *

59 | * Phase 3: 60 | * Update synapse permanence and internal variables.The third phase performs 61 | * learning; it updates the permanence values of all synapses as necessary, 62 | * as well as the boost and inhibition radius. The main learning rule is 63 | * implemented in lines 20-26. For winning columns, if a synapse is active, 64 | * its permanence value is incremented, otherwise it is decremented. Permanence 65 | * values are constrained to be between 0 and 1. 66 | * Lines 28-36 implement boosting. There are two separate boosting mechanisms 67 | * in place to help a column learn connections. If a column does not win often 68 | * enough (as measured by activeDutyCycle), its overall boost value is 69 | * increased (line 30-32). Alternatively, if a column's connected synapses do 70 | * not overlap well with any inputs often enough (as measured by 71 | * overlapDutyCycle), its permanence values are boosted (line 34-36). 72 | */ 73 | 74 | @Override 75 | public void execute() { 76 | double inhibitionRadius = layer.getAverageReceptiveFieldSize(); 77 | if (layer.isSkipSpatial()) { 78 | for (Column currentColumn : layer.getElementsList()) { 79 | currentColumn.setActive(layer.getInputSpace().getInputValue(currentColumn.getIndex())); 80 | } 81 | } else { 82 | phaseOne(); 83 | phaseThree(phaseTwo(inhibitionRadius), inhibitionRadius); 84 | } 85 | } 86 | 87 | public void phaseOne() { 88 | //Phase 1: Compute the overlap 89 | for (Column column : layer.getElementsList()) { 90 | computeOverlapForColumn(column); 91 | } 92 | } 93 | 94 | public List phaseTwo(double inhibitionRadius) { 95 | //Phase 2:Compute the winning columns after inhibition 96 | List activeColumns = new ArrayList(); 97 | for (Column column : layer.getElementsList()) { 98 | if (computeActiveDoInhibitionForColumn(column, inhibitionRadius)) { 99 | activeColumns.add(column); 100 | } 101 | } 102 | return activeColumns; 103 | } 104 | 105 | 106 | public void phaseThree(List activeColumns, double inhibitionRadius) { 107 | // Phase 3: Update synapse permanence and internal variables 108 | if (isLearningMode()) { 109 | for (Column activeColumn : activeColumns) { 110 | learnSpatialForActiveForColumn(activeColumn); 111 | } 112 | for (Column column : layer.getElementsList()) { 113 | boostWeakForColumn(column, inhibitionRadius); 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * WP 120 | * SPATIAL POOLING 121 | *

122 | * Phase 1: Overlap 123 | * Given an input vector, the first phase calculates the overlap of each column with that vector. 124 | * The overlap for each column is simply the number of connected synapses with active inputs, 125 | * multiplied by its boost. If this value is below minOverlap, we set the overlap score to zero. 126 | * 127 | * @return 128 | */ 129 | public double computeOverlapForColumn(Column currentColumn) { 130 | double currentOverLap = currentColumn.getActiveConnectedSynapses().size(); 131 | if (currentOverLap < this.getMinimalOverlap()) { 132 | currentOverLap = 0; 133 | } else { 134 | currentOverLap = currentOverLap * currentColumn.getBoost(); 135 | } 136 | currentColumn.updateOverlap(currentOverLap); 137 | return currentOverLap; 138 | } 139 | 140 | /** 141 | * WP 142 | * SPATIAL POOLING 143 | *

144 | * Phase 2: Inhibition 145 | * The second phase calculates which columns remain as winners after the inhibition step. 146 | * desiredLocalActivity is a parameter that controls the number of columns that end up winning. 147 | * For example, if desiredLocalActivity is 10, a column will be a winner if its overlap score is 148 | * greater than the score of the 10'th highest column within its inhibition radius. 149 | * 150 | * @param inhibitionRadius 151 | * @return 152 | */ 153 | 154 | public boolean computeActiveDoInhibitionForColumn(Column currentColumn, double inhibitionRadius) { 155 | double minLocalActivity = kthScore(currentColumn.getNeighbors(inhibitionRadius), this.getDesiredLocalActivity()); 156 | currentColumn.setActive(currentColumn.getOverlap() > 0 && currentColumn.getOverlap() >= minLocalActivity); 157 | return currentColumn.isActive(); 158 | } 159 | 160 | /** 161 | * WP 162 | * SPATIAL POOLING 163 | *

164 | * Phase 3: Learning 165 | * The third phase performs learning; it updates the permanence values of all synapses as necessary, as well as the boost and inhibition radius. 166 | *

167 | * First part 168 | * The main learning rule is implemented in lines 20-26. For winning columns, if a synapse is active, its permanence value is incremented, otherwise it is decremented. Permanence values are constrained to be between 0 and 1. 169 | */ 170 | 171 | public void learnSpatialForActiveForColumn(Column currentColumn) { 172 | if (currentColumn.isActive()) { 173 | List potentialSynapses = currentColumn.getPotentialSynapses(); 174 | for (Synapse.ProximalSynapse potentialSynapse : potentialSynapses) { 175 | if (potentialSynapse.getConnectedSensoryInput().getValue()) { 176 | potentialSynapse.setPermanence( 177 | potentialSynapse.getPermanence() + Synapse.ProximalSynapse.PERMANENCE_INCREASE); 178 | } else { 179 | potentialSynapse.setPermanence( 180 | potentialSynapse.getPermanence() - Synapse.ProximalSynapse.PERMANENCE_DECREASE); 181 | } 182 | } 183 | } 184 | } 185 | 186 | /** 187 | * Second part 188 | * Lines 28-36 implement boosting. There are two separate boosting mechanisms in place to help a column learn connections. If a column does not win often enough (as measured by activeDutyCycle), its overall boost value is increased (line 30-32). Alternatively, if a column's connected synapses do not overlap well with any inputs often enough (as measured by overlapDutyCycle), its permanence values are boosted (line 34-36). Note: once learning is turned off, boost(c) is frozen. 189 | * Finally, at the end of Phase 3 the inhibition radius is recomputed (line 38). 190 | * 191 | * @param inhibitionRadius 192 | */ 193 | public void boostWeakForColumn(Column currentColumn, double inhibitionRadius) { 194 | double minDutyCycle = 0.01 * currentColumn.getMaxDutyCycle(inhibitionRadius); 195 | currentColumn.updateBoost(minDutyCycle, this.getBoostRate()); 196 | if (currentColumn.getOverlapDutyCycle() < minDutyCycle) { 197 | currentColumn.increasePermanence(0.1 * Synapse.ProximalSynapse.CONNECTED_PERMANENCE); 198 | } 199 | } 200 | 201 | 202 | /** 203 | * WP 204 | * kthScore(cols, k) 205 | * Given the list of columns, return the k'th highest overlap value. 206 | */ 207 | private double kthScore(List neighbors, int desiredLocalActivity) { 208 | Collections.sort(neighbors, OVERLAP_COMPARATOR); 209 | if (desiredLocalActivity > neighbors.size()) { 210 | desiredLocalActivity = neighbors.size(); 211 | } 212 | return neighbors.get(desiredLocalActivity - 1).getOverlap(); 213 | 214 | } 215 | 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/BaseSurface.java: -------------------------------------------------------------------------------- 1 | package htm.visualizer.surface; 2 | 3 | import htm.utils.MathUtils; 4 | 5 | import java.awt.*; 6 | import java.awt.event.MouseAdapter; 7 | import java.awt.event.MouseEvent; 8 | import java.awt.event.MouseMotionAdapter; 9 | import java.util.ArrayList; 10 | import java.util.Collection; 11 | import javax.swing.*; 12 | 13 | public abstract class BaseSurface extends JPanel { 14 | protected static final int SPACE_BETWEEN_ELEMENTS = 4; 15 | public static final Color BACKGROUND_COLOR = Color.WHITE; 16 | public static final Color ACTIVE_COLOR = Color.BLACK; 17 | 18 | protected final Dimension dimension; 19 | /** 20 | * need two following parameters to buffer input on mouse drag event 21 | */ 22 | private int lastVisitedInputIndex = -1; 23 | private boolean mouseDragged = false; 24 | 25 | public BaseSurface(int xSize, int ySize) { 26 | this.dimension = new Dimension(xSize, ySize); 27 | setBackground(BACKGROUND_COLOR); 28 | addMouseListener(new MouseAdapter() { 29 | 30 | @Override 31 | public void mouseReleased(MouseEvent e) { 32 | lastVisitedInputIndex = -1; 33 | if (!mouseDragged) { 34 | mouseOver(e.getX(), e.getY()); 35 | } 36 | mouseDragged = false; 37 | } 38 | }); 39 | 40 | addMouseMotionListener(new MouseMotionAdapter() { 41 | @Override 42 | public void mouseDragged(MouseEvent e) { 43 | mouseDragged = true; 44 | mouseOver(e.getX(), e.getY()); 45 | } 46 | }); 47 | } 48 | 49 | protected int getElementSpaceAllocation() { 50 | Dimension size = this.getSize(); 51 | double result = MathUtils.findMin((size.getHeight() - 2) / dimension.height, 52 | (size.getWidth() - 2) / dimension.width); 53 | return result < 1 ? 1 : (int)result - 1; 54 | } 55 | 56 | protected Point getElementStartPoint(int elementSpaceAllocation) { 57 | Dimension size = this.getSize(); 58 | int startX = (int)(size.getWidth() - elementSpaceAllocation * this.dimension.width) / 2; 59 | int startY = (int)(size.getHeight() - elementSpaceAllocation * this.dimension.height) / 2; 60 | return new Point(startX, startY); 61 | } 62 | 63 | protected void doDrawing(Graphics2D g2d) { 64 | int elementSpaceAllocation = getElementSpaceAllocation(); 65 | Point startPoint = getElementStartPoint(elementSpaceAllocation); 66 | 67 | int index = 0; 68 | for (int y = 0; y < dimension.height; y++) { 69 | for (int x = 0; x < dimension.width; x++) { 70 | drawElement(g2d, index, elementSpaceAllocation * x + startPoint.x, elementSpaceAllocation * y + startPoint.y, 71 | elementSpaceAllocation - SPACE_BETWEEN_ELEMENTS, elementSpaceAllocation - SPACE_BETWEEN_ELEMENTS); 72 | index++; 73 | } 74 | } 75 | } 76 | 77 | private void mouseOver(int mouseX, int mouseY) { 78 | int elementSpaceAllocation = getElementSpaceAllocation(), elementWidth = (elementSpaceAllocation - BaseSurface.SPACE_BETWEEN_ELEMENTS); 79 | Point startPoint = getElementStartPoint(elementSpaceAllocation); 80 | int index = 0; 81 | outer: 82 | for (int y = 0; y < dimension.height; y++) { 83 | for (int x = 0; x < dimension.width; x++) { 84 | int elementCenterX = elementSpaceAllocation * x + startPoint.x + elementWidth / 2; 85 | int elementCenterY = elementSpaceAllocation * y + startPoint.y + elementWidth / 2; 86 | if (lastVisitedInputIndex != index && isMouseOverElement(mouseX, mouseY, elementCenterX, elementCenterY, 87 | elementWidth)) { 88 | fireElementMouseEnterEvent(index); 89 | lastVisitedInputIndex = index; 90 | break outer; 91 | } 92 | index++; 93 | } 94 | } 95 | } 96 | 97 | public Point getElementPositionByIndex(int byIndex) { 98 | int index = 0; 99 | for (int y = 0; y < dimension.height; y++) { 100 | for (int x = 0; x < dimension.width; x++) { 101 | if (byIndex == index) { 102 | return new Point(x, y); 103 | } 104 | index++; 105 | } 106 | } 107 | throw new IllegalArgumentException("No Element found by Index:" + byIndex); 108 | } 109 | 110 | public Rectangle getElementAreaByIndex(int byIndex) { 111 | return getElementArea(getElementPositionByIndex(byIndex)); 112 | } 113 | 114 | public Rectangle getElementArea(Point position) { 115 | int elementSpaceAllocation = getElementSpaceAllocation(); 116 | Point startPoint = getElementStartPoint(elementSpaceAllocation); 117 | return new Rectangle(elementSpaceAllocation * position.x + startPoint.x, 118 | elementSpaceAllocation * position.y + startPoint.y, 119 | elementSpaceAllocation - BaseSurface.SPACE_BETWEEN_ELEMENTS + 1, 120 | elementSpaceAllocation - BaseSurface.SPACE_BETWEEN_ELEMENTS + 1); 121 | 122 | 123 | } 124 | 125 | 126 | /** 127 | * Return element area scaled by scaleFactor parameter 128 | * 129 | * @param position 130 | * @param scaleFactor 131 | * @return 132 | */ 133 | 134 | public Rectangle getElementAreaWithScale(Point position, double scaleFactor) { 135 | Rectangle outsideArea = getElementArea(position); 136 | double newWidth = outsideArea.getWidth() * scaleFactor, newHeight = outsideArea.getHeight() * scaleFactor, 137 | newX = outsideArea.getX() - (newWidth - outsideArea.getWidth()) / 2, newY = outsideArea.getY() - (newHeight - outsideArea.getHeight()) / 2; 138 | return new Rectangle((int)newX, (int)newY, (int)newWidth, (int)newHeight); 139 | } 140 | 141 | public Rectangle getElementAreaWithScale(int byIndex, double scaleFactor) { 142 | return getElementAreaWithScale(getElementPositionByIndex(byIndex), scaleFactor); 143 | } 144 | 145 | 146 | protected abstract boolean isMouseOverElement(int mouseX, int mouseY, int elementCenterX, int elementCenterY, 147 | int elementWidth); 148 | 149 | protected abstract void drawElement(Graphics2D g2d, int index, int x, int y, int width, int height); 150 | 151 | 152 | @Override 153 | protected void paintComponent(Graphics g) { 154 | super.paintComponent(g); 155 | Graphics2D g2d = (Graphics2D)g; 156 | doDrawing(g2d); 157 | } 158 | 159 | /*Custom events implementation*/ 160 | private final Collection _listeners = new ArrayList(); 161 | 162 | public synchronized void addElementMouseEnterListener(ElementMouseEnterListener listener) { 163 | _listeners.add(listener); 164 | } 165 | 166 | public synchronized void removeElementMouseEnterListener(ElementMouseEnterListener listener) { 167 | _listeners.remove(listener); 168 | } 169 | 170 | private synchronized void fireElementMouseEnterEvent(int index) { 171 | ElementMouseEnterEvent event = new ElementMouseEnterEvent(this, index); 172 | for (ElementMouseEnterListener _listener : _listeners) { 173 | (_listener).onElementMouseEnter(event); 174 | } 175 | } 176 | 177 | /** 178 | * the amount of elements over x 179 | */ 180 | public int getXSize() { 181 | return dimension.width; 182 | } 183 | 184 | /** 185 | * the amount of elements over y 186 | */ 187 | public int getYSize() { 188 | return dimension.height; 189 | } 190 | 191 | public static class ElementMouseEnterEvent extends java.util.EventObject { 192 | private final int index; 193 | 194 | public ElementMouseEnterEvent(Object source, int index) { 195 | super(source); 196 | this.index = index; 197 | } 198 | 199 | public int getIndex() { 200 | return index; 201 | } 202 | 203 | } 204 | 205 | public interface ElementMouseEnterListener { 206 | public void onElementMouseEnter(ElementMouseEnterEvent e); 207 | } 208 | 209 | public static class CircleElementsSurface extends BaseSurface { 210 | protected CircleElementsSurface(int xSize, int ySize) { 211 | super(xSize, ySize); 212 | } 213 | 214 | /* 215 | Just draw empty circle. 216 | */ 217 | @Override protected void drawElement(Graphics2D g2d, int index, int x, int y, int width, int height) { 218 | g2d.setColor(ACTIVE_COLOR); 219 | g2d.drawOval(x, y, width, height); 220 | } 221 | 222 | @Override 223 | protected boolean isMouseOverElement(int mouseX, int mouseY, int elementCenterX, int elementCenterY, 224 | int elementWidth) { 225 | /*circle eq in coordinates*/ 226 | return Math.pow(mouseX - elementCenterX, 2) + Math.pow(mouseY - elementCenterY, 2) - Math.pow(elementWidth / 2, 227 | 2) <= 0; 228 | } 229 | } 230 | 231 | public static class SquareElementsSurface extends BaseSurface { 232 | protected SquareElementsSurface(int xSize, int ySize) { 233 | super(xSize, ySize); 234 | } 235 | 236 | /*Just draw empty square*/ 237 | @Override protected void drawElement(Graphics2D g2d, int index, int x, int y, int width, int height) { 238 | g2d.setColor(ACTIVE_COLOR); 239 | g2d.drawRect(x, y, width, height); 240 | } 241 | 242 | @Override 243 | protected boolean isMouseOverElement(int mouseX, int mouseY, int elementCenterX, int elementCenterY, 244 | int elementWidth) { 245 | return MathUtils.inRange(mouseX, elementCenterX - elementWidth / 2, elementCenterX + elementWidth / 2) && 246 | MathUtils.inRange(mouseY, elementCenterY - elementWidth / 2, elementCenterY + elementWidth / 2); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/htm/model/Cell.java: -------------------------------------------------------------------------------- 1 | package htm.model; 2 | 3 | import htm.model.fractal.Composite; 4 | import htm.utils.CircularArrayList; 5 | import org.apache.commons.logging.Log; 6 | import org.apache.commons.logging.LogFactory; 7 | 8 | import java.util.*; 9 | 10 | public class Cell extends Composite{ 11 | private static final Log LOG = LogFactory.getLog(Cell.class); 12 | 13 | /** 14 | * WP 15 | *

16 | * newSynapseCount 17 | * The maximum number of synapses added to a segment during learning. 18 | */ 19 | 20 | public static int AMOUNT_OF_SYNAPSES = 30; 21 | /** 22 | * cell will keep a buffer of its last TIME_STEPS states 23 | */ 24 | public static int TIME_STEPS = 6; 25 | 26 | public int getCellIndex() { 27 | return cellIndex; 28 | } 29 | 30 | public List getSegmentUpdates() { 31 | return segmentUpdates; 32 | } 33 | 34 | public enum State { 35 | ACTIVE, 36 | LEARN 37 | } 38 | 39 | 40 | //current and step before 41 | public static final int BEFORE = 1; 42 | public static final int NOW = 0; 43 | 44 | //no prediction in up coming steps 45 | public static final int NOT_IN_STEP_PREDICTION = -1; 46 | 47 | 48 | private final int cellIndex; 49 | /** 50 | * Boolean vector of Cell's active state in time t-n, ..., t-1, t 51 | */ 52 | private final CellStateBuffer activeState = new CellStateBuffer(); 53 | /** 54 | * learnState(c, i, t) A boolean indicating whether cell i in column c is 55 | * chosen as the cell to learn on. 56 | */ 57 | private final CellStateBuffer learnState = new CellStateBuffer(); 58 | 59 | /** 60 | * Boolean vector of Cell's predictive state in time t-n, ..., t-1, t 61 | */ 62 | //private CellStateBuffer predictiveState = new CellStateBuffer(); 63 | 64 | private final PredictInStepBuffer predictedInStepState = new PredictInStepBuffer(); 65 | 66 | 67 | private final List segmentUpdates = new ArrayList(); 68 | 69 | public static void updateFromConfig(Config cellCfg) { 70 | AMOUNT_OF_SYNAPSES = cellCfg.getAmountOfSynapses(); 71 | TIME_STEPS = cellCfg.getTimeSteps(); 72 | } 73 | 74 | public Cell(Column belongsToColumn, int cellIndex) { 75 | this.owner = belongsToColumn; 76 | this.cellIndex = cellIndex; 77 | } 78 | 79 | public List getSegments(){ 80 | return getElements(); 81 | } 82 | 83 | /* 84 | *Set Learn State in current time Cell.NOW 85 | */ 86 | public void setLearnState() { 87 | if(!this.getActiveState(Cell.NOW)){ 88 | LOG.warn("Setting non active cell as learning:" + this); 89 | } 90 | this.learnState.setState(); 91 | } 92 | 93 | /** 94 | * Get Learn state in Time 95 | * 96 | * @param time 97 | */ 98 | public boolean getLearnState(int time) { 99 | return this.learnState.get(time); 100 | } 101 | 102 | /** 103 | * Set active state 104 | */ 105 | public void setActiveState() { 106 | this.activeState.setState(); 107 | /*Added by Kirill to track speed of permanence changes for active cells*/ 108 | for (DistalDendriteSegment segment : this.elementList) { 109 | for (Synapse.DistalSynapse distalSynapse : segment.getElementsList()) { 110 | distalSynapse.updatePermanenceRangeForActiveCell(); 111 | } 112 | } 113 | } 114 | 115 | 116 | 117 | /** 118 | * Get Active state in Time 119 | *

120 | * WP 121 | *

122 | * activeState(c, i, t) 123 | *

124 | * A boolean vector with one number per cell. 125 | * It represents the active state of the column c cell i 126 | * at time t given the current feed-forward input and the 127 | * past temporal context. 128 | * activeState(c, i, t) is the contribution from column c cell i at time t. 129 | * If true, the cell has current feed-forward input as well as an appropriate temporal context. 130 | * 131 | * @param time 132 | */ 133 | public boolean getActiveState(int time) { 134 | return this.activeState.get(time); 135 | } 136 | 137 | /** 138 | * Set Predictive state 139 | */ 140 | /*public void setPredictiveState(boolean predictiveState) { 141 | this.predictiveState.setState(predictiveState); 142 | }*/ 143 | 144 | /** 145 | * Get Predictive state in Time 146 | *

147 | * WP 148 | *

149 | * predictiveState(c, i, t) 150 | * A boolean vector with one number per cell. 151 | * It represents the prediction of the column c cell i at time t, 152 | * given the bottom-up activity of other columns and the past temporal context. 153 | * predictiveState(c, i, t) is the contribution of column c cell i at time t. 154 | * If 1, the cell is predicting feed-forward input in the current temporal context. 155 | * 156 | * @param time 157 | */ 158 | public boolean getPredictiveState(int time) { 159 | //return this.predictiveState.get(time); 160 | return getPredictInStepState(time) != NOT_IN_STEP_PREDICTION; 161 | } 162 | 163 | public void setPredictInStepState(int step) { 164 | predictedInStepState.setPredictInStep(step); 165 | } 166 | 167 | public int getPredictInStepState(int time) { 168 | return predictedInStepState.get(time); 169 | } 170 | 171 | 172 | 173 | public boolean deleteSegment(DistalDendriteSegment toDelete) { 174 | return elementList.remove(toDelete); 175 | } 176 | 177 | public void deleteAllSegment() { 178 | elementList.clear(); 179 | } 180 | 181 | 182 | @Override public String toString() { 183 | StringBuilder result = new StringBuilder().append("Column Inx:").append(this.getOwner().getIndex()); 184 | result = result.append("; Cell Inx:").append(this.getCellIndex()); 185 | result = result.append("; Position:").append(this.getOwner().getPosition()); 186 | result = result.append("; Active:").append(this.getActiveState(Cell.NOW)); 187 | result = result.append("; Learn:").append(this.getLearnState(Cell.NOW)); 188 | result = result.append("; Predicted:").append(this.getPredictiveState(Cell.NOW)); 189 | return result.toString(); 190 | } 191 | 192 | 193 | 194 | public List getNeighborsAndMyColumn() { 195 | return this.owner.getOwner().getAllWithinRadius(this.owner.getPosition(), 196 | this.owner.getOwner().getLearningRadius()); 197 | 198 | } 199 | 200 | 201 | 202 | 203 | /*Custom events implementation*/ 204 | private final Collection _segmentsChangeEventListeners = new HashSet(); 205 | 206 | public synchronized void addSegmentsChangeListener(SegmentsChangeEventListener listener) { 207 | _segmentsChangeEventListeners.add(listener); 208 | } 209 | 210 | public synchronized void removeSegmentsChangeListener(SegmentsChangeEventListener listener) { 211 | _segmentsChangeEventListeners.remove(listener); 212 | } 213 | 214 | public synchronized void fireUpdatesChange() { 215 | SegmentsChangeEvent event = new SegmentsChangeEvent(this); 216 | for (SegmentsChangeEventListener segmentsChangeEventListener : _segmentsChangeEventListeners) { 217 | segmentsChangeEventListener.onUpdatesChange(event); 218 | } 219 | } 220 | 221 | public synchronized void fireSegmentsChange() { 222 | SegmentsChangeEvent event = new SegmentsChangeEvent(this); 223 | for (SegmentsChangeEventListener segmentsChangeEventListener : _segmentsChangeEventListeners) { 224 | segmentsChangeEventListener.onSegmentsChange(event); 225 | } 226 | } 227 | 228 | 229 | public static class SegmentsChangeEvent extends java.util.EventObject { 230 | 231 | public SegmentsChangeEvent(Cell source) { 232 | super(source); 233 | } 234 | 235 | } 236 | 237 | public interface SegmentsChangeEventListener { 238 | public void onSegmentsChange(SegmentsChangeEvent e); 239 | 240 | public void onUpdatesChange(SegmentsChangeEvent e); 241 | } 242 | 243 | 244 | /* 245 | *Advances this cell to the next time step. 246 | *The current state of this cell (active, learning, predicting) will be set as the 247 | *previous state and the current state will be reset to no cell activity by 248 | *default until it can be determined. 249 | *Call this function before each temporal cycle 250 | */ 251 | public void nextTimeStep() { 252 | this.activeState.add(Cell.NOW, false); 253 | this.predictedInStepState.add(Cell.NOW, NOT_IN_STEP_PREDICTION); 254 | this.learnState.add(Cell.NOW, false); 255 | } 256 | 257 | private static class CellStateBuffer extends CircularArrayList { 258 | public CellStateBuffer() { 259 | super(TIME_STEPS); 260 | for (int i = 0; i < TIME_STEPS; i++) { 261 | this.add(false); 262 | } 263 | } 264 | 265 | /** 266 | * Set the current state(time NOW) 267 | * 268 | */ 269 | void setState() { 270 | this.set(NOW, true); 271 | } 272 | } 273 | 274 | private static class PredictInStepBuffer extends CircularArrayList { 275 | public PredictInStepBuffer() { 276 | super(TIME_STEPS); 277 | for (int i = 0; i < TIME_STEPS; i++) { 278 | this.add(NOT_IN_STEP_PREDICTION); 279 | } 280 | } 281 | 282 | void setPredictInStep(int step) { 283 | this.set(NOW, step); 284 | } 285 | } 286 | 287 | public static class Config { 288 | private final int amountOfSynapses; 289 | private final int timeSteps; 290 | 291 | public Config(int amountOfSynapses, int timeSteps) { 292 | this.amountOfSynapses = amountOfSynapses; 293 | this.timeSteps = timeSteps; 294 | } 295 | 296 | 297 | public int getAmountOfSynapses() { 298 | return amountOfSynapses; 299 | } 300 | 301 | public int getTimeSteps() { 302 | return timeSteps; 303 | } 304 | } 305 | 306 | } -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/surface/LayerSlicedHorizontalView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer.surface; 10 | 11 | import htm.model.Cell; 12 | import htm.model.Column; 13 | import htm.model.DistalDendriteSegment; 14 | import htm.model.Layer; 15 | import htm.model.Synapse; 16 | import htm.utils.UIUtils; 17 | import org.apache.commons.logging.Log; 18 | import org.apache.commons.logging.LogFactory; 19 | 20 | import java.awt.*; 21 | import java.util.ArrayList; 22 | import java.util.Collections; 23 | import java.util.List; 24 | import javax.swing.*; 25 | 26 | public class LayerSlicedHorizontalView extends JPanel { 27 | private static final Log LOG = LogFactory.getLog(LayerSlicedHorizontalView.class); 28 | private final List layers = new ArrayList(); 29 | private CellPosition clickedOnCellPosition = null; 30 | private CellPosition selectedSynapseCellPosition = null; 31 | private final List selectedSegmentSynapsesCellPositionList = new ArrayList(); 32 | 33 | 34 | public List getLayers() { 35 | return Collections.unmodifiableList(layers); 36 | } 37 | 38 | public ColumnCellsByIndexSurface getLayer(int layerInx) { 39 | return layers.get(layerInx); 40 | } 41 | 42 | public void addElementMouseEnterListener(BaseSurface.ElementMouseEnterListener listener) { 43 | for (BaseSurface layer : layers) { 44 | layer.addElementMouseEnterListener(listener); 45 | } 46 | } 47 | 48 | 49 | public LayerSlicedHorizontalView(Layer region) { 50 | super(new GridLayout(0, 1)); 51 | for (int i = 0; i < region.getCellsInColumn(); i++) { 52 | final ColumnCellsByIndexSurface cellLayer = new ColumnCellsByIndexSurface(this, region, i); 53 | layers.add(i, cellLayer); 54 | cellLayer.setBorder(UIUtils.LIGHT_GRAY_BORDER); 55 | this.add(new Container() { 56 | private Container init(String caption) { 57 | this.setLayout(new BorderLayout()); 58 | this.add(new JLabel(caption), BorderLayout.NORTH); 59 | this.add(cellLayer, BorderLayout.CENTER); 60 | return this; 61 | } 62 | }.init("Layer #" + i)); 63 | } 64 | } 65 | 66 | public CellPosition getClickedOnCellPosition() { 67 | return clickedOnCellPosition; 68 | } 69 | 70 | public void setClickedOnCell(Cell clickedOnCell) { 71 | this.setClickedOnCellPosition(new CellPosition(clickedOnCell.getOwner().getIndex(), 72 | clickedOnCell.getCellIndex())); 73 | } 74 | 75 | public void setClickedOnCellPosition(CellPosition clickedOnCellPosition) { 76 | this.clickedOnCellPosition = clickedOnCellPosition.equals( 77 | this.clickedOnCellPosition) ? null : clickedOnCellPosition; 78 | this.selectedSynapseCellPosition = null; 79 | selectedSegmentSynapsesCellPositionList.clear(); 80 | repaint(); 81 | } 82 | 83 | 84 | public CellPosition getSelectedSynapseCellPosition() { 85 | return selectedSynapseCellPosition; 86 | } 87 | 88 | 89 | public void resetSelectedSynapseCellPosition() { 90 | this.selectedSynapseCellPosition = null; 91 | } 92 | 93 | public void setSelectedSynapse(Synapse.DistalSynapse selectedSynapse) { 94 | CellPosition newSelectedSynapseCellPosition = new CellPosition( 95 | selectedSynapse.getFromCell().getOwner().getIndex(), 96 | selectedSynapse.getFromCell().getCellIndex()); 97 | this.selectedSynapseCellPosition = this.selectedSynapseCellPosition == newSelectedSynapseCellPosition ? null : newSelectedSynapseCellPosition; 98 | } 99 | 100 | public void setSelectedSegment(DistalDendriteSegment selectedSegment) { 101 | selectedSegmentSynapsesCellPositionList.clear(); 102 | if (selectedSegment != null) { 103 | for (Synapse.DistalSynapse distalSynapse : selectedSegment.getElementsList()) { 104 | selectedSegmentSynapsesCellPositionList.add(new CellPosition( 105 | distalSynapse.getFromCell().getOwner().getIndex(), 106 | distalSynapse.getFromCell().getCellIndex())); 107 | } 108 | } 109 | } 110 | 111 | public List getSelectedSegmentSynapsesCellPositionList() { 112 | return selectedSegmentSynapsesCellPositionList; 113 | } 114 | 115 | 116 | public static class CellPosition { 117 | private final int columnIndex; 118 | private final int cellIndex; 119 | 120 | private CellPosition(Integer columnIndex, Integer cellIndex) { 121 | this.columnIndex = columnIndex; 122 | this.cellIndex = cellIndex; 123 | } 124 | 125 | public Integer getColumnIndex() { 126 | return columnIndex; 127 | } 128 | 129 | public Integer getCellIndex() { 130 | return cellIndex; 131 | } 132 | 133 | public boolean equals(Object obj) { 134 | if (obj instanceof CellPosition) { 135 | CellPosition cp = (CellPosition)obj; 136 | return (columnIndex == cp.columnIndex) && (cellIndex == cp.cellIndex); 137 | } 138 | return super.equals(obj); 139 | } 140 | } 141 | 142 | public static class ColumnCellsByIndexSurface extends CellSurface { 143 | 144 | 145 | public ColumnCellsByIndexSurface(LayerSlicedHorizontalView view, Layer region, int sliceIndex) { 146 | super(region.getDimension().width, region.getDimension().height, region); 147 | this.parentView = view; 148 | this.layerIndex = sliceIndex; 149 | this.addElementMouseEnterListener(new ElementMouseEnterListener() { 150 | @Override 151 | public void onElementMouseEnter(ElementMouseEnterEvent e) { 152 | CellPosition clickedOnPosition = new CellPosition(e.getIndex(), layerIndex); 153 | parentView.setClickedOnCellPosition(clickedOnPosition); 154 | } 155 | }); 156 | } 157 | 158 | @Override 159 | public Cell getCell(int columnIndex) { 160 | return region.getElementByIndex(columnIndex).getElementByIndex(layerIndex); 161 | } 162 | 163 | 164 | private final LayerSlicedHorizontalView parentView; 165 | private final int layerIndex; 166 | 167 | 168 | private CellPosition getClickedOnCellPosition() { 169 | return parentView.getClickedOnCellPosition(); 170 | } 171 | 172 | private CellPosition getSelectedSynapseCellPosition() { 173 | return parentView.getSelectedSynapseCellPosition(); 174 | } 175 | 176 | private List getSelectedSegmentSynapsesCellPositionList() { 177 | return parentView.getSelectedSegmentSynapsesCellPositionList(); 178 | } 179 | 180 | /* private void repaintAll() { 181 | for (ColumnCellsByIndexSurface layer : parentView.getLayers()) { 182 | layer.repaint(); 183 | } 184 | } 185 | 186 | public void setSelectedSynapseColumnIndex(int selectedSynapseInx) { 187 | parentView.setSelectedSynapseCellPosition(selectedSynapseInx == -1 ? null : new CellPosition(selectedSynapseInx, 188 | this.layerIndex)); 189 | repaintAll(); 190 | } */ 191 | 192 | 193 | public void drawNeighbors(int columnIndex, Graphics2D g2d) { 194 | Cell clickedOnCell = this.getCell(columnIndex); 195 | List neighborColumns = getRegion().getAllWithinRadius(clickedOnCell.getOwner().getPosition(), 196 | getRegion().getLearningRadius()); 197 | neighborColumns.remove(clickedOnCell.getOwner()); 198 | g2d.setColor(Color.LIGHT_GRAY); 199 | Composite original = g2d.getComposite(); 200 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 201 | 0.4f)); 202 | for (Column column : neighborColumns) { 203 | Rectangle columnRec = this.getElementArea(column.getPosition()); 204 | g2d.fillOval(columnRec.x, columnRec.y, columnRec.width, columnRec.height); 205 | } 206 | g2d.setComposite(original); 207 | 208 | } 209 | 210 | @Override 211 | protected void doDrawing(Graphics2D g2d) { 212 | super.doDrawing(g2d); 213 | //LOG.debug("Draw Sliced Region"); 214 | CellPosition clickedOn = getClickedOnCellPosition(), selectedSynapse = getSelectedSynapseCellPosition(); 215 | List selectedSegmentSynapsesCellPositionListCol = getSelectedSegmentSynapsesCellPositionList(); 216 | if (clickedOn != null) { 217 | Stroke originalStroke = g2d.getStroke(); 218 | g2d.setStroke(new BasicStroke(1.5f)); 219 | if (clickedOn.getCellIndex() == layerIndex) { 220 | g2d.setColor(Color.RED); 221 | Rectangle aroundRec = getElementAreaWithScale(clickedOn.getColumnIndex(), 1 / (Math.PI / 4) * 1.05); 222 | //Rectangle aroundRec = getElementAreaByIndex(clickedOn.getColumnIndex()); 223 | //g2d.drawLine(aroundRec.x + aroundRec.width/2, aroundRec.y, aroundRec.x + aroundRec.width/2, aroundRec.y + aroundRec.height); 224 | //g2d.drawLine(aroundRec.x, aroundRec.y + aroundRec.height/2, aroundRec.x + aroundRec.width, aroundRec.y + aroundRec.height/2); 225 | g2d.drawOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 226 | } else { 227 | Rectangle aroundRec = getElementAreaWithScale(clickedOn.getColumnIndex(), 1 / (Math.PI / 4) * 1.05); 228 | g2d.setColor(Color.ORANGE); 229 | g2d.drawOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 230 | } 231 | g2d.setStroke(originalStroke); 232 | } 233 | if (clickedOn != null) { 234 | drawNeighbors(clickedOn.getColumnIndex(), g2d); 235 | } 236 | if (selectedSynapse != null && selectedSynapse.getCellIndex() == this.layerIndex) { 237 | Composite original = g2d.getComposite(); 238 | Rectangle aroundRec = getElementAreaWithScale(selectedSynapse.getColumnIndex(), 1 / (Math.PI / 4) * 1.5); 239 | g2d.setColor(UIUtils.LIGHT_BLUE); 240 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 241 | 0.5f)); 242 | g2d.fillOval(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 243 | g2d.setComposite(original); 244 | } 245 | for (CellPosition cellPosition : selectedSegmentSynapsesCellPositionListCol) { 246 | if (cellPosition.getCellIndex() == this.layerIndex) { 247 | Color originalColor = g2d.getColor(); 248 | g2d.setColor(Color.DARK_GRAY); 249 | Rectangle aroundRec = getElementAreaByIndex(cellPosition.getColumnIndex()); 250 | g2d.drawRect(aroundRec.x, aroundRec.y, aroundRec.width, aroundRec.height); 251 | g2d.setColor(originalColor); 252 | } 253 | } 254 | } 255 | 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/SpatialInfo.java: -------------------------------------------------------------------------------- 1 | package htm.visualizer; 2 | 3 | import htm.model.Column; 4 | import htm.model.Synapse; 5 | import htm.model.space.BaseSpace; 6 | import htm.utils.UIUtils; 7 | 8 | import java.awt.*; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | import javax.swing.*; 12 | import javax.swing.border.TitledBorder; 13 | import javax.swing.table.AbstractTableModel; 14 | 15 | 16 | public class SpatialInfo extends JPanel { 17 | private Column currentColumn; 18 | private final JTable proximalSynapsesTable; 19 | private final JTable neighborColumnsTable; 20 | 21 | 22 | public SpatialInfo() { 23 | this.setLayout(new GridBagLayout()); 24 | GridBagConstraints c = new GridBagConstraints(); 25 | c.fill = GridBagConstraints.BOTH; 26 | c.anchor = GridBagConstraints.NORTH; 27 | c.weighty = 1.0; 28 | c.weightx = 1.4; 29 | ColumnAttributesInfo left = new ColumnAttributesInfo(); 30 | left.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), 31 | "Column Properties", 32 | TitledBorder.CENTER, 33 | TitledBorder.TOP)); 34 | this.add(left, c); 35 | c.gridx = 1; 36 | c.weightx = 1.8; 37 | //Create the scroll pane and add the table to it. 38 | proximalSynapsesTable = initSynapsesTable(); 39 | JComponent center = (new JPanel() { 40 | private JPanel init() { 41 | this.setBackground(Color.WHITE); 42 | this.setLayout(new BorderLayout()); 43 | add(new JScrollPane(proximalSynapsesTable), BorderLayout.CENTER); 44 | proximalSynapsesTable.setFillsViewportHeight(true); 45 | return this; 46 | } 47 | }.init()); 48 | add(center); 49 | center.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), 50 | "Proximal Synapses", 51 | TitledBorder.CENTER, 52 | TitledBorder.TOP)); 53 | 54 | 55 | this.add(center, c); 56 | c.gridx = 2; 57 | c.weightx = 2.2; 58 | neighborColumnsTable = initNeighborColumnsTable(); 59 | JComponent right = (new JPanel() { 60 | private JPanel init() { 61 | this.setBackground(Color.WHITE); 62 | this.setLayout(new BorderLayout()); 63 | add(new JScrollPane(neighborColumnsTable), BorderLayout.CENTER); 64 | neighborColumnsTable.setFillsViewportHeight(true); 65 | return this; 66 | } 67 | }.init()); 68 | add(right); 69 | right.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), 70 | "Neighbor Columns", 71 | TitledBorder.CENTER, 72 | TitledBorder.TOP)); 73 | this.add(right, c); 74 | 75 | 76 | } 77 | 78 | private JTable initSynapsesTable() { 79 | JTable table = new JTable(new ProximalSynapsesModel()); 80 | table.setAutoCreateRowSorter(true); 81 | table.getColumnModel().getColumn(0).setCellRenderer(new UIUtils.PermanenceRenderer()); 82 | table.getColumnModel().getColumn(1).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 83 | table.getColumnModel().getColumn(2).setPreferredWidth(50); 84 | table.getColumnModel().getColumn(3).setPreferredWidth(50); 85 | table.getColumnModel().getColumn(4).setCellRenderer(new UIUtils.PositionRenderer()); 86 | return table; 87 | } 88 | 89 | public JTable getSynapsesTable() { 90 | return proximalSynapsesTable; 91 | } 92 | 93 | public JTable getNeighborColumnsTable() { 94 | return neighborColumnsTable; 95 | } 96 | 97 | 98 | private JTable initNeighborColumnsTable() { 99 | JTable table = new JTable(new NeighborColumnsModel()); 100 | table.setAutoCreateRowSorter(true); 101 | table.getColumnModel().getColumn(0).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 102 | table.getColumnModel().getColumn(1).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 103 | table.getColumnModel().getColumn(1).setPreferredWidth(50); 104 | table.getColumnModel().getColumn(2).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 105 | table.getColumnModel().getColumn(3).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 106 | table.getColumnModel().getColumn(4).setCellRenderer(new UIUtils.SmallDoubleRenderer()); 107 | table.getColumnModel().getColumn(4).setPreferredWidth(50); 108 | table.getColumnModel().getColumn(5).setPreferredWidth(40); 109 | table.getColumnModel().getColumn(6).setPreferredWidth(40); 110 | table.getColumnModel().getColumn(7).setCellRenderer(new UIUtils.PositionRenderer()); 111 | return table; 112 | } 113 | 114 | 115 | public void setCurrentColumn(Column currentColumn) { 116 | this.currentColumn = this.currentColumn != currentColumn ? currentColumn : null; 117 | ((ProximalSynapsesModel)proximalSynapsesTable.getModel()).setColumn(this.currentColumn); 118 | ((NeighborColumnsModel)neighborColumnsTable.getModel()).setColumn(this.currentColumn); 119 | this.repaint(); 120 | } 121 | 122 | 123 | private class ColumnAttributesInfo extends UIUtils.TextColumnInfo { 124 | 125 | @Override 126 | protected Map getAttributeMap() { 127 | Column column = currentColumn; 128 | Map result = new LinkedHashMap(); 129 | if (column != null) { 130 | double inhibitionRadius = column.getOwner().getAverageReceptiveFieldSize(); 131 | result.put("Index", column.getIndex() + ""); 132 | result.put("Position", "X:" + (column.getPosition().x) + ", Y:" + column.getPosition().y); 133 | result.put("Active", column.isActive() ? "Yes" : "No"); 134 | result.put("Active Duty Cycle", UIUtils.DF_4.format(column.getActiveDutyCycle())); 135 | result.put("Max Duty Cycle", UIUtils.DF_4.format(column.getMaxDutyCycle(inhibitionRadius))); 136 | result.put("Boost", UIUtils.DF_2.format(column.getBoost())); 137 | result.put("Overlap", UIUtils.DF_2.format(column.getOverlap())); 138 | result.put("Over. Duty Cycle", UIUtils.DF_4.format(column.getOverlapDutyCycle())); 139 | result.put("Neighbors Count", column.getNeighbors(inhibitionRadius).size() + ""); 140 | result.put("Connected Syn.", column.getConnectedSynapses().size() + ""); 141 | result.put("Active Syn.", column.getActiveConnectedSynapses().size() + ""); 142 | result.put("Avg. Rec. Field", UIUtils.DF_2.format(inhibitionRadius) + ""); 143 | } 144 | return result; 145 | } 146 | 147 | } 148 | 149 | class NeighborColumnsModel extends AbstractTableModel { 150 | private Column column = null; 151 | private java.util.List neighbors = null; 152 | private final String[] columnNames = { 153 | "Overlap", 154 | "Dist", 155 | "ADC", 156 | "ODC", 157 | "Boost", 158 | "Act", 159 | "Inx", 160 | "Position"}; 161 | 162 | public void setColumn(Column column) { 163 | this.column = column != null ? column : null; 164 | neighbors = column != null ? column.getNeighbors(column.getOwner().getAverageReceptiveFieldSize()) : null; 165 | this.fireTableDataChanged(); 166 | } 167 | 168 | @Override public int getRowCount() { 169 | return neighbors == null ? 0 : neighbors.size(); 170 | } 171 | 172 | @Override public int getColumnCount() { 173 | return columnNames.length; 174 | } 175 | 176 | @Override 177 | public String getColumnName(int col) { 178 | return columnNames[col]; 179 | } 180 | 181 | @Override public Object getValueAt(int rowIndex, int columnIndex) { 182 | Object value = null; 183 | if (neighbors != null && column != null) { 184 | Column row = neighbors.get(rowIndex); 185 | switch (columnIndex) { 186 | case 0: 187 | value = row.getOverlap(); 188 | break; 189 | case 1: 190 | value = BaseSpace.getDistance(column.getPosition(), row.getPosition()); 191 | break; 192 | case 2: 193 | value = row.getActiveDutyCycle(); 194 | break; 195 | case 3: 196 | value = row.getOverlapDutyCycle(); 197 | break; 198 | case 4: 199 | value = row.getBoost(); 200 | break; 201 | case 5: 202 | value = row.isActive(); 203 | break; 204 | case 6: 205 | value = row.getIndex(); 206 | break; 207 | case 7: 208 | value = new UIUtils.SortablePoint(row.getPosition()); 209 | break; 210 | default: 211 | value = null; 212 | } 213 | } 214 | return value; 215 | } 216 | 217 | @Override public Class getColumnClass(int columnIndex) { 218 | Class result; 219 | switch (columnIndex) { 220 | case 0: 221 | result = Double.class; 222 | break; 223 | case 1: 224 | result = Double.class; 225 | break; 226 | case 2: 227 | result = Double.class; 228 | break; 229 | case 3: 230 | result = Double.class; 231 | break; 232 | case 4: 233 | result = Double.class; 234 | break; 235 | case 5: 236 | result = Boolean.class; 237 | break; 238 | case 6: 239 | result = Integer.class; 240 | break; 241 | case 7: 242 | result = UIUtils.SortablePoint.class; 243 | break; 244 | default: 245 | result = super.getColumnClass( 246 | columnIndex); 247 | } 248 | return result; 249 | } 250 | 251 | } 252 | 253 | class ProximalSynapsesModel extends AbstractTableModel { 254 | private java.util.List synapses = null; 255 | private final String[] columnNames = { 256 | "Perm", 257 | "Dist", 258 | "I-Act", 259 | "I-Inx", 260 | "I-Position"}; 261 | 262 | public void setColumn(Column column) { 263 | synapses = column != null ? column.getPotentialSynapses() : null; 264 | this.fireTableDataChanged(); 265 | } 266 | 267 | @Override public int getRowCount() { 268 | return synapses == null ? 0 : synapses.size(); 269 | } 270 | 271 | @Override public int getColumnCount() { 272 | return columnNames.length; 273 | } 274 | 275 | @Override 276 | public String getColumnName(int col) { 277 | return columnNames[col]; 278 | } 279 | 280 | @Override public Object getValueAt(int rowIndex, int columnIndex) { 281 | Object value = null; 282 | if (synapses != null) { 283 | Synapse.ProximalSynapse row = synapses.get(rowIndex); 284 | switch (columnIndex) { 285 | case 0: 286 | value = row.getPermanence(); 287 | break; 288 | case 1: 289 | value = row.getDistanceToColumn(); 290 | break; 291 | case 2: 292 | value = row.getConnectedSensoryInput().getValue(); 293 | break; 294 | case 3: 295 | value = row.getConnectedSensoryInput().getIndex(); 296 | break; 297 | case 4: 298 | value = new UIUtils.SortablePoint(row.getConnectedSensoryInput().getPosition()); 299 | break; 300 | default: 301 | value = null; 302 | } 303 | } 304 | return value; 305 | } 306 | 307 | @Override public Class getColumnClass(int columnIndex) { 308 | Class result; 309 | switch (columnIndex) { 310 | case 0: 311 | result = Double.class; 312 | break; 313 | case 1: 314 | result = Double.class; 315 | break; 316 | case 2: 317 | result = Boolean.class; 318 | break; 319 | case 3: 320 | result = Integer.class; 321 | break; 322 | case 4: 323 | result = UIUtils.SortablePoint.class; 324 | break; 325 | default: 326 | result = super.getColumnClass( 327 | columnIndex); 328 | } 329 | return result; 330 | } 331 | } 332 | 333 | 334 | } 335 | 336 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/ParametersEditor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer; 10 | 11 | import java.awt.*; 12 | import java.awt.event.ActionEvent; 13 | import java.awt.event.ActionListener; 14 | import java.awt.event.ComponentAdapter; 15 | import java.awt.event.ComponentEvent; 16 | import java.awt.event.KeyEvent; 17 | import java.awt.event.WindowAdapter; 18 | import java.awt.event.WindowEvent; 19 | import java.io.Serializable; 20 | import javax.swing.*; 21 | import javax.swing.border.Border; 22 | import javax.swing.border.TitledBorder; 23 | 24 | public class ParametersEditor extends JComponent { 25 | private final static Color LIGHT_BLUE = new Color(150, 150, 255); 26 | private static final Border DEFAULT_BORDER = BorderFactory.createEmptyBorder(4, 4, 4, 4); 27 | private static final Font LABEL_FONT = UIManager.getFont("JLabel.font"); 28 | private static final Color TITLE_COLOR = UIManager.getColor("Slider.foreground"); 29 | 30 | 31 | public static HTMGraphicInterface.Config showDialog(Component component, 32 | String title, 33 | HTMGraphicInterface.Config initialParams) throws HeadlessException { 34 | 35 | final ParametersEditor pane = new ParametersEditor(initialParams); 36 | 37 | ParametersTracker ok = new ParametersTracker(pane); 38 | JDialog dialog = createDialog(component, title, true, pane, ok, null); 39 | 40 | dialog.setVisible(true); // blocks until user brings dialog down... 41 | 42 | return ok.getParameters(); 43 | } 44 | 45 | public static JDialog createDialog(Component c, String title, boolean modal, 46 | ParametersEditor chooserPane, ActionListener okListener, 47 | ActionListener cancelListener) throws HeadlessException { 48 | 49 | Window window = getWindowForComponent(c); 50 | ParametersEditorDialog dialog; 51 | if (window instanceof Frame) { 52 | dialog = new ParametersEditorDialog((Frame)window, title, modal, c, chooserPane, 53 | okListener, cancelListener); 54 | } else { 55 | dialog = new ParametersEditorDialog((Dialog)window, title, modal, c, chooserPane, 56 | okListener, cancelListener); 57 | } 58 | return dialog; 59 | } 60 | 61 | static Window getWindowForComponent(Component parentComponent) 62 | throws HeadlessException { 63 | if (parentComponent == null) { 64 | return JOptionPane.getRootFrame(); 65 | } 66 | if (parentComponent instanceof Frame || parentComponent instanceof Dialog) { 67 | return (Window)parentComponent; 68 | } 69 | return getWindowForComponent(parentComponent.getParent()); 70 | } 71 | 72 | private final Parameters.TemporalPoolerParameters temporalPoolerParameters; 73 | private final Parameters.SpatialPoolerParameters spatialPoolerParameters; 74 | private final Parameters.RegionParameters regionParameters; 75 | private final Parameters.ColumnParameters columnParameters; 76 | private final Parameters.CellParameters cellParameters; 77 | private final Parameters.SynapseParameters proximalSynapsesParameters; 78 | private final Parameters.SynapseParameters distalSynapsesParameters; 79 | 80 | public void setParameters(HTMGraphicInterface.Config params) { 81 | temporalPoolerParameters.setParameters(params.getTemporalPoolerConfig()); 82 | spatialPoolerParameters.setParameters(params.getSpatialPoolerConfig()); 83 | regionParameters.setParameters(params.getRegionConfig()); 84 | columnParameters.setParameters(params.getColumnConfig()); 85 | proximalSynapsesParameters.setParameters(params.getProximalSynapseConfig()); 86 | distalSynapsesParameters.setParameters(params.getDistalSynapseConfig()); 87 | cellParameters.setParameters(params.getCellConfig()); 88 | } 89 | 90 | public HTMGraphicInterface.Config getParameters() { 91 | return new HTMGraphicInterface.Config(null, 92 | temporalPoolerParameters.getParameters(), 93 | spatialPoolerParameters.getParameters(), 94 | regionParameters.getParameters(), 95 | columnParameters.getParameters(), 96 | cellParameters.getParameters(), 97 | proximalSynapsesParameters.getParameters(), 98 | distalSynapsesParameters.getParameters()); 99 | } 100 | 101 | public ParametersEditor(HTMGraphicInterface.Config params) { 102 | regionParameters = new Parameters.RegionParameters(params.getRegionConfig()); 103 | columnParameters = new Parameters.ColumnParameters(params.getColumnConfig()); 104 | cellParameters = new Parameters.CellParameters(params.getCellConfig()); 105 | spatialPoolerParameters = new Parameters.SpatialPoolerParameters(params.getSpatialPoolerConfig()); 106 | temporalPoolerParameters = new Parameters.TemporalPoolerParameters(params.getTemporalPoolerConfig()); 107 | proximalSynapsesParameters = new Parameters.SynapseParameters(params.getProximalSynapseConfig()); 108 | distalSynapsesParameters = new Parameters.SynapseParameters(params.getDistalSynapseConfig()); 109 | 110 | this.setLayout(new BorderLayout()); 111 | JTabbedPane tabs = new JTabbedPane(); 112 | tabs.addTab("General", new JComponent() { 113 | private Container init() { 114 | this.setLayout(new BorderLayout()); 115 | this.add(decorateWithBorder(regionParameters, "Region Properties")); 116 | return this; 117 | } 118 | }.init()); 119 | tabs.addTab("Spatial", new JComponent() { 120 | private Container init() { 121 | this.setLayout(new GridBagLayout()); 122 | GridBagConstraints c = new GridBagConstraints(); 123 | c.fill = GridBagConstraints.BOTH; 124 | c.gridx = 0; 125 | c.gridy = 0; 126 | c.weighty = 3.0; 127 | this.add(decorateWithBorder(spatialPoolerParameters, "Spatial Pooler"), c); 128 | c.gridy = 1; 129 | c.weighty = 1.0; 130 | this.add(decorateWithBorder(columnParameters, "Column Parameters"), c); 131 | c.gridy = 2; 132 | c.weighty = 3.0; 133 | this.add(decorateWithBorder(proximalSynapsesParameters, "Proximal Synapses"), c); 134 | return this; 135 | } 136 | }.init()); 137 | tabs.addTab("Temporal", new JComponent() { 138 | private Container init() { 139 | this.setLayout(new GridBagLayout()); 140 | GridBagConstraints c = new GridBagConstraints(); 141 | c.fill = GridBagConstraints.BOTH; 142 | c.gridx = 0; 143 | c.gridy = 0; 144 | c.weighty = 3.0; 145 | this.add(decorateWithBorder(temporalPoolerParameters, "Temporal Pooler"), c); 146 | c.gridy = 1; 147 | c.weighty = 2.0; 148 | this.add(decorateWithBorder(cellParameters, "Cell Parameters"), c); 149 | c.gridy = 2; 150 | c.weighty = 3.0; 151 | this.add(decorateWithBorder(distalSynapsesParameters, "Distal Synapses"), c); 152 | return this; 153 | } 154 | }.init()); 155 | this.add(tabs); 156 | } 157 | 158 | private JComponent decorateWithBorder(JComponent component, String title) { 159 | component.setBorder(BorderFactory.createCompoundBorder( 160 | BorderFactory.createTitledBorder(null, title, TitledBorder.CENTER, TitledBorder.TOP, LABEL_FONT, 161 | TITLE_COLOR), 162 | DEFAULT_BORDER)); 163 | return component; 164 | } 165 | 166 | } 167 | 168 | class ParametersEditorDialog extends JDialog { 169 | private HTMGraphicInterface.Config initialCfg; 170 | private ParametersEditor chooserPane; 171 | private JButton cancelButton; 172 | 173 | public ParametersEditorDialog(Dialog owner, String title, boolean modal, 174 | Component c, ParametersEditor chooserPane, 175 | ActionListener okListener, ActionListener cancelListener) 176 | throws HeadlessException { 177 | super(owner, title, modal); 178 | initParametersChooserDialog(c, chooserPane, okListener, cancelListener); 179 | } 180 | 181 | public ParametersEditorDialog(Frame owner, String title, boolean modal, 182 | Component c, ParametersEditor chooserPane, 183 | ActionListener okListener, ActionListener cancelListener) 184 | throws HeadlessException { 185 | super(owner, title, modal); 186 | initParametersChooserDialog(c, chooserPane, okListener, cancelListener); 187 | } 188 | 189 | protected void initParametersChooserDialog(Component c, ParametersEditor chooserPane, 190 | ActionListener okListener, ActionListener cancelListener) { 191 | //setResizable(false); 192 | 193 | this.chooserPane = chooserPane; 194 | 195 | String okString = "Ok"; 196 | String cancelString = "Cancel"; 197 | String resetString = "Reset"; 198 | 199 | Container contentPane = getContentPane(); 200 | contentPane.setLayout(new BorderLayout()); 201 | contentPane.add(chooserPane, BorderLayout.CENTER); 202 | 203 | /* 204 | * Create Lower button panel 205 | */ 206 | JPanel buttonPane = new JPanel(); 207 | buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER)); 208 | JButton okButton = new JButton(okString); 209 | getRootPane().setDefaultButton(okButton); 210 | okButton.setActionCommand("OK"); 211 | okButton.addActionListener(new ActionListener() { 212 | @Override 213 | public void actionPerformed(ActionEvent e) { 214 | setVisible(false); 215 | } 216 | }); 217 | if (okListener != null) { 218 | okButton.addActionListener(okListener); 219 | } 220 | buttonPane.add(okButton); 221 | 222 | cancelButton = new JButton(cancelString); 223 | 224 | // The following few lines are used to register esc to close the dialog 225 | Action cancelKeyAction = new AbstractAction() { 226 | @Override 227 | public void actionPerformed(ActionEvent e) { 228 | for (ActionListener a : ((AbstractButton)e.getSource()).getActionListeners()) { 229 | a.actionPerformed(e); 230 | } 231 | } 232 | }; 233 | KeyStroke cancelKeyStroke = KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE); 234 | InputMap inputMap = cancelButton.getInputMap(JComponent. 235 | WHEN_IN_FOCUSED_WINDOW); 236 | ActionMap actionMap = cancelButton.getActionMap(); 237 | if (inputMap != null && actionMap != null) { 238 | inputMap.put(cancelKeyStroke, "cancel"); 239 | actionMap.put("cancel", cancelKeyAction); 240 | } 241 | // end esc handling 242 | 243 | cancelButton.setActionCommand("cancel"); 244 | cancelButton.addActionListener(new ActionListener() { 245 | @Override 246 | public void actionPerformed(ActionEvent e) { 247 | setVisible(false); 248 | } 249 | }); 250 | if (cancelListener != null) { 251 | cancelButton.addActionListener(cancelListener); 252 | } 253 | buttonPane.add(cancelButton); 254 | 255 | JButton resetButton = new JButton(resetString); 256 | resetButton.addActionListener(new ActionListener() { 257 | @Override 258 | public void actionPerformed(ActionEvent e) { 259 | reset(); 260 | } 261 | }); 262 | buttonPane.add(resetButton); 263 | contentPane.add(buttonPane, BorderLayout.SOUTH); 264 | 265 | if (JDialog.isDefaultLookAndFeelDecorated()) { 266 | boolean supportsWindowDecorations = 267 | UIManager.getLookAndFeel().getSupportsWindowDecorations(); 268 | if (supportsWindowDecorations) { 269 | getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG); 270 | } 271 | } 272 | applyComponentOrientation(((c == null) ? getRootPane() : c).getComponentOrientation()); 273 | pack(); 274 | setLocationRelativeTo(c); 275 | 276 | this.addWindowListener(new Closer()); 277 | this.addComponentListener(new DisposeOnClose()); 278 | } 279 | 280 | @Override public void setVisible(boolean b) { 281 | initialCfg = chooserPane.getParameters(); 282 | super.setVisible(b); 283 | } 284 | 285 | public void reset() { 286 | chooserPane.setParameters(initialCfg); 287 | } 288 | 289 | class Closer extends WindowAdapter implements Serializable { 290 | @Override 291 | public void windowClosing(WindowEvent e) { 292 | cancelButton.doClick(0); 293 | Window w = e.getWindow(); 294 | w.setVisible(false); 295 | } 296 | } 297 | 298 | static class DisposeOnClose extends ComponentAdapter implements Serializable { 299 | @Override 300 | public void componentHidden(ComponentEvent e) { 301 | Window w = (Window)e.getComponent(); 302 | w.dispose(); 303 | } 304 | } 305 | } 306 | 307 | class ParametersTracker implements ActionListener, Serializable { 308 | final ParametersEditor chooser; 309 | HTMGraphicInterface.Config cfg; 310 | 311 | public ParametersTracker(ParametersEditor c) { 312 | chooser = c; 313 | } 314 | 315 | @Override 316 | public void actionPerformed(ActionEvent e) { 317 | cfg = chooser.getParameters(); 318 | } 319 | 320 | public HTMGraphicInterface.Config getParameters() { 321 | return cfg; 322 | } 323 | } 324 | 325 | -------------------------------------------------------------------------------- /examples/pong.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 5.0 6 | 50.0 7 | 3 8 | 12 9 | 24 10 | 11 | 12 | 12 13 | 24 14 | 15 | 16 | 20 17 | 3 18 | 3 19 | 0.01 20 | 21 | 22 | 5 23 | 2 24 | 0 25 | 30 26 | 6 27 | 28 | 29 | 0.2 30 | 0.0050 31 | 0.0050 32 | 33 | 34 | 0.2 35 | 0.0050 36 | 0.0050 37 | 38 | 39 | 110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 40 | 000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 41 | 000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | 000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 43 | 000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 44 | 000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 45 | 000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 46 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 48 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 49 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 50 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 51 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 52 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 53 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 54 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000 55 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000 56 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000 57 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000 58 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000 59 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000 60 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000 61 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000 62 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000 63 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000 64 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000 65 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000 66 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000 67 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000 68 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 69 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 70 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 71 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 72 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 73 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 74 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 75 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 76 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 77 | 000000000000000000000000000000000000000000000000000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 78 | 000000000000000000000000000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 79 | 000000000000000000000000000000000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 80 | 000000000000000000000000000000000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 81 | 000000000000000000000000000011000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 82 | 000000000000000000110000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 83 | 000000001100000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/main/java/htm/model/Column.java: -------------------------------------------------------------------------------- 1 | package htm.model; 2 | 3 | import htm.model.space.BaseSpace; 4 | import htm.model.space.Element; 5 | import htm.model.space.InputSpace; 6 | import htm.utils.CircularArrayList; 7 | import htm.utils.CollectionUtils; 8 | import htm.utils.MathUtils; 9 | import org.apache.commons.logging.Log; 10 | import org.apache.commons.logging.LogFactory; 11 | 12 | import java.awt.*; 13 | import java.util.*; 14 | import java.util.List; 15 | 16 | public class Column extends Element { 17 | private static final Log LOG = LogFactory.getLog(Column.class); 18 | public static int AMOUNT_OF_PROXIMAL_SYNAPSES = 30; 19 | 20 | private static final CollectionUtils.Predicate ACTIVE_CONNECTED_PROXIMAL_SYNAPSES_PREDICATE = new CollectionUtils.Predicate() { 21 | @Override 22 | public boolean apply(Synapse.ProximalSynapse synapse) { 23 | return synapse.isConnected( 24 | Synapse.ProximalSynapse.CONNECTED_PERMANENCE) && synapse.getConnectedSensoryInput().getValue(); 25 | } 26 | }; 27 | 28 | private static final CollectionUtils.Predicate CONNECTED_PROXIMAL_SYNAPSES_PREDICATE = new CollectionUtils.Predicate() { 29 | @Override 30 | public boolean apply(Synapse.ProximalSynapse synapse) { 31 | return synapse.isConnected(Synapse.ProximalSynapse.CONNECTED_PERMANENCE); 32 | } 33 | }; 34 | 35 | private static final Comparator ACTIVE_DUTY_CYCLE_COMPARATOR = new Comparator() { 36 | @Override public int compare(Column column1, Column column2) { 37 | Double activeDutyCycle1 = column1.getActiveDutyCycle(), activeDutyCycle2 = column2.getActiveDutyCycle(); 38 | return activeDutyCycle2.compareTo(activeDutyCycle1); 39 | } 40 | }; 41 | 42 | 43 | @Override 44 | public boolean addAll(List all) { 45 | throw new NoSuchElementException("Not supported for Column, fixed number of cells"); 46 | } 47 | 48 | @Override 49 | public boolean addElement(Cell element) { 50 | throw new NoSuchElementException("Not supported for Column, fixed number of cells"); 51 | } 52 | 53 | @Override 54 | public void removeElement(Cell element) { 55 | throw new NoSuchElementException("Not supported for Column, fixed number of cells"); 56 | } 57 | 58 | 59 | private static final int COLUMN_CYCLE_BUFFER_SIZE = 1000; 60 | 61 | 62 | public static void updateFromConfig(Config columnCfg) { 63 | Column.AMOUNT_OF_PROXIMAL_SYNAPSES = columnCfg.getAmountOfProximalSynapses(); 64 | } 65 | 66 | 67 | private final List proximalSynapses = new ArrayList(); 68 | private double boost = 1.0; 69 | 70 | /** 71 | * WP 72 | * overlap(c) The spatial pooler overlap of column c with a particular 73 | * input pattern. 74 | */ 75 | private final ColumnBufferedState overlap; //Need to create it later in constructor to access Column instance 76 | 77 | private final ColumnBufferedState active = new ColumnBufferedState(false) { 78 | @Override protected boolean positiveCondition(Boolean active) { 79 | return active; 80 | } 81 | }; 82 | 83 | private final Map> neighbors_cache = new HashMap>(); 84 | 85 | public Column(final Layer layer, int columnIndex, Point columnGridPosition) { 86 | super(layer, columnGridPosition, columnIndex); 87 | for (int i = 0; i < layer.getCellsInColumn(); i++) { 88 | this.elementList.add(new Cell(this, i)); 89 | } 90 | 91 | 92 | overlap = new ColumnBufferedState(0.0) { 93 | 94 | @Override protected boolean positiveCondition(Double overlap) { 95 | //TODO not sure if Column should directly reference algorithmic classes: Temporal/Spatial Pooler, 96 | //TODO but having TP properties in column as static prop even worse 97 | if(layer.getSpatialPooler() == null){ 98 | throw new RuntimeException("Spatial Pooler should be defined"); 99 | } 100 | return overlap >= layer.getSpatialPooler().getMinimalOverlap(); 101 | } 102 | }; 103 | } 104 | 105 | public void updateOverlap(double currentOverLap) { 106 | overlap.addState(currentOverLap); 107 | } 108 | 109 | 110 | /* 111 | *A Point (srcX,srcY) of this Column's 'center' position in 112 | * terms of the proximal-synapse input space. 113 | **/ 114 | 115 | public Point getInputSpacePosition() { 116 | return this.getOwner().convertColumnPositionToInputSpace(this.getPosition()); 117 | } 118 | 119 | /** 120 | * WP 121 | * Prior to receiving any inputs, the region is initialized by computing a list of initial 122 | * potential synapses for each column. This consists of a random set of inputs selected 123 | * from the input space. Each input is represented by a synapse and assigned a 124 | * random permanence value. The random permanence values are chosen with two 125 | * criteria. First, the values are chosen to be in a small range around connectedPerm 126 | * (the minimum permanence value at which a synapse is considered "connected"). 127 | * This enables potential synapses to become connected (or disconnected) after a 128 | * small number of training iterations. Second, each column has a natural center over 129 | * the input region, and the permanence values have a bias towards this center (they 130 | * have higher values near the center). 131 | * 132 | * @param inputRadius 133 | */ 134 | 135 | public void createProximalSegment(double inputRadius) { 136 | InputSpace sensoryInput = this.getOwner().getInputSpace(); 137 | Point inputSpacePosition = this.getInputSpacePosition(); 138 | List potentialProximalInputs = sensoryInput.getAllWithinRadius(inputSpacePosition, inputRadius); 139 | if (potentialProximalInputs.size() < AMOUNT_OF_PROXIMAL_SYNAPSES) { 140 | throw new IllegalArgumentException("Amount of potential synapses:" + AMOUNT_OF_PROXIMAL_SYNAPSES 141 | + " is bigger than number of inputs:" + potentialProximalInputs.size() + ", increase input radius"); 142 | } 143 | Collections.shuffle(potentialProximalInputs); 144 | // Tie the random seed to this Column's position for reproducibility 145 | inputRadius = inputRadius < 1 ? Math.sqrt(Math.pow(sensoryInput.getDimension().height, 2) + Math.pow( 146 | sensoryInput.getDimension().width, 2)) : inputRadius; 147 | Random randomGenerator = new Random(this.getLocationSeed()); 148 | for (int j = 0; j < AMOUNT_OF_PROXIMAL_SYNAPSES; j++) { 149 | InputSpace.Input input = potentialProximalInputs.get(j); 150 | //Permanence value is based on Gaussian distribution around the ConnectedPerm value, biased by distance from this Column. 151 | double distanceToInputSrc = BaseSpace.getDistance(inputSpacePosition, input.getPosition()), 152 | distanceToInputColumn = BaseSpace.getDistance(this.getOwner().convertInputPositionToColumnSpace( 153 | input.getPosition()), position), 154 | initPermanence = Synapse.ProximalSynapse.PERMANENCE_INCREASE * randomGenerator.nextGaussian() + Synapse.ProximalSynapse.CONNECTED_PERMANENCE, 155 | radiusBiasDeviation = 0.1f, //1.1 to 0.9 -> Y = 1.1 - radiusBiasDeviation / 2inputRadius * X 156 | radiusBiasScale = 1 + radiusBiasDeviation - radiusBiasDeviation / inputRadius * 2 * distanceToInputSrc, 157 | radiusBiasPermanence = initPermanence * radiusBiasScale; 158 | LOG.debug("PERMANENCE INITIALIZATION: init permanence" + initPermanence 159 | + " ,distanceToInputSrc:" + distanceToInputSrc + ", distanceToInputColumn:" + distanceToInputColumn + ", radiusBiasScale:" + radiusBiasScale + " , radiusBiasPermanence:" + radiusBiasPermanence); 160 | proximalSynapses.add(new Synapse.ProximalSynapse(radiusBiasPermanence, input, this)); 161 | } 162 | } 163 | 164 | /** 165 | * WP 166 | * increasePermanence(c, s) 167 | * Increase the permanence value of every synapse in column c by a scale factor s. 168 | * 169 | * @param increaseBy 170 | */ 171 | public void increasePermanence(double increaseBy) { 172 | //List proximalSynapses = this.getPotentialSynapses(); 173 | for (Synapse.ProximalSynapse proximalSynapse : proximalSynapses) { 174 | proximalSynapse.setPermanence(proximalSynapse.getPermanence() + increaseBy); 175 | } 176 | 177 | } 178 | 179 | 180 | /** 181 | * overlap(c) The spatial pooler overlap of column c with a particular 182 | * input pattern. 183 | * 184 | * @return 185 | */ 186 | 187 | public double getOverlap() { 188 | return overlap.getLast(); 189 | } 190 | 191 | /** 192 | * WP 193 | * overlapDutyCycle(c) A sliding average representing how often column c has had 194 | * significant overlap (i.e. greater than minOverlap) with its 195 | * inputs (e.g. over the last 1000 iterations). 196 | * 197 | * @return 198 | */ 199 | 200 | public double getOverlapDutyCycle() { 201 | return overlap.getSlidingAverage(); 202 | } 203 | 204 | public boolean isActive() { 205 | return active.getLast(); 206 | } 207 | 208 | 209 | /** 210 | * Get column active state at time 211 | * 212 | * @param time (t - 0) - current step, (t - 1) - previous step, (t- n) - n step 213 | * @return 214 | */ 215 | public boolean isActive(int time) { 216 | if (time > active.size()) { 217 | throw new IllegalArgumentException("time: " + time + " can't exceed history buffer limit: " + active.size()); 218 | } 219 | return active.get(time); 220 | } 221 | 222 | 223 | public void setActive(boolean active) { 224 | this.active.addState(active); 225 | } 226 | 227 | /** 228 | * WP 229 | * activeDutyCycle(c) A sliding average representing how often column c has 230 | * been active after inhibition (e.g. over the last 1000 iterations). 231 | */ 232 | public double getActiveDutyCycle() { 233 | return active.getSlidingAverage(); 234 | } 235 | 236 | /** 237 | * maxDutyCycle(cols) 238 | * Returns the maximum active duty cycle of the columns in the given list of columns. 239 | * 240 | * @param inhibitionRadius 241 | * @return 242 | */ 243 | public double getMaxDutyCycle(double inhibitionRadius) { 244 | List neighbors = this.getNeighbors(inhibitionRadius); 245 | Collections.sort(neighbors, ACTIVE_DUTY_CYCLE_COMPARATOR); 246 | return neighbors.get(0).getActiveDutyCycle(); 247 | } 248 | 249 | /* 250 | * WP 251 | * The boost value for column c as computed during learning - 252 | * used to increase the overlap value for inactive columns. 253 | */ 254 | public double getBoost() { 255 | return boost; 256 | } 257 | 258 | 259 | /** 260 | * WP 261 | * boostFunction(c) 262 | * Returns the boost value of a column. The boost value is a scalar >= 1. 263 | * If activeDutyCycle(c) is above minDutyCycle(c), the boost value is 1. 264 | * The boost increases linearly once the column's activeDutyCycle starts falling below its minDutyCycle. 265 | * 266 | * @param minDutyCycle 267 | * @return 268 | */ 269 | public void updateBoost(double minDutyCycle, double boostRate) { 270 | if (this.getActiveDutyCycle() > minDutyCycle) { 271 | this.boost = 1.0; 272 | } else { 273 | this.boost += boostRate; 274 | } 275 | } 276 | 277 | /* 278 | * WP 279 | * neighbors(c) A list of all the columns that are within inhibitionRadius of 280 | * column c. 281 | */ 282 | public List getNeighbors(Double inhibitionRadius) { 283 | //to limit cache to 0.1 fraction 284 | Double roundedInhibitionRadius = MathUtils.round(inhibitionRadius, 1); 285 | List result; 286 | result = neighbors_cache.get(roundedInhibitionRadius); 287 | if (result == null) { 288 | result = this.getOwner().getAllWithinRadius(this.getPosition(), roundedInhibitionRadius); 289 | //remove itself 290 | result.remove(result.indexOf(this)); 291 | if (result.size() == 0) { 292 | throw new IllegalArgumentException( 293 | "No neighbors found within inhibitionRadius of: " + inhibitionRadius + ". Please increase receptiveFieldSize by increasing inputRadius for input Space."); 294 | } 295 | neighbors_cache.put(roundedInhibitionRadius, result); 296 | } 297 | return result; 298 | } 299 | 300 | public List getActiveConnectedSynapses() { 301 | return CollectionUtils.filter(proximalSynapses, ACTIVE_CONNECTED_PROXIMAL_SYNAPSES_PREDICATE); 302 | } 303 | 304 | /** 305 | * WP 306 | * connectedSynapses(c) 307 | * A subset of potentialSynapses(c) where the permanence value is greater than connectedPerm. 308 | * These are the bottom-up inputs that are currently connected to column c. 309 | * 310 | * @return 311 | */ 312 | public List getConnectedSynapses() { 313 | return CollectionUtils.filter(proximalSynapses, CONNECTED_PROXIMAL_SYNAPSES_PREDICATE); 314 | } 315 | 316 | /** 317 | * WP 318 | * potentialSynapses(c) 319 | * The list of potential synapses and their permanence values. 320 | * 321 | * @return 322 | */ 323 | public List getPotentialSynapses() { 324 | return Collections.unmodifiableList(proximalSynapses); 325 | } 326 | 327 | 328 | public void nextTimeStep() { 329 | for (Cell cell : this.getElementsList()) { 330 | cell.nextTimeStep(); 331 | } 332 | } 333 | 334 | 335 | private static abstract class ColumnBufferedState extends CircularArrayList { 336 | public ColumnBufferedState(E defValue) { 337 | super(COLUMN_CYCLE_BUFFER_SIZE); 338 | addState(defValue); 339 | } 340 | 341 | /** 342 | * Set the column state 343 | * 344 | * @param value 345 | */ 346 | void addState(E value) { 347 | this.add(0, value); 348 | } 349 | 350 | public E getLast() { 351 | return this.get(0); 352 | } 353 | 354 | public double getSlidingAverage() { 355 | double result; 356 | int length = this.size(), activeCount = 0; 357 | for (int i = 0; i < length; i++) { 358 | if (positiveCondition(get(i))) { 359 | activeCount++; 360 | } 361 | } 362 | result = 1.0 * activeCount / length; 363 | return result; 364 | } 365 | 366 | protected abstract boolean positiveCondition(E state); 367 | } 368 | 369 | public static class Config { 370 | private final int amountOfProximalSynapses; 371 | public Config(int amountOfProximalSynapses) { 372 | this.amountOfProximalSynapses = amountOfProximalSynapses; 373 | } 374 | 375 | public int getAmountOfProximalSynapses() { 376 | return amountOfProximalSynapses; 377 | } 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /src/main/java/htm/utils/UIUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.utils; 10 | 11 | import htm.visualizer.surface.SensoryInputSurface; 12 | import org.apache.commons.logging.Log; 13 | import org.apache.commons.logging.LogFactory; 14 | 15 | import java.awt.*; 16 | import java.awt.font.FontRenderContext; 17 | import java.awt.font.TextLayout; 18 | import java.text.DecimalFormat; 19 | import java.util.Map; 20 | import java.util.Set; 21 | import javax.swing.*; 22 | import javax.swing.border.Border; 23 | import javax.swing.table.DefaultTableCellRenderer; 24 | 25 | public enum UIUtils { 26 | INSTANCE; 27 | public static final DecimalFormat DF_4 = new DecimalFormat("##0.0000"); 28 | public static final DecimalFormat DF_3 = new DecimalFormat("##0.000"); 29 | public static final DecimalFormat DF_2 = new DecimalFormat("##0.00"); 30 | 31 | 32 | private static final Log LOG = LogFactory.getLog(UIUtils.class); 33 | public final static Color LIGHT_BLUE = new Color(153, 204, 255); 34 | 35 | public static final Border DEFAULT_BORDER = BorderFactory.createEmptyBorder(0, 4, 0, 4); 36 | public static final Border LIGHT_GRAY_BORDER = BorderFactory.createLineBorder(Color.lightGray); 37 | private static final Font sanSerifFont = new Font("SanSerif", Font.BOLD, 11); 38 | 39 | private UIUtils() { 40 | } 41 | 42 | public static void drawStatesInCircle(Graphics2D g2d, int x, int y, int width, int height, Color... stateColors) { 43 | int states = stateColors.length; 44 | if (states > 0) { 45 | int startAngle = 0, arcAngle = 360 / states; 46 | for (Color stateColor : stateColors) { 47 | g2d.setColor(stateColor); 48 | g2d.fillArc(x, y, width, height, startAngle, arcAngle); 49 | startAngle = startAngle + arcAngle; 50 | } 51 | } 52 | g2d.setColor(Color.BLACK); 53 | g2d.drawOval(x, y, width, height); 54 | } 55 | 56 | public static void drawTextInCenter(Graphics2D g2d, int x, int y, int width, int height, String predictInStepStr) { 57 | g2d.setFont(sanSerifFont); 58 | g2d.setColor(Color.WHITE); 59 | FontMetrics fm = g2d.getFontMetrics(); 60 | int w = fm.stringWidth(predictInStepStr); 61 | int h = fm.getAscent(); 62 | g2d.drawString(predictInStepStr, x + width/2 - (w / 2) + 2, y + height/2+ (h / 4) + 2); 63 | } 64 | 65 | public ImageIcon createImageIcon(String path) { 66 | java.net.URL imgURL = getClass().getResource(path); 67 | if (imgURL != null) { 68 | return new ImageIcon(imgURL); 69 | } else { 70 | LOG.error("Couldn't find file: " + path); 71 | throw new IllegalArgumentException("Couldn't find file: " + path); 72 | } 73 | } 74 | 75 | /* 76 | * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. 77 | * 78 | * Redistribution and use in source and binary forms, with or without 79 | * modification, are permitted provided that the following conditions 80 | * are met: 81 | * 82 | * - Redistributions of source code must retain the above copyright 83 | * notice, this list of conditions and the following disclaimer. 84 | * 85 | * - Redistributions in binary form must reproduce the above copyright 86 | * notice, this list of conditions and the following disclaimer in the 87 | * documentation and/or other materials provided with the distribution. 88 | * 89 | * - Neither the name of Oracle or the names of its 90 | * contributors may be used to endorse or promote products derived 91 | * from this software without specific prior written permission. 92 | * 93 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 94 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 95 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 96 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 97 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 98 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 99 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 100 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 101 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 102 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 103 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 104 | */ 105 | 106 | /** 107 | * A 1.4 file that provides utility methods for 108 | * creating form- or grid-style layouts with SpringLayout. 109 | * These utilities are used by several programs, such as 110 | * SpringBox and SpringCompactGrid. 111 | */ 112 | 113 | /** 114 | * Aligns the first rows * cols 115 | * components of parent in 116 | * a grid. Each component in a column is as wide as the maximum 117 | * preferred width of the components in that column; 118 | * height is similarly determined for each row. 119 | * The parent is made just big enough to fit them all. 120 | * 121 | * @param rows number of rows 122 | * @param cols number of columns 123 | * @param initialX x location to start the grid at 124 | * @param initialY y location to start the grid at 125 | * @param xPad x padding between cells 126 | * @param yPad y padding between cells 127 | */ 128 | public static void makeSpringCompactGrid(Container parent, 129 | int rows, int cols, 130 | int initialX, int initialY, 131 | int xPad, int yPad) { 132 | SpringLayout layout; 133 | try { 134 | layout = (SpringLayout)parent.getLayout(); 135 | } catch (ClassCastException exc) { 136 | System.err.println("The first argument to makeCompactGrid must use SpringLayout."); 137 | return; 138 | } 139 | 140 | //Align all cells in each column and make them the same width. 141 | Spring x = Spring.constant(initialX); 142 | for (int c = 0; c < cols; c++) { 143 | Spring width = Spring.constant(0); 144 | for (int r = 0; r < rows; r++) { 145 | width = Spring.max(width, 146 | getConstraintsForCell(r, c, parent, cols). 147 | getWidth()); 148 | } 149 | for (int r = 0; r < rows; r++) { 150 | SpringLayout.Constraints constraints = 151 | getConstraintsForCell(r, c, parent, cols); 152 | constraints.setX(x); 153 | constraints.setWidth(width); 154 | } 155 | x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); 156 | } 157 | 158 | //Align all cells in each row and make them the same height. 159 | Spring y = Spring.constant(initialY); 160 | for (int r = 0; r < rows; r++) { 161 | Spring height = Spring.constant(0); 162 | for (int c = 0; c < cols; c++) { 163 | height = Spring.max(height, 164 | getConstraintsForCell(r, c, parent, cols). 165 | getHeight()); 166 | } 167 | for (int c = 0; c < cols; c++) { 168 | SpringLayout.Constraints constraints = 169 | getConstraintsForCell(r, c, parent, cols); 170 | constraints.setY(y); 171 | constraints.setHeight(height); 172 | } 173 | y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); 174 | } 175 | 176 | //Set the parent's size. 177 | SpringLayout.Constraints pCons = layout.getConstraints(parent); 178 | pCons.setConstraint(SpringLayout.SOUTH, y); 179 | pCons.setConstraint(SpringLayout.EAST, x); 180 | } 181 | 182 | /** 183 | * Aligns the first rows * cols 184 | * components of parent in 185 | * a grid. Each component is as big as the maximum 186 | * preferred width and height of the components. 187 | * The parent is made just big enough to fit them all. 188 | * 189 | * @param rows number of rows 190 | * @param cols number of columns 191 | * @param initialX x location to start the grid at 192 | * @param initialY y location to start the grid at 193 | * @param xPad x padding between cells 194 | * @param yPad y padding between cells 195 | */ 196 | public static void makeSpringGrid(Container parent, 197 | int rows, int cols, 198 | int initialX, int initialY, 199 | int xPad, int yPad) { 200 | SpringLayout layout; 201 | try { 202 | layout = (SpringLayout)parent.getLayout(); 203 | } catch (ClassCastException exc) { 204 | System.err.println("The first argument to makeGrid must use SpringLayout."); 205 | return; 206 | } 207 | 208 | Spring xPadSpring = Spring.constant(xPad); 209 | Spring yPadSpring = Spring.constant(yPad); 210 | Spring initialXSpring = Spring.constant(initialX); 211 | Spring initialYSpring = Spring.constant(initialY); 212 | int max = rows * cols; 213 | 214 | //Calculate Springs that are the max of the width/height so that all 215 | //cells have the same size. 216 | Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)). 217 | getWidth(); 218 | Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)). 219 | getHeight(); 220 | for (int i = 1; i < max; i++) { 221 | SpringLayout.Constraints cons = layout.getConstraints( 222 | parent.getComponent(i)); 223 | 224 | maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); 225 | maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); 226 | } 227 | 228 | //Apply the new width/height Spring. This forces all the 229 | //components to have the same size. 230 | for (int i = 0; i < max; i++) { 231 | SpringLayout.Constraints cons = layout.getConstraints( 232 | parent.getComponent(i)); 233 | 234 | cons.setWidth(maxWidthSpring); 235 | cons.setHeight(maxHeightSpring); 236 | } 237 | 238 | //Then adjust the x/y constraints of all the cells so that they 239 | //are aligned in a grid. 240 | SpringLayout.Constraints lastCons = null; 241 | SpringLayout.Constraints lastRowCons = null; 242 | for (int i = 0; i < max; i++) { 243 | SpringLayout.Constraints cons = layout.getConstraints( 244 | parent.getComponent(i)); 245 | if (i % cols == 0) { //start of new row 246 | lastRowCons = lastCons; 247 | cons.setX(initialXSpring); 248 | } else { //x position depends on previous component 249 | cons.setX(Spring.sum(lastCons != null ? lastCons.getConstraint(SpringLayout.EAST) : null, 250 | xPadSpring)); 251 | } 252 | 253 | if (i / cols == 0) { //first row 254 | cons.setY(initialYSpring); 255 | } else { //y position depends on previous row 256 | assert lastRowCons != null; 257 | cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH), 258 | yPadSpring)); 259 | } 260 | lastCons = cons; 261 | } 262 | 263 | //Set the parent's size. 264 | SpringLayout.Constraints pCons = layout.getConstraints(parent); 265 | assert lastCons != null; 266 | pCons.setConstraint(SpringLayout.SOUTH, 267 | Spring.sum( 268 | Spring.constant(yPad), 269 | lastCons.getConstraint(SpringLayout.SOUTH))); 270 | pCons.setConstraint(SpringLayout.EAST, 271 | Spring.sum( 272 | Spring.constant(xPad), 273 | lastCons.getConstraint(SpringLayout.EAST))); 274 | } 275 | 276 | /* Used by makeCompactGrid. */ 277 | private static SpringLayout.Constraints getConstraintsForCell( 278 | int row, int col, 279 | Container parent, 280 | int cols) { 281 | SpringLayout layout = (SpringLayout)parent.getLayout(); 282 | Component c = parent.getComponent(row * cols + col); 283 | return layout.getConstraints(c); 284 | } 285 | 286 | public static abstract class TextColumnInfo extends JPanel { 287 | protected float finishParagraphY; 288 | protected int startX = 100; 289 | 290 | public TextColumnInfo() { 291 | setBackground(Color.WHITE); 292 | } 293 | 294 | @Override 295 | public void paint(Graphics g) { 296 | super.paint(g); 297 | Graphics2D graphics2D = (Graphics2D)g; 298 | Map cellAttributes = getAttributeMap(); 299 | finishParagraphY = drawPropertyParagraph(graphics2D, cellAttributes, startX , 5, 20); 300 | } 301 | 302 | 303 | abstract protected Map getAttributeMap(); 304 | 305 | protected float drawPropertyParagraph(Graphics2D g2, Map properties, float width, float x, 306 | float y) { 307 | FontRenderContext frc = g2.getFontRenderContext(); 308 | float drawPosY = y; 309 | Font nameFont = new Font("Helvetica", Font.BOLD, 12); 310 | Font valueFont = new Font("Helvetica", Font.PLAIN, 12); 311 | Set names = properties.keySet(); 312 | for (String name : names) { 313 | String value = properties.get(name); 314 | TextLayout nameLayout = new TextLayout(name + ":", nameFont, frc); 315 | TextLayout valueLayout = new TextLayout(value, valueFont, frc); 316 | // Set position to the index of the first character in the paragraph. 317 | float drawPosX; 318 | drawPosX = x + width - nameLayout.getAdvance(); 319 | // Move y-coordinate by the ascent of the layout. 320 | drawPosY += nameLayout.getAscent(); 321 | // Draw the TextLayout at (drawPosX, drawPosY). 322 | nameLayout.draw(g2, drawPosX, drawPosY); 323 | double newX = x + width + 4; 324 | valueLayout.draw(g2, (float)newX, drawPosY); 325 | // Move y-coordinate in preparation for next layout. 326 | drawPosY += nameLayout.getDescent() + nameLayout.getLeading(); 327 | } 328 | return drawPosY; 329 | } 330 | 331 | } 332 | 333 | public static class SortablePoint extends Point implements Comparable { 334 | public SortablePoint(Point p) { 335 | super(p); 336 | } 337 | 338 | @Override 339 | public int compareTo(SortablePoint point) { 340 | return this.getSquare() - point.getSquare(); 341 | } 342 | 343 | int getSquare() { 344 | return (int)(Math.pow(x, 2) + Math.pow(y, 2)); 345 | } 346 | } 347 | 348 | public static class SmallDoubleRenderer extends DefaultTableCellRenderer { 349 | { 350 | this.setHorizontalAlignment(SwingConstants.RIGHT); 351 | } 352 | 353 | @Override protected void setValue(Object value) { 354 | super.setValue(DF_2.format(value)); 355 | } 356 | } 357 | 358 | public static class PositionRenderer extends DefaultTableCellRenderer { 359 | { 360 | this.setHorizontalAlignment(SwingConstants.CENTER); 361 | } 362 | 363 | @Override protected void setValue(Object value) { 364 | Point point = (Point)value; 365 | super.setValue("X:" + (point.x) + ", Y:" + point.y); 366 | } 367 | } 368 | 369 | 370 | 371 | public static class PermanenceRenderer extends DefaultTableCellRenderer { 372 | private double permanence = 0; 373 | 374 | { // initializer block 375 | this.setHorizontalAlignment(SwingConstants.RIGHT); 376 | } 377 | /* public PermanenceRenderer() { 378 | this.setHorizontalAlignment(SwingConstants.CENTER); 379 | }*/ 380 | 381 | @Override public void paint(Graphics g) { 382 | super.paint(g); 383 | Dimension size = this.getSize(); 384 | Rectangle insideRec = new Rectangle(2, 2, size.height - 4, size.height - 4); 385 | Graphics2D g2d = (Graphics2D)g; 386 | SensoryInputSurface.renderSynapse(g2d, permanence, insideRec); 387 | g2d.setColor(Color.BLACK); 388 | //g2d.drawString(DF_4.format(permanence) + "", size.height + 4, 12); 389 | } 390 | 391 | @Override 392 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 393 | int row, int column) { 394 | this.permanence = (Double)value; 395 | return super.getTableCellRendererComponent(table, DF_3.format(value), isSelected, hasFocus, row, 396 | column); 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /src/main/java/htm/visualizer/Parameters.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, Peace Technology, Inc. 3 | * $Author:$ 4 | * $Revision:$ 5 | * $Date:$ 6 | * $NoKeywords$ 7 | */ 8 | 9 | package htm.visualizer; 10 | 11 | import htm.model.Cell; 12 | import htm.model.Column; 13 | import htm.model.Layer; 14 | import htm.model.Synapse; 15 | import htm.model.algorithms.spatial.SpatialPooler; 16 | import htm.model.algorithms.temporal.TemporalPooler; 17 | import htm.utils.MathUtils; 18 | import htm.utils.UIUtils; 19 | 20 | import java.awt.*; 21 | import java.util.Hashtable; 22 | import javax.swing.*; 23 | import javax.swing.event.ChangeEvent; 24 | import javax.swing.event.ChangeListener; 25 | 26 | public class Parameters { 27 | 28 | static class FixedWidthLabel extends JLabel { 29 | @Override public Dimension getPreferredSize() { 30 | return new Dimension(135, super.getPreferredSize().height); 31 | } 32 | 33 | FixedWidthLabel(String text) { 34 | super(text); 35 | } 36 | } 37 | 38 | static abstract class NumberParameter extends Container implements ChangeListener { 39 | protected static final int SLIDER_SCALE = 100; 40 | protected final int sliderScale; 41 | 42 | protected JSpinner spinnerField; 43 | protected JSlider sliderField; 44 | 45 | NumberParameter(E minValue, E maxValue, E value) { 46 | this(minValue, maxValue, value, SLIDER_SCALE); 47 | } 48 | 49 | NumberParameter(E minValue, E maxValue, E value, int sliderScale) { 50 | this.sliderScale = sliderScale; 51 | setLayout(new GridBagLayout()); 52 | initFields(minValue, maxValue, value); 53 | spinnerField.setPreferredSize(new Dimension(60, 30)); 54 | GridBagConstraints c = new GridBagConstraints(); 55 | c.fill = GridBagConstraints.HORIZONTAL; 56 | c.weighty = 1.0; 57 | c.weightx = 3; 58 | this.add(sliderField, c); 59 | c.weightx = 1; 60 | this.add(spinnerField, c); 61 | spinnerField.addChangeListener(this); 62 | sliderField.addChangeListener(this); 63 | } 64 | 65 | public void setValue(E value) { 66 | if (sliderField.getValue() != value.intValue()) { 67 | setSliderValue(value); 68 | } 69 | if (spinnerField.getValue() != value) { 70 | spinnerField.setValue(value); 71 | } 72 | } 73 | 74 | 75 | @SuppressWarnings("unchecked") public E getValue() { 76 | return (E)spinnerField.getValue(); 77 | } 78 | 79 | @SuppressWarnings("unchecked") @Override public void stateChanged(ChangeEvent e) { 80 | if (e.getSource() instanceof JSlider) { 81 | setValue(getSliderValue()); 82 | } else if (e.getSource() instanceof JSpinner) { 83 | setValue((E)spinnerField.getValue()); 84 | } 85 | } 86 | 87 | abstract protected void initFields(E minValue, E maxValue, E value); 88 | 89 | abstract protected E getSliderValue(); 90 | 91 | abstract protected void setSliderValue(E value); 92 | } 93 | 94 | static class IntegerParameter extends NumberParameter { 95 | 96 | IntegerParameter(Integer minValue, Integer maxValue, Integer value) { 97 | super(minValue, maxValue, value); 98 | } 99 | 100 | @Override protected void initFields(Integer minValue, Integer maxValue, Integer value) { 101 | spinnerField = new JSpinner( 102 | new SpinnerNumberModel(value.intValue(), minValue.intValue(), maxValue.intValue(), 1)); 103 | sliderField = new JSlider(JSlider.HORIZONTAL, minValue, maxValue, value); 104 | sliderField.setPaintLabels(true); 105 | Hashtable labelTable = new Hashtable(); 106 | labelTable.put(minValue, new JLabel(minValue + "")); 107 | labelTable.put((maxValue - Math.abs(minValue)) / 2, new JLabel((maxValue - Math.abs(minValue)) / 2 + "")); 108 | labelTable.put(maxValue, new JLabel(maxValue + "")); 109 | sliderField.setLabelTable(labelTable); 110 | } 111 | 112 | @Override protected Integer getSliderValue() { 113 | return sliderField.getValue(); 114 | } 115 | 116 | @Override protected void setSliderValue(Integer value) { 117 | sliderField.setValue(value); 118 | } 119 | } 120 | 121 | static class DoubleParameter extends NumberParameter { 122 | 123 | DoubleParameter(Double minValue, Double maxValue, Double value, int sliderScale) { 124 | super(minValue, maxValue, value, sliderScale); 125 | } 126 | 127 | DoubleParameter(Double minValue, Double maxValue, Double value) { 128 | super(minValue, maxValue, value); 129 | } 130 | 131 | @Override public void setValue(Double value) { 132 | Double valueConverted = MathUtils.round(value, 3); 133 | Double sliderValueConverted = MathUtils.round(1.0 * sliderField.getValue() / sliderScale, 3); 134 | Double spinnerValueConverted = MathUtils.round((Double)spinnerField.getValue(), 3); 135 | if (sliderValueConverted.doubleValue() != value) { 136 | setSliderValue(valueConverted); 137 | } 138 | if (spinnerValueConverted.doubleValue() != value) { 139 | spinnerField.setValue(valueConverted); 140 | } 141 | } 142 | 143 | @Override protected void initFields(Double minValue, Double maxValue, Double value) { 144 | int sliderMin = (int)(minValue * sliderScale), 145 | sliderMax = (int)(maxValue * sliderScale), 146 | sliderValue = (int)(value * sliderScale); 147 | spinnerField = new JSpinner( 148 | new SpinnerNumberModel(value, minValue, maxValue, new Double((maxValue - minValue) / sliderScale))); 149 | sliderField = new JSlider(JSlider.HORIZONTAL, sliderMin, sliderMax, 150 | sliderValue); 151 | sliderField.setPaintLabels(true); 152 | Hashtable labelTable = new Hashtable(); 153 | labelTable.put(sliderMin, new JLabel(minValue + "")); 154 | labelTable.put((sliderMax - Math.abs(sliderMin)) / 2, new JLabel((maxValue - Math.abs(minValue)) / 2 + "")); 155 | labelTable.put(sliderMax, new JLabel(maxValue + "")); 156 | sliderField.setLabelTable(labelTable); 157 | } 158 | 159 | @Override protected Double getSliderValue() { 160 | return 1.0 * sliderField.getValue() / sliderScale; 161 | } 162 | 163 | @Override protected void setSliderValue(Double value) { 164 | sliderField.setValue((int)(value * sliderScale)); 165 | } 166 | 167 | } 168 | 169 | static class RegionParameters extends JPanel { 170 | private final Parameters.IntegerParameter regionWidthParam; 171 | private final Parameters.IntegerParameter regionHeightParam; 172 | private final Parameters.IntegerParameter inputSpaceWidthParam; 173 | private final Parameters.IntegerParameter inputSpaceHeightParam; 174 | private final DoubleParameter learningRadiusParam; 175 | private final DoubleParameter inputRadiusParam; 176 | private final Parameters.IntegerParameter cellsInColumnParam; 177 | private final JCheckBox skipSpatialCb; 178 | 179 | RegionParameters(Layer.Config cfg) { 180 | setLayout(new SpringLayout()); 181 | regionWidthParam = new IntegerParameter(1, 50, cfg.getRegionDimension().width); 182 | regionHeightParam = new IntegerParameter(1, 50, cfg.getRegionDimension().height); 183 | inputSpaceWidthParam = new IntegerParameter(1, 50, cfg.getSensoryInputDimension().width); 184 | inputSpaceHeightParam = new IntegerParameter(1, 50, cfg.getSensoryInputDimension().height); 185 | learningRadiusParam = new DoubleParameter(1.0, 50.0, cfg.getLearningRadius(), 200); 186 | inputRadiusParam = new DoubleParameter(1.0, 25.0, cfg.getInputRadius(), 200); 187 | cellsInColumnParam = new IntegerParameter(1, 20, cfg.getCellsInColumn()); 188 | skipSpatialCb = new JCheckBox(null, null, cfg.isSkipSpatial()); 189 | JLabel l = new FixedWidthLabel("Region Width"); 190 | this.add(l); 191 | this.add(regionWidthParam); 192 | l = new FixedWidthLabel("Region Height"); 193 | this.add(l); 194 | this.add(regionHeightParam); 195 | l = new FixedWidthLabel("Input Space Width"); 196 | this.add(l); 197 | this.add(inputSpaceWidthParam); 198 | l = new FixedWidthLabel("Input Space Height"); 199 | this.add(l); 200 | this.add(inputSpaceHeightParam); 201 | l = new FixedWidthLabel("Input Radius"); 202 | this.add(l); 203 | this.add(inputRadiusParam); 204 | l = new FixedWidthLabel("Learning Radius"); 205 | this.add(l); 206 | this.add(learningRadiusParam); 207 | l = new FixedWidthLabel("Cells per Column"); 208 | this.add(l); 209 | this.add(cellsInColumnParam); 210 | l = new FixedWidthLabel("Skip Spatial"); 211 | this.add(l); 212 | this.add(skipSpatialCb); 213 | UIUtils.makeSpringCompactGrid(this, 214 | 8, 2, //rows, cols 215 | 6, 6, //initX, initY 216 | 6, 6); //xPad, yPad 217 | } 218 | 219 | Layer.Config getParameters() { 220 | return new Layer.Config(new Dimension(regionWidthParam.getValue(), 221 | regionHeightParam.getValue()), 222 | new Dimension(inputSpaceWidthParam.getValue(), 223 | inputSpaceHeightParam.getValue()), 224 | inputRadiusParam.getValue(), 225 | learningRadiusParam.getValue(), 226 | skipSpatialCb.isSelected(), 227 | cellsInColumnParam.getValue()); 228 | } 229 | 230 | void setParameters(Layer.Config cfg) { 231 | regionWidthParam.setValue(cfg.getRegionDimension().width); 232 | regionHeightParam.setValue(cfg.getRegionDimension().height); 233 | inputSpaceWidthParam.setValue(cfg.getSensoryInputDimension().width); 234 | inputSpaceHeightParam.setValue(cfg.getSensoryInputDimension().height); 235 | inputRadiusParam.setValue(cfg.getInputRadius()); 236 | learningRadiusParam.setValue(cfg.getLearningRadius()); 237 | skipSpatialCb.setSelected(cfg.isSkipSpatial()); 238 | } 239 | } 240 | 241 | static class SpatialPoolerParameters extends JPanel { 242 | private final Parameters.IntegerParameter minOverlapParam; 243 | private final Parameters.IntegerParameter desiredLocalActivityParam; 244 | private final Parameters.DoubleParameter boostRateParam; 245 | 246 | SpatialPoolerParameters(SpatialPooler.Config cfg) { 247 | minOverlapParam = new IntegerParameter(1, 10, cfg.getMinOverlap()); 248 | desiredLocalActivityParam = new IntegerParameter(1, 10, cfg.getDesiredLocalActivity()); 249 | boostRateParam = new Parameters.DoubleParameter(0.005, 0.2, cfg.getBoostRate(), 200); 250 | setLayout(new SpringLayout()); 251 | JLabel l = new FixedWidthLabel("Min Overlap"); 252 | this.add(l); 253 | this.add(minOverlapParam); 254 | l = new FixedWidthLabel("Desired Local Activity"); 255 | this.add(l); 256 | this.add(desiredLocalActivityParam); 257 | l = new FixedWidthLabel("Boost Rate"); 258 | this.add(l); 259 | this.add(boostRateParam); 260 | UIUtils.makeSpringCompactGrid(this, 261 | 3, 2, //rows, cols 262 | 6, 6, //initX, initY 263 | 6, 6); //xPad, yPad 264 | } 265 | 266 | SpatialPooler.Config getParameters() { 267 | return new SpatialPooler.Config(minOverlapParam.getValue(), 268 | desiredLocalActivityParam.getValue(), 269 | boostRateParam.getValue()); 270 | } 271 | 272 | void setParameters(SpatialPooler.Config cfg) { 273 | minOverlapParam.setValue(cfg.getMinOverlap()); 274 | desiredLocalActivityParam.setValue(cfg.getDesiredLocalActivity()); 275 | boostRateParam.setValue(cfg.getBoostRate()); 276 | } 277 | } 278 | 279 | static class ColumnParameters extends JPanel { 280 | private final Parameters.IntegerParameter amountOfProximalSynapsesParam; 281 | 282 | 283 | ColumnParameters(Column.Config cfg) { 284 | setLayout(new SpringLayout()); 285 | amountOfProximalSynapsesParam = new IntegerParameter(2, 60, cfg.getAmountOfProximalSynapses()); 286 | JLabel l = new FixedWidthLabel("N of Proximal Synapses"); 287 | this.add(l); 288 | this.add(amountOfProximalSynapsesParam); 289 | UIUtils.makeSpringCompactGrid(this, 290 | 1, 2, //rows, cols 291 | 6, 6, //initX, initY 292 | 6, 6); //xPad, yPad 293 | } 294 | 295 | Column.Config getParameters() { 296 | return new Column.Config(amountOfProximalSynapsesParam.getValue()); 297 | } 298 | 299 | void setParameters(Column.Config cfg) { 300 | amountOfProximalSynapsesParam.setValue(cfg.getAmountOfProximalSynapses()); 301 | } 302 | } 303 | 304 | static class TemporalPoolerParameters extends JPanel { 305 | private final Parameters.IntegerParameter newSynapseCountParam; 306 | private final Parameters.IntegerParameter activationThresholdParam; 307 | private final Parameters.IntegerParameter minThresholdParam; 308 | 309 | TemporalPoolerParameters(TemporalPooler.Config temporalPoolerCfg) { 310 | setLayout(new SpringLayout()); 311 | newSynapseCountParam = new IntegerParameter(1, 10, temporalPoolerCfg.getNewSynapseCount()); 312 | activationThresholdParam = new IntegerParameter(0, 15, temporalPoolerCfg.getActivationThreshold()); 313 | minThresholdParam = new IntegerParameter(0, 5, temporalPoolerCfg.getMinThreshold()); 314 | JLabel l = new FixedWidthLabel("N of New Synapses"); 315 | this.add(l); 316 | this.add(newSynapseCountParam); 317 | l = new FixedWidthLabel("Activation Threshold"); 318 | this.add(l); 319 | this.add(activationThresholdParam); 320 | l = new FixedWidthLabel("Minimum Threshold"); 321 | this.add(l); 322 | this.add(minThresholdParam); 323 | UIUtils.makeSpringCompactGrid(this, 324 | 3, 2, //rows, cols 325 | 6, 6, //initX, initY 326 | 6, 6); //xPad, yPad 327 | } 328 | 329 | 330 | TemporalPooler.Config getParameters() { 331 | return new TemporalPooler.Config(newSynapseCountParam.getValue(), 332 | activationThresholdParam.getValue(), 333 | minThresholdParam.getValue()); 334 | } 335 | 336 | void setParameters(TemporalPooler.Config temporalPoolerCfg) { 337 | newSynapseCountParam.setValue(temporalPoolerCfg.getNewSynapseCount()); 338 | activationThresholdParam.setValue(temporalPoolerCfg.getActivationThreshold()); 339 | minThresholdParam.setValue(temporalPoolerCfg.getMinThreshold()); 340 | } 341 | } 342 | 343 | static class CellParameters extends JPanel { 344 | 345 | private final Parameters.IntegerParameter amountOfSynapsesParam; 346 | private final Parameters.IntegerParameter timeStepsParam; 347 | 348 | CellParameters(Cell.Config cellCfg) { 349 | setLayout(new SpringLayout()); 350 | amountOfSynapsesParam = new IntegerParameter(5, 60, cellCfg.getAmountOfSynapses()); 351 | timeStepsParam = new IntegerParameter(2, 30, cellCfg.getTimeSteps()); 352 | JLabel l = new FixedWidthLabel("Amount of Synapses"); 353 | this.add(l); 354 | this.add(amountOfSynapsesParam); 355 | l = new FixedWidthLabel("Time Buffer"); 356 | this.add(l); 357 | this.add(timeStepsParam); 358 | UIUtils.makeSpringCompactGrid(this, 359 | 2, 2, //rows, cols 360 | 6, 6, //initX, initY 361 | 6, 6); //xPad, yPad 362 | } 363 | 364 | Cell.Config getParameters() { 365 | return new Cell.Config(amountOfSynapsesParam.getValue(), 366 | timeStepsParam.getValue()); 367 | } 368 | 369 | 370 | void setParameters(Cell.Config cfg) { 371 | amountOfSynapsesParam.setValue(cfg.getAmountOfSynapses()); 372 | timeStepsParam.setValue(cfg.getTimeSteps()); 373 | } 374 | } 375 | 376 | 377 | static class SynapseParameters extends JPanel { 378 | private final Parameters.DoubleParameter connectedPermanenceParam; 379 | private final Parameters.DoubleParameter incPermanenceParam; 380 | private final Parameters.DoubleParameter decPermanenceParam; 381 | 382 | SynapseParameters(Synapse.Config cfg) { 383 | setLayout(new SpringLayout()); 384 | connectedPermanenceParam = new Parameters.DoubleParameter(0.0, 1.0, cfg.getConnectedPerm()); 385 | incPermanenceParam = new Parameters.DoubleParameter(0.005, 0.2, cfg.getPermanenceInc(), 200); 386 | decPermanenceParam = new Parameters.DoubleParameter(0.005, 0.2, cfg.getPermanenceDec(), 200); 387 | JLabel l = new FixedWidthLabel("Conn.Permanence"); 388 | this.add(l); 389 | this.add(connectedPermanenceParam); 390 | l = new FixedWidthLabel("Increase By"); 391 | this.add(l); 392 | this.add(incPermanenceParam); 393 | l = new FixedWidthLabel("Decrease By"); 394 | this.add(l); 395 | this.add(decPermanenceParam); 396 | UIUtils.makeSpringCompactGrid(this, 397 | 3, 2, //rows, cols 398 | 6, 6, //initX, initY 399 | 6, 6); //xPad, yPad 400 | } 401 | 402 | Synapse.Config getParameters() { 403 | return new Synapse.Config(connectedPermanenceParam.getValue(), incPermanenceParam.getValue(), 404 | decPermanenceParam.getValue()); 405 | } 406 | 407 | void setParameters(Synapse.Config cfg) { 408 | connectedPermanenceParam.setValue(cfg.getConnectedPerm()); 409 | incPermanenceParam.setValue(cfg.getPermanenceInc()); 410 | decPermanenceParam.setValue(cfg.getPermanenceDec()); 411 | } 412 | 413 | 414 | } 415 | 416 | 417 | } 418 | --------------------------------------------------------------------------------