# -*- coding: utf-8 -*-
"""
ANN based on Todd's design
"""

from pybrain.structure.connections.connection import Connection
from pybrain.datasets.sequential import SequentialDataSet
from scipy import dot

class WeightedPartialIdentityConnection(Connection):
    """Connection which connects the i'th element from the first module's 
    output buffer to the i'th element of the second module's input buffer, 
    multiplying the output by a weight value except for nodes greater than a 
    given index."""

    def __init__(self, weight, maxIndex, *args, **kwargs):
        Connection.__init__(self, *args, **kwargs)
        assert self.indim == self.outdim, \
               "Indim (%i) does not equal outdim (%i)" % (
               self.indim, self.outdim)
        self.weight = weight
        self.maxIndex = maxIndex

    def _forwardImplementation(self, inbuf, outbuf):
        outbuf += dot([i*self.weight for i in inbuf],[1]*self.maxIndex + [0]*self.maxIndex)

    def _backwardImplementation(self, outerr, inerr, inbuf):
        inerr += dot([i*self.weight for i in outerr],[1]*self.maxIndex + [0]*self.maxIndex)

pitchCount = 12
planCount = 0

def sampleSize():
    return pitchCount + planCount + 1
    
def outputSize():
    return pitchCount + 1

def makeNoteSample(pitch, newNote, plan):
    sample = [0] * sampleSize()
    for i in range(pitchCount):
        if i == pitch:
            sample[i] = 1
        else:
            sample[i] = 0
    sample[pitchCount] = newNote
    for i in range(planCount):
        if i == plan or plan == None:
            # If there is no plan, use all the available plans so far
            sample[i+pitchCount+1] = 1
        else:
            sample[i+pitchCount+1] = 0
    return sample

class Melody():
    def __init__(self,plan):
        self.pitches = []
        self.newNotes = []
        self.plan = plan

    def addSamples(self, dataSet):
        for s in range(len(self.pitches)):
            dataSet.addSample(makeNoteSample(self.pitches[s], self.newNotes[s], self.plan))

    def addNote(self, pitch, newNote):
        self.pitches.append(pitch)
        self.newNotes.append(newNote)

def makeMelodyDataSet(melodies):
    seqDataSet = SequentialDataSet(sampleSize(), outputSize())
    for m in melodies:
        seqDataSet.newSequence()
        m.addSamples(seqDataSet)
    
    


@@ -117,16 +117,164 @@
 nection%0A
+from pybrain.structure import LinearLayer, SigmoidLayer%0Afrom pybrain.structure import RecurrentNetwork%0Afrom pybrain.structure import FullConnection%0A
 from pyb
@@ -1087,32 +1087,44 @@
 .maxIndex + %5B0%5D*
+(self.indim-
 self.maxIndex)%0A%0A
@@ -1121,16 +1121,17 @@
 axIndex)
+)
 %0A%0A    de
@@ -1262,16 +1262,28 @@
 x + %5B0%5D*
+(self.indim-
 self.max
@@ -1288,16 +1288,17 @@
 axIndex)
+)
 %0A%0ApitchC
@@ -1404,32 +1404,46 @@
 e():%0A    return 
+sampleSize() #
 pitchCount + 1%0A%0A
@@ -1918,16 +1918,298 @@
 n sample
+%0A    %0Adef makeNoteTarget(pitch, newNote):%0A    target = %5B0%5D * outputSize()%0A    for i in range(pitchCount):%0A        if i == pitch:%0A            target%5Bi%5D = 1%0A        else:%0A            target%5Bi%5D = 0%0A    target%5BpitchCount%5D = newNote%0A    #target = target + %5B0%5D*planCount%0A    return target
 %0A%0Aclass 
@@ -2401,16 +2401,18 @@
 pitches)
+-1
 ):%0A     
@@ -2496,16 +2496,101 @@
 lf.plan)
+,%0A                              makeNoteTarget(self.pitches%5Bs+1%5D, self.newNotes%5Bs+1%5D)
 )%0A%0A    d
@@ -2886,15 +2886,784 @@
 et)%0A    
-%0A    
+return seqDataSet%0A%0Adef buildToddNetwork():%0A    net = RecurrentNetwork()%0A    inLayer = LinearLayer(sampleSize())%0A    hiddenLayer = SigmoidLayer(6)%0A    outLayer = SigmoidLayer(outputSize())%0A    net.addInputModule(inLayer)%0A    net.addModule(hiddenLayer)%0A    net.addOutputModule(outLayer)%0A    inRecursive = WeightedPartialIdentityConnection(0.8, pitchCount, inLayer, inLayer)%0A    inToHidden = FullConnection(inLayer, hiddenLayer)%0A    hiddenToOut = FullConnection(hiddenLayer, outLayer)%0A    feedbackRecursive = WeightedPartialIdentityConnection(1, pitchCount, outLayer, inLayer)%0A    net.addRecurrentConnection(inRecursive)%0A    net.addConnection(inToHidden)%0A    net.addConnection(hiddenToOut)%0A    net.addRecurrentConnection(feedbackRecursive)%0A    net.sortModules()%0A    return net%0A
 %0A%0A

Fix sample, add network building