gt:             for(double j = 0;j < INPUT_GROUP_COUNT;j++) {
context: /* ---------------------------------------------------------------------
   * Numenta Platform for Intelligent Computing (NuPIC)
   * Copyright (C) 2016, Numenta, Inc.  Unless you have an agreement
   * with Numenta, Inc., for a separate license for this software code, the
   * following terms and conditions apply:
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Affero Public License version 3 as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   * See the GNU Affero Public License for more details.
   *
   * You should have received a copy of the GNU Affero Public License
   * along with this program.  If not, see http://www.gnu.org/licenses.
   *
   * http://numenta.org/licenses/
   * ---------------------------------------------------------------------
   */
  package org.numenta.nupic.network;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNotEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  import static org.numenta.nupic.algorithms.Anomaly.KEY_MODE;
  import static org.numenta.nupic.algorithms.Anomaly.KEY_USE_MOVING_AVG;
  import static org.numenta.nupic.algorithms.Anomaly.KEY_WINDOW_SIZE;
  import static org.numenta.nupic.network.NetworkTestHarness.*;
  
  import java.io.File;
  import java.math.BigDecimal;
  import java.math.RoundingMode;
  import java.nio.file.Files;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.concurrent.CyclicBarrier;
  import java.util.function.BiFunction;
  import java.util.stream.Collectors;
  import java.util.stream.IntStream;
  import java.util.stream.Stream;
  
  import org.junit.AfterClass;
  import org.junit.BeforeClass;
  import org.junit.Test;
  import org.numenta.nupic.FieldMetaType;
  import org.numenta.nupic.Parameters;
  import org.numenta.nupic.Parameters.KEY;
  import org.numenta.nupic.algorithms.Anomaly;
  import org.numenta.nupic.algorithms.Anomaly.Mode;
  import org.numenta.nupic.algorithms.AnomalyLikelihood;
  import org.numenta.nupic.algorithms.AnomalyLikelihoodMetrics;
  import org.numenta.nupic.algorithms.AnomalyLikelihoodTest;
  import org.numenta.nupic.algorithms.CLAClassifier;
  import org.numenta.nupic.algorithms.Classification;
  import org.numenta.nupic.algorithms.Sample;
  import org.numenta.nupic.algorithms.SpatialPooler;
  import org.numenta.nupic.algorithms.TemporalMemory;
  import org.numenta.nupic.datagen.ResourceLocator;
  import org.numenta.nupic.encoders.DateEncoder;
  import org.numenta.nupic.encoders.MultiEncoder;
  import org.numenta.nupic.model.Cell;
  import org.numenta.nupic.model.Connections;
  import org.numenta.nupic.model.SDR;
  import org.numenta.nupic.network.Persistence.PersistenceAccess;
  import org.numenta.nupic.network.sensor.FileSensor;
  import org.numenta.nupic.network.sensor.HTMSensor;
  import org.numenta.nupic.network.sensor.ObservableSensor;
  import org.numenta.nupic.network.sensor.Publisher;
  import org.numenta.nupic.network.sensor.Sensor;
  import org.numenta.nupic.network.sensor.SensorParams;
  import org.numenta.nupic.network.sensor.SensorParams.Keys;
  import org.numenta.nupic.serialize.SerialConfig;
  import org.numenta.nupic.util.ArrayUtils;
  import org.numenta.nupic.util.Condition;
  import org.numenta.nupic.util.FastRandom;
  import org.numenta.nupic.util.MersenneTwister;
  import org.numenta.nupic.util.Tuple;
  
  import com.cedarsoftware.util.DeepEquals;
  
  import gnu.trove.list.array.TIntArrayList;
  import rx.Observer;
  import rx.Subscriber;
  import rx.observers.TestObserver;
  
  
  public class PersistenceAPITest extends ObservableTestBase {
      // TO TURN ON PRINTOUT: SET "TRUE" BELOW
      /** Printer to visualize DayOfWeek printouts - SET TO TRUE FOR PRINTOUT */
      private BiFunction<Inference, Integer, Integer> dayOfWeekPrintout = createDayOfWeekInferencePrintout(false);
      
      
      @BeforeClass
      public static void beforeClass(){
      	// Sample data contains datetimes that are invalid in some timezones due to DST.
      	// If UTC is forced, then test runs should yield the same result regardless of timezone
      	System.setProperty("user.timezone", "UTC");
      }
  
      @AfterClass
      public static void cleanUp() {
          System.out.println("cleaning up...");
          try {
              File serialDir = new File(System.getProperty("user.home") + File.separator + SerialConfig.SERIAL_TEST_DIR);
              if(serialDir.exists()) {
                  Files.list(serialDir.toPath()).forEach(
                      f ->  { 
                          try { Files.deleteIfExists(f.toAbsolutePath()); }
                          catch(Exception io) { throw new RuntimeException(io); } 
                      }
                  );
              }
          }catch(Exception e) {
              e.printStackTrace();
          }
      }
      
      @Test
      public void testEnsurePathExists() {
          SerialConfig config = new SerialConfig("testEnsurePathExists", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI persist = Persistence.get();
          persist.setConfig(config);
          
          try {
              ((PersistenceAccess)persist).ensurePathExists(config);
          }catch(Exception e) { fail(); }
          
          File f1 = new File(System.getProperty("user.home") + File.separator + config.getFileDir() + File.separator + "testEnsurePathExists");
          assertTrue(f1.exists());
      }
      
      @Test
      public void testSearchAndListPreviousCheckPoint() {
          Parameters p = NetworkTestHarness.getParameters();
          Network network = Network.create("test network", p).add(Network.createRegion("r1")
              .add(Network.createLayer("1", p)
                  .add(Anomaly.create())
                  .add(new TemporalMemory())
                  .add(new SpatialPooler())));
          
          PersistenceAPI pa = Persistence.get(new SerialConfig(null, SerialConfig.SERIAL_TEST_DIR));
          IntStream.range(0, 5).forEach(i -> ((PersistenceAccess)pa).getCheckPointFunction(network).apply(network));
          
          List<String> checkPointFiles = pa.listCheckPointFiles();
          assertTrue(checkPointFiles.size() > 4);
          
          assertEquals(checkPointFiles.get(checkPointFiles.size() - 2), 
              pa.getPreviousCheckPoint(checkPointFiles.get(checkPointFiles.size() - 1)));
      }
      
      /////////////////////////////////////////////////////////////////////////////
      //     First, Test Serialization of Each (Critical) Object Individually    //
      /////////////////////////////////////////////////////////////////////////////
  
      /////////////////////
      //    Parameters   //
      /////////////////////
      @Test
      public void testSerializeParameters() {
          Parameters p = getParameters();
          
          SerialConfig config = new SerialConfig("testSerializeParameters", SerialConfig.SERIAL_TEST_DIR);
          
          PersistenceAPI api = Persistence.get(config);
          
          // 1. serialize
          byte[] data = api.write(p, "testSerializeParameters");
  
          // 2. deserialize
          Parameters serialized = api.read(data);
  
          assertTrue(p.keys().size() == serialized.keys().size());
          assertTrue(DeepEquals.deepEquals(p, serialized));
          for(KEY k : p.keys()) {
              deepCompare(serialized.get(k), p.get(k));
          }
  
          // 3. reify from file
          /////////////////////////////////////
          //  SHOW RETRIEVAL USING FILENAME  //
          /////////////////////////////////////
          Parameters fromFile = api.read("testSerializeParameters");
          assertTrue(p.keys().size() == fromFile.keys().size());
          assertTrue(DeepEquals.deepEquals(p, fromFile));
          for(KEY k : p.keys()) {
              deepCompare(fromFile.get(k), p.get(k));
          }
      }
      
      /////////////////////
      //   Connections   //
      /////////////////////
      @Test
      public void testSerializeConnections() {
          Parameters p = getParameters();
          Connections con = new Connections();
          p.apply(con);
  
          TemporalMemory.init(con);
  
          SerialConfig config = new SerialConfig("testSerializeConnections", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          
          // 1. serialize
          byte[] data = api.write(con);
  
          // 2. deserialize
          Connections serialized = api.read(data);
          assertTrue(DeepEquals.deepEquals(con, serialized));
  
          serialized.printParameters();
          int cellCount = con.getCellsPerColumn();
          for(int i = 0;i < con.getNumColumns();i++) {
              deepCompare(con.getColumn(i), serialized.getColumn(i));
              for(int j = 0;j < cellCount;j++) {
                  Cell cell = serialized.getCell(i * cellCount + j);
                  deepCompare(con.getCell(i * cellCount + j), cell);
              }
          }
  
          // 3. reify from file
          Connections fromFile = api.read(data);
          assertTrue(DeepEquals.deepEquals(con, fromFile));
          for(int i = 0;i < con.getNumColumns();i++) {
              deepCompare(con.getColumn(i), fromFile.getColumn(i));
              for(int j = 0;j < cellCount;j++) {
                  Cell cell = fromFile.getCell(i * cellCount + j);
                  deepCompare(con.getCell(i * cellCount + j), cell);
              }
          }
      }
      
      // Connections with all types populated
  //    @SuppressWarnings("unused")
  //    @Test
  //    public void testMorePopulatedConnections() {
  //        TemporalMemory tm = new TemporalMemory();
  //        Connections cn = new Connections();
  //        cn.setConnectedPermanence(0.50);
  //        cn.setMinThreshold(1);
  //        // Init with default params defined in Connections.java default fields.
  //        tm.init(cn);
  //        
  //        SerialConfig config = new SerialConfig("testSerializeConnections2", SerialConfig.SERIAL_TEST_DIR);
  //        PersistenceAPI api = Persistence.get(config);
  //        
  //        DistalDendrite dd = cn.getCell(0).createSegment(cn);
  //        Synapse s0 = dd.createSynapse(cn, cn.getCell(23), 0.6);
  //        Synapse s1 = dd.createSynapse(cn, cn.getCell(37), 0.4);
  //        Synapse s2 = dd.createSynapse(cn, cn.getCell(477), 0.9);
  //        
  //        byte[] dda = api.write(dd);
  //        DistalDendrite ddo = api.read(dda);
  //        deepCompare(dd, ddo);
  //        List<Synapse> l1 = dd.getAllSynapses(cn);
  //        List<Synapse> l2 = ddo.getAllSynapses(cn);
  //        assertTrue(l2.equals(l1));
  //        
  //        DistalDendrite dd1 = cn.getCell(0).createSegment(cn);
  //        Synapse s3 = dd1.createSynapse(cn, cn.getCell(49), 0.9);
  //        Synapse s4 = dd1.createSynapse(cn, cn.getCell(3), 0.8);
  //        
  //        DistalDendrite dd2 = cn.getCell(1).createSegment(cn);
  //        Synapse s5 = dd2.createSynapse(cn, cn.getCell(733), 0.7);
  //        
  //        DistalDendrite dd3 = cn.getCell(8).createSegment(cn);
  //        Synapse s6 = dd3.createSynapse(cn, cn.getCell(486), 0.9);
  //        
  //        
  //        Connections cn2 = new Connections();
  //        cn2.setConnectedPermanence(0.50);
  //        cn2.setMinThreshold(1);
  //        tm.init(cn2);
  //        
  //        DistalDendrite ddb = cn2.getCell(0).createSegment(cn2);
  //        Synapse s0b = ddb.createSynapse(cn2, cn2.getCell(23), 0.6);
  //        Synapse s1b = ddb.createSynapse(cn2, cn2.getCell(37), 0.4);
  //        Synapse s2b = ddb.createSynapse(cn2, cn2.getCell(477), 0.9);
  //        
  //        DistalDendrite dd1b = cn2.getCell(0).createSegment(cn2);
  //        Synapse s3b = dd1b.createSynapse(cn2, cn2.getCell(49), 0.9);
  //        Synapse s4b = dd1b.createSynapse(cn2, cn2.getCell(3), 0.8);
  //        
  //        DistalDendrite dd2b = cn2.getCell(1).createSegment(cn2);
  //        Synapse s5b = dd2b.createSynapse(cn2, cn2.getCell(733), 0.7);
  //        
  //        DistalDendrite dd3b = cn2.getCell(8).createSegment(cn2);
  //        Synapse s6b = dd3b.createSynapse(cn2, cn2.getCell(486), 0.9);
  //        
  //        assertTrue(cn.equals(cn2));
  //        
  //        Set<Cell> activeCells = cn.getCellSet(new int[] { 733, 37, 974, 23 });
  //        
  //        SegmentSearch result = tm.getBestMatchingSegment(cn, cn.getCell(0), activeCells);
  //        assertEquals(dd, result.bestSegment);
  //        assertEquals(2, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(1), activeCells);
  //        assertEquals(dd2, result.bestSegment);
  //        assertEquals(1, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(8), activeCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(100), activeCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        //Test that we can repeat this
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(0), activeCells);
  //        assertEquals(dd, result.bestSegment);
  //        assertEquals(2, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(1), activeCells);
  //        assertEquals(dd2, result.bestSegment);
  //        assertEquals(1, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(8), activeCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(cn, cn.getCell(100), activeCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        // 1. serialize
  //        byte[] data = api.write(cn, "testSerializeConnections2");
  //        
  //        // 2. deserialize
  //        Connections serialized = api.read(data);
  //        
  //        Set<Cell> serialActiveCells = serialized.getCellSet(new int[] { 733, 37, 974, 23 });
  //        
  //        deepCompare(activeCells, serialActiveCells);
  //        
  //        result = tm.getBestMatchingSegment(serialized, serialized.getCell(0), serialActiveCells);
  //        assertEquals(dd, result.bestSegment);
  //        assertEquals(2, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(serialized, serialized.getCell(1), serialActiveCells);
  //        assertEquals(dd2, result.bestSegment);
  //        assertEquals(1, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(serialized, serialized.getCell(8), serialActiveCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        result = tm.getBestMatchingSegment(serialized, serialized.getCell(100), serialActiveCells);
  //        assertEquals(null, result.bestSegment);
  //        assertEquals(0, result.numActiveSynapses);
  //        
  //        boolean b = DeepEquals.deepEquals(cn, serialized);
  //        deepCompare(cn, serialized);
  //        assertTrue(b);
  //        
  //        //{0=[synapse: [ synIdx=0, inIdx=23, sgmtIdx=0, srcCellIdx=23 ], synapse: [ synIdx=1, inIdx=37, sgmtIdx=0, srcCellIdx=37 ], synapse: [ synIdx=2, inIdx=477, sgmtIdx=0, srcCellIdx=477 ]], 1=[synapse: [ synIdx=3, inIdx=49, sgmtIdx=1, srcCellIdx=49 ], synapse: [ synIdx=4, inIdx=3, sgmtIdx=1, srcCellIdx=3 ]], 2=[synapse: [ synIdx=5, inIdx=733, sgmtIdx=2, srcCellIdx=733 ]], 3=[synapse: [ synIdx=6, inIdx=486, sgmtIdx=3, srcCellIdx=486 ]]}
  //        //{0=[synapse: [ synIdx=0, inIdx=23, sgmtIdx=0, srcCellIdx=23 ], synapse: [ synIdx=1, inIdx=37, sgmtIdx=0, srcCellIdx=37 ], synapse: [ synIdx=2, inIdx=477, sgmtIdx=0, srcCellIdx=477 ]], 1=[synapse: [ synIdx=3, inIdx=49, sgmtIdx=1, srcCellIdx=49 ], synapse: [ synIdx=4, inIdx=3, sgmtIdx=1, srcCellIdx=3 ]], 2=[synapse: [ synIdx=5, inIdx=733, sgmtIdx=2, srcCellIdx=733 ]], 3=[synapse: [ synIdx=6, inIdx=486, sgmtIdx=3, srcCellIdx=486 ]]}
  //        
  //    }
      
      // Test Connections Serialization after running through TemporalMemory
      @Test
      public void testThreadedPublisher_TemporalMemoryNetwork() {
          Network network = createAndRunTestTemporalMemoryNetwork();
          Layer<?> l = network.lookup("r1").lookup("1");
          Connections cn = l.getConnections();
          
          SerialConfig config = new SerialConfig("testThreadedPublisher_TemporalMemoryNetwork", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          
          byte[] bytes = api.write(cn);
          Connections serializedConnections = api.read(bytes);
          
          Network network2 = createAndRunTestTemporalMemoryNetwork();
          Layer<?> l2 = network2.lookup("r1").lookup("1");
          Connections newCons = l2.getConnections();
          
          boolean b = DeepEquals.deepEquals(newCons, serializedConnections);
          deepCompare(newCons, serializedConnections);
          assertTrue(b);
      }
      
      // Test Connections Serialization after running through SpatialPooler
      @Test
      public void testThreadedPublisher_SpatialPoolerNetwork() {
          Network network = createAndRunTestSpatialPoolerNetwork(0, 6);
          Layer<?> l = network.lookup("r1").lookup("1");
          Connections cn = l.getConnections();
          
          SerialConfig config = new SerialConfig("testThreadedPublisher_SpatialPoolerNetwork", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          
          byte[] bytes = api.write(cn);
          //Serialize above Connections for comparison with same run but unserialized below...
          Connections serializedConnections = api.read(bytes);
          
          Network network2 = createAndRunTestSpatialPoolerNetwork(0, 6);
          Layer<?> l2 = network2.lookup("r1").lookup("1");
          Connections newCons = l2.getConnections();
          
          //Compare the two Connections (both serialized and regular runs) - should be equal
          boolean b = DeepEquals.deepEquals(newCons, serializedConnections);
          deepCompare(newCons, serializedConnections);
          assertTrue(b);
      }
      /////////////////////////// End Connections Serialization Testing //////////////////////////////////
      
      /////////////////////
      //    HTMSensor    //
      /////////////////////
      // Serialize HTMSensors though they'll probably be reconstituted rather than serialized
      @Test
      public void testHTMSensor_DaysOfWeek() {
          Object[] n = { "some name", ResourceLocator.path("days-of-week.csv") };
          HTMSensor<File> sensor = (HTMSensor<File>)Sensor.create(
              FileSensor::create, SensorParams.create(Keys::path, n));
  
          Parameters p = getParameters();
          p = p.union(NetworkTestHarness.getDayDemoTestEncoderParams());
          sensor.initEncoder(p);
  
          SerialConfig config = new SerialConfig("testHTMSensor_DaysOfWeek", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          
          byte[] bytes = api.write(sensor);
          HTMSensor<File> serializedSensor = api.read(bytes);
  
          boolean b = DeepEquals.deepEquals(serializedSensor, sensor);
          deepCompare(serializedSensor, sensor);
          assertTrue(b);
      }
      
      @Test
      public void testHTMSensor_HotGym() {
          Object[] n = { "some name", ResourceLocator.path("rec-center-hourly-small.csv") };
          HTMSensor<File> sensor = (HTMSensor<File>)Sensor.create(
              FileSensor::create, SensorParams.create(Keys::path, n));
          
          sensor.initEncoder(getTestEncoderParams());
          
          SerialConfig config = new SerialConfig("testHTMSensor_HotGym");
          PersistenceAPI api = Persistence.get(config);
          
          byte[] bytes = api.write(sensor);
          assertNotNull(bytes);
          assertTrue(bytes.length > 0);
          HTMSensor<File> serializedSensor = api.read(bytes);
          
          boolean b = DeepEquals.deepEquals(serializedSensor, sensor);
          deepCompare(serializedSensor, sensor);
          assertTrue(b);
      }
      
      @Test
      public void testSerializeObservableSensor() {
          PublisherSupplier supplier = PublisherSupplier.builder()
              .addHeader("dayOfWeek")
              .addHeader("darr")
              .addHeader("B").build();
          
          ObservableSensor<String[]> oSensor = new ObservableSensor<>(SensorParams.create(Keys::obs, new Object[] {"name", supplier}));
          
          SerialConfig config = new SerialConfig("testSerializeObservableSensor", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          
          byte[] bytes = api.write(oSensor);
          ObservableSensor<String[]> serializedOSensor = api.read(bytes);
          
          boolean b = DeepEquals.deepEquals(serializedOSensor, oSensor);
          deepCompare(serializedOSensor, oSensor);
          assertTrue(b);
      }
      //////////////////////////////////End HTMSensors ////////////////////////////////////
      
      /////////////////////
      //    Anomaly      //
      /////////////////////
      // Serialize Anomaly, AnomalyLikelihood and its support classes
      @Test
      public void testSerializeAnomaly() {
          Map<String, Object> params = new HashMap<>();
          params.put(KEY_MODE, Mode.PURE);
          Anomaly anomalyComputer = Anomaly.create(params);
  
          // Serialize the Anomaly Computer without errors
          SerialConfig config = new SerialConfig("testSerializeAnomaly1", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          byte[] bytes = api.write(anomalyComputer);
  
          // Deserialize the Anomaly Computer and make sure its usable (same tests as AnomalyTest.java)
          Anomaly serializedAnomalyComputer = api.read(bytes);
          double score = serializedAnomalyComputer.compute(new int[0], new int[0], 0, 0);
          assertEquals(0.0, score, 0);
  
          score = serializedAnomalyComputer.compute(new int[0], new int[] {3,5}, 0, 0);
          assertEquals(0.0, score, 0);
  
          score = serializedAnomalyComputer.compute(new int[] { 3, 5, 7 }, new int[] { 3, 5, 7 }, 0, 0);
          assertEquals(0.0, score, 0);
  
          score = serializedAnomalyComputer.compute(new int[] { 2, 3, 6 }, new int[] { 3, 5, 7 }, 0, 0);
          assertEquals(2.0 / 3.0, score, 0);
      }
      
      @Test
      public void testSerializeCumulativeAnomaly() {
          Map<String, Object> params = new HashMap<>();
          params.put(KEY_MODE, Mode.PURE);
          params.put(KEY_WINDOW_SIZE, 3);
          params.put(KEY_USE_MOVING_AVG, true);
          
          Anomaly anomalyComputer = Anomaly.create(params);
          
          // Serialize the Anomaly Computer without errors
          SerialConfig config = new SerialConfig("testSerializeCumulativeAnomaly", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          byte[] bytes = api.write(anomalyComputer);
          
          // Deserialize the Anomaly Computer and make sure its usable (same tests as AnomalyTest.java)
          Anomaly serializedAnomalyComputer = api.read(bytes);
          assertNotNull(serializedAnomalyComputer);        
          
          Object[] predicted = {
              new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 },
              new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 },
              new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }
          };
          Object[] actual = {
              new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }, new int[] { 1, 4, 6 },
              new int[] { 10, 11, 6 }, new int[] { 10, 11, 12 }, new int[] { 10, 11, 12 },
              new int[] { 10, 11, 12 }, new int[] { 1, 2, 6 }, new int[] { 1, 2, 6 }
          };
          
          double[] anomalyExpected = { 0.0, 0.0, 1.0/9.0, 3.0/9.0, 2.0/3.0, 8.0/9.0, 1.0, 2.0/3.0, 1.0/3.0 };
          for(int i = 0;i < 9;i++) {
              double score = serializedAnomalyComputer.compute((int[])actual[i], (int[])predicted[i], 0, 0);
              assertEquals(anomalyExpected[i], score, 0.01);
          }
      }
      
      @Test
      public void testSerializeAnomalyLikelihood() {
          Map<String, Object> params = new HashMap<>();
          params.put(KEY_MODE, Mode.LIKELIHOOD);
          AnomalyLikelihood an = (AnomalyLikelihood)Anomaly.create(params);
          
          // Serialize the Anomaly Computer without errors
          SerialConfig config = new SerialConfig("testSerializeAnomalyLikelihood", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          byte[] bytes = api.write(an);
          
          // Deserialize the Anomaly Computer and make sure its usable (same tests as AnomalyTest.java)
          Anomaly serializedAn = api.read(bytes);
          assertNotNull(serializedAn);
      }
      
      @Test
      public void testSerializeAnomalyLikelihoodForUpdates() {
          Map<String, Object> params = new HashMap<>();
          params.put(KEY_MODE, Mode.LIKELIHOOD);
          AnomalyLikelihood an = (AnomalyLikelihood)Anomaly.create(params);
          
          // Serialize the Anomaly Computer without errors
          SerialConfig config = new SerialConfig("testSerializeAnomalyLikelihood", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          byte[] bytes = api.write(an);
          
          // Deserialize the Anomaly Computer and make sure its usable (same tests as AnomalyTest.java)
          AnomalyLikelihood serializedAn = api.read(bytes);
          assertNotNull(serializedAn);
          
          //----------------------------------------
          // Step 1. Generate an initial estimate using fake distribution of anomaly scores.
          List<Sample> data1 = AnomalyLikelihoodTest.generateSampleData(0.2, 0.2, 0.2, 0.2).subList(0, 1000);
          AnomalyLikelihoodMetrics metrics1 = serializedAn.estimateAnomalyLikelihoods(data1, 5, 0);
          
          //----------------------------------------
          // Step 2. Generate some new data with a higher average anomaly
          // score. Using the estimator from step 1, to compute likelihoods. Now we
          // should see a lot more anomalies.
          List<Sample> data2 = AnomalyLikelihoodTest.generateSampleData(0.6, 0.2, 0.2, 0.2).subList(0, 300);
          AnomalyLikelihoodMetrics metrics2 = serializedAn.updateAnomalyLikelihoods(data2, metrics1.getParams());
          
          // Serialize the Metrics too just to be sure everything can be serialized
          SerialConfig metricsConfig = new SerialConfig("testSerializeMetrics", SerialConfig.SERIAL_TEST_DIR);
          api = Persistence.get(metricsConfig);
          api.write(metrics2);
          
          // Deserialize the Metrics
          AnomalyLikelihoodMetrics serializedMetrics = api.read();
          assertNotNull(serializedMetrics);
          
          assertEquals(serializedMetrics.getLikelihoods().length, data2.size());
          assertEquals(serializedMetrics.getAvgRecordList().size(), data2.size());
          assertTrue(serializedAn.isValidEstimatorParams(serializedMetrics.getParams()));
          
          // The new running total should be different
          assertFalse(metrics1.getAvgRecordList().total == serializedMetrics.getAvgRecordList().total);
          
          // We should have many more samples where likelihood is < 0.01, but not all
          Condition<Double> cond = new Condition.Adapter<Double>() {
              public boolean eval(double d) { return d < 0.01; }
          };
          int conditionCount = ArrayUtils.where(serializedMetrics.getLikelihoods(), cond).length;
          assertTrue(conditionCount >= 25);
          assertTrue(conditionCount <= 250);
      }
      ///////////////////////   End Serialize Anomaly //////////////////////////
      
      ///////////////////////////
      //      CLAClassifier    //
      ///////////////////////////
      // Test Serialize CLAClassifier
      @Test
      public void testSerializeCLAClassifier() {
          CLAClassifier classifier = new CLAClassifier(new TIntArrayList(new int[] { 1 }), 0.1, 0.1, 0);
          int recordNum = 0;
          Map<String, Object> classification = new LinkedHashMap<String, Object>();
          classification.put("bucketIdx", 4);
          classification.put("actValue", 34.7);
          Classification<Double> result = classifier.compute(recordNum, classification, new int[] { 1, 5, 9 }, true, true);
          recordNum += 1;
  
          classification.put("bucketIdx", 5);
          classification.put("actValue", 41.7);
          result = classifier.compute(recordNum, classification, new int[] { 0, 6, 9, 11 }, true, true);
          recordNum += 1;
  
          classification.put("bucketIdx", 5);
          classification.put("actValue", 44.9);
          result = classifier.compute(recordNum, classification, new int[] { 6, 9 }, true, true);
          recordNum += 1;
  
          classification.put("bucketIdx", 4);
          classification.put("actValue", 42.9);
          result = classifier.compute(recordNum, classification, new int[] { 1, 5, 9 }, true, true);
          recordNum += 1;
  
          // Serialize the Metrics too just to be sure everything can be serialized
          SerialConfig config = new SerialConfig("testSerializeCLAClassifier", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          api.write(classifier);
  
          // Deserialize the Metrics
          CLAClassifier serializedClassifier = api.read();
          assertNotNull(serializedClassifier);
  
          //Using the deserialized classifier, continue test
          classification.put("bucketIdx", 4);
          classification.put("actValue", 34.7);
          result = serializedClassifier.compute(recordNum, classification, new int[] { 1, 5, 9 }, true, true);
          recordNum += 1;
  
          assertTrue(Arrays.equals(new int[] { 1 }, result.stepSet()));
          assertEquals(35.520000457763672, result.getActualValue(4), 0.00001);
          assertEquals(42.020000457763672, result.getActualValue(5), 0.00001);
          assertEquals(6, result.getStatCount(1));
          assertEquals(0.0, result.getStat(1, 0), 0.00001);
          assertEquals(0.0, result.getStat(1, 1), 0.00001);
          assertEquals(0.0, result.getStat(1, 2), 0.00001);
          assertEquals(0.0, result.getStat(1, 3), 0.00001);
          assertEquals(0.12300123, result.getStat(1, 4), 0.00001);
          assertEquals(0.87699877, result.getStat(1, 5), 0.00001);
      }
      ////////////////////////  End CLAClassifier ///////////////////////
      
      ///////////////////////////
      //         Layers        //
      ///////////////////////////
      // Serialize a Layer
      @SuppressWarnings({ "unchecked", "rawtypes" })
      @Test
      public void testSerializeLayer() {
          Parameters p = NetworkTestHarness.getParameters().copy();
          p.set(KEY.RANDOM, new MersenneTwister(42));
          p.set(KEY.INFERRED_FIELDS, getInferredFieldsMap("dayOfWeek", CLAClassifier.class));
          Map<String, Map<String, Object>> settings = NetworkTestHarness.setupMap(
              null, // map
              8,    // n
              0,    // w
              0,    // min
              0,    // max
              0,    // radius
              0,    // resolution
              null, // periodic
              null,                 // clip
              Boolean.TRUE,         // forced
              "dayOfWeek",          // fieldName
              "darr",               // fieldType (dense array as opposed to sparse array or "sarr")
              "SDRPassThroughEncoder"); // encoderType
  
          p.set(KEY.FIELD_ENCODING_MAP, settings);
  
          Sensor<ObservableSensor<String[]>> sensor = Sensor.create(
              ObservableSensor::create, SensorParams.create(Keys::obs, new Object[] {"name", 
                  PublisherSupplier.builder()
                  .addHeader("dayOfWeek")
                  .addHeader("darr")
                  .addHeader("B").build() }));
  
          Layer<?> layer = Network.createLayer("1", p)
              .alterParameter(KEY.AUTO_CLASSIFY, true)
              .add(new SpatialPooler())
              .add(sensor);
  
          Observer obs = new Observer<Inference>() {
              @Override public void onCompleted() {}
              @Override public void onError(Throwable e) { e.printStackTrace(); }
              @Override
              public void onNext(Inference spatialPoolerOutput) {
                  System.out.println("in onNext()");
              }
          };
          layer.subscribe(obs);
          layer.close();
  
          SerialConfig config = new SerialConfig("testSerializeLayer", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          api.write(layer);
  
          //Serialize above Connections for comparison with same run but unserialized below...
          Layer<?> serializedLayer = api.read();
          assertEquals(serializedLayer, layer);
          deepCompare(layer, serializedLayer);
  
          // Now change one attribute and see that they are not equal
          serializedLayer.resetRecordNum();
          assertNotEquals(serializedLayer, layer);
      }
      //////////////////////  End Layers  ///////////////////////
      
      
      ///////////////////////////
      //      Full Network     //
      ///////////////////////////
      @Test
      public void testHierarchicalNetwork() {
          Network network = getLoadedHotGymHierarchy();
          try {
              SerialConfig config = new SerialConfig("testSerializeHierarchy", SerialConfig.SERIAL_TEST_DIR);
              PersistenceAPI api = Persistence.get(config);
              api.store(network);
          }catch(Exception e) {
              e.printStackTrace();
              fail();
          }
      }
      
      /**
       * Test that a serialized/de-serialized {@link Network} can be run...
       */
      @Test
      public void testSerializedUnStartedNetworkRuns() {
          final int NUM_CYCLES = 600;
          final int INPUT_GROUP_COUNT = 7; // Days of Week
          
          Network network = getLoadedDayOfWeekNetwork();
          
          SerialConfig config = new SerialConfig("testSerializedUnStartedNetworkRuns", SerialConfig.SERIAL_TEST_DIR);
          PersistenceAPI api = Persistence.get(config);
          api.store(network);
          
          //Serialize above Connections for comparison with same run but unserialized below...
          Network serializedNetwork = api.load();
          assertEquals(serializedNetwork, network);
          deepCompare(network, serializedNetwork);
          
          int cellsPerCol = (int)serializedNetwork.getParameters().get(KEY.CELLS_PER_COLUMN);
          
          serializedNetwork.observe().subscribe(new Observer<Inference>() { 
              @Override public void onCompleted() {}
              @Override public void onError(Throwable e) { e.printStackTrace(); }
              @Override
              public void onNext(Inference inf) {
                  /** see {@link #createDayOfWeekInferencePrintout()} */
                  dayOfWeekPrintout.apply(inf, cellsPerCol);
              }
          });
          
          Publisher pub = serializedNetwork.getPublisher();
          
          serializedNetwork.start();
          
          int cycleCount = 0;
          for(;cycleCount < NUM_CYCLES;cycleCount++) {
  