From 0ff1b77a6fa7152903e2a3f8e0fbe658fb314e5c Mon Sep 17 00:00:00 2001
From: Dilawar Singh <dilawars@ncbs.res.in>
Date: Fri, 21 Apr 2017 17:18:43 +0530
Subject: [PATCH] Squashed 'moose-core/' changes from 270c880..eb878dd

eb878dd Merge branch 'master' of https://github.com/BhallaLab/moose-core
68ef2ed Less verbose ReadSwc and rdesigneur. Fix to SeqSynHandler
2c93c52 return type from None to moose.shell
07fc0f9 Ignore /opt/bin/python3 on travis. Numpy is not available for this path. Try /usr/bin/python3.
45fb960 mtseed and mtrand are under moose namespace and defined in global.h file. Fixes for travis failure with BOOST.
dfa0ab1 Explicitly naming the source file in synapse directory.
cd32764 old makefile based flow is deprecated. Recent commit fixed the test faillure.
c0f5469 Merge branch 'master' of https://github.com/BhallaLab/moose-core
fd96222 Verbose flag for rdesigneur; added synapseOrder to SeqSynHandler, fixes to testSynapse
e7d57cf plot_tables can plot on user given axis.
43faa23 mu.plot_records is renamed to mu.plot_tables.
99f5ee7 Merge branch 'master' of github.com:BhallaLab/moose-core
953142d Fixed for snappy builds.
6931e80 Let cmake find path of Python.h file.
8e4291a Merge commit '4489d15994d2ab9ab2448afd937ba13c65a9907d'
9513005 More changes to snap. Needs to add Python.h path [skip ci]
a2a67bc Removed <<<<, ===  and >>> from improper merge.
1cd99cb Added snapcraft file.
2975d3f Fixes to plotTables utility function.

git-subtree-dir: moose-core
git-subtree-split: eb878ddb88f7d69fca0e0858bf9332ff0661e6d8
---
 .travis/travis_build_linux.sh   |  10 +--
 VERSION                         |   1 -
 basecode/global.cpp             |   2 +-
 basecode/global.h               |   2 +-
 biophysics/ReadSwc.cpp          |  10 +--
 pymoose/CMakeLists.txt          |  22 ++++--
 python/moose/SBML/readSBML.py   |   5 +-
 python/moose/plot_utils.py      |  44 +++++++-----
 python/rdesigneur/rdesigneur.py |   9 ++-
 synapse/CMakeLists.txt          |  15 +++-
 synapse/RollingMatrix.cpp       |   2 +-
 synapse/SeqSynHandler.cpp       | 122 ++++++++++++++++++++++++++++++--
 synapse/SeqSynHandler.h         |  25 ++++++-
 synapse/testSynapse.cpp         |  71 +++++++++++--------
 14 files changed, 262 insertions(+), 78 deletions(-)
 delete mode 100644 VERSION

diff --git a/.travis/travis_build_linux.sh b/.travis/travis_build_linux.sh
index 5530f9a7..3a2ebbfa 100755
--- a/.travis/travis_build_linux.sh
+++ b/.travis/travis_build_linux.sh
@@ -20,20 +20,22 @@
 set -o nounset                              # Treat unset variables as an error
 set -e
 
-PYTHON2="/usr/bin/python2"
-PYTHON3=`which python3`
 #MAKEFLAGS="-j 4"
 
+PYTHON2="/usr/bin/python2"
 # Bug: `which python` returns /opt/bin/python* etc on travis. For which numpy
 # many not be available. Therefore, it is neccessary to use fixed path for
 # python executable.
+PYTHON3="/usr/bin/python3"
 
 (
     # Old makefile based flow.
     $PYTHON2 -m compileall -q .
     if type $PYTHON3 > /dev/null; then $PYTHON3 -m compileall -q . ; fi
-    # Traditional make.
-    make 
+    ## DEPRECATED: No longer testing make file.
+
+    ## Traditional make.
+    #make 
     ## CMAKE based flow
     mkdir -p _GSL_BUILD && cd _GSL_BUILD && \
         cmake -DDEBUG=ON -DPYTHON_EXECUTABLE="$PYTHON2" ..
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 93738075..00000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-3.1.1-129-g669b981
\ No newline at end of file
diff --git a/basecode/global.cpp b/basecode/global.cpp
index ec5a523e..b54fc979 100644
--- a/basecode/global.cpp
+++ b/basecode/global.cpp
@@ -87,7 +87,7 @@ namespace moose {
      *
      * @param x 
      */
-    void mtseed( unsigned int x )
+    void mtseed( int x )
     {
         moose::__rng_seed__ = x;
         moose::rng.setSeed( x );
diff --git a/basecode/global.h b/basecode/global.h
index 9b06b282..40b2dba5 100644
--- a/basecode/global.h
+++ b/basecode/global.h
@@ -109,7 +109,7 @@ namespace moose
      *
      * @param seed
      */
-    void mtseed( unsigned int seed );
+    void mtseed( int seed );
 
     /**
      * @brief Generate a random double between 0 and 1
diff --git a/biophysics/ReadSwc.cpp b/biophysics/ReadSwc.cpp
index 9894e047..3fde18ec 100644
--- a/biophysics/ReadSwc.cpp
+++ b/biophysics/ReadSwc.cpp
@@ -23,6 +23,7 @@ static const double MinRadius = 0.04;
 
 ReadSwc::ReadSwc( const string& fname )
 {
+	bool verbose = false;
 	ifstream fin( fname.c_str() );
 	if ( !fin ) {
 		cerr << "ReadSwc:: could not open file " << fname << endl;
@@ -52,12 +53,13 @@ ReadSwc::ReadSwc( const string& fname )
 		cleanZeroLength();
 		parseBranches();
 	}
-	cout << "ReadSwc: " << fname << "	: NumSegs = " << segs_.size() << 
+	cout << "ReadSwc: " << fname << "	: " << (valid ? "OK" : "FAILED" )<<
+			", # Branches = " << branches_.size() << 
+			". # Segs = " << segs_.size() << 
 			", bad = " << badSegs <<
-			", Validated = " << valid << 
-			", numBranches = " << branches_.size() << 
 			endl;
-	diagnostics();
+	if ( verbose )
+		diagnostics();
 }
 
 bool ReadSwc::validate() const
diff --git a/pymoose/CMakeLists.txt b/pymoose/CMakeLists.txt
index 83397de4..af4e8e74 100644
--- a/pymoose/CMakeLists.txt
+++ b/pymoose/CMakeLists.txt
@@ -1,6 +1,8 @@
 add_definitions(-DPYMOOSE)
 include_directories(../basecode ../msg)
 
+find_package( PythonInterp REQUIRED )
+
 set(PYMOOSE_SRCS 
     moosemodule.cpp
     vec.cpp
@@ -18,10 +20,18 @@ EXEC_PROGRAM(${PYTHON_EXECUTABLE}
 except Exception: pass'"
     OUTPUT_VARIABLE PYTHON_SO_EXTENSION
     )
+
+message( STATUS "Python path ${PYTHON_EXECUTABLE}" )
 message( STATUS "Python so extension ${PYTHON_SO_EXTENSION}" )
 
 find_package(NumPy REQUIRED)
-include_directories(${NUMPY_INCLUDE_DIRS})
+find_package(PythonLibs REQUIRED)
+
+include_directories( ${NUMPY_INCLUDE_DIRS} )
+include_directories( ${PYTHON_INCLUDE_DIRS} )
+
+message( STATUS "Python include dir : ${PYTHON_INCLUDE_DIRS} " )
+
 add_definitions(-DUSE_NUMPY)
 
 add_definitions(-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION)
@@ -34,7 +44,12 @@ execute_process( COMMAND ${PYTHON_EXECUTABLE}-config --libs
     OUTPUT_VARIABLE PYTHON_LIBRARIES
     OUTPUT_STRIP_TRAILING_WHITESPACE
     )
+
+if( NOT PYTHON_INCLUDE_FLAGS )
+    set( PYTHON_INCLUDE_FLAGS "-I ${PYTHON_INCLUDE_DIRS} " )
+endif( )
 message( STATUS "Python include flags: ${PYTHON_INCLUDE_FLAGS}" )
+
 set_target_properties(_moose PROPERTIES 
     COMPILE_DEFINITIONS "PYMOOSE"
     COMPILE_FLAGS "${PYTHON_INCLUDE_FLAGS}"
@@ -43,11 +58,6 @@ set_target_properties(_moose PROPERTIES
     SUFFIX ".so"
     )
 
-#if(NOT(PYTHON_SO_EXTENSION STREQUAL ""))
-#    set_target_properties(_moose PROPERTIES
-#    SUFFIX ${PYTHON_SO_EXTENSION})
-#endif()
-
 # see issue #80
 if(HDF5_LIBRARY_DIRS)
     set_target_properties( _moose PROPERTIES LINK_FLAGS "-L${HDF5_LIBRARY_DIRS}" )
diff --git a/python/moose/SBML/readSBML.py b/python/moose/SBML/readSBML.py
index 22044297..255d9678 100644
--- a/python/moose/SBML/readSBML.py
+++ b/python/moose/SBML/readSBML.py
@@ -66,11 +66,12 @@ def mooseReadSBML(filepath, loadpath, solver="ee"):
             '\n\t easy_install python-libsbml'
             '\n\t apt-get install python-libsbml'
             )
-        return None
+        return moose.element('/')
 
     if not os.path.isfile(filepath):
         print('%s is not found ' % filepath)
-        return None
+        return moose.element('/')
+
 
     with open(filepath, "r") as filep:
         filep = open(filepath, "r")
diff --git a/python/moose/plot_utils.py b/python/moose/plot_utils.py
index b2740954..94c8577e 100644
--- a/python/moose/plot_utils.py
+++ b/python/moose/plot_utils.py
@@ -135,7 +135,7 @@ def plotTables(tables, outfile=None, **kwargs):
     subplot = kwargs.get('subplot', True)
     for i, tname in enumerate(tables):
         if subplot:
-            plt.subplot(len(tables), 1, i)
+            plt.subplot(len(tables), 1, i+1)
         yvec = tables[tname].vector 
         xvec = np.linspace(0, moose.Clock('/clock').currentTime, len(yvec))
         plt.plot(xvec, yvec, label=tname)
@@ -165,7 +165,7 @@ def plotVector(vec, xvec = None, **options):
     :param vec: Given vector.
     :param **kwargs: Optional to pass to maplotlib.
     """
-
+    ax = options[ 'ax' ]
     assert type(vec) == np.ndarray, "Expected type %s" % type(vec)
     legend = options.get('legend', True)
 
@@ -176,28 +176,29 @@ def plotVector(vec, xvec = None, **options):
         xx = xvec[:]
 
     assert len(xx) == len(vec), "Expecting %s got %s" % (len(vec), len(xvec))
+    ax.plot(xx, vec, label=options.get('label', ''))
 
-    plt.plot(xx, vec, label=options.get('label', ''))
     if legend:
         # This may not be available on older version of matplotlib.
         try:
-            plt.legend(loc='best', framealpha=0.4)
+            ax.legend(loc='best', framealpha=0.4)
         except:
-            plt.legend(loc='best')
+            ax.legend(loc='best')
 
     if xvec is None:
-        plt.xlabel('Time (sec)')
+        ax.set_xlabel('Time (sec)')
     else:
-        plt.xlabel(options.get('xlabel', ''))
+        ax.set_xlabel(options.get('xlabel', ''))
     
-    plt.ylabel = options.get('ylabel', '')
-    plt.title(options.get('title', ''))
+    ax.set_ylabel = options.get('ylabel', '')
+    ax.set_title(options.get('title', ''))
 
     if(options.get('legend', True)):
         try:
-            plt.legend(loc='best', framealpha=0.4, prop={'size' : 9})
+            ax.legend(loc='best', framealpha=0.4, prop={'size' : 9})
         except:
-            plt.legend(loc='best', prop={'size' : 9})
+            ax.legend(loc='best', prop={'size' : 9})
+    return ax
 
 
 def saveRecords(records, xvec = None, **kwargs):
@@ -267,7 +268,7 @@ def plotRecords(records, xvec = None, **kwargs):
                 yvec = dataDict[k].vector
                 plotVector(yvec, xvec, label=k, **kwargs)
             else:
-                plt.subplot(len(dataDict), 1, i)
+                kwargs[ 'ax' ] = plt.subplot(len(dataDict), 1, i)
                 yvec = dataDict[k].vector
                 plotVector(yvec, xvec, label=k, **kwargs)
 
@@ -286,9 +287,13 @@ def plotRecords(records, xvec = None, **kwargs):
     else:
         plt.show()
 
+def plot_records( data_dict, xvec = None, **kwargs ):
+    """Renamed (deprecated)
+    """
+    return plot_tables( data_dict, xvec, **kwargs )
 
-def plot_records(data_dict, xvec = None, **kwargs):
-    """plot_records Plot given dictionary.
+def plot_tables(data_dict, xvec = None, **kwargs):
+    """plot_tables plots moose.Table stored in a dictionary.
 
     :param data_dict:
     :param xvec: If None, use moose.Clock to generate xvec.
@@ -300,7 +305,12 @@ def plot_records(data_dict, xvec = None, **kwargs):
     subplot = kwargs.get('subplot', False)
     filters = [ x.lower() for x in kwargs.get('filter', [])]
 
-    plt.figure(figsize=(10, 1.5*len(data_dict)))
+    ax = kwargs.get( 'ax', None )
+    if ax is None:
+        plt.figure(figsize=(10, 1.5*len(data_dict)))
+        if not subplot:
+            ax = plt.subplot( 1, 1, 1 )
+
     for i, k in enumerate(data_dict):
         pu.info("+ Plotting for %s" % k)
         plotThis = False
@@ -312,10 +322,10 @@ def plot_records(data_dict, xvec = None, **kwargs):
                 
         if plotThis:
             if not subplot: 
-                yvec = data_dict[k]
+                yvec = data_dict[k].vector
                 plotVector(yvec, xvec, label=k, **kwargs)
             else:
-                plt.subplot(len(data_dict), 1, i)
+                ax = plt.subplot(len(data_dict), 1, i)
                 yvec = data_dict[k]
                 plotVector(yvec, xvec, label=k, **kwargs)
     if subplot:
diff --git a/python/rdesigneur/rdesigneur.py b/python/rdesigneur/rdesigneur.py
index ed38fce9..632e7ead 100644
--- a/python/rdesigneur/rdesigneur.py
+++ b/python/rdesigneur/rdesigneur.py
@@ -80,6 +80,7 @@ class rdesigneur:
             useGssa = True,
             combineSegments = True,
             stealCellFromLibrary = False,
+            verbose = True,
             diffusionLength= 2e-6,
             meshLambda = -1.0,    #This is a backward compatibility hack
             temperature = 32,
@@ -111,6 +112,7 @@ class rdesigneur:
         self.useGssa = useGssa
         self.combineSegments = combineSegments
         self.stealCellFromLibrary = stealCellFromLibrary
+        self.verbose = verbose
         self.diffusionLength= diffusionLength
         if meshLambda > 0.0:
             print("Warning: meshLambda argument is deprecated. Please use 'diffusionLength' instead.\nFor now rdesigneur will accept this argument.")
@@ -201,7 +203,8 @@ class rdesigneur:
             self._buildMoogli()
             self._buildStims()
             self._configureClocks()
-            self._printModelStats()
+            if self.verbose:
+                self._printModelStats()
             self._savePlots()
 
         except BuildError as msg:
@@ -315,7 +318,8 @@ class rdesigneur:
                 return True
             if moose.exists( '/library/' + protoVec[0] ):
                 #moose.copy('/library/' + protoVec[0], '/library/', protoVec[1])
-                print('renaming /library/' + protoVec[0] + ' to ' + protoVec[1])
+                if self.verbose:
+                    print('renaming /library/' + protoVec[0] + ' to ' + protoVec[1])
                 moose.element( '/library/' + protoVec[0]).name = protoVec[1]
                 #moose.le( '/library' )
                 return True
@@ -596,6 +600,7 @@ class rdesigneur:
     def _buildMoogli( self ):
         knownFields = {
             'Vm':('CompartmentBase', 'getVm', 1000, 'Memb. Potential (mV)', -80.0, 40.0 ),
+            'initVm':('CompartmentBase', 'getInitVm', 1000, 'Init. Memb. Potl (mV)', -80.0, 40.0 ),
             'Im':('CompartmentBase', 'getIm', 1e9, 'Memb. current (nA)', -10.0, 10.0 ),
             'inject':('CompartmentBase', 'getInject', 1e9, 'inject current (nA)', -10.0, 10.0 ),
             'Gbar':('ChanBase', 'getGbar', 1e9, 'chan max conductance (nS)', 0.0, 1.0 ),
diff --git a/synapse/CMakeLists.txt b/synapse/CMakeLists.txt
index bb47b977..2b7d3622 100644
--- a/synapse/CMakeLists.txt
+++ b/synapse/CMakeLists.txt
@@ -1,5 +1,18 @@
 cmake_minimum_required(VERSION 2.8)
+
 include_directories( ../basecode ../utility ../kinetics)
 include_directories( ../external/muparser/include/ )
-file(GLOB SYNAPSE_SRCS *.cpp)
+
+set( SYNAPSE_SRCS 
+    GraupnerBrunel2012CaPlasticitySynHandler.cpp
+    RollingMatrix.cpp
+    SeqSynHandler.cpp
+    SimpleSynHandler.cpp
+    STDPSynapse.cpp
+    STDPSynHandler.cpp
+    Synapse.cpp
+    SynHandlerBase.cpp
+    testSynapse.cpp
+    )
+
 add_library(synapse ${SYNAPSE_SRCS} )
diff --git a/synapse/RollingMatrix.cpp b/synapse/RollingMatrix.cpp
index f4f5193f..01818a83 100644
--- a/synapse/RollingMatrix.cpp
+++ b/synapse/RollingMatrix.cpp
@@ -72,7 +72,7 @@ double RollingMatrix::dotProduct( const vector< double >& input,
 	unsigned int index = (row + currentStartRow_) % nrows_;
 	const SparseVector& sv = rows_[index];
 	unsigned int i2 = input.size()/2;
-	unsigned int istart = (startColumn <= i2) ? 0 : startColumn - i2;
+	unsigned int istart = (startColumn >= i2) ? 0 : i2-startColumn;
 	unsigned int colstart = (startColumn <= i2) ? 0 : startColumn - i2;
 	unsigned int iend = (sv.size()-startColumn > i2 ) ? input.size() :
 			i2 - startColumn + sv.size();
diff --git a/synapse/SeqSynHandler.cpp b/synapse/SeqSynHandler.cpp
index e6ca94f8..f31f9117 100644
--- a/synapse/SeqSynHandler.cpp
+++ b/synapse/SeqSynHandler.cpp
@@ -8,6 +8,7 @@
 **********************************************************************/
 
 #include <queue>
+#include "global.h"
 #include "header.h"
 #include "Synapse.h"
 #include "SynEvent.h"
@@ -105,6 +106,29 @@ const Cinfo* SeqSynHandler::initCinfo()
 			&SeqSynHandler::setSequenceScale,
 			&SeqSynHandler::getSequenceScale
 	);
+	static ValueFinfo< SeqSynHandler, vector< unsigned int > > synapseOrder(
+			"synapseOrder",
+			"Mapping of synapse input order to spatial order on syn array."
+			"Entries in this vector are indices which must remain smaller "
+			"than numSynapses. The system will fix up if you mess up. "
+			"It does not insist on unique mappings, but these are "
+			"desirable as outcome is undefined for repeated entries.",
+			&SeqSynHandler::setSynapseOrder,
+			&SeqSynHandler::getSynapseOrder
+	);
+	static ValueFinfo< SeqSynHandler, int > synapseOrderOption(
+			"synapseOrderOption",
+			"How to do the synapse order remapping. This rule stays in "
+			"place and guarantees safe mappings even if the number of "
+			"synapses is altered. Options:\n"
+		    "-2: User ordering.\n"
+		    "-1: Sequential ordering, 0 to numSynapses-1.\n"
+		    "0: Random ordering using existing system seed.\n"
+		    ">0: Random ordering using seed specified by this number\n"
+			"Default is -1, sequential ordering.",
+			&SeqSynHandler::setSynapseOrderOption,
+			&SeqSynHandler::getSynapseOrderOption
+	);
 	static ReadOnlyValueFinfo< SeqSynHandler, double > seqActivation(
 			"seqActivation",
 			"Reports summed activation of synaptic channel by sequence",
@@ -141,9 +165,11 @@ const Cinfo* SeqSynHandler::initCinfo()
 		&historyTime,				// Field
 		&sequenceScale,				// Field
 		&baseScale,					// Field
-		&seqActivation,				// Field
+		&synapseOrder,				// Field
+		&synapseOrderOption,		// Field
+		&seqActivation,				// ReadOnlyField
 		&plasticityScale,			// Field
-		&weightScaleVec,			// Field
+		&weightScaleVec,			// ReadOnlyField
 		&kernel,					// ReadOnlyField
 		&history					// ReadOnlyField
 	};
@@ -172,10 +198,11 @@ SeqSynHandler::SeqSynHandler()
 		kernelWidth_( 5 ),
 		historyTime_( 2.0 ), 
 		seqDt_ ( 1.0 ), 
-		sequenceScale_( 1.0 ),
 		baseScale_( 0.0 ),
+		sequenceScale_( 1.0 ),
 		plasticityScale_( 0.0 ),
-		seqActivation_( 0.0 )
+		seqActivation_( 0.0 ),
+		synapseOrderOption_( -1 ) // sequential ordering
 { 
 	history_.resize( numHistory(), 0 );
 }
@@ -208,6 +235,7 @@ void SeqSynHandler::vSetNumSynapses( const unsigned int v )
 	history_.resize( numHistory(), v );
 	latestSpikes_.resize( v, 0.0 );
 	weightScaleVec_.resize( v, 0.0 );
+	refillSynapseOrder( v );
 	updateKernel();
 }
 
@@ -227,6 +255,65 @@ Synapse* SeqSynHandler::vGetSynapse( unsigned int i )
 }
 
 //////////////////////////////////////////////////////////////////////
+
+// Checks for numbers bigger than the size. Replaces with
+// values within the range that have not yet been used.
+void SeqSynHandler::fixSynapseOrder() 
+{
+	unsigned int sz = synapseOrder_.size();
+	vector< unsigned int > availableEntries( sz );
+	iota( availableEntries.begin(), availableEntries.end(), 0 );
+	for( unsigned int i = 0; i < sz; ++i ) {
+		if ( synapseOrder_[i] < sz )
+			availableEntries[ synapseOrder_[i] ] = sz;
+	}
+	vector< unsigned int > ae;
+	for( unsigned int i = 0; i < sz; ++i )
+		if ( availableEntries[i] < sz )
+			ae.push_back( availableEntries[i] );
+
+	auto jj = ae.begin();
+	for( unsigned int i = 0; i < sz; ++i ) {
+		if ( synapseOrder_[i] >= sz )
+			synapseOrder_[i] = *jj++;
+	}
+}
+
+// Beautiful snippet from Lukasz Wiklendt on StackOverflow. Returns order
+// of entries in a vector.
+template <typename T> vector<size_t> sort_indexes(const vector<T> &v) {
+	// initialize original index locations
+	vector<size_t> idx(v.size());
+	iota(idx.begin(), idx.end(), 0);
+	// sort indexes based on comparing values in v
+	sort(idx.begin(), idx.end(),
+		[&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
+	return idx;
+}
+
+void SeqSynHandler::refillSynapseOrder( unsigned int newSize )
+{
+	if ( synapseOrderOption_ <= -2 ) { // User order
+		synapseOrder_.resize( newSize, newSize );
+		fixSynapseOrder();
+	} else if ( synapseOrderOption_ == -1 ) { // Ordered
+		synapseOrder_.resize( newSize );
+		for ( unsigned int i = 0 ; i < newSize; ++i )
+			synapseOrder_[i] = i;
+	} else {
+		synapseOrder_.resize( newSize );
+		if ( synapseOrderOption_ > 0 ) { // Specify seed explicitly
+                    moose::mtseed( synapseOrderOption_ );
+		}
+		vector< double > x;
+		for ( unsigned int i = 0; i < newSize; ++i )
+			x.push_back( moose::mtrand() );
+		auto idx = sort_indexes< double >( x );
+		for ( unsigned int i = 0; i < newSize; ++i )
+			synapseOrder_[i] = idx[i];
+	}
+}
+
 void SeqSynHandler::updateKernel()
 {
 	if ( kernelEquation_ == "" || seqDt_ < 1e-9 || historyTime_ < 1e-9 )
@@ -362,6 +449,29 @@ vector< double > SeqSynHandler::getHistory() const
 	return ret;
 }
 
+void SeqSynHandler::setSynapseOrder( vector< unsigned int > v )
+{
+	synapseOrder_ = v;
+	fixSynapseOrder();
+	synapseOrderOption_ = -2; // Set the flag to say it is User defined.
+}
+
+vector< unsigned int > SeqSynHandler::getSynapseOrder() const
+{
+	return synapseOrder_;
+}
+
+void SeqSynHandler::setSynapseOrderOption( int v )
+{
+	synapseOrderOption_ = v;
+	refillSynapseOrder( synapseOrder_.size() );
+}
+
+int SeqSynHandler::getSynapseOrderOption() const
+{
+	return synapseOrderOption_;
+}
+
 /////////////////////////////////////////////////////////////////////
 
 void SeqSynHandler::addSpike(unsigned int index, double time, double weight)
@@ -373,7 +483,9 @@ void SeqSynHandler::addSpike(unsigned int index, double time, double weight)
 	// slice. For now, to get it going for LIF neurons, this will do.
 	// Even in the general case we will probably have a very wide window
 	// for the latestSpikes slice.
-	latestSpikes_[index] += weight;
+	//
+	// Here we reorder the entries in latestSpikes by the synapse order.
+	latestSpikes_[ synapseOrder_[index] ] += weight;
 }
 
 unsigned int SeqSynHandler::addSynapse()
diff --git a/synapse/SeqSynHandler.h b/synapse/SeqSynHandler.h
index 73578b04..45217ba0 100644
--- a/synapse/SeqSynHandler.h
+++ b/synapse/SeqSynHandler.h
@@ -59,6 +59,10 @@ class SeqSynHandler: public SynHandlerBase
  		double getBaseScale() const;
 		void setSequenceScale( double v );
  		double getSequenceScale() const;
+		void setSynapseOrder( vector< unsigned int> v );
+ 		vector< unsigned int> getSynapseOrder() const;
+		void setSynapseOrderOption( int v );
+ 		int getSynapseOrderOption() const;
  		double getSeqActivation() const; // summed activation of syn chan
 		void setPlasticityScale( double v );
  		double getPlasticityScale() const;
@@ -69,6 +73,8 @@ class SeqSynHandler: public SynHandlerBase
 		////////////////////////////////////////////////////////////////
 		// Utility func
 		int numHistory() const;
+		void refillSynapseOrder( unsigned int newSize );
+		void fixSynapseOrder();
 		////////////////////////////////////////////////////////////////
 		static const Cinfo* initCinfo();
 	private:
@@ -116,8 +122,23 @@ class SeqSynHandler: public SynHandlerBase
 		vector< double > latestSpikes_; 
 
 		///////////////////////////////////////////
-		vector< vector<  double > > kernel_;	//Kernel for seq selectivity
-		RollingMatrix history_;	// Rows = time; cols = synInputs
+		vector< vector<  double > > kernel_; ///Kernel for seq selectivity
+		RollingMatrix history_;	/// Rows = time; cols = synInputs
+		/**
+		 * Remaps synapse order to avoid correlations based on presynaptic 
+		 * object Id order, or on connection building order. This 
+		 * undesirable ordering occurs even when random synaptic
+		 * projections are used. User can alter as preferred. This is 
+		 * simply a look up table so that the incoming synapse index is
+		 * remapped: index_on_Handler = synapseOrder_[original_syn_index]
+		 * This must only have numbers from zero to numSynapses, and should
+		 * normally have all the numbers.
+		 */
+		vector< unsigned int > synapseOrder_; 
+
+		/// Options: -2: User. -1: ordered. 0: random by system seed. 
+		/// > 0: Random by seed specified by this number
+		int synapseOrderOption_;
 
 		vector< Synapse > synapses_;
 		priority_queue< PreSynEvent, vector< PreSynEvent >, CompareSynEvent > events_;
diff --git a/synapse/testSynapse.cpp b/synapse/testSynapse.cpp
index 944525ff..b39b87bd 100644
--- a/synapse/testSynapse.cpp
+++ b/synapse/testSynapse.cpp
@@ -99,32 +99,44 @@ void testRollingMatrix()
 	for ( int i = 0; i < nr; ++i )
 			input[i] = i + 1;
 
-	assert( doubleEq( rm.dotProduct( input, 0, 0 ), 0.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 1, 0 ), 1.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 2, 0 ), 4.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 3, 0 ), 9.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 4, 0 ), 16.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 4, 1 ), 12.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 4, 2 ), 8.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 4, 3 ), 4.0 ) );
-	assert( doubleEq( rm.dotProduct( input, 4, 4 ), 0.0 ) );
-
+	assert( doubleEq( rm.dotProduct( input, 0, 5 ), 0.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 1, 5 ), 1.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 2, 5 ), 4.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 3, 5 ), 9.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 4, 5 ), 16.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 4, 6 ), 12.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 4, 7 ), 8.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 4, 8 ), 4.0 ) );
+	assert( doubleEq( rm.dotProduct( input, 4, 9 ), 0.0 ) );
+
+	// Note that the input and the row are aligned at col=5, the 
+	// middle of the input vector. 
 	rm.sumIntoRow( input, 0 );	// input == [1234500000]
 	vector< double > corr;
 	rm.correl( corr, input, 4 );	// rm[4] == [00040000]
-	assert( doubleEq( corr[0], 16.0 ) );
-	assert( doubleEq( corr[1], 12.0 ) );
-	assert( doubleEq( corr[2], 8.0 ) );
-	assert( doubleEq( corr[3], 4.0 ) );
-	assert( doubleEq( corr[4], 0.0 ) );
+	assert( doubleEq( corr[0], 0.0 ) );
+	assert( doubleEq( corr[1], 0.0 ) );
+	assert( doubleEq( corr[2], 0.0 ) );
+	assert( doubleEq( corr[3], 0.0 ) );
+	assert( doubleEq( corr[4], 20.0 ) );
+	assert( doubleEq( corr[5], 16.0 ) );
+	assert( doubleEq( corr[6], 12.0 ) );
+	assert( doubleEq( corr[7], 8.0 ) );
+	assert( doubleEq( corr[8], 4.0 ) );
+	assert( doubleEq( corr[9], 0.0 ) );
 
 	corr.assign( corr.size(), 0 );
 	rm.correl( corr, input, 0 );	// rm[0] == [1234500000]
-	assert( doubleEq( corr[0], 55.0 ) );
-	assert( doubleEq( corr[1], 40.0 ) );
-	assert( doubleEq( corr[2], 26.0 ) );
-	assert( doubleEq( corr[3], 14.0 ) );
-	assert( doubleEq( corr[4], 5.0 ) );
+	assert( doubleEq( corr[0], 0.0 ) );
+	assert( doubleEq( corr[1], 5.0 ) );
+	assert( doubleEq( corr[2], 14.0 ) );
+	assert( doubleEq( corr[3], 26.0 ) );
+	assert( doubleEq( corr[4], 40.0 ) );
+	assert( doubleEq( corr[5], 55.0 ) );
+	assert( doubleEq( corr[6], 40.0 ) );
+	assert( doubleEq( corr[7], 26.0 ) );
+	assert( doubleEq( corr[8], 14.0 ) );
+	assert( doubleEq( corr[9], 5.0 ) );
 
 	cout << "." << flush;
 }
@@ -158,14 +170,12 @@ void testSeqSynapse()
 
 	cout << "." << flush;
 
-        // FIXME: See issue BhallaLab/moose-core#174 
-        // ssh.setResponseScale( 1.0 );
+	ssh.setBaseScale( 1.0 );
+	ssh.setSequenceScale( 1.0 );
 	for ( int i = 0; i < numSyn; ++i ) {
 		ssh.addSpike( i, 0.0, 1.0 );
 	}
-
-        // FIXME: See issue BhallaLab/moose-core#174 
-	// ssh.setWeightScale( 1.0 );
+	ssh.setPlasticityScale( 1.0 );
 	ProcInfo p;
 
 	Eref sheller( Id().eref() );
@@ -177,14 +187,13 @@ void testSeqSynapse()
 	// Here we correlate the vector [1,1,1,1,1,1,1,1,1,1,1] with
 	// the kernel [4,1,-1,-1,-1]
 	// Other lines are zeros.
-	// Should really make the kernel mapping symmetrical.
-	assert( doubleEq( ssh.getSeqActivation(), 28.0 ) );
+	assert( doubleEq( ssh.getSeqActivation(), 14.0 ) );
 	vector< double > wts = ssh.getWeightScaleVec();
-	for ( int i = 0; i < numSyn-4; ++i )
+	for ( int i = 2; i < numSyn-2; ++i )
 		assert( doubleEq( wts[i], 2.0 ) );
-	assert( doubleEq( wts[6], 3 ) ); // Edge effects. Last -1 vanishes.
-	assert( doubleEq( wts[7], 4 ) ); // Edge effects. 
-	assert( doubleEq( wts[8], 5 ) ); // Edge effects.
+	assert( doubleEq( wts[0], -3 ) ); // Edge effects.
+	assert( doubleEq( wts[1], -2 ) ); // Edge effects. 
+	assert( doubleEq( wts[8], 3 ) ); // Edge effects.
 	assert( doubleEq( wts[9], 4 ) ); // Edge effects.
 		
 	cout << "." << flush;
-- 
GitLab