[dasher: 8/27] Reorganize control/conversion-node generation



commit 6b8d6c20f9182fb43dee5a4b361341734b6a2112
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Wed Aug 4 22:03:35 2010 +0100

    Reorganize control/conversion-node generation
    
    Added CAlphabetManager::AddExtras for such nodes, rather than treat as symbols.
    Moved NCManager::GetProbs into CAlphabetManager...
       *Tidied, fixed to use correct normalization, reinstated checking assertion
       *Leaves out control node prob.
    
    If conversion required, ConvertingAlphMgr stores ConversionManager and
     adds conversion root. (ConvMgr / GetConvRoot() removed from NCManager)
    
    Tidies to Alphabet: make things const, remove once-only methods, standardize on
     using GetNumberTextSymbols() (GetNumberSymbols() dropped; TODO: the difference
     between these looks to have been supposed to be to do with conversion, but does
     not look to have been implemented nor is it clear what is/was intended...)

 Src/DasherCore/Alphabet/Alphabet.cpp        |   82 +++------------
 Src/DasherCore/Alphabet/Alphabet.h          |   46 ++-------
 Src/DasherCore/AlphabetManager.cpp          |  152 ++++++++++++++++-----------
 Src/DasherCore/AlphabetManager.h            |   30 ++++--
 Src/DasherCore/ConvertingAlphMgr.cpp        |   30 +++++
 Src/DasherCore/ConvertingAlphMgr.h          |   32 ++++++
 Src/DasherCore/Makefile.am                  |    2 +
 Src/DasherCore/MandarinAlphMgr.cpp          |    6 +-
 Src/DasherCore/MandarinAlphMgr.h            |    2 +-
 Src/DasherCore/NodeCreationManager.cpp      |  128 ++++++-----------------
 Src/DasherCore/NodeCreationManager.h        |   12 ++-
 Src/MacOSX/Dasher.xcodeproj/project.pbxproj |    8 ++
 12 files changed, 253 insertions(+), 277 deletions(-)
---
diff --git a/Src/DasherCore/Alphabet/Alphabet.cpp b/Src/DasherCore/Alphabet/Alphabet.cpp
index 97f88bc..2309fed 100644
--- a/Src/DasherCore/Alphabet/Alphabet.cpp
+++ b/Src/DasherCore/Alphabet/Alphabet.cpp
@@ -43,23 +43,13 @@ static char THIS_FILE[] = __FILE__;
 
 /////////////////////////////////////////////////////////////////////////////
 
-CAlphabet::CAlphabet()
-:m_DefaultEncoding(Opts::Western), m_Orientation(Opts::LeftToRight), m_ControlSymbol(-1) {
-  m_Characters.push_back("");
-  m_Display.push_back("");
-  m_Colours.push_back(-1);
-  m_Foreground.push_back("");
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo)
-:m_DefaultEncoding(Opts::Western), m_Orientation(Opts::LeftToRight), m_ControlSymbol(-1) {
+CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo) : m_pBaseGroup(AlphInfo.m_pBaseGroup), iNumChildNodes(AlphInfo.iNumChildNodes) {
   m_Characters.push_back("");
   m_Display.push_back("");
   m_Colours.push_back(-1);
   m_Foreground.push_back("");
 
+  m_ControlSymbol = -1;
   m_StartConversionSymbol = -1;
   m_EndConversionSymbol = -1;
 
@@ -67,11 +57,11 @@ CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo)
 
   // Set miscellaneous options
 
-  SetOrientation(AlphInfo.Orientation);
-  SetLanguage(AlphInfo.Type);
-  SetTrainingFile(AlphInfo.TrainingFile);
-  SetGameModeFile(AlphInfo.GameModeFile);
-  SetPalette(AlphInfo.PreferredColours);
+  m_Orientation = AlphInfo.Orientation;
+  m_DefaultEncoding = AlphInfo.Type;
+  m_TrainingFile = AlphInfo.TrainingFile;
+  m_GameModeFile = AlphInfo.GameModeFile;
+  m_DefaultPalette = AlphInfo.PreferredColours;
 
   for(std::vector<CAlphIO::AlphInfo::character>::const_iterator it(AlphInfo.m_vCharacters.begin()); it != AlphInfo.m_vCharacters.end(); ++it)
     AddChar(it->Text, it->Display, it->Colour, it->Foreground);
@@ -85,17 +75,17 @@ CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo)
   std::string empty = "";
 
   if(AlphInfo.ParagraphCharacter.Text != empty)
-    AddParagraphSymbol(AlphInfo.ParagraphCharacter.Text, AlphInfo.ParagraphCharacter.Display, AlphInfo.ParagraphCharacter.Colour, AlphInfo.ParagraphCharacter.Foreground);
+    m_ParagraphSymbol = AddChar(AlphInfo.ParagraphCharacter.Text, AlphInfo.ParagraphCharacter.Display, AlphInfo.ParagraphCharacter.Colour, AlphInfo.ParagraphCharacter.Foreground);
 
   if(AlphInfo.SpaceCharacter.Text != empty)
-    AddSpaceSymbol(AlphInfo.SpaceCharacter.Text, AlphInfo.SpaceCharacter.Display, AlphInfo.SpaceCharacter.Colour, AlphInfo.SpaceCharacter.Foreground);
+    m_SpaceSymbol = AddChar(AlphInfo.SpaceCharacter.Text, AlphInfo.SpaceCharacter.Display, AlphInfo.SpaceCharacter.Colour, AlphInfo.SpaceCharacter.Foreground);
 
   //-- Added for Kanji Conversion 13 July 2005 by T.Kaburagi START
   if(AlphInfo.StartConvertCharacter.Text != empty)
-    AddStartConversionSymbol(AlphInfo.StartConvertCharacter.Text, AlphInfo.StartConvertCharacter.Display, AlphInfo.StartConvertCharacter.Colour, AlphInfo.StartConvertCharacter.Foreground);
+    m_StartConversionSymbol = AddChar(AlphInfo.StartConvertCharacter.Text, AlphInfo.StartConvertCharacter.Display, AlphInfo.StartConvertCharacter.Colour, AlphInfo.StartConvertCharacter.Foreground);
 
   if(AlphInfo.EndConvertCharacter.Text != empty)
-    AddEndConversionSymbol(AlphInfo.EndConvertCharacter.Text, AlphInfo.EndConvertCharacter.Display, AlphInfo.EndConvertCharacter.Colour, AlphInfo.EndConvertCharacter.Foreground);
+    m_EndConversionSymbol = AddChar(AlphInfo.EndConvertCharacter.Text, AlphInfo.EndConvertCharacter.Display, AlphInfo.EndConvertCharacter.Colour, AlphInfo.EndConvertCharacter.Foreground);
   //-- Added for Kanji Conversion 13 July 2005 by T.Kaburagi END
 
   // DJW - now the control symbol is always a part of the alphabet
@@ -104,14 +94,8 @@ CAlphabet::CAlphabet(const CAlphIO::AlphInfo &AlphInfo)
   // FIXME - We really need to ensure that the control symbol is last in the alphabet with the current logic.
 
   if(AlphInfo.ControlCharacter.Display != std::string("") && GetControlSymbol() == -1)
-    AddControlSymbol(AlphInfo.ControlCharacter.Text, AlphInfo.ControlCharacter.Display, AlphInfo.ControlCharacter.Colour, AlphInfo.ControlCharacter.Foreground);
+    m_ControlSymbol = AddChar(AlphInfo.ControlCharacter.Text, AlphInfo.ControlCharacter.Display, AlphInfo.ControlCharacter.Colour, AlphInfo.ControlCharacter.Foreground);
 
-
-
-  // New group stuff
-
-  m_pBaseGroup = AlphInfo.m_pBaseGroup;
-  iNumChildNodes = AlphInfo.iNumChildNodes;
 #ifdef DASHER_TRACE
   Trace();
 #endif
@@ -217,8 +201,8 @@ void CAlphabet::GetSymbols(std::vector<symbol>& Symbols, const std::string& Inpu
     Symbols.push_back(sym);
 }
 
-// add single char to the character set
-void CAlphabet::AddChar(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
+
+symbol CAlphabet::AddChar(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
   m_Characters.push_back(NewCharacter);
   m_Display.push_back(Display);
   m_Colours.push_back(Colour);
@@ -226,41 +210,7 @@ void CAlphabet::AddChar(const std::string NewCharacter, const std::string Displa
 
   symbol ThisSymbol = m_Characters.size() - 1;
   TextMap.Add(NewCharacter, ThisSymbol);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAlphabet::AddParagraphSymbol(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
-  AddChar(NewCharacter, Display, Colour, Foreground);
-  m_ParagraphSymbol = GetNumberSymbols() - 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAlphabet::AddSpaceSymbol(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
-  AddChar(NewCharacter, Display, Colour, Foreground);
-  m_SpaceSymbol = GetNumberSymbols() - 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAlphabet::AddControlSymbol(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
-  AddChar(NewCharacter, Display, Colour, Foreground);
-  m_ControlSymbol = GetNumberSymbols() - 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAlphabet::AddStartConversionSymbol(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
-  AddChar(NewCharacter, Display, Colour, Foreground);
-  m_StartConversionSymbol = GetNumberSymbols() - 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAlphabet::AddEndConversionSymbol(const std::string NewCharacter, const std::string Display, int Colour, const std::string Foreground) {
-  AddChar(NewCharacter, Display, Colour, Foreground);
-  m_EndConversionSymbol = GetNumberSymbols() - 1;
+  return ThisSymbol;
 }
 
 
@@ -290,7 +240,7 @@ void CAlphabet::Trace() const {
 
 /////////////////////////////////////////////////////////////////////////////
 
-int CAlphabet::GetTextColour(symbol Symbol) {
+int CAlphabet::GetTextColour(symbol Symbol) const {
   std::string TextColour = m_Foreground[Symbol];
   if(TextColour != std::string("")) {
     return atoi(TextColour.c_str());
diff --git a/Src/DasherCore/Alphabet/Alphabet.h b/Src/DasherCore/Alphabet/Alphabet.h
index ba31c45..189d9d6 100644
--- a/Src/DasherCore/Alphabet/Alphabet.h
+++ b/Src/DasherCore/Alphabet/Alphabet.h
@@ -37,14 +37,8 @@ namespace Dasher {
 
   class CAlphabet {
   public:
-    CAlphabet();
     CAlphabet(const CAlphIO::AlphInfo & AlphInfo);
 
-    // Return size of alphabet, including control symbols
-    int GetNumberSymbols() const {
-      return m_Characters.size();
-    }                           // return size of alphabet
-
     /// Return number of text symbols 
     /// Text symbols are everything which doesn't generate a new root, 
     /// i.e. control mode and conversion mode
@@ -54,21 +48,21 @@ namespace Dasher {
       return m_Characters.size() - 1;
     } 
 
-    Opts::ScreenOrientations GetOrientation() {
+    Opts::ScreenOrientations GetOrientation() const {
       return m_Orientation;
     } 
 
-    Opts::AlphabetTypes GetType() {
+    Opts::AlphabetTypes GetType() const {
       return m_DefaultEncoding;
     }
 
     const std::string & GetTrainingFile() const {
       return m_TrainingFile;
     }
-    std::string GetGameModeFile() {
+    const std::string &GetGameModeFile() const {
       return m_GameModeFile;
     }
-    std::string & GetPalette() {
+    const std::string & GetPalette() const {
       return m_DefaultPalette;
     }
 
@@ -90,7 +84,7 @@ namespace Dasher {
 
     int GetColour(symbol i, int iPhase) const;
 
-    int GetTextColour(symbol i);      // return the foreground colour for i'th symbol
+    int GetTextColour(symbol i) const;      // return the foreground colour for i'th symbol
     const std::string & GetForeground(symbol i) const {
       return m_Foreground[i];
     } // return the foreground colour for i'th symbol
@@ -127,39 +121,17 @@ namespace Dasher {
 
     void Trace() const;         // diagnostic
 
-    void SetOrientation(Opts::ScreenOrientations Orientation) {
-      m_Orientation = Orientation;
-    }
-    void SetLanguage(Opts::AlphabetTypes Group) {
-      m_DefaultEncoding = Group;
-    }
-    void SetTrainingFile(std::string TrainingFile) {
-      m_TrainingFile = TrainingFile;
-    }
-    void SetGameModeFile(std::string GameModeFile) {
-      m_GameModeFile = GameModeFile;
-    }
-    void SetPalette(std::string Palette) {
-      m_DefaultPalette = Palette;
-    }
-
     const std::string &GetDefaultContext() const {
       return m_strDefaultContext;
     }
 
-    SGroupInfo *m_pBaseGroup;
-    int iNumChildNodes;
+    const SGroupInfo *m_pBaseGroup;
+    const int iNumChildNodes;
   private:
 
     // Add the characters that can appear in Nodes
-    void AddChar(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);    // add single char to the alphabet
-
-    // Alphabet language parameters
-    void AddParagraphSymbol(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);
-    void AddSpaceSymbol(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);
-    void AddControlSymbol(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);
-    void AddStartConversionSymbol(std::string NewCharacter, std::string Display , int Colour, std::string Foreground);
-    void AddEndConversionSymbol(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);
+    /// add single char to the character set; return it's index as a symbol
+    symbol AddChar(std::string NewCharacter, std::string Display, int Colour, std::string Foreground);    // add single char to the alphabet
 
     Opts::AlphabetTypes m_DefaultEncoding;
     Opts::ScreenOrientations m_Orientation;
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index ce97765..2b06b52 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -45,30 +45,34 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel)
-  : m_pLanguageModel(pLanguageModel), m_pNCManager(pNCManager) {
+CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel)
+  : m_pLanguageModel(pLanguageModel), m_pNCManager(pNCManager), m_pAlphabet(pAlphabet) {
   m_pInterface = pInterface;
 
   m_iLearnContext = m_pLanguageModel->CreateEmptyContext();
 
 }
 
+CAlphabetManager::~CAlphabetManager() {
+  m_pLanguageModel->ReleaseContext(m_iLearnContext);
+}
+
 CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr)
 : CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText), m_pProbInfo(NULL), m_pMgr(pMgr) {
 };
 
 CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CAlphabetManager *pMgr, symbol _iSymbol)
-: CAlphNode(pParent, iOffset, iLbnd, iHbnd, pMgr->m_pNCManager->GetAlphabet()->GetColour(_iSymbol, iOffset%2), pMgr->m_pNCManager->GetAlphabet()->GetDisplayText(_iSymbol), pMgr), iSymbol(_iSymbol) {
+: CAlphNode(pParent, iOffset, iLbnd, iHbnd, pMgr->m_pAlphabet->GetColour(_iSymbol, iOffset%2), pMgr->m_pAlphabet->GetDisplayText(_iSymbol), pMgr), iSymbol(_iSymbol) {
 };
 
 CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr, symbol _iSymbol)
 : CAlphNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, pMgr), iSymbol(_iSymbol) {
 };
 
-CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CAlphabetManager *pMgr, SGroupInfo *pGroup)
+CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CAlphabetManager *pMgr, const SGroupInfo *pGroup)
 : CAlphNode(pParent, iOffset, iLbnd, iHbnd,
             pGroup ? (pGroup->bVisible ? pGroup->iColour : pParent->getColour())
-                   : pMgr->m_pNCManager->GetAlphabet()->GetColour(0, iOffset%2),
+                   : pMgr->m_pAlphabet->GetColour(0, iOffset%2),
             pGroup ? pGroup->strLabel : "", pMgr), m_pGroup(pGroup) {
 };
 
@@ -76,7 +80,7 @@ CAlphabetManager::CSymbolNode *CAlphabetManager::makeSymbol(CDasherNode *pParent
   return new CSymbolNode(pParent, iOffset, iLbnd, iHbnd, this, iSymbol);
 }
 
-CAlphabetManager::CGroupNode *CAlphabetManager::makeGroup(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, SGroupInfo *pGroup) {
+CAlphabetManager::CGroupNode *CAlphabetManager::makeGroup(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const SGroupInfo *pGroup) {
   return new CGroupNode(pParent, iOffset, iLbnd, iHbnd, this, pGroup);
 }
 
@@ -92,9 +96,9 @@ CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, uns
     pParent->GetContext(m_pInterface, vContextSymbols, iStart, iNewOffset+1 - iStart);
   } else {
     std::string strContext = (iNewOffset == -1) 
-      ? m_pNCManager->GetAlphabet()->GetDefaultContext()
+      ? m_pAlphabet->GetDefaultContext()
       : m_pInterface->GetContext(iStart, iNewOffset+1 - iStart);
-    m_pNCManager->GetAlphabet()->GetSymbols(vContextSymbols, strContext);
+    m_pAlphabet->GetSymbols(vContextSymbols, strContext);
   }
   
   CAlphNode *pNewNode;
@@ -114,7 +118,7 @@ CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, uns
     bEnteredLast=false;
     //instead, Create a node as if we were starting a new sentence...
     vContextSymbols.clear();
-    m_pNCManager->GetAlphabet()->GetSymbols(vContextSymbols, m_pNCManager->GetAlphabet()->GetDefaultContext());
+    m_pAlphabet->GetSymbols(vContextSymbols, m_pAlphabet->GetDefaultContext());
     it = vContextSymbols.begin();
     //TODO: What it the default context somehow contains symbols not in the alphabet?
   }
@@ -140,7 +144,7 @@ CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, uns
 }
 
 bool CAlphabetManager::CSymbolNode::GameSearchNode(string strTargetUtf8Char) {
-  if (m_pMgr->m_pNCManager->GetAlphabet()->GetText(iSymbol) == strTargetUtf8Char) {
+  if (m_pMgr->m_pAlphabet->GetText(iSymbol) == strTargetUtf8Char) {
     SetFlag(NF_GAME, true);
     return true;
   }
@@ -176,13 +180,52 @@ void CAlphabetManager::CSymbolNode::PopulateChildren() {
   m_pMgr->IterateChildGroups(this, NULL, NULL);
 }
 int CAlphabetManager::CAlphNode::ExpectedNumChildren() {
-  return m_pMgr->m_pNCManager->GetAlphabet()->iNumChildNodes;
+  return m_pMgr->m_pAlphabet->iNumChildNodes;
+}
+
+void CAlphabetManager::GetProbs(vector<unsigned int> *pProbInfo, CLanguageModel::Context context) {
+  const unsigned int iSymbols = m_pAlphabet->GetNumberTextSymbols() - 1;      // lose the root node
+  unsigned long iNorm(m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  
+  // 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.
+  
+  const int iControlSpace = m_pNCManager->GetBoolParameter(BP_CONTROL_MODE) ? iNorm / 20 : 0;
+  
+  iNorm -= iControlSpace;
+  
+  const unsigned long uniform(m_pNCManager->GetLongParameter(LP_UNIFORM)); 
+  //the case for control mode on, generalizes to handle control mode off also,
+  // as then iNorm - control_space == iNorm...
+  const unsigned int iUniformAdd = ((iNorm * uniform) / 1000) / iSymbols;
+  const unsigned long iNonUniformNorm = iNorm - iSymbols * iUniformAdd;
+  //  m_pLanguageModel->GetProbs(context, Probs, iNorm, ((iNorm * uniform) / 1000));
+  
+  //ACL used to test explicitly for MandarinDasher and if so called GetPYProbs instead
+  // (by statically casting to PPMPYLanguageModel). However, have renamed PPMPYLanguageModel::GetPYProbs
+  // to GetProbs as per ordinary language model, so no need to test....
+  m_pLanguageModel->GetProbs(context, *pProbInfo, iNonUniformNorm, 0);
+  
+  DASHER_ASSERT(pProbInfo->size() == m_pAlphabet->GetNumberTextSymbols());
+  
+  for(unsigned int k(1); k < pProbInfo->size(); ++k)
+    (*pProbInfo)[k] += iUniformAdd;
+  
+#ifdef DEBUG
+  {
+    int iTotal = 0;
+    for(int k = 0; k < pProbInfo->size(); ++k)
+      iTotal += (*pProbInfo)[k];
+    DASHER_ASSERT(iTotal == m_pNCManager->GetLongParameter(LP_NORMALIZATION) - iControlSpace);
+  }
+#endif  
 }
 
 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));
+    m_pMgr->GetProbs(m_pProbInfo, iContext);
+
     // work out cumulative probs in place
     for(unsigned int i = 1; i < m_pProbInfo->size(); i++) {
       (*m_pProbInfo)[i] += (*m_pProbInfo)[i - 1];
@@ -208,7 +251,7 @@ 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) {
+CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
 
   // When creating a group node...
   // ...the offset is the same as the parent...
@@ -220,7 +263,7 @@ CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pPare
   return pNewNode;
 }
 
-CAlphabetManager::CGroupNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
+CAlphabetManager::CGroupNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
   if (pInfo == m_pGroup) {
     SetRange(iLbnd, iHbnd);
     SetParent(pParent);
@@ -236,7 +279,7 @@ CAlphabetManager::CGroupNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNo
   return pRet;
 }
 
-CAlphabetManager::CGroupNode *CAlphabetManager::CSymbolNode::RebuildGroup(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd) {
+CAlphabetManager::CGroupNode *CAlphabetManager::CSymbolNode::RebuildGroup(CAlphNode *pParent, const 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);
@@ -253,48 +296,19 @@ CLanguageModel::Context CAlphabetManager::CreateSymbolContext(CAlphNode *pParent
 
 CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
 
-  CDasherNode *pNewNode = NULL;
+    // TODO: Exceptions / error handling in general
 
-  //Does not invoke conversion node
+    CAlphNode *pAlphNode = makeSymbol(pParent, pParent->offset()+1, iLbnd, iHbnd, iSymbol);
 
-  // TODO: Better way of specifying alternate roots
+    //     std::stringstream ssLabel;
 
-  // TODO: Need to fix fact that this is created even when control mode is switched off
-  if(iSymbol == m_pNCManager->GetAlphabet()->GetControlSymbol()) {
-    CControlManager *pMgr = m_pNCManager->GetControlManager();
-    if (pMgr) {
-#ifdef _WIN32_WCE
-      DASHER_ASSERT(false);
-#endif
-      //ACL leave offset as is - like its groupnode parent, but unlike its alphnode siblings,
-      //the control node does not enter a symbol....
-      pNewNode = pMgr->GetRoot(pParent, iLbnd, iHbnd, pParent->offset());
-    } else {
-      //Control mode currently turned off...
-      DASHER_ASSERT(iLbnd == iHbnd); //zero size
-      pNewNode = NULL;
-    }
-  } else if(iSymbol == m_pNCManager->GetAlphabet()->GetStartConversionSymbol()) {
-      //  else if(iSymbol == m_pNCManager->GetSpaceSymbol()) {
-
-      //ACL setting m_iOffset+1 for consistency with "proper" symbol nodes...
-      pNewNode = m_pNCManager->GetConvRoot(pParent, iLbnd, iHbnd, pParent->offset()+1);
-  } else {
-      // TODO: Exceptions / error handling in general
-
-      CAlphNode *pAlphNode;
-      pNewNode = pAlphNode = makeSymbol(pParent, pParent->offset()+1, iLbnd, iHbnd, iSymbol);
+    //     ssLabel << m_pAlphabet->GetDisplayText(iSymbol) << ": " << pNewNode;
 
-      //     std::stringstream ssLabel;
+    //    pDisplayInfo->strDisplayText = ssLabel.str();
 
-      //     ssLabel << m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol) << ": " << pNewNode;
+    pAlphNode->iContext = CreateSymbolContext(pParent, iSymbol);
 
-      //    pDisplayInfo->strDisplayText = ssLabel.str();
-
-      pAlphNode->iContext = CreateSymbolContext(pParent, iSymbol);
-  }
-
-  return pNewNode;
+  return pAlphNode;
 }
 
 CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd) {
@@ -311,17 +325,20 @@ CDasherNode *CAlphabetManager::CGroupNode::RebuildSymbol(CAlphNode *pParent, sym
   return m_pMgr->CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd);
 }
 
-void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParentGroup, CAlphNode *buildAround) {
+void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphNode *buildAround) {
   std::vector<unsigned int> *pCProb(pParent->GetProbInfo());
+  DASHER_ASSERT((*pCProb)[0] == 0);
   const int iMin(pParentGroup ? pParentGroup->iStart : 1);
-  const int iMax(pParentGroup ? pParentGroup->iEnd : pCProb->size());
+  const int iMax(pParentGroup ? pParentGroup->iEnd : m_pAlphabet->GetNumberTextSymbols());
+  unsigned int iRange(pParentGroup ? ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]) : m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  
   // 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(pParentGroup ? pParentGroup->pChild : m_pNCManager->GetAlphabet()->m_pBaseGroup);
+  const SGroupInfo *pCurrentNode(pParentGroup ? pParentGroup->pChild : m_pAlphabet->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) {
@@ -332,14 +349,14 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParen
     //uint64 is platform-dependently #defined in DasherTypes.h as an (unsigned) 64-bit int ("__int64" or "long long int")
     unsigned int iLbnd = (((*pCProb)[iStart-1] - (*pCProb)[iMin-1]) *
                           (uint64)(m_pNCManager->GetLongParameter(LP_NORMALIZATION))) /
-                         ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]);
+                         iRange;
     unsigned int iHbnd = (((*pCProb)[iEnd-1] - (*pCProb)[iMin-1]) *
                           (uint64)(m_pNCManager->GetLongParameter(LP_NORMALIZATION))) /
-                         ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]);
+                         iRange;
     //loop for eliding groups with single children (see below).
     // Variables store necessary properties of any elided groups:
     std::string groupPrefix=""; int iOverrideColour=-1;
-    SGroupInfo *pInner=pCurrentNode;
+    const SGroupInfo *pInner=pCurrentNode;
     while (true) {
       if (bSymbol) {
         pNewChild = (buildAround) ? buildAround->RebuildSymbol(pParent, i, iLbnd, iHbnd) : CreateSymbolNode(pParent, i, iLbnd, iHbnd);
@@ -370,26 +387,41 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParen
       //3. loop round inner loop...
     }
     //created a new node - symbol or (group which will have >1 child).
-    DASHER_ASSERT((i-1 == m_pNCManager->GetAlphabet()->GetControlSymbol() && pNewChild==NULL) || pParent->GetChildren().back()==pNewChild);
+    DASHER_ASSERT(pParent->GetChildren().back()==pNewChild);
     //now adjust the node we've actually created, to take account of any elided group(s)...
     // tho not if we've reused the existing node, assume that's been adjusted already
     if (pNewChild && pNewChild!=buildAround) pNewChild->PrependElidedGroup(iOverrideColour, groupPrefix);
   }
 
+  if (!pParentGroup) AddExtras(pParent,pCProb);
   pParent->SetFlag(NF_ALLCHILDREN, true);
 }
 
+void CAlphabetManager::AddExtras(CAlphNode *pParent, vector<unsigned int> *pCProb) {
+  //control mode:
+  DASHER_ASSERT((pParent->GetChildren().back()->Hbnd() == m_pNCManager->GetLongParameter(LP_NORMALIZATION)) ^ m_pNCManager->GetBoolParameter(BP_CONTROL_MODE));
+  if (m_pNCManager->GetBoolParameter(BP_CONTROL_MODE)) {
+#ifdef _WIN32_WCE
+    DASHER_ASSERT(false);
+#endif
+    //ACL leave offset as is - like its groupnode parent, but unlike its alphnode siblings,
+    //the control node does not enter a symbol....
+    m_pNCManager->GetControlManager()->GetRoot(pParent, pParent->GetChildren().back()->Hbnd(), m_pNCManager->GetLongParameter(LP_NORMALIZATION), pParent->offset());
+  }
+}
+
+
 CAlphabetManager::CAlphNode::~CAlphNode() {
   delete m_pProbInfo;
   m_pMgr->m_pLanguageModel->ReleaseContext(iContext);
 }
 
 const std::string &CAlphabetManager::CSymbolNode::outputText() {
-  return mgr()->m_pNCManager->GetAlphabet()->GetText(iSymbol);
+  return mgr()->m_pAlphabet->GetText(iSymbol);
 }
 
 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;
+  //std::cout << this << " " << Parent() << ": Output at offset " << m_iOffset << " *" << m_pMgr->m_pAlphabet->GetText(t) << "* " << std::endl;
 
   Dasher::CEditEvent oEvent(1, outputText(), offset());
   m_pMgr->m_pNCManager->InsertEvent(&oEvent);
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index 6b98c6b..6ab9c82 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -44,7 +44,8 @@ namespace Dasher {
   class CAlphabetManager : public CNodeManager {
   public:
 
-    CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel);
+    CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel);
+    virtual ~CAlphabetManager();
 
   protected:
     class CGroupNode;
@@ -63,7 +64,7 @@ namespace Dasher {
       virtual std::vector<unsigned int> *GetProbInfo();
       virtual int ExpectedNumChildren();
       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;
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd)=0;
     private:
       std::vector<unsigned int> *m_pProbInfo;
     protected:
@@ -90,7 +91,7 @@ namespace Dasher {
       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);
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
     private:
       virtual const std::string &outputText();
     protected:
@@ -100,7 +101,7 @@ namespace Dasher {
 
     class CGroupNode : public CAlphNode {
     public:
-      CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CAlphabetManager *pMgr, SGroupInfo *pGroup);
+      CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CAlphabetManager *pMgr, const SGroupInfo *pGroup);
       
       ///
       /// Provide children for the supplied node
@@ -110,10 +111,10 @@ namespace Dasher {
       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);
+      virtual CGroupNode *RebuildGroup(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
       std::vector<unsigned int> *GetProbInfo();
     private:
-      SGroupInfo *m_pGroup;
+      const SGroupInfo *m_pGroup;
     };
     
   public:
@@ -129,18 +130,25 @@ namespace Dasher {
     /// Factory method for CAlphNode construction, so subclasses can override.
     ///
     virtual CSymbolNode *makeSymbol(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
-    virtual CGroupNode *makeGroup(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, SGroupInfo *pGroup);
+    virtual CGroupNode *makeGroup(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const SGroupInfo *pGroup);
     
     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);
-    
+    virtual CGroupNode *CreateGroupNode(CAlphNode *pParent, const SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
+
+    ///Called to add any non-alphabet (non-symbol) children to a top-level node (root or symbol).
+    /// Default is just to add the control node, if appropriate.
+    virtual void AddExtras(CAlphNode *pParent, std::vector<unsigned int> *pCProb);
+
     CLanguageModel *m_pLanguageModel;
     CNodeCreationManager *m_pNCManager;
+    const CAlphabet *m_pAlphabet;
 
   private:
-    
-    void IterateChildGroups(CAlphNode *pParent, SGroupInfo *pParentGroup, CAlphNode *buildAround);
+    ///Wraps m_pLanguageModel->GetProbs to implement nonuniformity & leave space for control node.
+    /// Returns array of non-cumulative probs. Should this be protected and/or virtual???
+    void GetProbs(std::vector<unsigned int> *pProbs, CLanguageModel::Context iContext);
+    void IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphNode *buildAround);
 
     CLanguageModel::Context m_iLearnContext;
     CDasherInterfaceBase *m_pInterface;
diff --git a/Src/DasherCore/ConvertingAlphMgr.cpp b/Src/DasherCore/ConvertingAlphMgr.cpp
new file mode 100644
index 0000000..6b2158d
--- /dev/null
+++ b/Src/DasherCore/ConvertingAlphMgr.cpp
@@ -0,0 +1,30 @@
+/*
+ *  ConvertingAlphMgr.cpp
+ *  Dasher
+ *
+ *  Created by Alan Lawrence on 06/08/2010.
+ *  Copyright 2010 Cavendish Laboratory. All rights reserved.
+ *
+ */
+
+#include "ConvertingAlphMgr.h"
+#include "NodeCreationManager.h"
+
+using namespace Dasher;
+
+CConvertingAlphMgr::CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel)
+ : CAlphabetManager(pInterface, pNCManager, pAlphabet, pLanguageModel), m_pConvMgr(pConvMgr) {
+ }
+
+CConvertingAlphMgr::~CConvertingAlphMgr() {
+  m_pConvMgr->Unref();
+}
+
+void CConvertingAlphMgr::AddExtras(CAlphNode *pParent, std::vector<unsigned int> *pCProb) {
+    //should have another probability....
+  const unsigned int i(m_pNCManager->GetAlphabet()->GetNumberTextSymbols());
+  DASHER_ASSERT(pCProb->size() == i+1);
+  //ACL setting m_iOffset+1 for consistency with "proper" symbol nodes...
+  m_pConvMgr->GetRoot(pParent, (*pCProb)[i-1], (*pCProb)[i], pParent->offset()+1);
+  CAlphabetManager::AddExtras(pParent, pCProb);
+}
\ No newline at end of file
diff --git a/Src/DasherCore/ConvertingAlphMgr.h b/Src/DasherCore/ConvertingAlphMgr.h
new file mode 100644
index 0000000..a6a3ae0
--- /dev/null
+++ b/Src/DasherCore/ConvertingAlphMgr.h
@@ -0,0 +1,32 @@
+/*
+ *  ConvertingAlphMgr.h
+ *  Dasher
+ *
+ *  Created by Alan Lawrence on 06/08/2010.
+ *  Copyright 2010 Cavendish Laboratory. All rights reserved.
+ *
+ */
+
+#ifndef __CONVERTING_ALPH_MGR_H__
+#define __CONVERTING_ALPH_MGR_H__
+
+#include "AlphabetManager.h"
+#include "ConversionManager.h"
+
+namespace Dasher {
+  class CConvertingAlphMgr : public CAlphabetManager {
+  public:
+    CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel);
+    virtual ~CConvertingAlphMgr();
+  protected:
+    void AddExtras(CAlphNode *pParent, std::vector<unsigned int> *pCProb);
+  private:
+    CConversionManager *m_pConvMgr;
+    
+    //TODO do we need to override
+    //void GetProbs(vector<unsigned int> *pProbInfo, CLanguageModel::Context context);
+    //to do something for the conversion symbol, or does the LM do that for us???
+  };
+}
+
+#endif
diff --git a/Src/DasherCore/Makefile.am b/Src/DasherCore/Makefile.am
index ae4b1b1..5ca350a 100644
--- a/Src/DasherCore/Makefile.am
+++ b/Src/DasherCore/Makefile.am
@@ -43,6 +43,8 @@ libdashercore_a_SOURCES = \
 		ConversionHelper.h \
 		ConversionManager.cpp \
 		ConversionManager.h \
+		ConvertingAlphMgr.cpp \
+		ConvertingAlphMgr.h \
 		DasherButtons.cpp \
 		DasherButtons.h \
 		DasherComponent.cpp \
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index 939301b..87d47d4 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -46,8 +46,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CMandarinAlphMgr::CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel)
-  : CAlphabetManager(pInterface, pNCManager, pLanguageModel),
+CMandarinAlphMgr::CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel)
+  : CAlphabetManager(pInterface, pNCManager, pAlphabet, pLanguageModel),
     m_pParser(new CPinyinParser(pInterface->GetStringParameter(SP_SYSTEM_LOC) +"/alphabet.chineseRuby.xml")),
     m_pCHAlphabet(new CAlphabet(pInterface->GetInfo("Chinese / ç®?ä½?中æ?? (simplified chinese, in pin yin groups)"))) {
 }
@@ -74,7 +74,7 @@ CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, symbol iSymb
 
     //CTrieNode parallels old PinyinConversionHelper's SetConvSymbol; we keep
     // the same offset as we've still not entered/selected a symbol (leaf)
-    CConvRoot *pNewNode = new CConvRoot(pParent, pParent->offset(), iLbnd, iHbnd, this, m_pParser->GetTrieNode(m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol)));
+    CConvRoot *pNewNode = new CConvRoot(pParent, pParent->offset(), iLbnd, iHbnd, this, m_pParser->GetTrieNode(m_pAlphabet->GetDisplayText(iSymbol)));
 
     //from ConversionHelper:
     //pNewNode->m_pLanguageModel = m_pLanguageModel;
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index e09e54b..65be35e 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -36,7 +36,7 @@ namespace Dasher {
   class CMandarinAlphMgr : public CAlphabetManager {
   public:
 
-    CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel);
+    CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CAlphabet *pAlphabet, CLanguageModel *pLanguageModel);
 
     virtual ~CMandarinAlphMgr();
     
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index 510448f..e57f4d5 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -8,6 +8,7 @@
 #include "LanguageModelling/CTWLanguageModel.h"
 #include "NodeCreationManager.h"
 #include "MandarinAlphMgr.h"
+#include "ConvertingAlphMgr.h"
 #include "ControlManager.h"
 #include "EventHandler.h"
 
@@ -75,12 +76,29 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
     
   // TODO: Tell the alphabet manager about the alphabet here, so we
   // don't end up having to duck out to the NCM all the time
-  
-  //(ACL) Modify AlphabetManager for Mandarin Dasher
-  if (oAlphInfo.m_iConversionID == 2)
-    m_pAlphabetManager = new CMandarinAlphMgr(pInterface, this, m_pLanguageModel);
-  else
-    m_pAlphabetManager = new CAlphabetManager(pInterface, this, m_pLanguageModel);
+
+    switch(oAlphInfo.m_iConversionID) {
+      default:
+        //TODO: Error reporting here
+        //fall through to
+      case 0: // No conversion required
+        m_pAlphabetManager = new CAlphabetManager(pInterface, this, m_pAlphabet, m_pLanguageModel);
+        break;
+#ifdef JAPANESE
+      case 1: // Japanese
+        CConversionManager *pConversionManager =
+#ifdef WIN32
+        new CIMEConversionHelper;
+#else
+        new CCannaConversionHelper(this, m_pAlphabet, GetLongParameter(LP_CONVERSION_TYPE), GetLongParameter(LP_CONVERSION_ORDER));
+#endif
+        //TODO ownership/deletion
+        m_pAlphabetManager = new CConvertingAlphMgr(pInterface, this, pConversionManager, m_pAlphabet, m_pLanguageModel);
+        break;
+#endif
+      case 2:   //(ACL) Modify AlphabetManager for Mandarin Dasher
+        m_pAlphabetManager = new CMandarinAlphMgr(pInterface, this, m_pAlphabet, m_pLanguageModel);
+    }
 
   if (!m_pAlphabet->GetTrainingFile().empty()) {
     //1. Look for system training text...
@@ -115,25 +133,7 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
 #endif
 
   HandleEvent(&CParameterNotificationEvent(BP_CONTROL_MODE));
-  
-  switch(oAlphInfo.m_iConversionID) {
-    default:
-      //TODO: Error reporting here
-      //fall through to
-    case 0: // No conversion required
-      m_pConversionManager = new CConversionManager(this, m_pAlphabet);
-      //ACL no, not quite - ConvMgrFac would always be created, so (ConvMgrFac==NULL) would always fail; but then segfault on ConvMgr->GetRoot() ?
-      break;
-#ifdef JAPANESE
-    case 1: // Japanese
-#ifdef WIN32
-      m_pConversionManager = new CIMEConversionHelper;
-#else
-      m_pConversionManager = new CCannaConversionHelper(this, m_pAlphabet, GetLongParameter(LP_CONVERSION_TYPE), GetLongParameter(LP_CONVERSION_ORDER));
-#endif
-      break;
-#endif
-  }
+
 }
 
 CNodeCreationManager::~CNodeCreationManager() {
@@ -141,80 +141,18 @@ CNodeCreationManager::~CNodeCreationManager() {
   delete m_pTrainer;
   
   delete m_pControlManager;
-
-  if (m_pConversionManager) m_pConversionManager->Unref();
-}
-
-CDasherNode *CNodeCreationManager::GetConvRoot(Dasher::CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset) { 
- if(m_pConversionManager)
-   return m_pConversionManager->GetRoot(pParent, iLower, iUpper, iOffset);
- return NULL;
-}
-
-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();
-  
-  // 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.
-
-  int uniform_add;
-  int nonuniform_norm;
-  int control_space = 0;
-  int uniform = GetLongParameter(LP_UNIFORM);
-
-   if(!GetBoolParameter(BP_CONTROL_MODE)) {
-     control_space = 0;
-     uniform_add = ((iNorm * uniform) / 1000) / (iSymbols - 2);  // Subtract 2 from no symbols to lose control/root nodes
-     nonuniform_norm = iNorm - (iSymbols - 2) * uniform_add;
-   }
-   else {
-     control_space = int (iNorm * 0.05);
-     uniform_add = (((iNorm - control_space) * uniform / 1000) / (iSymbols - 2));        // Subtract 2 from no symbols to lose control/root nodes
-     nonuniform_norm = iNorm - control_space - (iSymbols - 2) * uniform_add;
-   }
-   
-   //  m_pLanguageModel->GetProbs(context, Probs, iNorm, ((iNorm * uniform) / 1000));
-   
-   //ACL used to test explicitly for MandarinDasher and if so called GetPYProbs instead
-   // (by statically casting to PPMPYLanguageModel). However, have renamed PPMPYLanguageModel::GetPYProbs
-   // to GetProbs as per ordinary language model, so no need to test....
-   m_pLanguageModel->GetProbs(context, Probs, iNorm, 0);
-
-   // #if _DEBUG
-   //int iTotal = 0;
-   //for(int k = 0; k < Probs.size(); ++k)
-     //     iTotal += Probs[k];
-   //   DASHER_ASSERT(iTotal == nonuniform_norm);
-// #endif
-
-//   //  Probs.insert(Probs.begin(), 0);
-
-   for(unsigned int k(1); k < Probs.size(); ++k)
-     Probs[k] += uniform_add;
-
-  Probs.push_back(control_space);
-
-#if _DEBUG
-  int iTotal = 0;
-  for(int k = 0; k < Probs.size(); ++k)
-    iTotal += Probs[k];
-  DASHER_ASSERT(iTotal == iNorm);
-#endif
-
 }
 
 void CNodeCreationManager::HandleEvent(CEvent *pEvent) {
   if (pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    if (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter == BP_CONTROL_MODE) {
-      delete m_pControlManager;
-      m_pControlManager = (GetBoolParameter(BP_CONTROL_MODE))
-        ? new CControlManager(m_pEventHandler, m_pSettingsStore, this, m_pInterface)
-        : NULL;
-    } 
+    switch (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter) {
+      case BP_CONTROL_MODE:
+        delete m_pControlManager;
+        m_pControlManager = (GetBoolParameter(BP_CONTROL_MODE))
+          ? new CControlManager(m_pEventHandler, m_pSettingsStore, this, m_pInterface)
+          : NULL;        
+        break;
+    }
   }
 }
 
diff --git a/Src/DasherCore/NodeCreationManager.h b/Src/DasherCore/NodeCreationManager.h
index e50d322..0f160c3 100644
--- a/Src/DasherCore/NodeCreationManager.h
+++ b/Src/DasherCore/NodeCreationManager.h
@@ -37,12 +37,9 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
   ///
 
   Dasher::CAlphabetManager *GetAlphabetManager() {return m_pAlphabetManager;}
-  Dasher::CDasherNode *GetConvRoot(Dasher::CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset);
 
   Dasher::CControlManager *GetControlManager() {return m_pControlManager;}
   
-  void GetProbs(Dasher::CLanguageModel::Context context, std::vector <unsigned int >&Probs, int iNorm) const;
-
   ///
   /// Get a reference to the alphabet
   ///
@@ -62,7 +59,14 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
   
   Dasher::CAlphabetManager *m_pAlphabetManager;
   Dasher::CControlManager *m_pControlManager;
-  Dasher::CConversionManager *m_pConversionManager;
+  
+  ///Probability to assign to control node (0 if control mode off)
+  unsigned long m_iControlSpace;
+  ///Amount of probability space remaining, i.e. for language model to assign to letters:
+  unsigned long m_iNonUniformNorm;
+  ///Amount of probability space we will add to _each_ letter (on top of fraction of
+  /// m_iNonUniformNorm) to effect smoothing/uniformity:
+  unsigned long m_iUniformAdd;
 };
 /// @}
 
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index 9750753..6f8cfa2 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -345,6 +345,8 @@
 		3300114910A2E9C900D31B1D /* DelayedDraw.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300114810A2E9C900D31B1D /* DelayedDraw.h */; };
 		3300115210A2EA7700D31B1D /* ExpansionPolicy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */; };
 		3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300115110A2EA7700D31B1D /* ExpansionPolicy.h */; };
+		33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */; };
+		33008361120CB7F900C41FAA /* ConvertingAlphMgr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3300835F120CB7F900C41FAA /* ConvertingAlphMgr.cpp */; };
 		3306E0220FFD1CE60017324C /* PPMPYLanguageModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3306E0200FFD1CE60017324C /* PPMPYLanguageModel.cpp */; };
 		3306E0230FFD1CE60017324C /* PPMPYLanguageModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 3306E0210FFD1CE60017324C /* PPMPYLanguageModel.h */; };
 		3306E1F70FFE6CAD0017324C /* Trainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3306E1F50FFE6CAD0017324C /* Trainer.cpp */; };
@@ -760,6 +762,8 @@
 		3300114810A2E9C900D31B1D /* DelayedDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedDraw.h; sourceTree = "<group>"; };
 		3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExpansionPolicy.cpp; sourceTree = "<group>"; };
 		3300115110A2EA7700D31B1D /* ExpansionPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExpansionPolicy.h; sourceTree = "<group>"; };
+		3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertingAlphMgr.h; sourceTree = "<group>"; };
+		3300835F120CB7F900C41FAA /* ConvertingAlphMgr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertingAlphMgr.cpp; sourceTree = "<group>"; };
 		3306E0200FFD1CE60017324C /* PPMPYLanguageModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPMPYLanguageModel.cpp; sourceTree = "<group>"; };
 		3306E0210FFD1CE60017324C /* PPMPYLanguageModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMPYLanguageModel.h; sourceTree = "<group>"; };
 		3306E1F50FFE6CAD0017324C /* Trainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Trainer.cpp; sourceTree = "<group>"; };
@@ -1050,6 +1054,8 @@
 				1948BE950C226CFD001DFA32 /* UserLogTrial.h */,
 				1948BE9A0C226CFD001DFA32 /* XMLUtil.cpp */,
 				1948BE9B0C226CFD001DFA32 /* XMLUtil.h */,
+				3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */,
+				3300835F120CB7F900C41FAA /* ConvertingAlphMgr.cpp */,
 			);
 			name = DasherCore;
 			path = ../DasherCore;
@@ -1494,6 +1500,7 @@
 				3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */,
 				3300114910A2E9C900D31B1D /* DelayedDraw.h in Headers */,
 				339055E81195FBD0001BE240 /* Queue.h in Headers */,
+				33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1842,6 +1849,7 @@
 				33135355102C6D8E00E28220 /* ButtonMode.cpp in Sources */,
 				3300115210A2EA7700D31B1D /* ExpansionPolicy.cpp in Sources */,
 				339055E91195FBD0001BE240 /* Queue.m in Sources */,
+				33008361120CB7F900C41FAA /* ConvertingAlphMgr.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};



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