package org.numenta.nupic.algorithms; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; import org.numenta.nupic.Parameters; import org.numenta.nupic.Parameters.KEY; import org.numenta.nupic.model.Cell; import org.numenta.nupic.model.Column; import org.numenta.nupic.model.ComputeCycle; import org.numenta.nupic.model.Connections; import org.numenta.nupic.model.DistalDendrite; import org.numenta.nupic.model.Synapse; import org.numenta.nupic.util.UniversalRandom; import org.nustaq.serialization.FSTConfiguration; public class TemporalMemoryTest { private Parameters getDefaultParameters() { Parameters retVal = Parameters.getTemporalDefaultParameters(); retVal.set(KEY.COLUMN_DIMENSIONS, new int[] { 32 }); retVal.set(KEY.CELLS_PER_COLUMN, 4); retVal.set(KEY.ACTIVATION_THRESHOLD, 3); retVal.set(KEY.INITIAL_PERMANENCE, 0.21); retVal.set(KEY.CONNECTED_PERMANENCE, 0.5); retVal.set(KEY.MIN_THRESHOLD, 2); retVal.set(KEY.MAX_NEW_SYNAPSE_COUNT, 3); retVal.set(KEY.PERMANENCE_INCREMENT, 0.10); retVal.set(KEY.PERMANENCE_DECREMENT, 0.10); retVal.set(KEY.PREDICTED_SEGMENT_DECREMENT, 0.0); retVal.set(KEY.RANDOM, new UniversalRandom(42)); retVal.set(KEY.SEED, 42); return retVal; } private Parameters getDefaultParameters(Parameters p, KEY key, Object value) { Parameters retVal = p == null ? getDefaultParameters() : p; retVal.set(key, value); return retVal; } @SuppressWarnings("unchecked") private <T> T deepCopyPlain(T t) { FSTConfiguration fastSerialConfig = FSTConfiguration.createDefaultConfiguration(); byte[] bytes = fastSerialConfig.asByteArray(t); return (T)fastSerialConfig.asObject(bytes); } @Test public void testActivateCorrectlyPredictiveCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell cell4 = cn.getCell(4); Set<Cell> expectedActiveCells = Stream.of(cell4).collect(Collectors.toSet()); DistalDendrite activeSegment = cn.createSegment(cell4); cn.createSynapse(activeSegment, cn.getCell(0), 0.5); cn.createSynapse(activeSegment, cn.getCell(1), 0.5); cn.createSynapse(activeSegment, cn.getCell(2), 0.5); cn.createSynapse(activeSegment, cn.getCell(3), 0.5); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertTrue(cc.predictiveCells().equals(expectedActiveCells)); ComputeCycle cc2 = tm.compute(cn, activeColumns, true); assertTrue(cc2.activeCells().equals(expectedActiveCells)); } @Test public void testBurstUnpredictedColumns() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); int[] activeColumns = { 0 }; Set<Cell> burstingCells = cn.getCellSet(new int[] { 0, 1, 2, 3 }); ComputeCycle cc = tm.compute(cn, activeColumns, true); assertTrue(cc.activeCells().equals(burstingCells)); } @Test public void testZeroActiveColumns() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; Cell cell4 = cn.getCell(4); DistalDendrite activeSegment = cn.createSegment(cell4); cn.createSynapse(activeSegment, cn.getCell(0), 0.5); cn.createSynapse(activeSegment, cn.getCell(1), 0.5); cn.createSynapse(activeSegment, cn.getCell(2), 0.5); cn.createSynapse(activeSegment, cn.getCell(3), 0.5); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertFalse(cc.activeCells().size() == 0); assertFalse(cc.winnerCells().size() == 0); assertFalse(cc.predictiveCells().size() == 0); int[] zeroColumns = new int[0]; ComputeCycle cc2 = tm.compute(cn, zeroColumns, true); assertTrue(cc2.activeCells().size() == 0); assertTrue(cc2.winnerCells().size() == 0); assertTrue(cc2.predictiveCells().size() == 0); } @Test public void testPredictedActiveCellsAreAlwaysWinners() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell[] previousActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; List<Cell> expectedWinnerCells = new ArrayList<>(cn.getCellSet(new int[] { 4, 6 })); DistalDendrite activeSegment1 = cn.createSegment(expectedWinnerCells.get(0)); cn.createSynapse(activeSegment1, previousActiveCells[0], 0.5); cn.createSynapse(activeSegment1, previousActiveCells[1], 0.5); cn.createSynapse(activeSegment1, previousActiveCells[2], 0.5); DistalDendrite activeSegment2 = cn.createSegment(expectedWinnerCells.get(1)); cn.createSynapse(activeSegment2, previousActiveCells[0], 0.5); cn.createSynapse(activeSegment2, previousActiveCells[1], 0.5); cn.createSynapse(activeSegment2, previousActiveCells[2], 0.5); ComputeCycle cc = tm.compute(cn, previousActiveColumns, false); // learn=false cc = tm.compute(cn, activeColumns, false); // learn=false assertTrue(cc.winnerCells.equals(new LinkedHashSet<Cell>(expectedWinnerCells))); } @Test public void testReinforcedCorrectlyActiveSegments() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.INITIAL_PERMANENCE, 0.2); p = getDefaultParameters(p, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PERMANENCE_DECREMENT, 0.08); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell[] previousActiveCells = {cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; Cell activeCell = cn.getCell(5); DistalDendrite activeSegment = cn.createSegment(activeCell); Synapse as1 = cn.createSynapse(activeSegment, previousActiveCells[0], 0.5); Synapse as2 = cn.createSynapse(activeSegment, previousActiveCells[1], 0.5); Synapse as3 = cn.createSynapse(activeSegment, previousActiveCells[2], 0.5); Synapse is1 = cn.createSynapse(activeSegment, cn.getCell(81), 0.5); tm.compute(cn, previousActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0.6, as1.getPermanence(), 0.1); assertEquals(0.6, as2.getPermanence(), 0.1); assertEquals(0.6, as3.getPermanence(), 0.1); assertEquals(0.42, is1.getPermanence(), 0.001); } @Test public void testReinforcedSelectedMatchingSegmentInBurstingColumn() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.PERMANENCE_DECREMENT, 0.08); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell[] previousActiveCells = {cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; Cell[] burstingCells = {cn.getCell(4), cn.getCell(5) }; DistalDendrite activeSegment = cn.createSegment(burstingCells[0]); Synapse as1 = cn.createSynapse(activeSegment, previousActiveCells[0], 0.3); Synapse as2 = cn.createSynapse(activeSegment, previousActiveCells[0], 0.3); Synapse as3 = cn.createSynapse(activeSegment, previousActiveCells[0], 0.3); Synapse is1 = cn.createSynapse(activeSegment, cn.getCell(81), 0.3); DistalDendrite otherMatchingSegment = cn.createSegment(burstingCells[1]); cn.createSynapse(otherMatchingSegment, previousActiveCells[0], 0.3); cn.createSynapse(otherMatchingSegment, previousActiveCells[1], 0.3); cn.createSynapse(otherMatchingSegment, cn.getCell(81), 0.3); tm.compute(cn, previousActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0.4, as1.getPermanence(), 0.01); assertEquals(0.4, as2.getPermanence(), 0.01); assertEquals(0.4, as3.getPermanence(), 0.01); assertEquals(0.22, is1.getPermanence(), 0.001); } @Test public void testNoChangeToNonSelectedMatchingSegmentsInBurstingColumn() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.PERMANENCE_DECREMENT, 0.08); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell[] previousActiveCells = {cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; Cell[] burstingCells = {cn.getCell(4), cn.getCell(5) }; DistalDendrite selectedMatchingSegment = cn.createSegment(burstingCells[0]); cn.createSynapse(selectedMatchingSegment, previousActiveCells[0], 0.3); cn.createSynapse(selectedMatchingSegment, previousActiveCells[1], 0.3); cn.createSynapse(selectedMatchingSegment, previousActiveCells[2], 0.3); cn.createSynapse(selectedMatchingSegment, cn.getCell(81), 0.3); DistalDendrite otherMatchingSegment = cn.createSegment(burstingCells[1]); Synapse as1 = cn.createSynapse(otherMatchingSegment, previousActiveCells[0], 0.3); Synapse as2 = cn.createSynapse(otherMatchingSegment, previousActiveCells[1], 0.3); Synapse is1 = cn.createSynapse(otherMatchingSegment, cn.getCell(81), 0.3); tm.compute(cn, previousActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0.3, as1.getPermanence(), 0.01); assertEquals(0.3, as2.getPermanence(), 0.01); assertEquals(0.3, is1.getPermanence(), 0.01); } @Test public void testNoChangeToMatchingSegmentsInPredictedActiveColumn() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; int[] activeColumns = { 1 }; Cell[] previousActiveCells = {cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; Cell expectedActiveCell = cn.getCell(4); Set<Cell> expectedActiveCells = Stream.of(expectedActiveCell).collect(Collectors.toCollection(LinkedHashSet<Cell>::new)); Cell otherBurstingCell = cn.getCell(5); DistalDendrite activeSegment = cn.createSegment(expectedActiveCell); cn.createSynapse(activeSegment, previousActiveCells[0], 0.5); cn.createSynapse(activeSegment, previousActiveCells[1], 0.5); cn.createSynapse(activeSegment, previousActiveCells[2], 0.5); cn.createSynapse(activeSegment, previousActiveCells[3], 0.5); DistalDendrite matchingSegmentOnSameCell = cn.createSegment(expectedActiveCell); Synapse s1 = cn.createSynapse(matchingSegmentOnSameCell, previousActiveCells[0], 0.3); Synapse s2 = cn.createSynapse(matchingSegmentOnSameCell, previousActiveCells[1], 0.3); DistalDendrite matchingSegmentOnOtherCell = cn.createSegment(otherBurstingCell); Synapse s3 = cn.createSynapse(matchingSegmentOnOtherCell, previousActiveCells[0], 0.3); Synapse s4 = cn.createSynapse(matchingSegmentOnOtherCell, previousActiveCells[1], 0.3); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertTrue(cc.predictiveCells().equals(expectedActiveCells)); tm.compute(cn, activeColumns, true); assertEquals(0.3, s1.getPermanence(), 0.01); assertEquals(0.3, s2.getPermanence(), 0.01); assertEquals(0.3, s3.getPermanence(), 0.01); assertEquals(0.3, s4.getPermanence(), 0.01); } @Test public void testNoNewSegmentIfNotEnoughWinnerCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 3); p.apply(cn); TemporalMemory.init(cn); int[] zeroColumns = {}; int[] activeColumns = { 0 }; tm.compute(cn, zeroColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0, cn.numSegments(), 0); } @Test public void testNewSegmentAddSynapsesToSubsetOfWinnerCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 2); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0, 1, 2 }; int[] activeColumns = { 4 }; ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); Set<Cell> prevWinnerCells = cc.winnerCells(); assertEquals(3, prevWinnerCells.size()); cc = tm.compute(cn, activeColumns, true); List<Cell> winnerCells = new ArrayList<>(cc.winnerCells()); assertEquals(1, winnerCells.size()); List<DistalDendrite> segments = winnerCells.get(0).getSegments(cn); assertEquals(1, segments.size()); List<Synapse> synapses = cn.getSynapses(segments.get(0)); assertEquals(2, synapses.size()); for(Synapse synapse : synapses) { assertEquals(0.21, synapse.getPermanence(), 0.01); assertTrue(prevWinnerCells.contains(synapse.getPresynapticCell())); } } @Test public void testNewSegmentAddSynapsesToAllWinnerCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0, 1, 2 }; int[] activeColumns = { 4 }; ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); List<Cell> prevWinnerCells = new ArrayList<>(cc.winnerCells()); assertEquals(3, prevWinnerCells.size()); cc = tm.compute(cn, activeColumns, true); List<Cell> winnerCells = new ArrayList<>(cc.winnerCells()); assertEquals(1, winnerCells.size()); List<DistalDendrite> segments = winnerCells.get(0).getSegments(cn); assertEquals(1, segments.size()); List<Synapse> synapses = segments.get(0).getAllSynapses(cn); List<Cell> presynapticCells = new ArrayList<>(); for(Synapse synapse : synapses) { assertEquals(0.21, synapse.getPermanence(), 0.01); presynapticCells.add(synapse.getPresynapticCell()); } Collections.sort(presynapticCells); assertTrue(prevWinnerCells.equals(presynapticCells)); } @Test public void testMatchingSegmentAddSynapsesToSubsetOfWinnerCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.CELLS_PER_COLUMN, 1); p = getDefaultParameters(p, KEY.MIN_THRESHOLD, 1); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0, 1, 2, 3 }; Set<Cell> prevWinnerCells = cn.getCellSet(new int[] { 0, 1, 2, 3 }); int[] activeColumns = { 4 }; DistalDendrite matchingSegment = cn.createSegment(cn.getCell(4)); cn.createSynapse(matchingSegment, cn.getCell(0), 0.5); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertTrue(cc.winnerCells().equals(prevWinnerCells)); cc = tm.compute(cn, activeColumns, true); List<Synapse> synapses = cn.getSynapses(matchingSegment); assertEquals(3, synapses.size()); Collections.sort(synapses); for(Synapse synapse : synapses) { if(synapse.getPresynapticCell().getIndex() == 0) continue; assertEquals(0.21, synapse.getPermanence(), 0.01); assertTrue(synapse.getPresynapticCell().getIndex() == 1 || synapse.getPresynapticCell().getIndex() == 2 || synapse.getPresynapticCell().getIndex() == 3); } } @Test public void testMatchingSegmentAddSynapsesToAllWinnerCells() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.CELLS_PER_COLUMN, 1); p = getDefaultParameters(p, KEY.MIN_THRESHOLD, 1); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0, 1 }; Set<Cell> prevWinnerCells = cn.getCellSet(new int[] { 0, 1 }); int[] activeColumns = { 4 }; DistalDendrite matchingSegment = cn.createSegment(cn.getCell(4)); cn.createSynapse(matchingSegment, cn.getCell(0), 0.5); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertTrue(cc.winnerCells().equals(prevWinnerCells)); cc = tm.compute(cn, activeColumns, true); List<Synapse> synapses = cn.getSynapses(matchingSegment); assertEquals(2, synapses.size()); Collections.sort(synapses); for(Synapse synapse : synapses) { if(synapse.getPresynapticCell().getIndex() == 0) continue; assertEquals(0.21, synapse.getPermanence(), 0.01); assertEquals(1, synapse.getPresynapticCell().getIndex()); } } /** * When a segment becomes active, grow synapses to previous winner cells. * * The number of grown synapses is calculated from the "matching segment" * overlap, not the "active segment" overlap. */ @Test public void testActiveSegmentGrowSynapsesAccordingToPotentialOverlap() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.CELLS_PER_COLUMN, 1); p = getDefaultParameters(p, KEY.MIN_THRESHOLD, 1); p = getDefaultParameters(p, KEY.ACTIVATION_THRESHOLD, 2); p = getDefaultParameters(p, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p.apply(cn); TemporalMemory.init(cn); // Use 1 cell per column so that we have easy control over the winner cells. int[] previousActiveColumns = { 0, 1, 2, 3, 4 }; Set<Cell> prevWinnerCells = Arrays.asList(0, 1, 2, 3, 4) .stream() .map(i -> cn.getCell(i)) .collect(Collectors.toCollection(LinkedHashSet::new)); int[] activeColumns = { 5 }; DistalDendrite activeSegment = cn.createSegment(cn.getCell(5)); cn.createSynapse(activeSegment, cn.getCell(0), 0.5); cn.createSynapse(activeSegment, cn.getCell(1), 0.5); cn.createSynapse(activeSegment, cn.getCell(2), 0.2); ComputeCycle cc = tm.compute(cn, previousActiveColumns, true); assertEquals(prevWinnerCells, cc.winnerCells()); cc = tm.compute(cn, activeColumns, true); Set<Cell> presynapticCells = cn.getSynapses(activeSegment).stream() .map(s -> s.getPresynapticCell()) .collect(Collectors.toSet()); assertTrue( presynapticCells.size() == 4 && ( presynapticCells.containsAll(Arrays.asList(cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3))) || presynapticCells.containsAll(Arrays.asList(cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(4))))); } @Test public void testDestroyWeakSynapseOnWrongPrediction() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.INITIAL_PERMANENCE, 0.2); p = getDefaultParameters(p, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; Cell[] previousActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; int[] activeColumns = { 2 }; Cell expectedActiveCell = cn.getCell(5); DistalDendrite activeSegment = cn.createSegment(expectedActiveCell); cn.createSynapse(activeSegment, previousActiveCells[0], 0.5); cn.createSynapse(activeSegment, previousActiveCells[1], 0.5); cn.createSynapse(activeSegment, previousActiveCells[2], 0.5); // Weak Synapse cn.createSynapse(activeSegment, previousActiveCells[3], 0.015); tm.compute(cn, previousActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(3, cn.numSynapses(activeSegment)); } @Test public void testDestroyWeakSynapseOnActiveReinforce() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.INITIAL_PERMANENCE, 0.2); p = getDefaultParameters(p, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p.apply(cn); TemporalMemory.init(cn); int[] previousActiveColumns = { 0 }; Cell[] previousActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; int[] activeColumns = { 2 }; Cell expectedActiveCell = cn.getCell(5); DistalDendrite activeSegment = cn.createSegment(expectedActiveCell); cn.createSynapse(activeSegment, previousActiveCells[0], 0.5); cn.createSynapse(activeSegment, previousActiveCells[1], 0.5); cn.createSynapse(activeSegment, previousActiveCells[2], 0.5); // Weak Synapse cn.createSynapse(activeSegment, previousActiveCells[3], 0.009); tm.compute(cn, previousActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(3, cn.numSynapses(activeSegment)); } @Test public void testRecycleWeakestSynapseToMakeRoomForNewSynapse() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.CELLS_PER_COLUMN, 1); p.set(KEY.COLUMN_DIMENSIONS, new int[] { 100 }); p = getDefaultParameters(p, KEY.MIN_THRESHOLD, 1); p = getDefaultParameters(p, KEY.PERMANENCE_INCREMENT, 0.02); p = getDefaultParameters(p, KEY.PERMANENCE_DECREMENT, 0.02); p.set(KEY.MAX_SYNAPSES_PER_SEGMENT, 3); p.apply(cn); TemporalMemory.init(cn); assertEquals(3, cn.getMaxSynapsesPerSegment()); int[] prevActiveColumns = { 0, 1, 2 }; Set<Cell> prevWinnerCells = cn.getCellSet(new int[] { 0, 1, 2 }); int[] activeColumns = { 4 }; DistalDendrite matchingSegment = cn.createSegment(cn.getCell(4)); cn.createSynapse(matchingSegment, cn.getCell(81), 0.6); // Weakest Synapse cn.createSynapse(matchingSegment, cn.getCell(0), 0.11); ComputeCycle cc = tm.compute(cn, prevActiveColumns, true); assertEquals(prevWinnerCells, cc.winnerCells); tm.compute(cn, activeColumns, true); List<Synapse> synapses = cn.getSynapses(matchingSegment); assertEquals(3, synapses.size()); Set<Cell> presynapticCells = synapses.stream().map(s -> s.getPresynapticCell()).collect(Collectors.toSet()); assertFalse(presynapticCells.stream().mapToInt(cell -> cell.getIndex()).anyMatch(i -> i == 0)); } @Test public void testRecycleLeastRecentlyActiveSegmentToMakeRoomForNewSegment() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.CELLS_PER_COLUMN, 1); p = getDefaultParameters(p, KEY.INITIAL_PERMANENCE, 0.5); p = getDefaultParameters(p, KEY.PERMANENCE_INCREMENT, 0.02); p = getDefaultParameters(p, KEY.PERMANENCE_DECREMENT, 0.02); p.set(KEY.MAX_SEGMENTS_PER_CELL, 2); p.apply(cn); TemporalMemory.init(cn); int[] prevActiveColumns1 = { 0, 1, 2 }; int[] prevActiveColumns2 = { 3, 4, 5 }; int[] prevActiveColumns3 = { 6, 7, 8 }; int[] activeColumns = { 9 }; Cell cell9 = cn.getCell(9); tm.compute(cn, prevActiveColumns1, true); tm.compute(cn, activeColumns, true); assertEquals(1, cn.getSegments(cell9).size()); DistalDendrite oldestSegment = cn.getSegments(cell9).get(0); tm.reset(cn); tm.compute(cn, prevActiveColumns2, true); tm.compute(cn, activeColumns, true); assertEquals(2, cn.getSegments(cell9).size()); Set<Cell> oldPresynaptic = cn.getSynapses(oldestSegment) .stream() .map(s -> s.getPresynapticCell()) .collect(Collectors.toSet()); tm.reset(cn); tm.compute(cn, prevActiveColumns3, true); tm.compute(cn, activeColumns, true); assertEquals(2, cn.getSegments(cell9).size()); // Verify none of the segments are connected to the cells the old // segment was connected to. for(DistalDendrite segment : cn.getSegments(cell9)) { Set<Cell> newPresynaptic = cn.getSynapses(segment) .stream() .map(s -> s.getPresynapticCell()) .collect(Collectors.toSet()); assertTrue(Collections.disjoint(oldPresynaptic, newPresynaptic)); } } @Test public void testDestroySegmentsWithTooFewSynapsesToBeMatching() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.INITIAL_PERMANENCE, .2); p = getDefaultParameters(p, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p.apply(cn); TemporalMemory.init(cn); int[] prevActiveColumns = { 0 }; Cell[] prevActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; int[] activeColumns = { 2 }; Cell expectedActiveCell = cn.getCell(5); DistalDendrite matchingSegment = cn.createSegment(cn.getCell(5)); cn.createSynapse(matchingSegment, prevActiveCells[0], .015); cn.createSynapse(matchingSegment, prevActiveCells[1], .015); cn.createSynapse(matchingSegment, prevActiveCells[2], .015); cn.createSynapse(matchingSegment, prevActiveCells[3], .015); tm.compute(cn, prevActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0, cn.numSegments(expectedActiveCell)); } @Test public void testPunishMatchingSegmentsInInactiveColumns() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.INITIAL_PERMANENCE, 0.2); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p.apply(cn); TemporalMemory.init(cn); int[] prevActiveColumns = { 0 }; Cell[] prevActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; int[] activeColumns = { 1 }; Cell previousInactiveCell = cn.getCell(81); DistalDendrite activeSegment = cn.createSegment(cn.getCell(42)); Synapse as1 = cn.createSynapse(activeSegment, prevActiveCells[0], .5); Synapse as2 = cn.createSynapse(activeSegment, prevActiveCells[1], .5); Synapse as3 = cn.createSynapse(activeSegment, prevActiveCells[2], .5); Synapse is1 = cn.createSynapse(activeSegment, previousInactiveCell, .5); DistalDendrite matchingSegment = cn.createSegment(cn.getCell(43)); Synapse as4 = cn.createSynapse(matchingSegment, prevActiveCells[0], .5); Synapse as5 = cn.createSynapse(matchingSegment, prevActiveCells[1], .5); Synapse is2 = cn.createSynapse(matchingSegment, previousInactiveCell, .5); tm.compute(cn, prevActiveColumns, true); tm.compute(cn, activeColumns, true); assertEquals(0.48, as1.getPermanence(), 0.01); assertEquals(0.48, as2.getPermanence(), 0.01); assertEquals(0.48, as3.getPermanence(), 0.01); assertEquals(0.48, as4.getPermanence(), 0.01); assertEquals(0.48, as5.getPermanence(), 0.01); assertEquals(0.50, is1.getPermanence(), 0.01); assertEquals(0.50, is2.getPermanence(), 0.01); } @Test public void testAddSegmentToCellWithFewestSegments() { boolean grewOnCell1 = false; boolean grewOnCell2 = false; for(int seed = 0;seed < 100;seed++) { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p = getDefaultParameters(p, KEY.SEED, seed); p.apply(cn); TemporalMemory.init(cn); int[] prevActiveColumns = { 1, 2, 3, 4 }; Cell[] prevActiveCells = { cn.getCell(4), cn.getCell(5), cn.getCell(6), cn.getCell(7) }; int[] activeColumns = { 0 }; Cell[] nonMatchingCells = { cn.getCell(0), cn.getCell(3) }; Set<Cell> activeCells = cn.getCellSet(new int[] { 0, 1, 2, 3}); DistalDendrite segment1 = cn.createSegment(nonMatchingCells[0]); cn.createSynapse(segment1, prevActiveCells[0], 0.5); DistalDendrite segment2 = cn.createSegment(nonMatchingCells[1]); cn.createSynapse(segment2, prevActiveCells[1], 0.5); tm.compute(cn, prevActiveColumns, true); ComputeCycle cc = tm.compute(cn, activeColumns, true); assertTrue(cc.activeCells().equals(activeCells)); assertEquals(3, cn.numSegments()); assertEquals(1, cn.numSegments(cn.getCell(0))); assertEquals(1, cn.numSegments(cn.getCell(3))); assertEquals(1, cn.numSynapses(segment1)); assertEquals(1, cn.numSynapses(segment2)); List<DistalDendrite> segments = new ArrayList<>(cn.getSegments(cn.getCell(1))); if(segments.size() == 0) { List<DistalDendrite> segments2 = cn.getSegments(cn.getCell(2)); assertFalse(segments2.size() == 0); grewOnCell2 = true; segments.addAll(segments2); } else { grewOnCell1 = true; } assertEquals(1, segments.size()); List<Synapse> synapses = segments.get(0).getAllSynapses(cn); assertEquals(4, synapses.size()); Set<Column> columnCheckList = cn.getColumnSet(prevActiveColumns); for(Synapse synapse : synapses) { assertEquals(0.2, synapse.getPermanence(), 0.01); Column column = synapse.getPresynapticCell().getColumn(); assertTrue(columnCheckList.contains(column)); columnCheckList.remove(column); } assertEquals(0, columnCheckList.size()); } assertTrue(grewOnCell1); assertTrue(grewOnCell2); } @Test public void testConnectionsNeverChangeWhenLearningDisabled() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.MAX_NEW_SYNAPSE_COUNT, 4); p = getDefaultParameters(p, KEY.PREDICTED_SEGMENT_DECREMENT, 0.02); p = getDefaultParameters(p, KEY.INITIAL_PERMANENCE, 0.2); p.apply(cn); TemporalMemory.init(cn); int[] prevActiveColumns = { 0 }; Cell[] prevActiveCells = { cn.getCell(0), cn.getCell(1), cn.getCell(2), cn.getCell(3) }; int[] activeColumns = { 1, 2 }; Cell prevInactiveCell = cn.getCell(81); Cell expectedActiveCell = cn.getCell(4); DistalDendrite correctActiveSegment = cn.createSegment(expectedActiveCell); cn.createSynapse(correctActiveSegment, prevActiveCells[0], 0.5); cn.createSynapse(correctActiveSegment, prevActiveCells[1], 0.5); cn.createSynapse(correctActiveSegment, prevActiveCells[2], 0.5); DistalDendrite wrongMatchingSegment = cn.createSegment(cn.getCell(43)); cn.createSynapse(wrongMatchingSegment, prevActiveCells[0], 0.5); cn.createSynapse(wrongMatchingSegment, prevActiveCells[1], 0.5); cn.createSynapse(wrongMatchingSegment, prevInactiveCell, 0.5); Map<Cell, HashSet<Synapse>> synMapBefore = deepCopyPlain(cn.getReceptorSynapseMapping()); Map<Cell, List<DistalDendrite>> segMapBefore = deepCopyPlain(cn.getSegmentMapping()); tm.compute(cn, prevActiveColumns, false); tm.compute(cn, activeColumns, false); assertTrue(synMapBefore != cn.getReceptorSynapseMapping()); assertEquals(synMapBefore, cn.getReceptorSynapseMapping()); assertTrue(segMapBefore != cn.getSegmentMapping()); assertEquals(segMapBefore, cn.getSegmentMapping()); } @Test public void testLeastUsedCell() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = getDefaultParameters(null, KEY.COLUMN_DIMENSIONS, new int[] { 2 }); p = getDefaultParameters(p, KEY.CELLS_PER_COLUMN, 2); p.apply(cn); TemporalMemory.init(cn); DistalDendrite dd = cn.createSegment(cn.getCell(0)); cn.createSynapse(dd, cn.getCell(3), 0.3); for(int i = 0;i < 100;i++) { assertEquals(1, tm.leastUsedCell(cn, cn.getColumn(0).getCells(), cn.getRandom()).getIndex()); } } @Test public void testAdaptSegment() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = Parameters.getAllDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); DistalDendrite dd = cn.createSegment(cn.getCell(0)); Synapse s1 = cn.createSynapse(dd, cn.getCell(23), 0.6); Synapse s2 = cn.createSynapse(dd, cn.getCell(37), 0.4); Synapse s3 = cn.createSynapse(dd, cn.getCell(477), 0.9); tm.adaptSegment(cn, dd, cn.getCellSet(23, 37), cn.getPermanenceIncrement(), cn.getPermanenceDecrement()); assertEquals(0.7, s1.getPermanence(), 0.01); assertEquals(0.5, s2.getPermanence(), 0.01); assertEquals(0.8, s3.getPermanence(), 0.01); } @Test public void testAdaptSegmentToMax() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = Parameters.getAllDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); DistalDendrite dd = cn.createSegment(cn.getCell(0)); Synapse s1 = cn.createSynapse(dd, cn.getCell(23), 0.9); tm.adaptSegment(cn, dd, cn.getCellSet(23), cn.getPermanenceIncrement(), cn.getPermanenceDecrement()); assertEquals(1.0, s1.getPermanence(), 0.1); // Now permanence should be at max tm.adaptSegment(cn, dd, cn.getCellSet(23), cn.getPermanenceIncrement(), cn.getPermanenceDecrement()); assertEquals(1.0, s1.getPermanence(), 0.1); } @Test public void testAdaptSegmentToMin() { TemporalMemory tm = new TemporalMemory(); Connections cn = new Connections(); Parameters p = Parameters.getAllDefaultParameters(); p.apply(cn); TemporalMemory.init(cn); DistalDendrite dd = cn.createSegment(cn.getCell(0)); Synapse s1 = cn.createSynapse(dd, cn.getCell(23), 0.1); cn.createSynapse(dd, cn.getCell(1), 0.3); tm.adaptSegment(cn, dd, cn.getCellSet(), cn.getPermanenceIncrement(), cn.getPermanenceDecrement()); assertFalse(cn.getSynapses(dd).contains(s1)); } @Test public void testNumberOfColumns() { Connections cn = new Connections(); Parameters p = Parameters.getAllDefaultParameters(); p.set(KEY.COLUMN_DIMENSIONS, new int[] { 64, 64 }); p.set(KEY.CELLS_PER_COLUMN, 32); p.apply(cn); TemporalMemory.init(cn); assertEquals(64 * 64, cn.getNumColumns()); } @Test public void testNumberOfCells() { Connections cn = new Connections(); Parameters p = Parameters.getAllDefaultParameters(); p.set(KEY.COLUMN_DIMENSIONS, new int[] { 64, 64 }); p.set(KEY.CELLS_PER_COLUMN, 32); p.apply(cn); TemporalMemory.init(cn); assertEquals(64 * 64 * 32, cn.getCells().length); } }