#!/usr/bin/env python
# coding: utf-8
# # SYDE 556/750: Simulating Neurobiological Systems
#
# ### Symbols and symbolic-like representations
# ## Symbols and Symbol-like representation in neurons
#
# - We've seen how to represent vectors in neurons
# - And how to compute functions on those vectors
# - And dynamical systems
# - But how can we do anything like human language?
# - How could we represent the fact that "the number after 8 is 9"
# - Or "dogs chase cats"
# - Or "Anne knows that Bill thinks that Charlie likes Dave"
# - Does the NEF help us at all with this?
# - Or is this just too hard a problem yet?
# ### Traditional Cognitive Science
#
# - Lots of theories that work with structured information like this
# - Pretty much all of them use some representation framework like this:
# - `after(eight, nine)`
# - `chase(dogs, cats)`
# - `knows(Anne, thinks(Bill, likes(Charlie, Dave)))`
#
# - Cognitive models manipulate these sorts of representations
# - mental arithmetic
# - driving a car
# - using a GUI
# - parsing language
# - etc etc
# - Seems to match well to behavioural data, so something like this should be right
# - So how can we do this in neurons?
#
# - This is a hard problem
# - Jackendoff (2002) posed this as a major problem
# - Four linguistic challenges for cognitive neuroscience
# - The Binding Problem
# - The Problem of 2
# - The Problem of Variables
# - Working Memory vs Long-term memory
# - The Binding Problem
# - Suppose you see a red square and a blue circle
# - How do you keep these ideas separate? How does "red" get bound with "square", and how is it kept separate from "blue" and "circle"?
# - The Problem of 2
# - "The little star's beside the big star"
# - How do we keep those two uses of "star" separate?
# - The Problem of Variables
# - Words seem to have types (nouns, verbs, adjectives, etc, etc)
# - How do you make use of that?
# - E.g. "blue *NOUN*" is fine, but "blue *VERB*" is not (or is very different)
# - Working memory vs Long-term memory
# - We can both use sentences (working memory) and store them indefinitely (long-term memory)
# - How do these transfer back and forth?
# - What are they in the brain? This seems to require moving from storing something in neural activity to storing it in connection weights
#
# ### Possible solutions
#
# 1. Oscillations
# - "red square and blue circle"
# - Different patterns of activity for RED, SQUARE, BLUE, and CIRCLE
# - Have the patterns for RED and SQUARE happen, then BLUE and CIRCLE, then back to RED and SQUARE
# - More complex structures possible too:
# - E.g. the LISA architecture
#
#
#
# - Problems
# - What controls this oscillation?
# - How is it parsed? (i.e., mapped to sets of oscillators)
# - How do we deal with the exponentional explosion of nodes needed?
#
# '2. Implementing Symbol Systems in Neurons
# - Build a general-purpose symbol-binding system
# - Lots of temporary pools of neurons
# - Ways to temporarily associate them with particular concepts
# - Ways to temporarily associate pools together
# - Neural Blackboard Architecture
#
#
#
# - Problems
# - Very particular structure (doesn't seem to match biology)
# - Uses a very large number of neurons (~500 million) to be flexible enough for simple sentences
# - And that's just to represent the sentence, never mind controlling and manipulating it
#
#
# '3. Vector operators
# - Paul Smolensky [1990](http://verbs.colorado.edu/~llbecker/papers/Smolensky-TensorProductVariableBinding.pdf) suggests using a mathematical operator called a 'tensor product' to bind vectors together.
# - The idea is that this operator can 'bind' and its inverse 'unbind' these vectors together.
# - It provides an algebraic way of specifying symbolic structures in a vector space.
# - If you can represent vector spaces and operators in neurons (e.g. NEF), then it provides a way of working with symbolic structures in neurons.
#
#
#
# - Problems
# - Every time you bind vectors, the result has $D^2$ as many dimensions.
# - It scales extremely poorly: the dimensionality of a structure representation is the base space to the power of depth, i.e. $D_S = D^{depth+1}$
#
#
# ### A deeper issue
# - If we're just implementing something like the original symbol system in neurons, then we're reducing the neural aspects to *mere implementational details*
# - That is, if we had a perfectly good way to implement symbol structures in neurons, then we could take existing cognitive theories based on symbol structures and implement them in neurons
# - But so what? That'd just be conceeding the point that the neurons don't matter -- you don't need them to develop the theory.
# - They're useful for testing some aspects, like what firing patterns should be
# - But it's more for completeness sake than for understanding
# - No more interesting than the question of "well, how does that neuron get implemented in terms of chemistry" or atoms. Or quarks.
# - This is why the majority of cognitive scientists don't worry about neurons
# ### Semantic pointers
#
# - Tensor products are on the right track, if we can solve the scaling problem.
# - 'How to build a brain' exploits a compression operator introduced by Tony Plate called 'circular convolution' $\circledast$
# - In the book, I suggest that neurally realized compressed vector representations are prevalent in the brain, and call such representations 'semantic pointers'
# - Pointers: because they can be used like computer science pointers to be efficient references to complex representations
# - Semantic: because (unlike CS pointers), their content is derived (through compression) from semantically related representations
#
#
# - This provides something that's similar to the symbolic approach, but much more tied to biology
# - Most of the same capabilities as the classic symbol systems
# - But not all
# - Based on vectors and functions on those vectors
# - There is a vector for each concept
# - Build up structures by doing math on those vectors
#
#
# - Example
# - blue square and red circle
# - can't just do BLUE+SQUARE+RED+CIRCLE
# - why?
# - need some other operation as well
# - Requirements
# - input 2 vectors, get a new vector as output
# - reversible (given the output and one of the input vectors, generate the other input vector)
# - output vector is highly dissimilar to either input vector
# - unlike addition, where the output is highly similar
#
# - Circular convoluation can act as such a function
# - (There are many other such functions: XOR, Multiply, etc... collectively this kind of vector space binding to represent structures are sometimes called 'Vector Symbolic Architectures' (Gayler, 2003))
#
# - Why circular convolution?
# - Extensively studied (Plate, 1997: Holographic Reduced Representations)
# - Easy to approximately invert (circular correlation)
#
# - Examples:
# - `BLUE` $\circledast$ `SQUARE + RED` $\circledast$ `CIRCLE`
# - `DOG` $\circledast$ `AGENT + CAT` $\circledast$ `THEME + VERB` $\circledast$ `CHASE`
#
#
# - unbinding:
#
#
#
#
#
#
# - Can also think of this operator as a compressed outer product
#
#
# - Lots of nice properties
# - Can store complex structures
# - `after(eight, nine)`
# - `NUMBER` $\circledast$ `EIGHT + NEXT` $\circledast$ `NINE`
# - `knows(Anne, thinks(Bill, likes(Charlie, Dave)))`
# - `SUBJ` $\circledast$ `ANNE + ACT` $\circledast$ `KNOWS + OBJ` $\circledast$ `(SUBJ` $\circledast$ `BILL + ACT` $\circledast$ `THINKS + OBJ` $\circledast$ `(SUBJ` $\circledast$ `CHARLIE + ACT` $\circledast$ `LIKES + OBJ` $\circledast$ `DAVE))`
# - But gracefully degrades!
# - as representation gets more complex, the accuracy of breaking it apart decreases
# - Keeps similarity information
# - if `RED` is similar to `PINK` then `RED` $\circledast$ `CIRCLE` is similar to `PINK` $\circledast$ `CIRCLE`
#
# - But rather complicated
# - Seems like a weird operation for neurons to do
# ### Circular convolution in the NEF
#
# - Or is it?
# - Circular convolution is a whole bunch ($D^2$) of multiplies
# - Like any convolution, it can also be written as a Fourier transform, an elementwise multiply, and another Fourier transform
# - i.e. $A \circledast B = IDFT(DFT(A).DFT(B)))$
# - The discrete fourier transform is just a linear operation, hence a matrix
# - So that's just $D$ pairwise multiplies
# - In fact, circular convolution turns out to be *exactly* what the NEF shows neurons are good at
# ### Jackendoff's Challenges
#
# - As pointed out in [Vector Symbolic Architectures Answer Jackendoff's Challenges for Cognitive Neuroscience](http://arxiv.org/ftp/cs/papers/0412/0412059.pdf)
# - The Binding Problem
# - There is a lot of "binding" (structurally combining items) in linguistics (more than vision)
# - `RED` $\circledast$ `CIRCLE + BLUE` $\circledast$ `TRIANGLE`
# - After it is bound, we can ask "what color is the circle by doing $\circledast$ `CIRCLE'`
# - where `'` is "inverse"
# - (`RED` $\circledast$ `CIRCLE + BLUE` $\circledast$ `TRIANGLE`) $\circledast$ `CIRCLE'`
# - = `RED` $\circledast$ `CIRCLE` $\circledast$ `CIRCLE' + BLUE` $\circledast$ `TRIANGLE` $\circledast$ `CIRCLE'`
# - = `RED + BLUE` $\circledast$ `TRIANGLE` $\circledast$ `CIRCLE'`
# - = `RED + noise`
# - $\approx$ `RED`
#
# - The Problem of 2
# - How can we distinguish two uses of the same concept in a sentence?
# - "The little star's beside the big star"
# - `OBJ1` $\circledast$ `(TYPE` $\circledast$ `STAR + SIZE` $\circledast$ `LITTLE) + OBJ2` $\circledast$ `(TYPE` $\circledast$ `STAR + SIZE` $\circledast$ `BIG) + BESIDE` $\circledast$ `OBJ1` $\circledast$ `OBJ2`
# - notice that `BESIDE` $\circledast$ `OBJ1` $\circledast$ `OBJ2` = `BESIDE` $\circledast$ `OBJ2` $\circledast$ `OBJ1`
# - and that we can distinguish the two uses of star
# - The Problem of Variables
# - How can we manipulate abstract place holders?
# - `S` = `RED` $\circledast$ `NOUN`
# - `VAR` = `BALL` $\circledast$ `NOUN'`
# - `S` $\circledast$ `VAR` = `RED` $\circledast$ `BALL`
# - Binding in Working Memory vs Long-term memory
# - How can we use and manipulate the same structures in both WM and LTM?
# - vectors are what we work with (activity of neurons)
# - functions are long-term memory (connection weights)
# - functions return (and modify) vectors
# ### Symbol-like manipulation
#
# - Can do a lot of standard symbol stuff
# - Have to explicitly bind and unbind to manipulate the data
# - Less accuracy for more complex structures
# - *But we can also do more with these representations*
#
#
#
# ### Raven's Progressive Matrices
#
# - An IQ test that's generally considered to be the best at measuring general-purpose "fluid" intelligence
# - nonverbal (so it's not measuring language skills, and fairly unbiased across cultures, hopefully)
# - fill in the blank
# - given eight possible answers; pick one
#
#
#
# - This is not an actual question on the test
# - The test is copyrighted
# - They don't want the test to leak out, since it's been the same set of 60 questions since 1936
# - But they do look like that
#
#
# - How can we model people doing this task?
# - A fair number of different attempts
# - None neural
# - Generally use the approach of building in a large set of different types of patterns to look for, and then trying them all in turn
# - Which seems wrong for a test that's supposed to be about flexible, fluid intelligence
#
# - Does this vector approach offer an alternative?
#
#
# - First we need to represent the different patterns as a vector
# - This is a hard image interpretation problem
# - Still ongoing work here
# - So we'll skip it and start with things in vector form
#
#
#
# - How do we represent a picture?
# - `SHAPE` $\circledast$ `ARROW + NUMBER` $\circledast$ `ONE + DIRECTION` $\circledast$ `UP`
# - can do variations like this for all the pictures
# - fairly standard with most assumptions about how people represent complex scenes
# - but that part is not being modelled (yet!)
#
# - We have shown that it's possible to build these sorts of representations up directly from visual stimuli
# - With a very simple vision system that can only recognize a few different shapes
# - And where items have to be shown sequentially as it has no way of moving its eyes
# ## Examples in Spaun
#
# - Let's look at a simpler but related example:
# - Binding used for building a list to remember
# In[14]:
from IPython.display import YouTubeVideo
YouTubeVideo('U_Q6Xjz9QHg', width=720, height=400, loop=1, autoplay=0, playlist='U_Q6Xjz9QHg')
# - The memory of the list is built up by using a basal ganglia action selection system to control feeding values into an integrator
# - The thought bubble shows how close the decoded values are to the ideal
# - Notice the forgetting!
#
#
#
# - The same system can be used to do a version of the Raven's Matrices task
# In[15]:
from IPython.display import YouTubeVideo
YouTubeVideo('Q_LRvnwnYp8', width=720, height=400, loop=1, autoplay=0, playlist='Q_LRvnwnYp8')
# - `S1 = ONE` $\circledast$ `P1`
# - `S2 = ONE` $\circledast$ `P1 + ONE` $\circledast$ `P2`
# - `S3 = ONE` $\circledast$ `P1 + ONE` $\circledast$ `P2 + ONE` $\circledast$ `P3`
# - `S4 = FOUR` $\circledast$ `P1`
# - `S5 = FOUR` $\circledast$ `P1 + FOUR` $\circledast$ `P2`
# - `S6 = FOUR` $\circledast$ `P1 + FOUR` $\circledast$ `P2 + FOUR` $\circledast$ `P3`
# - `S7 = FIVE` $\circledast$ `P1`
# - `S8 = FIVE` $\circledast$ `P1 + FIVE` $\circledast$ `P2`
#
# - what is `S9`?
# How does Spaun make a guess at the end?
#
# - Let's figure out what the transformation is
# - `T1 = S2` $\circledast$ `S1'`
# - `T2 = S3` $\circledast$ `S2'`
# - `T3 = S5` $\circledast$ `S4'`
# - `T4 = S6` $\circledast$ `S5'`
# - `T5 = S8` $\circledast$ `S7'`
#
# - `T = (T1 + T2 + T3 + T4 + T5)/5`
# - `S9 = S8` $\circledast$ `T`
#
# - `S9 = FIVE` $\circledast$ `P1 + FIVE` $\circledast$ `P2 + FIVE` $\circledast$ `P3`
#
# - This becomes a novel way of manipulating structured information
# - Exploiting the fact that it is a vector underneath
# - [A spiking neural model applied to the study of human performance and cognitive decline on Raven's Advanced Progressive Matrices](http://www.sciencedirect.com/science/article/pii/S0160289613001542)
# ### Using Nengo
# - How can we use Nengo to perform these kinds of operations?
# - There's a 'SPA' module you can import, and it lets you do all kinds of this stuff
# - Let's try answering simple questions about the bindings in a representation
# - I just stole this from the 'Question answering' example in Nengo
# In[16]:
get_ipython().run_line_magic('pylab', 'inline')
import nengo
from nengo import spa
# In[17]:
# Number of dimensions for the Semantic Pointers
dimensions = 32
model = spa.SPA(label="Simple question answering")
with model:
model.color_in = spa.Buffer(dimensions=dimensions)
model.shape_in = spa.Buffer(dimensions=dimensions)
model.conv = spa.Buffer(dimensions=dimensions)
model.cue = spa.Buffer(dimensions=dimensions)
model.out = spa.Buffer(dimensions=dimensions)
# Connect the buffers
cortical_actions = spa.Actions(
'conv = color_in * shape_in',
'out = conv * ~cue'
)
model.cortical = spa.Cortical(cortical_actions)
# The input will switch every 0.5 seconds between `RED` and `BLUE`. In the same way the shape input switches between `CIRCLE` and `SQUARE`. Thus, the network will bind alternatingly `RED * CIRCLE` and `BLUE * SQUARE` for 0.5 seconds each.
#
# The cue for deconvolving bound semantic pointers cycles through `CIRCLE`, `RED`, `SQUARE`, and `BLUE` within one second.
#
# In[18]:
def color_input(t):
if (t // 0.5) % 2 == 0:
return 'RED'
else:
return 'BLUE'
def shape_input(t):
if (t // 0.5) % 2 == 0:
return 'CIRCLE'
else:
return 'SQUARE'
def cue_input(t):
sequence = ['0', 'CIRCLE', 'RED', '0', 'SQUARE', 'BLUE']
idx = int((t // (1. / len(sequence))) % len(sequence))
return sequence[idx]
with model:
model.inp = spa.Input(color_in=color_input, shape_in=shape_input, cue=cue_input)
# In[19]:
with model:
model.config[nengo.Probe].synapse = nengo.Lowpass(0.03)
color_in = nengo.Probe(model.color_in.state.output)
shape_in = nengo.Probe(model.shape_in.state.output)
cue = nengo.Probe(model.cue.state.output)
conv = nengo.Probe(model.conv.state.output)
out = nengo.Probe(model.out.state.output)
# In[13]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/blue_red_spa.py.cfg")
# In[20]:
sim = nengo.Simulator(model)
sim.run(3.)
# In[21]:
plt.figure(figsize=(10, 10))
vocab = model.get_default_vocab(dimensions)
plt.subplot(5, 1, 1)
plt.plot(sim.trange(), model.similarity(sim.data, color_in))
plt.legend(model.get_output_vocab('color_in').keys, fontsize='x-small')
plt.ylabel("color")
plt.subplot(5, 1, 2)
plt.plot(sim.trange(), model.similarity(sim.data, shape_in))
plt.legend(model.get_output_vocab('shape_in').keys, fontsize='x-small')
plt.ylabel("shape")
plt.subplot(5, 1, 3)
plt.plot(sim.trange(), model.similarity(sim.data, cue))
plt.legend(model.get_output_vocab('cue').keys, fontsize='x-small')
plt.ylabel("cue")
plt.subplot(5, 1, 4)
for pointer in ['RED * CIRCLE', 'BLUE * SQUARE']:
plt.plot(sim.trange(), vocab.parse(pointer).dot(sim.data[conv].T), label=pointer)
plt.legend(fontsize='x-small')
plt.ylabel("convolved")
plt.subplot(5, 1, 5)
plt.plot(sim.trange(), spa.similarity(sim.data[out], vocab))
plt.legend(model.get_output_vocab('out').keys, fontsize='x-small')
plt.ylabel("output")
plt.xlabel("time [s]");
# In[22]:
sum(ens.n_neurons for ens in model.all_ensembles) #Total number of neurons
# In[ ]: