Ejemplo n.º 1
0
 def testConceptNetworkAddNodeTwice(self):
     "One node added twice implies an incremented occ"
     cn = ConceptNetwork()
     node = Node("Salut")
     cn.addNode(node)
     cn.addNode(node)
     self.assertEqual(2, node.getOcc())
Ejemplo n.º 2
0
    def testDumpLoad(self):
        "Test the saving of the Concept Network"
        conceptNetwork = ConceptNetwork()
        nodeFrom = Node("From")
        nodeTo1  = Node("To1")
        conceptNetwork.addNode(nodeFrom)
        conceptNetwork.addNode(nodeTo1)
        conceptNetwork.addLink(nodeFrom, nodeTo1)
        state = State(1)
        conceptNetwork.addState(state)
        state.setNodeActivationValue(100,"From")
        conceptNetwork.fastPropagateActivations(state,2)
        av = state.getNodeActivationValue("To1")

        f = open("cntest.data","w")
        try:
            conceptNetwork.dump(f,0)
        finally:
            f.close()

        f = open("cntest.data")
        try:
            cnLoaded = pickle.load(f)
        finally:
            f.close()

        import os
        os.remove("cntest.data")

        # No state is dumped!
        self.assertRaises(KeyError,cnLoaded.getState,1)

        nodeLoaded = cnLoaded.getNode("To1")
        self.assertTrue(nodeLoaded)
Ejemplo n.º 3
0
 def testConceptNetworkAddNodeTwice(self):
     "One node added twice implies an incremented occ"
     cn   = ConceptNetwork()
     node = Node("Salut")
     cn.addNode(node)
     cn.addNode(node)
     self.assertEqual(2,node.getOcc())
Ejemplo n.º 4
0
    def testDumpLoad(self):
        "Test the saving of the Concept Network"
        conceptNetwork = ConceptNetwork()
        nodeFrom = Node("From")
        nodeTo1 = Node("To1")
        conceptNetwork.addNode(nodeFrom)
        conceptNetwork.addNode(nodeTo1)
        conceptNetwork.addLink(nodeFrom, nodeTo1)
        state = State(1)
        conceptNetwork.addState(state)
        state.setNodeActivationValue(100, "From")
        conceptNetwork.fastPropagateActivations(state, 2)
        av = state.getNodeActivationValue("To1")

        f = open("cntest.data", "w")
        try:
            conceptNetwork.dump(f, 0)
        finally:
            f.close()

        f = open("cntest.data")
        try:
            cnLoaded = pickle.load(f)
        finally:
            f.close()

        import os
        os.remove("cntest.data")

        # No state is dumped!
        self.assertRaises(KeyError, cnLoaded.getState, 1)

        nodeLoaded = cnLoaded.getNode("To1")
        self.assertTrue(nodeLoaded)
Ejemplo n.º 5
0
 def testGetNodeStateTyped(self):
     "Test getting a node state with a type"
     cn    = ConceptNetwork()
     node1 = Node("Salut.")
     cn.addNode(node1)
     state = State(1)
     cn.addState(state)
     state.setNodeActivationValue(100, "Salut.","basic")
     self.assertEqual(100, state.getNodeActivationValue("Salut.","basic"))
Ejemplo n.º 6
0
 def testGetNodeStateTyped(self):
     "Test getting a node state with a type"
     cn = ConceptNetwork()
     node1 = Node("Salut.")
     cn.addNode(node1)
     state = State(1)
     cn.addState(state)
     state.setNodeActivationValue(100, "Salut.", "basic")
     self.assertEqual(100, state.getNodeActivationValue("Salut.", "basic"))
Ejemplo n.º 7
0
 def testCoOccLink(self):
     "Twice the same link -> its co-occurrence is incremented"
     conceptNetwork = ConceptNetwork()
     nodeFrom    = Node("from")
     nodeTo      = Node("to")
     conceptNetwork.addNode(nodeFrom)
     conceptNetwork.addNode(nodeTo)
     conceptNetwork.addLink(nodeFrom, nodeTo)
     link        = conceptNetwork.addLink(nodeFrom, nodeTo)
     self.assertEqual(2, link.getCoOcc())
Ejemplo n.º 8
0
 def testCoOccLink(self):
     "Twice the same link -> its co-occurrence is incremented"
     conceptNetwork = ConceptNetwork()
     nodeFrom = Node("from")
     nodeTo = Node("to")
     conceptNetwork.addNode(nodeFrom)
     conceptNetwork.addNode(nodeTo)
     conceptNetwork.addLink(nodeFrom, nodeTo)
     link = conceptNetwork.addLink(nodeFrom, nodeTo)
     self.assertEqual(2, link.getCoOcc())
Ejemplo n.º 9
0
 def testFastPropagation(self):
     "Test the propagation"
     conceptNetwork = ConceptNetwork()
     nodeFrom = Node("From")
     nodeTo1  = Node("To1")
     conceptNetwork.addNode(nodeFrom)
     conceptNetwork.addNode(nodeTo1)
     conceptNetwork.addLink(nodeFrom, nodeTo1)
     state = State(1)
     conceptNetwork.addState(state)
     state.setNodeActivationValue(100,"From","basic")
     conceptNetwork.fastPropagateActivations(state,2)
     self.assertEqual(True,state.getNodeActivationValue("To1") > 50)
Ejemplo n.º 10
0
 def testFastPropagation(self):
     "Test the propagation"
     conceptNetwork = ConceptNetwork()
     nodeFrom = Node("From")
     nodeTo1 = Node("To1")
     conceptNetwork.addNode(nodeFrom)
     conceptNetwork.addNode(nodeTo1)
     conceptNetwork.addLink(nodeFrom, nodeTo1)
     state = State(1)
     conceptNetwork.addState(state)
     state.setNodeActivationValue(100, "From", "basic")
     conceptNetwork.fastPropagateActivations(state, 2)
     self.assertEqual(True, state.getNodeActivationValue("To1") > 50)
Ejemplo n.º 11
0
 def testConceptNetworkGetNodeTyped(self):
     "Test getting a node with a type"
     class TestNode(Node):
         __type  = "test"
         __decay = 35
         def __init__(self, symbol, occ = 1):
             Node.__init__(self, symbol, occ=occ)
         def getTypeName(self):
             return self.__type
         def getDecay(self):
             return self.__decay
     cn    = ConceptNetwork()
     node1 = TestNode("Salut.")
     cn.addNode(node1)
     self.assertEqual(node1, cn.getNode("Salut.","test"))
     self.assertEqual("test", node1.getTypeName())
Ejemplo n.º 12
0
    def testAging(self):
        """See if a old node state is removed when too old.

        When a NodeState has more than 50 propagations, and that it is set to zero,
        it has to disappear from the state of the ConceptNetwork."""
        conceptNetwork = ConceptNetwork()
        nodeFrom = Node("From")
        nodeTo1  = Node("To1")
        conceptNetwork.addNode(nodeFrom)
        conceptNetwork.addNode(nodeTo1)
        conceptNetwork.addLink(nodeFrom, nodeTo1)
        state = State(1)
        conceptNetwork.addState(state)
        state.setNodeActivationValue(100,"From","basic")
        for i in range(0,51):
            conceptNetwork.fastPropagateActivations(state,2)
        state.setNodeActivationValue(0, "From", "basic")
        self.assertRaises(KeyError,state.nodeState.__getitem__,("From","basic"))
Ejemplo n.º 13
0
    def testAging(self):
        """See if a old node state is removed when too old.

        When a NodeState has more than 50 propagations, and that it is set to zero,
        it has to disappear from the state of the ConceptNetwork."""
        conceptNetwork = ConceptNetwork()
        nodeFrom = Node("From")
        nodeTo1 = Node("To1")
        conceptNetwork.addNode(nodeFrom)
        conceptNetwork.addNode(nodeTo1)
        conceptNetwork.addLink(nodeFrom, nodeTo1)
        state = State(1)
        conceptNetwork.addState(state)
        state.setNodeActivationValue(100, "From", "basic")
        for i in range(0, 51):
            conceptNetwork.fastPropagateActivations(state, 2)
        state.setNodeActivationValue(0, "From", "basic")
        self.assertRaises(KeyError, state.nodeState.__getitem__,
                          ("From", "basic"))
Ejemplo n.º 14
0
    def testConceptNetworkGetNodeTyped(self):
        "Test getting a node with a type"

        class TestNode(Node):
            __type = "test"
            __decay = 35

            def __init__(self, symbol, occ=1):
                Node.__init__(self, symbol, occ=occ)

            def getTypeName(self):
                return self.__type

            def getDecay(self):
                return self.__decay

        cn = ConceptNetwork()
        node1 = TestNode("Salut.")
        cn.addNode(node1)
        self.assertEqual(node1, cn.getNode("Salut.", "test"))
        self.assertEqual("test", node1.getTypeName())
Ejemplo n.º 15
0
class Ector:
    "The ECTOR class"

    def __init__(self, botname="Ector", username="******"):
        self.botname = botname
        self.username = username
        if os.path.exists("cn.pkl"):
            f = open("cn.pkl", "r")
            self.cn = pickle.load(f)
            f.close()
        else:
            self.cn = ConceptNetwork()
        self.loadUserState()
        self.prevsentences = "hello"

    def dump(self):
        """Save ECTOR.

        Save the ConceptNetwork in cn.pkl, and the state in usernameState.pkl"""
        # Save the ConceptNetwork
        f = open("cn.pkl", "w")
        self.cn.dump(f)
        f.close()
        # Save username's state
        if self.username:
            filename = self.__getStateId()
            f = open(filename, "w")
            state = self.cn.getState(self.username)
            pickle.dump(state, f)
            f.close()

    def showStatus(self):
        """Show Ector's status (ConceptNetwork stats, states)"""
        self.cn.showNodes()
        self.cn.showStates()

    def __getStateId(self):
        """Create a state id from the username"""
        return self.username + "_state.pkl"

    def setUser(self, username):
        """Change user's name.

        Create a new state, if it does not exist.
        """
        self.username = username
        try:
            self.cn.getState(username)
        except:
            self.loadUserState()

    def loadUserState(self):
        """Load the state matching username"""
        if self.username:
            filename = self.__getStateId()
            if os.path.exists(filename):
                f = open(filename, "r")
                state = pickle.load(f)
                f.close()
            else:
                state = State(self.username)
            self.cn.addState(state)

    def addEntry(self, entry):
        """Add an entry into the Concept Network of Ector.

        Add an entry into the Concept Network of Ector.
        An entry may be constituted from several sentences.
        When file is not NULL, it is taken instead utterer.

        - entry     entry to add

        Return the last sentenceNode of the entry.
        """
        state = self.cn.getState(self.username)
        e = Entry(entry, self.username, self.botname)
        sentences = e.getSentences()

        lastSentenceNode = None

        #print "sentence received is", sentences
        if "Wrong." in sentences[0]:
            sentences = sentences[1:len(sentences)]
            for sentence in sentences:
                sentenceNode = self.addSentence(sentence)
                state.fullyActivate(sentence, "sentence")
            if lastSentenceNode:
                self.cn.addLink(lastSentenceNode, sentenceNode)
            lastSentenceNode = sentenceNode
            self.prevsentences = sentences
            print lastSentenceNode
            return lastSentenceNode

        for sentence in sentences:
            sentenceNode = self.addSentence(sentence)
            state.fullyActivate(sentence, "sentence")
            if lastSentenceNode:
                self.cn.addLink(lastSentenceNode, sentenceNode)
            lastSentenceNode = sentenceNode
        self.prevsentences = sentences
        return lastSentenceNode

    def addSentence(self, sentence):
        """Add a sentence into the Concept Network of Ector.

        Add a sentence into the Concept Network of Ector.
        Adds its tokens too.

        /*
        except when
        the sentence already exists (in this case, the occurrence is not
        incremented, nor are expression created -this should lead to the
        creation of expressions identical to the sentence).
        */

        In the case where file exist, username is not
        taken into account, but file is, and is of type "file".

        -  sentence   sentence to add

        Return   the node of the sentence added."""
        state = self.cn.getState(self.username)
        # Activate the utterer, and add it to the concept network
        uttererNode = UttererNode(self.username)
        self.cn.addNode(uttererNode)
        state.fullyActivate(self.username, "utterer")
        # Add the sentence node to the concept network.
        sentenceNode = SentenceNode(sentence)
        self.cn.addNode(sentenceNode)
        #state.setNodeActivationValue(100, sentence, "sentence")
        state.fullyActivate(sentence, "sentence")
        # TODO: if the occurrence of the sentence node is only 1,
        #       compute the expressions
        pass
        # Link it to the utterer node.
        self.cn.addBidirectionalLink(uttererNode, sentenceNode)
        # Add the tokens to the concept network, link them to the sentence
        e = Entry("None")
        tokens = e.getTokens(sentence)
        beginning = 1
        middle = 0
        end = 0
        previousTokenNode = None
        i = 0
        for token in tokens:
            i += 1
            if i == len(tokens):
                end = 1
            # Add the token node to the concept network
            tokenNode = TokenNode(token, 1, beginning, middle, end)
            self.cn.addNode(tokenNode)
            state.fullyActivate(token, "token")
            if beginning:
                beginning = 0
                middle = 1
            if middle and i == len(tokens) - 1:
                middle = 0
                end = 1
            # Link it to the previous node
            if previousTokenNode:
                self.cn.addLink(previousTokenNode, tokenNode)
            previousTokenNode = tokenNode
            # Link it to the sentence node
            self.cn.addBidirectionalLink(tokenNode, sentenceNode)
        return sentenceNode

    def propagate(self, times=1):
        """Propagate the activation in the state of the utterer"""
        state = self.cn.getState(self.username)
        for i in range(times):
            self.cn.fastPropagateActivations(state)

    def getActivatedSentenceNode(self):
        """Get one of the most activated sentences"""
        state = self.cn.getState(self.username)
        maximumAV = state.getMaximumActivationValue(self.cn, "sentence")
        sentences = state.getActivatedTypedNodes(self.cn, "sentence",
                                                 maximumAV - 10)
        # TODO: compute a temperature according the state's activations
        temperature = Temperature(60)
        if sentences:
            sentenceNode = temperature.chooseWeightedItem(sentences)
            return sentenceNode
        else:
            return ''

    def showState(self, stateID):
        """Show the state matching stateID"""
        state = self.cn.getState(stateID)
        state.showNodes()

    def showLinks(self, stateId=None):
        """Show the links of the concept network, using stateID"""
        if stateId == None:
            stateId = self.username
        state = self.cn.getState(stateId)
        self.cn.showLinks(stateId)

    def generateForward(self, phrase, temperature):
        """Generate the end of a sentence, adding tokens to the list
        of token nodes in phrase."""
        state = self.cn.getState(self.username)
        outgoingLinks = phrase[-1].outgoingLinks
        nextNodes = []
        for link in outgoingLinks:
            toNode = link.getNodeTo()
            if toNode.getTypeName() == "token":
                av = state.getNodeActivationValue(toNode.getSymbol(), "token")
                if av == 0:
                    av = 1
                nbRepet = phrase.count(toNode)
                length = len(toNode.getSymbol())
                # If the node is not present more than 3 times
                if nbRepet * length <= 5 * 3:
                    repetition = 1 + nbRepet * nbRepet * length
                    nextNodes += [(toNode, link.getCoOcc() * av / repetition)]
        # Stop condition
        if len(nextNodes) == 0:
            return phrase
        # Choose one node among the tokens following the one at the end
        # of the phrase
        chosenToken = temperature.chooseWeightedItem(nextNodes)
        phrase += [chosenToken]

        return self.generateForward(phrase, temperature)

    def generateBackward(self, phrase, temperature):
        """Generate the beginning of a sentence, adding tokens to the list
        of token nodes in phrase."""
        state = self.cn.getState(self.username)
        incomingLinks = phrase[0].incomingLinks
        #        previousNodes    = [(link.getNodeFrom(), link.getCoOc())
        #                            for link in incomingLinks
        #                            if link.getNodeFrom().getTypeName() == "token"]
        previousNodes = []
        for link in incomingLinks:
            fromNode = link.getNodeFrom()
            if fromNode.getTypeName() == "token":
                av = state.getNodeActivationValue(fromNode.getSymbol(),
                                                  "token")
                if av == 0:
                    av = 1
                nbRepet = phrase.count(fromNode)
                length = len(fromNode.getSymbol())
                # If the node is not present more than 3 times
                if nbRepet * length <= 5 * 3:
                    repetition = 1 + nbRepet * nbRepet * length
                    previousNodes += [(link.getNodeFrom(),
                                       link.getCoOcc() * av)]
        # Stop condition
        if len(previousNodes) == 0:
            return phrase
        # Choose one node among the tokens preceding the one at the beginning
        # of the phrase
        chosenToken = temperature.chooseWeightedItem(previousNodes)
        phrase = [chosenToken] + phrase

        return self.generateBackward(phrase, temperature)

    def generateSentence(self, debug=False):
        """Get one node, generate a sentence from it forwards to the end
        of the sentence, and then generate backwards to the beginning of
        the sentence.

        Return a tuple containing the generated sentence as a string and
        the nodes of the sentence."""
        # Choose a token node among the most activated
        state = self.cn.getState(self.username)
        maximumAV = state.getMaximumActivationValue(self.cn, "token")
        tokens = state.getActivatedTypedNodes(self.cn, "token", maximumAV - 10)
        # TODO: compute a temperature according the state's activations
        temperature = Temperature(60)
        chosenToken = temperature.chooseWeightedItem(tokens)

        phrase = [chosenToken]
        # Generate forwards
        phrase = self.generateForward(phrase, temperature)
        # Generate backwards
        phrase = self.generateBackward(phrase, temperature)
        strPhrase = [token.getSymbol() for token in phrase]
        if debug:
            return (("_".join(strPhrase)) + " (%s)" % chosenToken.getSymbol(),
                    phrase)
        else:
            return (self.beautifySentence(" ".join(strPhrase)), phrase)

    def beautifySentence(self, sentence):
        """Beautify a string, which is a generated sentence, where
        tokens (words and punctuation) are separated by spaces.

        No need to get a space between a word and a comma."""
        sentence = sentence.replace(" , ", ", ")
        sentence = sentence.replace(" .", ".")
        sentence = sentence.replace(" : ", ": ")
        sentence = sentence.replace(" !", "!")
        sentence = sentence.replace(" ?", "?")
        sentence = sentence.replace(" ' ", "'")
        sentence = sentence.replace(" ( ", " (")
        sentence = sentence.replace(" )", ")")
        sentence = sentence.replace(" - ", "-")
        return sentence

    def cleanState(self):
        """Clean the not activated nodes states in the state"""
        state = self.cn.getState(self.username)
        state.clean()
Ejemplo n.º 16
0
 def testConceptNetworkGetNode(self):
     "Test getting a node from a Concept Network after adding it"
     cn    = ConceptNetwork()
     node1 = Node("Salut")
     cn.addNode(node1)
     self.assertEqual(node1, cn.getNode("Salut","basic"))
Ejemplo n.º 17
0
 def testConceptNetworkGetNode(self):
     "Test getting a node from a Concept Network after adding it"
     cn = ConceptNetwork()
     node1 = Node("Salut")
     cn.addNode(node1)
     self.assertEqual(node1, cn.getNode("Salut", "basic"))
Ejemplo n.º 18
0
class Ector:
    "The ECTOR class"
    def __init__(self,botname="Ector",username="******"):
        self.botname  = botname
        self.username = username
        if os.path.exists("cn.pkl"):
            f    = open("cn.pkl","r")
            self.cn    = pickle.load(f)
            f.close()
        else:
            self.cn    = ConceptNetwork()
        self.loadUserState()

    def dump(self):
        """Save ECTOR.

        Save the ConceptNetwork in cn.pkl, and the state in usernameState.pkl"""
        # Save the ConceptNetwork
        f = open("cn.pkl","w")
        self.cn.dump(f)
        f.close()
        # Save username's state
        if self.username:
            filename = self.__getStateId()
            f        = open(filename,"w")
            state    = self.cn.getState(self.username)
            pickle.dump(state,f)
            f.close()

    def showStatus(self):
        """Show Ector's status (ConceptNetwork stats, states)"""
        self.cn.showNodes()
        self.cn.showStates()

    def __getStateId(self):
        """Create a state id from the username"""
        return self.username + "_state.pkl"

    def setUser(self,username):
        """Change user's name.

        Create a new state, if it does not exist.
        """
        self.username    = username
        try:
            self.cn.getState(username)
        except:
            self.loadUserState()

    def loadUserState(self):
        """Load the state matching username"""
        if self.username:
            filename    = self.__getStateId()
            if os.path.exists(filename):
                f           = open(filename,"r")
                state       = pickle.load(f)
                f.close()
            else:
                state    = State(self.username)
            self.cn.addState(state)

    def addEntry(self,entry):
        """Add an entry into the Concept Network of Ector.

        Add an entry into the Concept Network of Ector.
        An entry may be constituted from several sentences.
        When file is not NULL, it is taken instead utterer.

        - entry     entry to add

        Return the last sentenceNode of the entry.
        """
        state               = self.cn.getState(self.username)
        e = Entry(entry, self.username, self.botname)
        sentences           = e.getSentences()
        lastSentenceNode    = None
        for sentence in sentences:
            sentenceNode = self.addSentence(sentence)
            state.fullyActivate(sentence, "sentence")
            if lastSentenceNode:
                self.cn.addLink(lastSentenceNode,sentenceNode)
            lastSentenceNode = sentenceNode
        return lastSentenceNode

    def addSentence(self,sentence):
        """Add a sentence into the Concept Network of Ector.

        Add a sentence into the Concept Network of Ector.
        Adds its tokens too.

        /*
        except when
        the sentence already exists (in this case, the occurrence is not
        incremented, nor are expression created -this should lead to the
        creation of expressions identical to the sentence).
        */

        In the case where file exist, username is not
        taken into account, but file is, and is of type "file".

        -  sentence   sentence to add

        Return   the node of the sentence added."""
        state          = self.cn.getState(self.username)
        # Activate the utterer, and add it to the concept network
        uttererNode    = UttererNode(self.username)
        self.cn.addNode(uttererNode)
        state.fullyActivate(self.username, "utterer")
        # Add the sentence node to the concept network.
        sentenceNode   = SentenceNode(sentence)
        self.cn.addNode(sentenceNode)
        #state.setNodeActivationValue(100, sentence, "sentence")
        state.fullyActivate(sentence, "sentence")
        # TODO: if the occurrence of the sentence node is only 1,
        #       compute the expressions
        pass
        # Link it to the utterer node.
        self.cn.addBidirectionalLink(uttererNode, sentenceNode)
        # Add the tokens to the concept network, link them to the sentence
        e                 = Entry("None")
        tokens            = e.getTokens(sentence)
        beginning         = 1
        middle            = 0
        end               = 0
        previousTokenNode = None
        i                 = 0
        for token in tokens:
            i += 1
            if i == len(tokens):
                end    = 1
            # Add the token node to the concept network
            tokenNode = TokenNode(token, 1, beginning, middle, end)
            self.cn.addNode(tokenNode)
            state.fullyActivate(token, "token")
            if beginning:
                beginning = 0
                middle    = 1
            if middle and i == len(tokens) - 1:
                middle    = 0
                end       = 1
            # Link it to the previous node
            if previousTokenNode:
                self.cn.addLink(previousTokenNode,tokenNode)
            previousTokenNode = tokenNode
            # Link it to the sentence node
            self.cn.addBidirectionalLink(tokenNode, sentenceNode)
        return sentenceNode

    def propagate(self,times=1):
        """Propagate the activation in the state of the utterer"""
        state = self.cn.getState(self.username)
        for i in range(times):
            self.cn.fastPropagateActivations(state)

    def getActivatedSentenceNode(self):
        """Get one of the most activated sentences"""
        state        = self.cn.getState(self.username)
        maximumAV    = state.getMaximumActivationValue(self.cn, "sentence")
        sentences    = state.getActivatedTypedNodes(self.cn, "sentence",
                                                    maximumAV - 10)
        # TODO: compute a temperature according the state's activations
        temperature  = Temperature(60)
        if sentences:
            sentenceNode = temperature.chooseWeightedItem(sentences)
            return sentenceNode
        else:
            return ''

    def showState(self, stateID):
        """Show the state matching stateID"""
        state        = self.cn.getState(stateID)
        state.showNodes()

    def showLinks(self, stateId=None):
        """Show the links of the concept network, using stateID"""
        if stateId == None:
            stateId = self.username
        state    = self.cn.getState(stateId)
        self.cn.showLinks(stateId)

    def generateForward(self, phrase, temperature):
        """Generate the end of a sentence, adding tokens to the list
        of token nodes in phrase."""
        state     = self.cn.getState(self.username)
        outgoingLinks    = phrase[-1].outgoingLinks
        nextNodes    = []
        for link in outgoingLinks:
            toNode    = link.getNodeTo()
            if toNode.getTypeName() == "token":
                av    = state.getNodeActivationValue(toNode.getSymbol(), "token")
                if av == 0:
                    av = 1
                nbRepet    = phrase.count(toNode)
                length     = len(toNode.getSymbol())
                # If the node is not present more than 3 times
                if nbRepet * length <= 5 * 3:
                    repetition    = 1 + nbRepet * nbRepet * length
                    nextNodes    += [(toNode, link.getCoOcc() * av / repetition)]
        # Stop condition
        if len(nextNodes) == 0:
            return phrase
        # Choose one node among the tokens following the one at the end
        # of the phrase
        chosenToken    = temperature.chooseWeightedItem(nextNodes)
        phrase        += [chosenToken]

        return self.generateForward(phrase, temperature)

    def generateBackward(self, phrase, temperature):
        """Generate the beginning of a sentence, adding tokens to the list
        of token nodes in phrase."""
        state     = self.cn.getState(self.username)
        incomingLinks    = phrase[0].incomingLinks
#        previousNodes    = [(link.getNodeFrom(), link.getCoOc())
#                            for link in incomingLinks
#                            if link.getNodeFrom().getTypeName() == "token"]
        previousNodes    = []
        for link in incomingLinks:
            fromNode    = link.getNodeFrom()
            if fromNode.getTypeName() == "token":
                av    = state.getNodeActivationValue(fromNode.getSymbol(), "token")
                if av == 0:
                    av = 1
                nbRepet    = phrase.count(fromNode)
                length     = len(fromNode.getSymbol())
                # If the node is not present more than 3 times
                if nbRepet * length <= 5 * 3:
                    repetition    = 1 + nbRepet * nbRepet * length
                    previousNodes    += [(link.getNodeFrom(), link.getCoOcc() * av)]
        # Stop condition
        if len(previousNodes) == 0:
            return phrase
        # Choose one node among the tokens preceding the one at the beginning
        # of the phrase
        chosenToken   = temperature.chooseWeightedItem(previousNodes)
        phrase        = [chosenToken] + phrase

        return self.generateBackward(phrase, temperature)

    def generateSentence(self, debug=False):
        """Get one node, generate a sentence from it forwards to the end
        of the sentence, and then generate backwards to the beginning of
        the sentence.

        Return a tuple containing the generated sentence as a string and
        the nodes of the sentence."""
        # Choose a token node among the most activated
        state     = self.cn.getState(self.username)
        maximumAV = state.getMaximumActivationValue(self.cn, "token")
        tokens    = state.getActivatedTypedNodes(self.cn,"token",
                                                 maximumAV - 10)
        # TODO: compute a temperature according the state's activations
        temperature    = Temperature(60)
        chosenToken    = temperature.chooseWeightedItem(tokens)

        phrase    = [chosenToken]
        # Generate forwards
        phrase    = self.generateForward(phrase, temperature)
        # Generate backwards
        phrase    = self.generateBackward(phrase, temperature)
        strPhrase = [token.getSymbol() for token in phrase]
        if debug:
            return (("_".join(strPhrase)) + " (%s)" % chosenToken.getSymbol(),
                    phrase)
        else:
            return (self.beautifySentence(" ".join(strPhrase)),
                    phrase)

    def beautifySentence(self, sentence):
        """Beautify a string, which is a generated sentence, where
        tokens (words and punctuation) are separated by spaces.

        No need to get a space between a word and a comma."""
        sentence    = sentence.replace(" , ",    ", ")
        sentence    = sentence.replace(" .",     ".")
        sentence    = sentence.replace(" : ",    ": ")
        sentence    = sentence.replace(" !",     "!")
        sentence    = sentence.replace(" ?",     "?")
        sentence    = sentence.replace(" ' ",    "'")
        sentence    = sentence.replace(" ( ",    " (")
        sentence    = sentence.replace(" )",     ")")
        sentence    = sentence.replace(" - ",    "-")
        return sentence

    def cleanState(self):
        """Clean the not activated nodes states in the state"""
        state     = self.cn.getState(self.username)
        state.clean()