[dasher] AlphabetManager subgroups populate themselves lazily, rather than use NF_SUBNODE



commit 63f418f6040d8c4926fa4fd30ab4964fb8e29386
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Tue Nov 24 10:58:34 2009 +0000

    AlphabetManager subgroups populate themselves lazily, rather than use NF_SUBNODE
    
      *Split CAlphNode into CSymbolNode and CGroupNode; latter stores state for lazy
      *IterateChildGroups (once RecursiveIterateGroup but no longer recurses)
      *combine code (mostly) common to GetRoot+RebuildParent into BuildNodeForOffset
      *Fix rendering: outlines, "invisible" nodes, nodes filling parent copy colour
      *Removed vSymbols vector from GetProbs etc. - was filled w/ vSymbols[i]==i !
      *Added DasherNode::ExpectedNumChildren
        *AlphIO counts & CAlphabet & SGroupInfo store no. of immediate child nodes
          (characters/subgroups, inc space/paragraph/start&end conversion symbols)
        *SCENode stores children in vector; ConversionHelper builds upon 1st request

 Src/DasherCore/Alphabet/AlphIO.cpp                 |    8 +
 Src/DasherCore/Alphabet/AlphIO.h                   |    1 +
 Src/DasherCore/Alphabet/Alphabet.cpp               |    2 +-
 Src/DasherCore/Alphabet/Alphabet.h                 |    2 +-
 Src/DasherCore/Alphabet/GroupInfo.h                |    1 +
 Src/DasherCore/AlphabetManager.cpp                 |  402 ++++++++++---------
 Src/DasherCore/AlphabetManager.h                   |  115 ++++---
 Src/DasherCore/ControlManager.cpp                  |    4 +-
 Src/DasherCore/ControlManager.h                    |    1 +
 Src/DasherCore/ConversionHelper.cpp                |  166 ++-------
 Src/DasherCore/ConversionHelper.h                  |    7 +-
 Src/DasherCore/ConversionManager.cpp               |   22 +-
 Src/DasherCore/ConversionManager.h                 |    1 +
 Src/DasherCore/DasherModel.cpp                     |   14 +-
 Src/DasherCore/DasherNode.h                        |    5 +
 Src/DasherCore/DasherViewSquare.cpp                |    6 +-
 .../LanguageModelling/PPMPYLanguageModel.cpp       |  115 +++---
 .../LanguageModelling/PPMPYLanguageModel.h         |    2 +-
 Src/DasherCore/MandarinAlphMgr.cpp                 |   17 +-
 Src/DasherCore/MandarinAlphMgr.h                   |    8 +-
 Src/DasherCore/NodeCreationManager.cpp             |    9 +-
 Src/DasherCore/NodeCreationManager.h               |    2 +-
 Src/DasherCore/PinYinConversionHelper.cpp          |   44 +--
 Src/DasherCore/PinYinConversionHelper.h            |    4 +-
 Src/DasherCore/PinyinParser.cpp                    |   14 +-
 Src/DasherCore/SCENode.cpp                         |   31 +--
 Src/DasherCore/SCENode.h                           |   23 +-
 27 files changed, 442 insertions(+), 584 deletions(-)
---
diff --git a/Src/DasherCore/Alphabet/AlphIO.cpp b/Src/DasherCore/Alphabet/AlphIO.cpp
index 130f0c1..53072da 100644
--- a/Src/DasherCore/Alphabet/AlphIO.cpp
+++ b/Src/DasherCore/Alphabet/AlphIO.cpp
@@ -421,6 +421,7 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
     Me->InputInfo.EndConvertCharacter.Text = "";
     Me->InputInfo.m_iCharacters = 1; // Start at 1 as 0 is the root node symbol
     Me->InputInfo.m_pBaseGroup = 0;
+    Me->InputInfo.iNumChildNodes = 1; // the "root node" symbol (with text "")
     Me->bFirstGroup = true;
     Me->iGroupIdx = 0;
     while(*atts != 0) {
@@ -552,8 +553,10 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
 
   if(strcmp(name, "group") == 0) {
     SGroupInfo *pNewGroup(new SGroupInfo);
+    pNewGroup->iNumChildNodes=0;
     pNewGroup->iColour = (Me->iGroupIdx % 3) + 110; 
     ++Me->iGroupIdx;
+    if (Me->m_vGroups.empty()) Me->InputInfo.iNumChildNodes++; else Me->m_vGroups.back()->iNumChildNodes++;
 
     if(Me->bFirstGroup) {
       pNewGroup->bVisible = false;
@@ -696,6 +699,7 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
     AlphInfo::character NewCharacter;
 
     ++Me->InputInfo.m_iCharacters;
+    if (Me->m_vGroups.empty()) Me->InputInfo.iNumChildNodes++; else Me->m_vGroups.back()->iNumChildNodes++;
 
     NewCharacter.Colour = -1;
 
@@ -751,6 +755,10 @@ void CAlphIO::XML_EndElement(void *userData, const XML_Char *name) {
 
   if(strcmp(name, "alphabet") == 0) {
     Reverse(Me->InputInfo.m_pBaseGroup);
+    if (Me->InputInfo.SpaceCharacter.Text != "") Me->InputInfo.iNumChildNodes++;
+    if (Me->InputInfo.ParagraphCharacter.Text != "") Me->InputInfo.iNumChildNodes++;
+    if (Me->InputInfo.StartConvertCharacter.Text != "") Me->InputInfo.iNumChildNodes++;
+    if (Me->InputInfo.EndConvertCharacter.Text != "") Me->InputInfo.iNumChildNodes++;
     Me->Alphabets[Me->InputInfo.AlphID] = Me->InputInfo;
     return;
   }
diff --git a/Src/DasherCore/Alphabet/AlphIO.h b/Src/DasherCore/Alphabet/AlphIO.h
index e9ae602..2e90f96 100644
--- a/Src/DasherCore/Alphabet/AlphIO.h
+++ b/Src/DasherCore/Alphabet/AlphIO.h
@@ -76,6 +76,7 @@ public:
 
     int m_iCharacters;
     SGroupInfo *m_pBaseGroup;
+    int iNumChildNodes;
 
     std::vector<character> m_vCharacters;
 
diff --git a/Src/DasherCore/Alphabet/Alphabet.cpp b/Src/DasherCore/Alphabet/Alphabet.cpp
index 875578e..2bfa11a 100644
--- a/Src/DasherCore/Alphabet/Alphabet.cpp
+++ b/Src/DasherCore/Alphabet/Alphabet.cpp
@@ -111,7 +111,7 @@ CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo)
   // New group stuff
 
   m_pBaseGroup = AlphInfo.m_pBaseGroup;
-
+  iNumChildNodes = AlphInfo.iNumChildNodes;
 #ifdef DASHER_TRACE
   Trace();
 #endif
diff --git a/Src/DasherCore/Alphabet/Alphabet.h b/Src/DasherCore/Alphabet/Alphabet.h
index f2df2fc..6822019 100644
--- a/Src/DasherCore/Alphabet/Alphabet.h
+++ b/Src/DasherCore/Alphabet/Alphabet.h
@@ -135,7 +135,7 @@ namespace Dasher {
     }
 
     SGroupInfo *m_pBaseGroup;
-
+    int iNumChildNodes;
   private:
 
     // Add the characters that can appear in Nodes
diff --git a/Src/DasherCore/Alphabet/GroupInfo.h b/Src/DasherCore/Alphabet/GroupInfo.h
index 6f738a1..4ce1b3d 100644
--- a/Src/DasherCore/Alphabet/GroupInfo.h
+++ b/Src/DasherCore/Alphabet/GroupInfo.h
@@ -12,6 +12,7 @@ struct SGroupInfo {
   int iEnd;
   int iColour;
   bool bVisible;
+  int iNumChildNodes;
 };
 /// \}
 
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index a6c4303..e0e0bee 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -54,85 +54,106 @@ CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreati
 }
 
 CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CAlphabetManager *pMgr)
-: CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo), m_pMgr(pMgr) {
+: CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo), m_pMgr(pMgr), m_pProbInfo(NULL) {
 };
 
-CAlphabetManager::CAlphNode *CAlphabetManager::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo) {
-  return new CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, this);
+CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CAlphabetManager *pMgr, symbol _iSymbol)
+: CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, pMgr), iSymbol(_iSymbol) {
+};
+
+CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CAlphabetManager *pMgr, SGroupInfo *pGroup)
+: CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, pMgr), m_pGroup(pGroup) {
+};
+
+CAlphabetManager::CSymbolNode *CAlphabetManager::makeSymbol(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, symbol iSymbol) {
+  return new CSymbolNode(pParent, iLbnd, iHbnd, pDisplayInfo, this, iSymbol);
+}
+
+CAlphabetManager::CGroupNode *CAlphabetManager::makeGroup(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, SGroupInfo *pGroup) {
+  return new CGroupNode(pParent, iLbnd, iHbnd, pDisplayInfo, this, pGroup);
 }
 
 CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, int iLower, int iUpper, bool bEnteredLast, int iOffset) {
   
-  std::vector<symbol> vContextSymbols;
+  CAlphNode *pNewNode = BuildNodeForOffset(pParent, iLower, iUpper, bEnteredLast, max(-1,iOffset-1), 0);
 
-  if(iOffset>0) {
-    // TODO: Utility function for looking up symbolic context
-    // also TODO: make the LM get the context, rather than force it to fix max context length as an int
-    int iStart = max(0, iOffset - (m_pLanguageModel->GetContextLength() + 1));
+  pNewNode->SetFlag(NF_SEEN, true);
+  
+  //    if(m_bGameMode) {
+  //    pNodeUserData->iGameOffset = -1;
+  pNewNode->SetFlag(NF_GAME, true);
+  //  }
+  
+  return pNewNode;
+}
 
-    pParent->GetContext(m_pInterface, vContextSymbols, iStart, iOffset - iStart);
-    //take one off offset: the children (leaf) nodes (symbols) should have the specified offset;
-    //the containing groups therefore have offset 1 less.
-    iOffset = iOffset - 1;
+CAlphabetManager::CAlphNode *CAlphabetManager::BuildNodeForOffset(CDasherNode *pParent, int iLower, int iUpper, bool bSym, int iNewOffset, int iNewPhase) {
+  
+  std::vector<symbol> vContextSymbols;
+  // TODO: make the LM get the context, rather than force it to fix max context length as an int
+  int iStart = max(0, iNewOffset - m_pLanguageModel->GetContextLength());
+  
+  if(pParent) {
+    pParent->GetContext(m_pInterface, vContextSymbols, iStart, iNewOffset+1 - iStart);
   } else {
-    iOffset = -1;
-    std::string strContext = m_pNCManager->GetAlphabet()->GetDefaultContext();
+    std::string strContext = (iNewOffset == -1) 
+      ? m_pNCManager->GetAlphabet()->GetDefaultContext()
+      : m_pInterface->GetContext(iStart, iNewOffset+1 - iStart);
     m_pNCManager->GetAlphabet()->GetSymbols(vContextSymbols, strContext);
   }
-  CLanguageModel::Context iContext;
-  int iSymbol;
-  BuildContext(vContextSymbols, !bEnteredLast, iContext, iSymbol);
-  int iColour = m_pNCManager->GetAlphabet()->GetColour(iSymbol, 0);
 
-  // FIXME - Make this a CDasherComponent
-
-  // Stuff which could in principle be done in the symbol node creation routine
   CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
-  pDisplayInfo->iColour = iColour;
   pDisplayInfo->bShove = true;
-  pDisplayInfo->bVisible = true;
-  pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
-
-  CAlphNode *pNewNode = makeNode(pParent, iLower, iUpper, pDisplayInfo);
+  pDisplayInfo->bVisible = true;  
+  
+  CAlphNode *pNewNode;
+  CLanguageModel::Context iContext = m_pLanguageModel->CreateEmptyContext();
+    
+  for(std::vector<symbol>::iterator it(vContextSymbols.begin()); it != vContextSymbols.end(); ++it)
+    if(*it != 0)
+      m_pLanguageModel->EnterSymbol(iContext, *it);
+    
+  if((vContextSymbols.size() == 0) || !bSym) {
+    //this node can't be responsible for entering the last symbol if there wasn't one!
+    pDisplayInfo->strDisplayText = ""; //equivalent to do m_pNCManager->GetAlphabet()->GetDisplayText(0)
+    pDisplayInfo->iColour = m_pNCManager->GetAlphabet()->GetColour(0, iNewPhase);
+    pNewNode = makeGroup(pParent, iLower, iUpper, pDisplayInfo, NULL);
+  } else {
+    const symbol iSymbol(vContextSymbols[vContextSymbols.size() - 1]);
+    pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
+    pDisplayInfo->iColour = m_pNCManager->GetAlphabet()->GetColour(iSymbol, iNewPhase);
+    pNewNode = makeSymbol(pParent, iLower, iUpper, pDisplayInfo, iSymbol);
+  }
 
-  pNewNode->m_iOffset = iOffset;
-  pNewNode->iPhase = 0;
-  pNewNode->iSymbol = iSymbol;
+  pNewNode->m_iOffset = iNewOffset;
+  pNewNode->iPhase = iNewPhase;
 
   pNewNode->iContext = iContext;
-
-  pNewNode->SetFlag(NF_SEEN, true);
-
-
-
-  //    if(m_bGameMode) {
-  //    pNodeUserData->iGameOffset = -1;
-       pNewNode->SetFlag(NF_GAME, true);
-    //  }
-
   return pNewNode;
 }
 
-bool CAlphabetManager::CAlphNode::GameSearchNode(string strTargetUtf8Char) {
-  if (GetFlag(NF_SUBNODE)) {
-    if (GameSearchChildren(strTargetUtf8Char)) {
-      SetFlag(NF_GAME, true);
-      return true;
-    }
-  } else if (m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol) == strTargetUtf8Char) {
+bool CAlphabetManager::CSymbolNode::GameSearchNode(string strTargetUtf8Char) {
+  if (m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol) == strTargetUtf8Char) {
     SetFlag(NF_GAME, true);
     return true;
   }
   return false;
 }
+bool CAlphabetManager::CGroupNode::GameSearchNode(string strTargetUtf8Char) {
+  if (GameSearchChildren(strTargetUtf8Char)) {
+    SetFlag(NF_GAME, true);
+    return true;
+  }
+return false;
+}
 
 CLanguageModel::Context CAlphabetManager::CAlphNode::CloneAlphContext(CLanguageModel *pLanguageModel) {
   if (iContext) return pLanguageModel->CloneContext(iContext);
   return CDasherNode::CloneAlphContext(pLanguageModel);
 }
 
-void CAlphabetManager::CAlphNode::GetContext(CDasherInterfaceBase *pInterface, vector<symbol> &vContextSymbols, int iOffset, int iLength) {
-  if (!GetFlag(NF_SEEN) && iOffset+iLength-1 == m_iOffset && iSymbol) {
+void CAlphabetManager::CSymbolNode::GetContext(CDasherInterfaceBase *pInterface, vector<symbol> &vContextSymbols, int iOffset, int iLength) {
+  if (!GetFlag(NF_SEEN) && iOffset+iLength-1 == m_iOffset) {
     if (iLength > 1) Parent()->GetContext(pInterface, vContextSymbols, iOffset, iLength-1);
     vContextSymbols.push_back(iSymbol);
   } else {
@@ -140,37 +161,105 @@ void CAlphabetManager::CAlphNode::GetContext(CDasherInterfaceBase *pInterface, v
   }
 }
 
-symbol CAlphabetManager::CAlphNode::GetAlphSymbol() {
+symbol CAlphabetManager::CSymbolNode::GetAlphSymbol() {
   return iSymbol;
 }
 
-void CAlphabetManager::CAlphNode::PopulateChildren() {
-  m_pMgr->PopulateChildrenWithSymbol( this, -2, 0 );
+void CAlphabetManager::CSymbolNode::PopulateChildren() {
+  m_pMgr->IterateChildGroups(this, NULL, NULL);
+}
+int CAlphabetManager::CAlphNode::ExpectedNumChildren() {
+  return m_pMgr->m_pNCManager->GetAlphabet()->iNumChildNodes;
+}
+
+std::vector<unsigned int> *CAlphabetManager::CAlphNode::GetProbInfo() {
+  if (!m_pProbInfo) {
+    m_pProbInfo = new std::vector<unsigned int>();
+    m_pMgr->m_pNCManager->GetProbs(iContext, *m_pProbInfo, m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+    // work out cumulative probs in place
+    for(unsigned int i = 1; i < m_pProbInfo->size(); i++) {
+      (*m_pProbInfo)[i] += (*m_pProbInfo)[i - 1];
+    }
+  }
+  return m_pProbInfo;
+}
+
+std::vector<unsigned int> *CAlphabetManager::CGroupNode::GetProbInfo() {
+  if (m_pGroup && Parent() && Parent()->mgrId() == 0) {
+    DASHER_ASSERT(Parent()->m_iOffset == m_iOffset);
+    return (static_cast<CAlphNode *>(Parent()))->GetProbInfo();
+  }
+  //nope, no usable parent. compute here...
+  return CAlphNode::GetProbInfo();
 }
 
-CAlphabetManager::CAlphNode *CAlphabetManager::CreateGroupNode(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
+void CAlphabetManager::CGroupNode::PopulateChildren() {
+  m_pMgr->IterateChildGroups(this, m_pGroup, NULL);
+  if (GetChildren().size()==1) {
+    CDasherNode *pChild = GetChildren()[0];
+    //single child, must therefore completely fill this node...
+    DASHER_ASSERT(pChild->Lbnd()==0 && pChild->Hbnd()==65536);
+    //in earlier versions of Dasher with subnodes, that child would have been created
+    // at the same time as this node, so this node would never be seen/rendered (as the
+    // child would cover it). However, lazily (as we do now) creating the child, will
+    // suddenly obscure this (parent) node, changing it's colour. Hence, avoid this by
+    // making the child look like the parent...(note that changing the parent, before the
+    // child is created, to look like the child will do, would more closely mirror the old
+    // behaviour, but we can't really do that!
+    CDasherNode::SDisplayInfo *pInfo = (CDasherNode::SDisplayInfo *)pChild->GetDisplayInfo();
+    //ick, note the cast to get rid of 'const'ness. TODO: do something about SDisplayInfo...!!
+    pInfo->bVisible=false;
+    pInfo->iColour = GetDisplayInfo()->iColour;
+  }
+}
+int CAlphabetManager::CGroupNode::ExpectedNumChildren() {
+  return (m_pGroup) ? m_pGroup->iNumChildNodes : CAlphNode::ExpectedNumChildren();
+}
 
+CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
   // TODO: More sensible structure in group data to map directly to this
   CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
-  pDisplayInfo->iColour = pInfo->iColour;
+  pDisplayInfo->iColour = (pInfo->bVisible ? pInfo->iColour : pParent->GetDisplayInfo()->iColour);
   pDisplayInfo->bShove = true;
   pDisplayInfo->bVisible = pInfo->bVisible;
   pDisplayInfo->strDisplayText = pInfo->strLabel;
 
-  CAlphNode *pNewNode = makeNode(pParent, iLbnd, iHbnd, pDisplayInfo);
+  CGroupNode *pNewNode = makeGroup(pParent, iLbnd, iHbnd, pDisplayInfo, pInfo);
 
-  pNewNode->SetFlag(NF_SUBNODE, true);
+  //pNewNode->SetFlag(NF_SUBNODE, true);
 
   // When creating a group node...
   pNewNode->m_iOffset = pParent->m_iOffset; // ...the offset is the same as the parent...
   pNewNode->iPhase = pParent->iPhase;
-  // TODO: Sort out symbol for groups
-  pNewNode->iSymbol = 0; //...but the Symbol is just a 0.
   pNewNode->iContext = m_pLanguageModel->CloneContext(pParent->iContext);
 
   return pNewNode;
 }
 
+CAlphabetManager::CGroupNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
+  if (pInfo == m_pGroup) {
+    SetRange(iLbnd, iHbnd);
+    SetParent(pParent);
+    //offset doesn't increase for groups...
+    DASHER_ASSERT (m_iOffset == pParent->m_iOffset);
+    return this;
+  }
+  CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, pInfo, iLbnd, iHbnd);
+  if (pInfo->iStart <= m_pGroup->iStart && pInfo->iEnd >= m_pGroup->iEnd) {
+    //created group node should contain this one
+    m_pMgr->IterateChildGroups(pRet,pInfo,this);
+  }
+  return pRet;
+}
+
+CAlphabetManager::CGroupNode *CAlphabetManager::CSymbolNode::RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
+  CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, pInfo, iLbnd, iHbnd);
+  if (pInfo->iStart <= iSymbol && pInfo->iEnd > iSymbol) {
+    m_pMgr->IterateChildGroups(pRet, pInfo, this);
+  }
+  return pRet;
+}
+
 CLanguageModel::Context CAlphabetManager::CreateSymbolContext(CAlphNode *pParent, symbol iSymbol)
 {
   CLanguageModel::Context iContext = m_pLanguageModel->CloneContext(pParent->iContext);
@@ -178,24 +267,16 @@ CLanguageModel::Context CAlphabetManager::CreateSymbolContext(CAlphNode *pParent
   return iContext;
 }
 
-CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild) {
+CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
 
   CDasherNode *pNewNode = NULL;
 
   //Does not invoke conversion node
 
   // TODO: Better way of specifying alternate roots
-  // TODO: Building with existing node
-    if(iSymbol == iExistingSymbol) {
-      pNewNode = pExistingChild;
-      pNewNode->SetRange(iLbnd, iHbnd);
-      pNewNode->SetParent(pParent);
 
-      DASHER_ASSERT(pExistingChild->m_iOffset == pParent->m_iOffset + 1);
-
-    }
-    // TODO: Need to fix fact that this is created even when control mode is switched off
-    else if(iSymbol == m_pNCManager->GetAlphabet()->GetControlSymbol()) {
+  // TODO: Need to fix fact that this is created even when control mode is switched off
+  if(iSymbol == m_pNCManager->GetAlphabet()->GetControlSymbol()) {
       //ACL setting offset as one more than parent for consistency with "proper" symbol nodes...
       pNewNode = m_pNCManager->GetCtrlRoot(pParent, iLbnd, iHbnd, pParent->m_iOffset+1); 
 
@@ -227,7 +308,7 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymb
       pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
 
       CAlphNode *pAlphNode;
-      pNewNode = pAlphNode = makeNode(pParent, iLbnd, iHbnd, pDisplayInfo);
+      pNewNode = pAlphNode = makeSymbol(pParent, iLbnd, iHbnd, pDisplayInfo,iSymbol);
 
       //     std::stringstream ssLabel;
 
@@ -240,7 +321,6 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymb
 
       pNewNode->m_iOffset = pParent->m_iOffset + 1;
       pAlphNode->iPhase = iPhase;
-      pAlphNode->iSymbol = iSymbol;
 
       pAlphNode->iContext = CreateSymbolContext(pParent, iSymbol);
   }
@@ -248,15 +328,31 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymb
   return pNewNode;
 }
 
+CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
+  if(iSymbol == this->iSymbol) {
+    SetRange(iLbnd, iHbnd);
+    SetParent(pParent);
+    DASHER_ASSERT(m_iOffset == pParent->m_iOffset + 1);
+    return this;
+  }
+  return m_pMgr->CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd);
+}
+
+CDasherNode *CAlphabetManager::CGroupNode::RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
+  return m_pMgr->CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd);
+}
 
-void CAlphabetManager::RecursiveIterateGroup(CAlphNode *pParent, SGroupInfo *pInfo, std::vector<symbol> *pSymbols, std::vector<unsigned int> *pCProb, int iMin, int iMax, symbol iExistingSymbol, CDasherNode *pExistingChild) {
+void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParentGroup, CAlphNode *buildAround) {
+  std::vector<unsigned int> *pCProb(pParent->GetProbInfo());
+  const int iMin(pParentGroup ? pParentGroup->iStart : 1);
+  const int iMax(pParentGroup ? pParentGroup->iEnd : pCProb->size());
   // TODO: Think through alphabet file formats etc. to make this class easier.
   // TODO: Throw a warning if parent node already has children
   
   // Create child nodes and add them
   
   int i(iMin); //lowest index of child which we haven't yet added
-  SGroupInfo *pCurrentNode(pInfo);
+  SGroupInfo *pCurrentNode(pParentGroup ? pParentGroup->pChild : m_pNCManager->GetAlphabet()->m_pBaseGroup);
   // The SGroupInfo structure has something like linked list behaviour
   // Each SGroupInfo contains a pNext, a pointer to a sibling group info
   while (i < iMax) {
@@ -277,21 +373,10 @@ void CAlphabetManager::RecursiveIterateGroup(CAlphNode *pParent, SGroupInfo *pIn
                          ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]);
     
     if (bSymbol) {
-      pNewChild = CreateSymbolNode(pParent, (*pSymbols)[i], iLbnd, iHbnd, iExistingSymbol, pExistingChild);
+      pNewChild = (buildAround) ? buildAround->RebuildSymbol(pParent, i, iLbnd, iHbnd) : CreateSymbolNode(pParent, i, iLbnd, iHbnd);
       i++; //make one symbol at a time - move onto next in next iteration
     } else { //in/reached subgroup - do entire group in one go:
-      CAlphNode *pNew;
-      pNewChild= pNew= CreateGroupNode(pParent,
-                                       pCurrentNode, iLbnd, iHbnd);
-
-      RecursiveIterateGroup(pNew,
-          pCurrentNode->pChild,
-          pSymbols,
-          pCProb,
-          pCurrentNode->iStart,
-          pCurrentNode->iEnd,
-          iExistingSymbol, pExistingChild);
-
+      pNewChild= (buildAround) ? buildAround->RebuildGroup(pParent, pCurrentNode, iLbnd, iHbnd) : CreateGroupNode(pParent, pCurrentNode, iLbnd, iHbnd);
       i = pCurrentNode->iEnd; //make one group at a time - so move past entire group...
       pCurrentNode = pCurrentNode->pNext;
     }
@@ -301,119 +386,73 @@ void CAlphabetManager::RecursiveIterateGroup(CAlphNode *pParent, SGroupInfo *pIn
   pParent->SetFlag(NF_ALLCHILDREN, true);
 }
 
-void CAlphabetManager::PopulateChildrenWithSymbol( CAlphNode *pNode, int iExistingSymbol, CDasherNode *pExistingChild ) {
-  // TODO: generally improve with iterators etc.
-  // FIXME: this has to change for history stuff and Japanese dasher
-  std::vector < symbol > newchars; // place to put this list of characters
-  std::vector < unsigned int >cum; // for the probability list
-
-  // TODO: Need to fix up relation to language model here (use one from node, not global).
-  m_pNCManager->GetProbs(pNode->iContext, newchars, cum, m_pNCManager->GetLongParameter(LP_NORMALIZATION));
-  int iChildCount = newchars.size();
-
-  // work out cumulative probs in place
-  for(int i = 1; i < iChildCount; i++) {
-    cum[i] += cum[i - 1];
-  }
-
-  RecursiveIterateGroup(pNode, m_pNCManager->GetAlphabet()->m_pBaseGroup, &newchars,
-    &cum, 1, iChildCount, iExistingSymbol, pExistingChild);
-}
-
 CAlphabetManager::CAlphNode::~CAlphNode() {
+  delete m_pProbInfo;
   m_pMgr->m_pLanguageModel->ReleaseContext(iContext);
 }
 
-void CAlphabetManager::CAlphNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
+void CAlphabetManager::CSymbolNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
   //std::cout << this << " " << Parent() << ": Output at offset " << m_iOffset << " *" << m_pMgr->m_pNCManager->GetAlphabet()->GetText(t) << "* " << std::endl;
 
-  if(iSymbol) { // Ignore symbol 0 (root node)
-    Dasher::CEditEvent oEvent(1, m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol), m_iOffset);
-    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
+  Dasher::CEditEvent oEvent(1, m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol), m_iOffset);
+  m_pMgr->m_pNCManager->InsertEvent(&oEvent);
 
-    // Track this symbol and its probability for logging purposes
-    if (pAdded != NULL) {
-      Dasher::SymbolProb sItem;
-      sItem.sym    = iSymbol;
-      sItem.prob   = GetProb(iNormalization);
+  // Track this symbol and its probability for logging purposes
+  if (pAdded != NULL) {
+    Dasher::SymbolProb sItem;
+    sItem.sym    = iSymbol;
+    sItem.prob   = GetProb(iNormalization);
 
-      pAdded->push_back(sItem);
-    }
+    pAdded->push_back(sItem);
   }
 }
 
-void CAlphabetManager::CAlphNode::Undo() {
-  if(iSymbol) { // Ignore symbol 0 (root node)
-    Dasher::CEditEvent oEvent(2, m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol), m_iOffset);
-    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
-  }
+void CAlphabetManager::CSymbolNode::Undo() {
+  Dasher::CEditEvent oEvent(2, m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol), m_iOffset);
+  m_pMgr->m_pNCManager->InsertEvent(&oEvent);
 }
 
-// TODO: Sort out node deletion etc.
-CDasherNode *CAlphabetManager::CAlphNode::RebuildParent() {
-  int iNewOffset = m_iOffset - 1;
-
-  int iOldPhase(iPhase);
-  int iNewPhase;
-
-  symbol iNewSymbol;
-
-  std::vector<symbol> vContextSymbols;
-  CLanguageModel::Context iContext;
+CDasherNode *CAlphabetManager::CGroupNode::RebuildParent() {
+  // CAlphNode's always have a parent, they inserted a symbol; CGroupNode's
+  // with an m_pGroup have a container i.e. the parent group, unless
+  // m_pGroup==NULL => "root" node where Alphabet->m_pBaseGroup is the *first*child*...
+  if (m_pGroup == NULL) return NULL;
+  //offset of group node is same as parent...
+  return CAlphNode::RebuildParent(m_iOffset, iPhase);
+}
 
-  if((m_iOffset == -1) || (iSymbol == 0)) {
-    // already a root, or for some other reason has the null
-    // symbol (eg because it was generated from a different alphabet)
-    return NULL;
-  }
+CDasherNode *CAlphabetManager::CSymbolNode::RebuildParent() {
+  //parent's offset is one less than this.
+  return CAlphNode::RebuildParent(m_iOffset-1, (iPhase + 1)%2);
+}
 
-  CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
-  pDisplayInfo->bShove = true;
-  pDisplayInfo->bVisible = true;
+CDasherNode *CAlphabetManager::CAlphNode::RebuildParent(int iNewOffset, int iNewPhase) {
+  //possible that we have a parent, as RebuildParent() rebuilds back to closest AlphNode.
+  if (Parent()) return Parent();
   
-  if(m_iOffset == 0) {
-    // TODO: Creating a root node, Shouldn't be a special case
-    std::string strContext = m_pMgr->m_pNCManager->GetAlphabet()->GetDefaultContext();
-    m_pMgr->m_pNCManager->GetAlphabet()->GetSymbols(vContextSymbols, strContext);
-    m_pMgr->BuildContext(vContextSymbols, true, iContext, iNewSymbol); //sets iNewSymbol to 0
-
-    iNewPhase = 0;
-
-    pDisplayInfo->strDisplayText = "";
-  }
-  else {
-    int iStart = max(0, m_iOffset - (m_pMgr->m_pLanguageModel->GetContextLength() + 1));
-    GetContext(m_pMgr->m_pInterface, vContextSymbols, iStart, m_iOffset - iStart);
-    m_pMgr->BuildContext(vContextSymbols, false, iContext, iNewSymbol);
-
-    iNewPhase = ((iOldPhase + 2 - 1) % 2);
-
-    pDisplayInfo->strDisplayText = m_pMgr->m_pNCManager->GetAlphabet()->GetDisplayText(iNewSymbol);
-  }
-  pDisplayInfo->iColour = m_pMgr->m_pNCManager->GetAlphabet()->GetColour(iNewSymbol, iNewPhase);
-
-  CAlphNode *pNewNode = m_pMgr->makeNode(NULL, 0, 0, pDisplayInfo);
+  //Hmmm. We require that if the new node's offset is -1 (the very beginning), phase is 0.
+  // If you escaped from control mode back to alphabet with an odd offset, GetRoot (with odd DasherNode offset)
+  // would construct a root with phase 0; if you then wrote far enough forwards first to lose the Control Mode nodes,
+  // and then erased back far enough to delete the entire (pre-Control-Mode) sentence, might that break this? TODO CHECK
+  // (and TODO: possibly remove phase - why not just use iOffset modulo 2? (Or however many, could then decide according
+  // to colour scheme or whatever!)
+  DASHER_ASSERT(iNewOffset !=-1 || iNewPhase == 0);
   
-  // TODO: Some of this context stuff could be consolidated
+  CAlphNode *pNewNode = m_pMgr->BuildNodeForOffset(NULL, 0, 0, iNewOffset!=-1, iNewOffset, iNewPhase);
 
   pNewNode->SetFlag(NF_SEEN, true);
 
-  pNewNode->m_iOffset = iNewOffset;
-  pNewNode->iPhase = iNewPhase;
-  pNewNode->iSymbol = iNewSymbol;
-  pNewNode->iContext = iContext;
-
+  //now fill in the new node - recursively - until it reaches us
+  m_pMgr->IterateChildGroups(pNewNode, NULL, this);
 
-  m_pMgr->PopulateChildrenWithSymbol(pNewNode, iSymbol, this);
-
-  //  std::cout << "**" << std::endl;
-
-  return pNewNode;
+  //finally return our immediate parent (pNewNode may be an ancestor rather than immediate parent!)
+  DASHER_ASSERT(Parent() != NULL);
+  return Parent();
 }
 
 // TODO: Shouldn't there be an option whether or not to learn as we write?
 // For want of a better solution, game mode exemption explicit in this function
-void CAlphabetManager::CAlphNode::SetFlag(int iFlag, bool bValue) {
+void CAlphabetManager::CSymbolNode::SetFlag(int iFlag, bool bValue) {
   CDasherNode::SetFlag(iFlag, bValue);
   switch(iFlag) {
   case NF_COMMITTED:
@@ -422,20 +461,3 @@ void CAlphabetManager::CAlphNode::SetFlag(int iFlag, bool bValue) {
     break;
   }
 }
-
-void CAlphabetManager::BuildContext(const std::vector<symbol> &vContextSymbols, bool bRoot, CLanguageModel::Context &oContext, symbol &iSymbol) {
-  // Hopefully this will obsolete any need to handle contexts outside
-  // of the alphabet manager - check this and remove resulting
-  // redundant code
-
-  oContext = m_pLanguageModel->CreateEmptyContext();
-
-  for(std::vector<symbol>::const_iterator it(vContextSymbols.begin()); it != vContextSymbols.end(); ++it)
-    if(*it != 0)
-      m_pLanguageModel->EnterSymbol(oContext, *it);
-
-  if((vContextSymbols.size() == 0) || bRoot)
-    iSymbol = 0;
-  else
-    iSymbol = vContextSymbols[vContextSymbols.size() - 1];
-}
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index a119f86..eef5774 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -31,7 +31,7 @@ struct SGroupInfo;
 namespace Dasher {
 
   class CDasherInterfaceBase;
-
+  
   /// \ingroup Model
   /// @{
 
@@ -46,45 +46,69 @@ namespace Dasher {
     CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel);
 
   protected:
+    class CGroupNode;
     class CAlphNode : public CDasherNode {
     public:
       int mgrId() {return 0;}
       CAlphNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr);
-    ///
-    /// Provide children for the supplied node
-    ///
-
-    virtual void PopulateChildren();
-
-    ///
-    /// Delete any storage alocated for this node
-    ///
-
-    virtual ~CAlphNode();
-
-    virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
-    virtual void Undo();
-
-    virtual CDasherNode *RebuildParent();
-
-    virtual void SetFlag(int iFlag, bool bValue);
-
-    virtual bool GameSearchNode(std::string strTargetUtf8Char);
-    
-    virtual CLanguageModel::Context CloneAlphContext(CLanguageModel *pLanguageModel);
-    virtual void GetContext(CDasherInterfaceBase *pInterface, std::vector<symbol> &vContextSymbols, int iOffset, int iLength);
-    virtual symbol GetAlphSymbol();
-    private:
-      CAlphabetManager *m_pMgr;
-    public: //to AlphabetManager and subclasses only, of course...
-    
-      symbol iSymbol;
       int iPhase;
       CLanguageModel::Context iContext;
- 
-      int iGameOffset;
+      ///
+      /// Delete any storage alocated for this node
+      ///      
+      virtual ~CAlphNode();
+      virtual CLanguageModel::Context CloneAlphContext(CLanguageModel *pLanguageModel);
+      CDasherNode *RebuildParent(int iNewOffset, int iNewPhase);
+      ///Have to call this from CAlphabetManager, and from CGroupNode on a _different_ CAlphNode, hence public...
+      virtual std::vector<unsigned int> *GetProbInfo();
+      virtual int ExpectedNumChildren();
+      CAlphabetManager *m_pMgr;
+      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd)=0;
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd)=0;
+    private:
+      std::vector<unsigned int> *m_pProbInfo;
+    };
+    class CSymbolNode : public CAlphNode {
+    public:
+      CSymbolNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr, symbol iSymbol);
+      
+      ///
+      /// Provide children for the supplied node
+      ///
+
+      virtual void PopulateChildren();
+      virtual CDasherNode *RebuildParent();
+      virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
+      virtual void Undo();
+
+      virtual void SetFlag(int iFlag, bool bValue);
+
+      virtual bool GameSearchNode(std::string strTargetUtf8Char);
+      virtual void GetContext(CDasherInterfaceBase *pInterface, std::vector<symbol> &vContextSymbols, int iOffset, int iLength);
+      virtual symbol GetAlphSymbol();
+      const symbol iSymbol;
+      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd);
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
     };
 
+    class CGroupNode : public CAlphNode {
+    public:
+      CGroupNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr, SGroupInfo *pGroup);
+      
+      ///
+      /// Provide children for the supplied node
+      ///
+      virtual CDasherNode *RebuildParent();
+      virtual void PopulateChildren();
+      virtual int ExpectedNumChildren();
+      virtual bool GameSearchNode(std::string strTargetUtf8Char);
+      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd);
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
+      std::vector<unsigned int> *GetProbInfo();
+    private:
+      SGroupInfo *m_pGroup;
+    };
+    
   public:
     ///
     /// Get a new root node owned by this manager
@@ -97,30 +121,33 @@ namespace Dasher {
     ///
     /// Factory method for CAlphNode construction, so subclasses can override.
     ///
-    virtual CAlphNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);    
-
+    virtual CSymbolNode *makeSymbol(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, symbol iSymbol);
+    virtual CGroupNode *makeGroup(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, SGroupInfo *pGroup);
     
-    void PopulateChildrenWithSymbol( CAlphNode *pNode, int iExistingSymbol, CDasherNode *pExistingChild );
-
-    virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild);
+    virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd);
     virtual CLanguageModel::Context CreateSymbolContext(CAlphNode *pParent, symbol iSymbol);
+    virtual CGroupNode *CreateGroupNode(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
 
+    ///
+    ///Builds a new node from the context leading up to the specified offset
+    /// bSym - true if the build node should be considered as having entered the last symbol (e.g. when rebuilding parent,
+    /// but not when escaping back to Alphabet)
+    /// iNewOffset - m_iOffset of the new node (i.e. index into context of character the node represents)
+    ///
+    CAlphNode *BuildNodeForOffset(CDasherNode *pParent, int iLower, int iUpper, bool bSym, int iNewOffset, int iNewPhase);
+    
     CLanguageModel *m_pLanguageModel;
     CNodeCreationManager *m_pNCManager;
 
   private:
     
-    void BuildContext(const std::vector<symbol> &vContextSymbols, bool bRoot, CLanguageModel::Context &oContext, symbol &iSymbol);
-
-    void RecursiveIterateGroup(CAlphNode *pParent, SGroupInfo *pInfo, std::vector<symbol> *pSymbols, std::vector<unsigned int> *pCProb, int iMin, int iMax, symbol iExistingSymbol, CDasherNode *pExistingChild);
-
-    CAlphNode *CreateGroupNode(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
+    void IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParentGroup, CAlphNode *buildAround);
 
     CLanguageModel::Context m_iLearnContext;
     CDasherInterfaceBase *m_pInterface;
-
+    
   };
-  /// @}
+/// @}
 
 }
 
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 3b4d217..a118839 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -339,7 +339,9 @@ void CControlManager::CContNode::PopulateChildren() {
      ++iIdx;
    }
 }
-
+int CControlManager::CContNode::ExpectedNumChildren() {
+  return pControlItem->vChildren.size();
+}
 void CControlManager::CContNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
 
   CControlEvent oEvent(pControlItem->iID);
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 560d2e4..7136485 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -95,6 +95,7 @@ namespace Dasher {
     ///
 
     virtual void PopulateChildren();
+      virtual int ExpectedNumChildren();
     
     virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization );
     virtual void Undo();
diff --git a/Src/DasherCore/ConversionHelper.cpp b/Src/DasherCore/ConversionHelper.cpp
index 03c1ac3..e09af69 100644
--- a/Src/DasherCore/ConversionHelper.cpp
+++ b/Src/DasherCore/ConversionHelper.cpp
@@ -72,100 +72,9 @@ CConversionManager::CConvNode *CConversionHelper::GetRoot(CDasherNode *pParent,
 // TODO: This function needs to be significantly tidied up
 // TODO: get rid of pSizes
 
-void CConversionHelper::AssignChildSizes(SCENode **pNode, CLanguageModel::Context context, int iNChildren) {
-
-    // Calculate sizes for the children. Note that normalisation is
-    // done additiviely rather than multiplicatively, so it's not
-    // quite what was originally planned (but I don't think this is
-    // much of a problem). More serious is the fact that the ordering
-    // is being lost when the tree is created, as nodes begininning
-    // with the same character are merged. This needs to be though
-    // out, but the probabilities should probably be done at the time
-    // of construction of the candidate tree rather than the Dasher
-    // tree (aside - is there any real point having two separate trees
-    // - surely we should just create Dasher nodes right away?).
-    //
-    // The algorithm should also allow for the possibility of the
-    // conversion engine returning probabilities itself, which should
-    // be used in preference to the values infered from the ordering
-    //
-    // Finally, maybe the choices should be presented in lexographic
-    // order, rather than in order returned (really not sure about
-    // this - it needs to be thought through).
-
-
-    //    std::cout << "b" << std::endl;
-
-    //TESTING FOR CALCULATESCORE STAGE 1
-    //int test;
-    //test = CalculateScore(pNode, 1);
-    //std::cout<<"current character"<<pCurrentSCENode->pszConversion<<std::endl;
-    //std::cout<<"the score for the second candidate is"<<test<<std::endl;
-
-
-
-    //ASSIGNING SCORES AND CALCULATING NODE SIZE
-    //Ph: feel free to edit this part to make it more structured
-//     int iSize[pCurrentSCEChild->IsHeadAndCandNum];
-//     int score[pCurrentSCEChild->IsHeadAndCandNum];
-//     int total =0;
-//     int max = 0;
-//     int CandNum = pCurrentSCEChild -> IsHeadAndCandNum;
-
-// CHANGE    int iRemaining(m_pNCManager->GetLongParameter(LP_NORMALIZATION));
-
-    // Thoughts on the general idea here - this is very close to being
-    // a fully fledged language model, so I think we should go with
-    // that idea, but maybe we need something mode flexible. I'd
-    // imagine:
-    //
-    // 1. Probabilities provided directly with translation? Maybe hard
-    // to represent in the lattice itself.
-    //
-    // 2. Full n-gram language model provided - in general assign
-    // probabilities to paths through the lattice
-    //
-    // 3. Ordered results, but no probabilities - using a power law
-    // rule or the like.
-    //
-    // Tempted to assume (1) and (2) can be implemented together, with
-    // a second call to the library at node creation time, and (3) can
-    // be implemented as a fallback if that doesn't work.
-    //
-    // Things to be thought out:
-    // - How to deal with contexts - backtrace at time of call or stored in node?
-    // - Sharing of language model infrastructure?
-
-
-
-    // Lookup scores for each of the children
-
-    // TODO: Reimplement -----
-
-  //     for(int i(0); i < pCurrentSCEChild->IsHeadAndCandNum; ++i){
-  //       score[i] = CalculateScore(pNode, i);
-  //       total += score[i];
-  //       if(i!=0)
-  // 	if (score[i]>score[i-1])
-  // 	  max = score[i];
-  //     }
-
-  // -----
-
-  // Use the scores to calculate the size of the nodes
-
-
-  iNChildren = 0;
-  SCENode *pChild(*pNode);
-
-  while(pChild) {
-    pChild = pChild->GetNext();
-    ++iNChildren;
-  }
-
-  //  std::cout<<"iNChildren: "<<iNChildren<<std::endl;
-  AssignSizes(pNode, context, m_pNCManager->GetLongParameter(LP_NORMALIZATION), m_pNCManager->GetLongParameter(LP_UNIFORM), iNChildren);
+void CConversionHelper::AssignChildSizes(const std::vector<SCENode *> &nodes, CLanguageModel::Context context) {
 
+  AssignSizes(nodes, context, m_pNCManager->GetLongParameter(LP_NORMALIZATION), m_pNCManager->GetLongParameter(LP_UNIFORM));
 
 }
 
@@ -177,47 +86,16 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
   //
 
 
-  if(bisRoot) {
+  if(bisRoot && !pSCENode) {
     mgr()->BuildTree(this);
   }
 
-  SCENode *pCurrentSCEChild;
-
-  if(pSCENode){
 
+  if(pSCENode && !pSCENode->GetChildren().empty()) {
+    const std::vector<SCENode *> &vChildren = pSCENode->GetChildren();
     //    RecursiveDumpTree(pSCENode, 1);
-    pCurrentSCEChild = pSCENode->GetChild();
-
-  }
-  else {
-    //    if(m_pRoot && !pCurrentDataNode->bType)
-    //  pCurrentSCEChild = m_pRoot[0];
-    //else
-      pCurrentSCEChild = 0;
-  }
-
-  if(pCurrentSCEChild) {
-    //    std::cout<<"Populating character nodes!"<<std::endl;
-    //    std::cout << "Current SCE Child: " << pCurrentSCEChild << std::endl;
-
-    // TODO: Reimplement (in subclass) -----
-
-//     if(m_iHZCount>1)
-//       if(!m_bPhrasesProcessed[pCurrentSCEChild->AcCharCount-1])
-//    	if(pCurrentSCEChild->AcCharCount<m_iHZCount)
-// 	  ProcessPhrase(pCurrentSCEChild->AcCharCount-1);
-
-    // -----
-
-    //int *iSize;
-
-    //    iSize = new int[pCurrentSCEChild->IsHeadAndCandNum];
-
-
-
-
-    mgr()->AssignChildSizes(&pCurrentSCEChild, iContext, pCurrentSCEChild->IsHeadAndCandNum);
-
+    mgr()->AssignChildSizes(vChildren, iContext);
+    
     int iIdx(0);
     int iCum(0);
 
@@ -227,9 +105,10 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
 
     // Finally loop through and create the children
 
-    do {
+    for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
       //      std::cout << "Current scec: " << pCurrentSCEChild << std::endl;
-
+      SCENode *pCurrentSCEChild(*it);
+      DASHER_ASSERT(pCurrentSCEChild != NULL);
       int iLbnd(iCum);
       int iHbnd(iCum + pCurrentSCEChild->NodeSize);
 		//m_pNCManager->GetLongParameter(LP_NORMALIZATION));//
@@ -263,24 +142,22 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
       pNewNode->m_iOffset = m_iOffset + 1;
 
       if(pLanguageModel) {
-	CLanguageModel::Context iContext;
-	iContext = pLanguageModel->CloneContext(this->iContext);
-	
-	if(pCurrentSCEChild ->Symbol !=-1)
-	  pNewNode->pLanguageModel->EnterSymbol(iContext, pCurrentSCEChild->Symbol); // TODO: Don't use symbols?
-
-
-	pNewNode->iContext = iContext;
+        CLanguageModel::Context iContext;
+        iContext = pLanguageModel->CloneContext(this->iContext);
+        
+        if(pCurrentSCEChild ->Symbol !=-1)
+          pNewNode->pLanguageModel->EnterSymbol(iContext, pCurrentSCEChild->Symbol); // TODO: Don't use symbols?
+        
+        
+        pNewNode->iContext = iContext;
       }
 
       DASHER_ASSERT(GetChildren().back()==pNewNode);
 
-      pCurrentSCEChild = pCurrentSCEChild->GetNext();
       ++iIdx;
-    }while(pCurrentSCEChild);
+    }
 
   }
-
   else {//End of conversion -> default to alphabet
 
       //Phil//
@@ -292,6 +169,11 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
     CConvNode::PopulateChildren();
   }
 }
+int CConversionHelper::CConvHNode::ExpectedNumChildren() {
+  if(bisRoot && !pSCENode) mgr()->BuildTree(this);  
+  if (pSCENode && !pSCENode->GetChildren().empty()) return pSCENode->GetChildren().size();
+  return CConvNode::ExpectedNumChildren();
+}
 
 void CConversionHelper::BuildTree(CConvHNode *pRoot) {
   // Build the string to convert.
diff --git a/Src/DasherCore/ConversionHelper.h b/Src/DasherCore/ConversionHelper.h
index f514bee..04f6c7e 100644
--- a/Src/DasherCore/ConversionHelper.h
+++ b/Src/DasherCore/ConversionHelper.h
@@ -65,9 +65,8 @@ namespace Dasher{
 	/// @param context Unsure - document this, shouldn't be in general class (include userdata pointer).
 	/// @param normalization Normalisation constant for the child sizes (TODO: check that this is a sensible value, ie the same as Dasher normalisation).
 	/// @param uniform Unsure - document this.
-	/// @param iNChildren The number of children to be expected (more efficient than iterating linked list).
 	///
-	virtual void AssignSizes(SCENode ** pStart, Dasher::CLanguageModel::Context context, long normalization, int uniform, int iNChildren)=0;
+  virtual void AssignSizes(const std::vector<SCENode *> &vChildren, Dasher::CLanguageModel::Context context, long normalization, int uniform)=0;
 		
 	/// Assign colours to the children of a given conversion node.
 	/// This function needs a rethink.
@@ -109,7 +108,7 @@ namespace Dasher{
     /// normalisation constant
     ///
     
-    virtual void AssignChildSizes(SCENode **pNode, CLanguageModel::Context context, int iNChildren);
+    virtual void AssignChildSizes(const std::vector<SCENode *> &vChildren, CLanguageModel::Context context);
 	
 	protected:
     class CConvHNode : public CConvNode {
@@ -119,7 +118,7 @@ namespace Dasher{
       /// Provide children for the supplied node
       ///
       virtual void PopulateChildren();
-    	
+    	virtual int ExpectedNumChildren();
     virtual void SetFlag(int iFlag, bool bValue);
     protected:
       inline CConversionHelper *mgr() {return static_cast<CConversionHelper *>(m_pMgr);}
diff --git a/Src/DasherCore/ConversionManager.cpp b/Src/DasherCore/ConversionManager.cpp
index 9b89b55..13d912c 100644
--- a/Src/DasherCore/ConversionManager.cpp
+++ b/Src/DasherCore/ConversionManager.cpp
@@ -107,6 +107,9 @@ void CConversionManager::CConvNode::PopulateChildren() {
 
   DASHER_ASSERT(GetChildren().back()==pNewNode);
 }
+int CConversionManager::CConvNode::ExpectedNumChildren() {
+  return 1; //the alphabet root
+}
 
 CConversionManager::CConvNode::~CConvNode() {
   pLanguageModel->ReleaseContext(iContext);
@@ -114,25 +117,14 @@ CConversionManager::CConvNode::~CConvNode() {
 }
 
 void CConversionManager::RecursiveDumpTree(SCENode *pCurrent, unsigned int iDepth) {
-  pCurrent = pCurrent->GetChild();
-
-  if(pCurrent){
-    while(pCurrent){
-        std::cout << " " << pCurrent->pszConversion << " " << pCurrent->IsHeadAndCandNum << " " << pCurrent->CandIndex << " " << pCurrent->IsComplete << " " << pCurrent->AcCharCount << std::endl;
-	pCurrent = pCurrent->GetNext();
-    }
-  }
-  /*
-  while(pCurrent) {
+  const std::vector<SCENode *> &children = pCurrent->GetChildren();
+  for (std::vector<SCENode *>::const_iterator it = children.begin(); it!=children.end(); it++) {
+    SCENode *pCurrent(*it);
     for(unsigned int i(0); i < iDepth; ++i)
       std::cout << "-";
-
     std::cout << " " << pCurrent->pszConversion << " " << pCurrent->IsHeadAndCandNum << " " << pCurrent->CandIndex << " " << pCurrent->IsComplete << " " << pCurrent->AcCharCount << std::endl;
-
-    RecursiveDumpTree(pCurrent->GetChild(), iDepth + 1);
-    pCurrent = pCurrent->GetNext();
+    RecursiveDumpTree(pCurrent, iDepth + 1);
   }
-  */
 }
 
 void CConversionManager::CConvNode::GetContext(CDasherInterfaceBase *pInterface, std::vector<symbol> &vContextSymbols, int iOffset, int iLength) {
diff --git a/Src/DasherCore/ConversionManager.h b/Src/DasherCore/ConversionManager.h
index de88c91..a820dd7 100644
--- a/Src/DasherCore/ConversionManager.h
+++ b/Src/DasherCore/ConversionManager.h
@@ -87,6 +87,7 @@ namespace Dasher {
     ///
 
     virtual void PopulateChildren();
+    virtual int ExpectedNumChildren();
     
     ~CConvNode();
 
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index 94d929e..d9ecc13 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -719,18 +719,10 @@ bool CDasherModel::RenderToView(CDasherView *pView, NodeQueue &nodeQueue) {
   //(however, note that doing this here will only expand one level per frame,
   //and won't really take effect until the *next* frame!)
   int iNodeBudget = GetLongParameter(LP_NODE_BUDGET);
-  //note: the 'number of symbols' is the number of leaves in the subtree created by
-  //expanding a node, i.e. excluding group nodes; it also counts only 1 for both
-  //the node at the root of any control mode group, *and* the same for any conversion node.
-  //So, expanding a node could create significantly more children than this.
-  //Doubling this is arbitrary, but I'm just hoping it's a reasonably upper bound for the
-  //number of descendants that'll actually be created; if expansion creates more nodes than
-  //this, the logic below will perform one more contraction, and expansion, per frame than
-  //we want - a performance issue, but hopefully not a correctness issue ;-).
-  int iExpansion = m_pNodeCreationManager->GetAlphabet()->GetNumberSymbols()*2;
+
   //first, make sure we are within our budget (probably only in case the budget's changed)
   while (nodeQueue.hasNodesToCollapse()
-		 && currentNumNodeObjects() > iNodeBudget + iExpansion)
+		 && currentNumNodeObjects() > iNodeBudget)
   {
     nodeQueue.nodeToCollapse()->Delete_children();
     nodeQueue.popNodeToCollapse();
@@ -740,7 +732,7 @@ bool CDasherModel::RenderToView(CDasherView *pView, NodeQueue &nodeQueue) {
   //nodes to expand (as zero-cost collapses have already been performed)
   while (nodeQueue.hasNodesToExpand())
   {
-	if (currentNumNodeObjects() < iNodeBudget)
+	if (currentNumNodeObjects() + nodeQueue.nodeToExpand()->ExpectedNumChildren() < iNodeBudget)
 	{
 		Push_Node(nodeQueue.nodeToExpand());
 		nodeQueue.popNodeToExpand();
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index 1692aec..ce8215c 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -228,6 +228,11 @@ class Dasher::CDasherNode:private NoClones {
   ///
   
   virtual void PopulateChildren() = 0;
+  
+  /// The number of children which a call to PopulateChildren can be expected to generate.
+  /// (This is not required to be 100% accurate, but any discrepancies will likely cause
+  /// the node budgetting algorithm to behave sub-optimally)
+  virtual int ExpectedNumChildren() = 0;
     
   ///
   /// Called whenever a node belonging to this manager first 
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index 235ee4a..bb4d640 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -308,9 +308,7 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
   int id=-1;
   //  int lower=-1,upper=-1;
   myint temp_parentwidth=y2-y1;
-  int temp_parentcolor = (pRender->GetDisplayInfo()->bVisible)
-    ? pRender->GetDisplayInfo()->iColour
-    : parent_color;
+  int temp_parentcolor = pRender->GetDisplayInfo()->iColour;
 
   const int Range(y2 - y1);
   
@@ -382,7 +380,7 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
 		}
   }  
     // Draw the outline
-    if(!(pRender->GetFlag(NF_SUBNODE))) {
+    if(pRender->GetDisplayInfo()->bVisible && !(pRender->GetFlag(NF_SUBNODE))) {
       RenderNodeOutlineFast(pRender->GetDisplayInfo()->iColour, 
 			    y1, y2, mostleft, 
 			    pRender->GetDisplayInfo()->strDisplayText, 
diff --git a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
index 64a84c5..169469e 100644
--- a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
@@ -187,14 +187,11 @@ void CPPMPYLanguageModel::GetProbs(Context context, std::vector<unsigned int> &p
   DASHER_ASSERT(iToSpend == 0);
 }
 
-void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int iNumSymbols, int norm, int iUniform){
+void CPPMPYLanguageModel::GetPartProbs(Context context, const std::vector<SCENode *> &vChildren, int norm, int iUniform){
   
   
-  SCENode * pNewStart = *pStart;
-  SCENode * pNode = pNewStart;
-
-  if(iNumSymbols == 1){
-    pNode->NodeSize = norm;
+  if(vChildren.size() == 1){
+    vChildren[0]->NodeSize = norm;
     return;
   }
   //  std::cout<<"Norms is "<<norm<<std::endl;
@@ -209,7 +206,7 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
   //  probs.resize(iNumSymbols);
 
   // Leave the vector treatment for now
-  std::vector < bool > exclusions(iNumSymbols);
+  std::vector < bool > exclusions(vChildren.size());
   
   unsigned int iToSpend = norm;
   unsigned int iUniformLeft = iUniform;
@@ -219,20 +216,18 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
   
   //Reproduce iterative calculations with SCENode trie
 
-  if(pNode){
-    pNode -> NodeSize = 0;
-    pNode = pNode->GetNext();
-  }
-
-  int i =1;
-  while(pNode){
-    pNode->NodeSize = iUniformLeft / (iNumSymbols - i);
-    //  std::cout<<"iUniformLeft: "<<iUniformLeft<<std::endl;
-    iUniformLeft -= pNode->NodeSize;
-    iToSpend -= pNode->NodeSize;
-    exclusions[i] = false;
-    pNode =pNode->GetNext();
-    i++;
+  if(vChildren.size()){
+    vChildren[0] -> NodeSize = 0;
+    int i=1;
+    for (std::vector<SCENode *>::const_iterator it = vChildren.begin()+1; it!=vChildren.end(); it++) {
+      SCENode *pNode(*it);
+      pNode->NodeSize = iUniformLeft / (vChildren.size() - i);
+      //  std::cout<<"iUniformLeft: "<<iUniformLeft<<std::endl;
+      iUniformLeft -= pNode->NodeSize;
+      iToSpend -= pNode->NodeSize;
+      exclusions[i] = false;
+      i++;
+    }
   }
 
   DASHER_ASSERT(iUniformLeft == 0);
@@ -251,10 +246,9 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
   while(pTemp!=0){
     int iTotal =0;
     vNodeStore.clear();
-
-    pNode = pNewStart;
-    i=0;
-    while(pNode){
+    int i=0;
+    for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+      SCENode *pNode(*it);
 
       pFound = pTemp->find_symbol(pNode->Symbol);
       //Mark: do we need to treat the exception of -1 separately?     
@@ -265,7 +259,6 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
       else
 	vNodeStore.push_back(NULL);
 	
-      pNode= pNode->GetNext();
       i++;
     }
     
@@ -274,19 +267,18 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
     if(iTotal){
       unsigned int size_of_slice = iToSpend;
       
-      i=0;
-      pNode=pNewStart;
-      while(pNode){
-	if((!(exclusions[i] && doExclusion))&&(vNodeStore[i])) {
-	    exclusions[i] = 1;
-	    unsigned int p = static_cast < myint > (size_of_slice) * (100 * vNodeStore[i]->count - beta) / (100 * iTotal + alpha);
-	    if((pNode->Symbol>-1)&&(pNode->Symbol<=m_iAlphSize)){
-	      pNode->NodeSize += p;
-	      iToSpend -= p;
-	    }
-	}
-	pNode= pNode->GetNext();
-	i++;
+      int i=0;
+      for (vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+        SCENode *pNode(*it);
+        if((!(exclusions[i] && doExclusion))&&(vNodeStore[i])) {
+          exclusions[i] = 1;
+          unsigned int p = static_cast < myint > (size_of_slice) * (100 * vNodeStore[i]->count - beta) / (100 * iTotal + alpha);
+          if((pNode->Symbol>-1)&&(pNode->Symbol<=m_iAlphSize)){
+            pNode->NodeSize += p;
+            iToSpend -= p;
+          }
+        }
+        i++;
       }
     }
     pTemp = pTemp->vine;
@@ -298,7 +290,7 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
   unsigned int size_of_slice = iToSpend;
   int symbolsleft = 0;
 
-  for(i = 1; i < iNumSymbols; i++)
+  for(unsigned int i = 1; i < vChildren.size(); i++)
     if(!(exclusions[i] && doExclusion))
       symbolsleft++;
 
@@ -316,35 +308,32 @@ void CPPMPYLanguageModel::GetPartProbs(Context context, SCENode ** pStart, int i
 //      DASHER_TRACEOUTPUT("valid %s",str2.str().c_str());
   //std::cout<<"after lan mod third loop"<<std::endl;
   
-  if(pNewStart)
-    pNode = pNewStart->GetNext();
-
-  i=1;
-  while(pNode){
-    if(!(exclusions[i] && doExclusion)) {
-      unsigned int p = size_of_slice / symbolsleft;
-      pNode->NodeSize += p;
-      iToSpend -= p;
+  if(vChildren.size()) {
+    int i=1;
+    for (std::vector<SCENode *>::const_iterator it = vChildren.begin()+1; it!=vChildren.end(); it++) {
+      if(!(exclusions[i] && doExclusion)) {
+        unsigned int p = size_of_slice / symbolsleft;
+        (*it)->NodeSize += p;
+        iToSpend -= p;
+      }
+      i++;
     }
-    pNode = pNode->GetNext();
-    i++;
   }
   // std::cout<<"after lan mod fourth loop"<<std::endl;
-  int iLeft = iNumSymbols-1;
+  int iLeft = vChildren.size()-1;
 
-  if(pNewStart)
-    pNode = pNewStart->GetNext();
-  //  std::cout<<"iNumsyjbols "<<iNumSymbols<<std::endl;
+  if(vChildren.size()) {
+    //  std::cout<<"iNumsyjbols "<<vChildren.size()<<std::endl;
 
-  while(pNode){
+    for (std::vector<SCENode *>::const_iterator it = vChildren.begin()+1; it!=vChildren.end(); it++) {
 
-    //     std::cout<<"iLeft "<<iLeft<<std::endl;
-    //  std::cout<<"iToSpend "<<iToSpend<<std::endl;
-    unsigned int p = iToSpend / iLeft;
-    pNode->NodeSize += p;
-    --iLeft;
-    iToSpend -= p;
-    pNode = pNode->GetNext();
+      //     std::cout<<"iLeft "<<iLeft<<std::endl;
+      //  std::cout<<"iToSpend "<<iToSpend<<std::endl;
+      unsigned int p = iToSpend / iLeft;
+      (*it)->NodeSize += p;
+      --iLeft;
+      iToSpend -= p;
+    }
   }
 
   //std::cout<<"after lan mod fifth loop"<<std::endl;
diff --git a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
index 94f466f..1fe2c42 100644
--- a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
@@ -90,7 +90,7 @@ namespace Dasher {
     virtual void GetProbs(Context context, std::vector < unsigned int >&Probs, int norm, int iUniform) const;
     void GetPYProbs(Context context, std::vector < unsigned int >&Probs, int norm, int iUniform);
 
-    void GetPartProbs(Context context, SCENode **pStart, int iNumSymbols, int norm, int iUniform);
+    void GetPartProbs(Context context, const std::vector<SCENode *> &vChildren, int norm, int iUniform);
 
     void dump();
 
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index 85833b7..3967ca5 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -61,10 +61,9 @@ CAlphabetManager::CAlphNode *CMandarinAlphMgr::GetRoot(CDasherNode *pParent, int
     pDispInfo->bVisible = true;
     pDispInfo->strDisplayText = "";
     pDispInfo->iColour = m_pNCManager->GetAlphabet()->GetColour(0, 0);
-    pNewNode = makeNode(pParent, iLower, iUpper, pDispInfo);
+    pNewNode = makeGroup(pParent, iLower, iUpper, pDispInfo, NULL);
     pNewNode->m_iOffset=max(0,iOffset)-1;
     pNewNode->iPhase=0;
-    pNewNode->iSymbol=0;
   } else {
     //probably rebuilding parent; call standard GetRoot, which'll extract the most recent symbol
     // (entered by the node (equivalent to that) which we are rebuilding)
@@ -83,9 +82,9 @@ CAlphabetManager::CAlphNode *CMandarinAlphMgr::GetRoot(CDasherNode *pParent, int
   return pNewNode;
 }
 
-CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild) {
+CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
 
-  if (iSymbol <= 1288 && iSymbol != iExistingSymbol) {
+  if (iSymbol <= 1288) {
     //Will wrote:
     //Modified for Mandarin Dasher
     //The following logic switch allows punctuation nodes in Mandarin to be treated in the same way as English (i.e. display and populate next round) instead of invoking a conversion node
@@ -95,7 +94,7 @@ CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, symbol iSymb
 	  static_cast<CPinYinConversionHelper::CPYConvNode *>(pNewNode)->SetConvSymbol(iSymbol);
 	  return pNewNode;
   }
-  return CAlphabetManager::CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd, iExistingSymbol, pExistingChild);
+  return CAlphabetManager::CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd);
 }
 
 CLanguageModel::Context CMandarinAlphMgr::CreateSymbolContext(CAlphNode *pParent, symbol iSymbol)
@@ -104,12 +103,12 @@ CLanguageModel::Context CMandarinAlphMgr::CreateSymbolContext(CAlphNode *pParent
 	return m_pLanguageModel->CloneContext(pParent->iContext);
 }
 
-CMandarinAlphMgr::CMandNode::CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr)
-: CAlphNode(pParent, iLbnd, iHbnd, pDispInfo, pMgr) {
+CMandarinAlphMgr::CMandNode::CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr, symbol iSymbol)
+: CSymbolNode(pParent, iLbnd, iHbnd, pDispInfo, pMgr, iSymbol) {
 }
 
-CAlphabetManager::CAlphNode *CMandarinAlphMgr::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo) {
-  return new CMandNode(pParent, iLbnd, iHbnd, pDispInfo, this);
+CAlphabetManager::CSymbolNode *CMandarinAlphMgr::makeSymbol(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, symbol iSymbol) {
+  return new CMandNode(pParent, iLbnd, iHbnd, pDispInfo, this, iSymbol);
 }
 
 void CMandarinAlphMgr::CMandNode::SetFlag(int iFlag, bool bValue) {
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index a54c5a9..906b02d 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -44,13 +44,13 @@ namespace Dasher {
     virtual CAlphNode *GetRoot(CDasherNode *pParent, int iLower, int iUpper, bool bEnteredLast, int iOffset);
 
   protected:
-    class CMandNode : public CAlphNode {
+    class CMandNode : public CSymbolNode {
     public:
-      CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr);
+      CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr, symbol iSymbol);
       virtual void SetFlag(int iFlag, bool bValue);
     };
-    CAlphNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);
-    virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild);
+    CSymbolNode *makeSymbol(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, symbol iSymbol);
+    virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd);
     virtual CLanguageModel::Context CreateSymbolContext(CAlphNode *pParent, symbol iSymbol);
   };
   /// @}
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index 8a417ba..0bdc3e0 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -196,20 +196,13 @@ CDasherNode *CNodeCreationManager::GetConvRoot(Dasher::CDasherNode *pParent, int
  return NULL;
 }
 
-void CNodeCreationManager::GetProbs(CLanguageModel::Context context, std::vector <symbol >&NewSymbols, std::vector <unsigned int >&Probs, int iNorm) const {
+void CNodeCreationManager::GetProbs(CLanguageModel::Context context, std::vector <unsigned int >&Probs, int iNorm) const {
   // Total number of symbols
   int iSymbols = m_pAlphabet->GetNumberSymbols();      // note that this includes the control node and the root node
   
   // Number of text symbols, for which the language model gives the distribution
   // int iTextSymbols = m_pAlphabet->GetNumberTextSymbols();
   
-  NewSymbols.resize(iSymbols);
-//      Groups.resize(iSymbols);
-  for(int i = 0; i < iSymbols; i++) {
-    NewSymbols[i] = i;          // This will be replaced by something that works out valid nodes for this context
-    //      Groups[i]=m_pAlphabet->get_group(i);
-  }
-
   // TODO - sort out size of control node - for the timebeing I'll fix the control node at 5%
   // TODO: New method (see commented code) has been removed as it wasn' working.
 
diff --git a/Src/DasherCore/NodeCreationManager.h b/Src/DasherCore/NodeCreationManager.h
index 43db392..8bfd194 100644
--- a/Src/DasherCore/NodeCreationManager.h
+++ b/Src/DasherCore/NodeCreationManager.h
@@ -54,7 +54,7 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
 
   void DisconnectNode(int iChild, int iParent);
 
-  void GetProbs(Dasher::CLanguageModel::Context context, std::vector <Dasher::symbol >&NewSymbols, std::vector <unsigned int >&Probs, int iNorm) const;
+  void GetProbs(Dasher::CLanguageModel::Context context, std::vector <unsigned int >&Probs, int iNorm) const;
 
   ///
   /// Get a reference to the alphabet
diff --git a/Src/DasherCore/PinYinConversionHelper.cpp b/Src/DasherCore/PinYinConversionHelper.cpp
index 32e8f04..f0ce267 100644
--- a/Src/DasherCore/PinYinConversionHelper.cpp
+++ b/Src/DasherCore/PinYinConversionHelper.cpp
@@ -75,16 +75,15 @@ bool CPinYinConversionHelper::Convert(const std::string &strSource, SCENode ** p
   return (pParser && pParser->Convert(strSource, pRoot));
 }
 
-unsigned int CPinYinConversionHelper::GetSumPYProbs(Dasher::CLanguageModel::Context context, SCENode * pPYCandStart, int norm){
+unsigned int CPinYinConversionHelper::GetSumPYProbs(Dasher::CLanguageModel::Context context, std::vector<SCENode *> &pPYCandStart, int norm){
 
   std::vector <unsigned int> Probs;
   unsigned int sumProb=0;
   
   GetLanguageModel()->GetProbs(context, Probs, norm, 0);
 
-  SCENode * pCurrentNode = pPYCandStart;
-
-  while(pCurrentNode){
+  for (std::vector<SCENode *>::iterator it = pPYCandStart.begin(); it != pPYCandStart.end(); it++) {
+    SCENode *pCurrentNode(*it);
     
     std::vector <symbol >Symbols;
     std::string HZ = static_cast<std::string>(pCurrentNode->pszConversion);
@@ -94,7 +93,6 @@ unsigned int CPinYinConversionHelper::GetSumPYProbs(Dasher::CLanguageModel::Cont
 
     if(Symbols.size()!=0)
       sumProb += Probs[Symbols[0]];
-    pCurrentNode = pCurrentNode->GetNext();
 
   }
 
@@ -104,21 +102,16 @@ unsigned int CPinYinConversionHelper::GetSumPYProbs(Dasher::CLanguageModel::Cont
 void CPinYinConversionHelper::GetProbs(Dasher::CLanguageModel::Context context, std::vector < unsigned int >&Probs, int norm){
 }
 
-void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageModel::Context context, long normalization, int uniform, int iNChildren){
+void CPinYinConversionHelper::AssignSizes(const std::vector<SCENode *> &vChildren, Dasher::CLanguageModel::Context context, long normalization, int uniform){
 
   //test print:
   int print = 0;
 
-  SCENode *pNewStart = *pStart;
-
-  SCENode *pNode = pNewStart;
-
-
   //  std::cout<<"Head node "<<pNewStart->pszConversion<<std::endl;
   std::vector <unsigned int> Probs;
 
   int iSymbols = m_pCHAlphabet->GetNumberSymbols(); 
-  int iLeft(iNChildren);
+  int iLeft(vChildren.size());
   int iRemaining(normalization);
 
   int uniform_add;
@@ -137,8 +130,8 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
   //CLanguageModel::Context iCurrentContext;
 
   //  int iNumSymbols =0;
-  while(pNode){
-
+  for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+    SCENode *pNode(*it);
     Symbols.clear();
 
     std::string HZ(pNode->pszConversion);
@@ -150,24 +143,18 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
     }
     else
       pNode->Symbol = -1;
-
-    pNode = pNode->GetNext();
   }
 
   //  std::cout<<"size of symbolstore "<<SymbolStore.size()<<std::endl;  
  
   //  std::cout<<"norm input: "<<nonuniform_norm/(iSymbols/iNChildren/100)<<std::endl;
 
-  GetLanguageModel()->GetPartProbs(context, pStart, iNChildren, nonuniform_norm, 0);
+  GetLanguageModel()->GetPartProbs(context, vChildren, nonuniform_norm, 0);
 
   //std::cout<<"after get probs "<<std::endl;
 
- pNode = pNewStart;
- while(pNode){
-    sumProb += pNode->NodeSize;
-
-    //    std::cout<<"Nodesize: "<<pNode->NodeSize<<std::endl;
-    pNode = pNode->GetNext();
+  for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+    sumProb += (*it)->NodeSize;
  }
 
  //  std::cout<<"Sum Prob "<<sumProb<<std::endl;
@@ -180,8 +167,8 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
   if(print)
     std::cout<<"sumProb "<<sumProb<<std::endl;
 
-  pNode = pNewStart;
-  while(pNode){
+  for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+    SCENode *pNode(*it);
     if((pNode->Symbol!=-1)&&(sumProb!=0)){
       // std::cout<<"Probs size "<<pNode->NodeSize<<std::endl;
       pNode->NodeSize = static_cast<unsigned long long int>(pNode->NodeSize*(normalization/sumProb));//*(100 - m_iPriorityScale * pNode->GetPriority()) 
@@ -207,8 +194,6 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
     // std::cout<<"Symbol i"<<SymbolStore[iIdx]<<std::endl;
     // std::cout<<"symbols size "<<SymbolStore.size()<<std::endl;
     // std::cout<<"Symbols address "<<&SymbolStore<<std::endl;
-
-    pNode = pNode->GetNext();
   }
 
   if(print)
@@ -219,8 +204,8 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
 
 
   
-  pNode = pNewStart;
-  while(pNode){
+  for (std::vector<SCENode *>::const_iterator it = vChildren.begin(); it!=vChildren.end(); it++) {
+    SCENode *pNode(*it);
     int iDiff(iRemaining / iLeft);
     
     pNode->NodeSize += iDiff;
@@ -230,7 +215,6 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
     
     //    std::cout<<"Node size for "<<pNode->pszConversion<<std::endl;
     //std::cout<<"is "<<pNode->NodeSize<<std::endl;
-    pNode = pNode->GetNext();
   }
   
 }
diff --git a/Src/DasherCore/PinYinConversionHelper.h b/Src/DasherCore/PinYinConversionHelper.h
index b617047..4a48e0c 100644
--- a/Src/DasherCore/PinYinConversionHelper.h
+++ b/Src/DasherCore/PinYinConversionHelper.h
@@ -25,11 +25,11 @@ class CPinYinConversionHelper : public CConversionHelper {
   
   virtual bool Convert(const std::string &strSource, SCENode ** pRoot);
 
-  virtual void AssignSizes(SCENode **pStart, Dasher::CLanguageModel::Context context , long normalization, int uniform, int iNChildren);
+  virtual void AssignSizes(const std::vector<SCENode *> &vChildren, Dasher::CLanguageModel::Context context , long normalization, int uniform);
 
   virtual void GetProbs(Dasher::CLanguageModel::Context context, std::vector < unsigned int >&Probs, int norm);
 
-  virtual unsigned int GetSumPYProbs(Dasher::CLanguageModel::Context context, SCENode * pPYCandStart,int norm);
+  virtual unsigned int GetSumPYProbs(Dasher::CLanguageModel::Context context, std::vector <SCENode *> &pPYCandStart,int norm);
 
 protected:
   class CPYConvNode : public CConvHNode {
diff --git a/Src/DasherCore/PinyinParser.cpp b/Src/DasherCore/PinyinParser.cpp
index 8c2a415..564a9bd 100644
--- a/Src/DasherCore/PinyinParser.cpp
+++ b/Src/DasherCore/PinyinParser.cpp
@@ -171,13 +171,10 @@ bool CPinyinParser::Convert(const std::string &pystr, SCENode **pRoot) {
       return 0;
 
     *pRoot = new SCENode;
-    SCENode *pCurrent = *pRoot;
-
-    pCurrent->pszConversion = "";
-    SCENode *pNewNode = new SCENode;
-    pCurrent->SetChild(pNewNode);
+    (*pRoot)->pszConversion = "";
 
     for(std::set<std::string>::iterator it = pCurrentNode->m_pList->begin(); it != pCurrentNode->m_pList->end(); ++it) {
+      SCENode *pNewNode = new SCENode;
         
       pNewNode->pszConversion = new char[it->size() + 1];
       strcpy(pNewNode->pszConversion, it->c_str());
@@ -187,14 +184,9 @@ bool CPinyinParser::Convert(const std::string &pystr, SCENode **pRoot) {
       // std::vector<int> CHSym;
       // m_pCHAlphabet->GetSymbols(&CHSym, &strChar, 0);
       // pNewNode->Symbol = CHSym[0];
-
-      pCurrent = pNewNode; 
       
-      pNewNode = new SCENode;
-      pCurrent->SetNext(pNewNode);
-      pCurrent->SetChild(NULL);
+      (*pRoot)->AddChild(pNewNode);
     }
-    pCurrent->SetNext(NULL);
 
     //Test code: will make program crash
     //    SCENode * pTemp = *pRoot;
diff --git a/Src/DasherCore/SCENode.cpp b/Src/DasherCore/SCENode.cpp
index f47c448..cc3cffc 100644
--- a/Src/DasherCore/SCENode.cpp
+++ b/Src/DasherCore/SCENode.cpp
@@ -21,39 +21,12 @@
 #include "SCENode.h"
 
 SCENode::SCENode() {
-  m_pNext = 0;
-  m_pChild = 0;
-  
   m_iRefCount = 1;
 }
 
 SCENode::~SCENode() {
   // TODO: Delete string?
 
-  if(m_pNext)
-    m_pNext->Unref();
-  
-  if(m_pChild)
-    m_pChild->Unref();
+  for (std::vector<SCENode *>::iterator it = m_vChildren.begin(); it!=m_vChildren.end(); it++)
+    (*it)->Unref();
 }
-
-void SCENode::SetNext(SCENode *pNext) {
-  if(m_pNext)
-    m_pNext->Unref();
-  
-  m_pNext = pNext;
-
-  if(m_pNext)
-    m_pNext->Ref();
-};
-
-void SCENode::SetChild(SCENode *pChild) {
-  if(m_pChild)
-    m_pChild->Unref();
-  
-  m_pChild = pChild;
-
-  if(m_pChild)
-    m_pChild->Ref();
-};
-
diff --git a/Src/DasherCore/SCENode.h b/Src/DasherCore/SCENode.h
index b3dda13..b7dcbfb 100644
--- a/Src/DasherCore/SCENode.h
+++ b/Src/DasherCore/SCENode.h
@@ -24,6 +24,8 @@
 /*Common Node Definition for Chinese Pinyin (possibly also Japanese) 
   Conversion Library and Dasher ConversionManager*/
 
+#include <vector>
+
 /// \ingroup Model
 /// \{
 class SCENode {
@@ -44,17 +46,13 @@ class SCENode {
     }
   };
   
-  SCENode *GetNext() {
-    return m_pNext;
-  };
-
-  void SetNext(SCENode *pNext);
-
-  SCENode *GetChild() {
-    return m_pChild;
-  };
-
-  void SetChild(SCENode *pChild);
+  const std::vector<SCENode *> &GetChildren() const {
+    return m_vChildren;
+  }
+  void AddChild(SCENode *pChild) {
+    m_vChildren.push_back(pChild);
+    pChild->Ref();
+  }
 
   void SetPriority(int iPriority) {
     m_iPriority = iPriority;
@@ -81,8 +79,7 @@ class SCENode {
  private:
   int m_iRefCount;
 
-  SCENode *m_pNext;
-  SCENode *m_pChild;
+  std::vector<SCENode *> m_vChildren;
 
   int m_iPriority;
 };



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]