public void LearningTest()
		{
			MathTextBitmap bitmap = 
				new MathTextBitmap(new FloatBitmap(5,5), new Gdk.Point(0,0));
			
			bitmap.ProcessImage(new List<BitmapProcesses.BitmapProcess>());
			
			CharacteristicTreeDatabase database = 
				new CharacteristicTreeDatabase();
			
			MathSymbol aSymbol = new MathSymbol("a");
			MathSymbol bSymbol = new MathSymbol("b");
			
			database.Learn(bitmap, aSymbol);
			
			List<MathSymbol> symbols = database.Match(bitmap);
			
			bool a1Learned = symbols.Count == 1 
				&& symbols[0] == aSymbol;
			
			bool a2Learned = true;
							
			a2Learned =	database.Learn(bitmap, aSymbol);
			
			
			database.Learn(bitmap, bSymbol);
			symbols = database.Match(bitmap);
			
			bool b1Learned = symbols.Count == 2;
			
			Assert.IsTrue(a1Learned, "Fallo el aprender la primera a");
			Assert.IsFalse(a2Learned, "No se detecto el conflicto de la segunda a");
			Assert.IsTrue(b1Learned, "Fallo el aprender la b");
		}
		/// <summary>
		/// Permite añadir un simbolo al nodo.
		/// </summary>
		/// <param name="symbol">
		/// El simbolo a añadir
		/// </param>
		public bool AddSymbol(MathSymbol symbol)
		{
			if(symbols==null)
				symbols = new List<MathSymbol>();
			
			if (this.symbols.Contains(symbol))
			{
				return false;
				
			}
			else
			{
				this.symbols.Add(symbol);
				return true;
			}
		}
		/// <summary>
		/// Con este metodos almacenamos un nuevo simbolo en la base de
		/// datos.
		/// 
		/// Lanza <c>DuplicateSymbolException</c> si ya existe un simbolo
		/// con la misma etiqueta y caracteristicas binarias en la base de datos.
		/// </summary>
		/// <param name="bitmap">
		/// La imagen cuyas caracteristicas aprenderemos.
		/// </param>
		/// <param name="symbol">
		/// El simbolo que representa a la imagen.
		///</param>
		public override bool Learn(MathTextBitmap bitmap,MathSymbol symbol)
		{
			if(characteristics == null)
				characteristics=CharacteristicFactory.CreateCharacteristicList();
			
			CharacteristicNode node=rootNode;
			bool characteristicValue;	
			
			FloatBitmap processedBitmap = bitmap.LastProcessedImage;
			
			// Recorremos las caracteristicas, y vamos creando el arbol segun
			// vamos necesitando nodos.
			foreach(BinaryCharacteristic bc in characteristics)
			{					
				if(characteristicValue=bc.Apply(processedBitmap))
				{
					if(node.TrueTree==null)
					{
						node.TrueTree=new CharacteristicNode();						
					}
					
					node=node.TrueTree;					
				}
				else
				{
					if(node.FalseTree==null)
					{
						node.FalseTree=new CharacteristicNode();						
					}					
					node=node.FalseTree;					
				}	
				
				StepDoneArgs a = 
						CreateStepDoneArgs(bc,characteristicValue,null);
					
				this.StepDoneInvoker(a);
			}	
			
			return node.AddSymbol(symbol);				
			
		}
		/// <summary>
		/// This method is used to add new symbols to the database.
		/// </summary>
		/// <param name="bitmap">
		/// The image containing the symbol.
		/// </param>
		/// <param name="symbol">
		/// The symbol contained in the image.
		/// </param>
		public override bool Learn(MathTextBitmap bitmap,MathSymbol symbol)
		{
			FloatBitmap processedBitmap = bitmap.LastProcessedImage;
			TristateCheckVector newVector = CreateVector(processedBitmap);			
			
			TristateCheckVector found =null;
			foreach (TristateCheckVector vector in symbolsDict) 
			{
				if(vector.Symbols.Contains(symbol))
				{
					found  = vector;
					break;
				}
			}
			
			if(found ==null)
			{
				// The symbol wasnt present in the database.
				newVector.Symbols.Add(symbol);
				symbolsDict.Add(newVector);
			}
			else
			{
				// The symbol is present, we may have to retrain the database.
				if(newVector.Equals(found))
				{
					// It's the same one, so there is a conflict.
					return false;
				}
				else
				{
					// We have to find the differnces, and change them to
					// don't care values.
					for(int i=0; i< found.Length; i++)
					{
						if(found[i] != TristateValue.DontCare
						   && found[i] != newVector[i])
						{
							// If the value is different from what we had learned, 
							// then we make the vector more general in that point.
							found[i] = TristateValue.DontCare;
						}
					}
				}
			}
			
			return true;
		}
		/// <summary>
		/// Con este metodos almacenamos un nuevo simbolo en la base de
		/// datos.
		/// </summary>
		/// <param name="bitmap">
		/// La imagen que aprenderemos.
		/// </param>
		/// <param name="symbol">
		/// El simbolo que representa a la imagen.
		/// </param>
		/// <returns>
		/// If the symbol was learned or there was a conflict.
		/// </returns>
		public abstract bool Learn(MathTextBitmap bitmap,MathSymbol symbol);
		/// <summary>
		/// Con este metodos almacenamos un nuevo simbolo en la base de
		/// datos.
		/// 
		/// Lanza <c>DuplicateSymbolException</c> si ya hay un simbolo con las
		/// mismas propiedades y etiqueta en la base de datos.
		/// </summary>
		/// <param name="bitmap">
		/// La imagen que queremos añadir a la base de datos.
		/// </param>
		/// <param name="symbol">
		/// El simbolo que representa a la imagen.
		/// </param>
		public bool Learn(MathTextBitmap bitmap,MathSymbol symbol)
		{
			return database.Learn(bitmap,symbol);
		}
		/// <summary>
		/// Con este metodos almacenamos un nuevo simbolo en la base de
		/// datos.
		/// 
		/// Lanza <c>DuplicateSymbolException</c> si ya existe un simbolo
		/// con la misma etiqueta y caracteristicas binarias en la base de datos.
		/// </summary>
		/// <param name="bitmap">
		/// La imagen cuyas caracteristicas aprenderemos.
		/// </param>
		/// <param name="symbol">
		/// El simbolo que representa a la imagen.
		/// </param>
		public override bool Learn(MathTextBitmap bitmap,MathSymbol symbol)
		{
			if(characteristics == null)
				characteristics=CharacteristicFactory.CreateCharacteristicList();
		
			FloatBitmap processedBitmap = bitmap.LastProcessedImage;
			CheckVector vector = CreateVector(processedBitmap);
			
			
			int position = symbolsDict.IndexOf(vector);
			if(position >=0)
			{
				// The vector exists in the list
			
				List<MathSymbol> symbols = symbolsDict[position].Symbols;
				if(symbols.Contains(symbol))
				{
					return false;
				}
				else
				{
					symbols.Add(symbol);
				}
			}
			else
			{
				vector.Symbols.Add(symbol);
				symbolsDict.Add(vector);
			}
			
			return true;
		}
		/// <summary>
		/// Aprende un simbolo en la base de datos.
		/// </summary>
		/// <param name="image">
		/// La imagen que representa al simbolo.
		/// </param>
		/// <param name="symbol">
		/// El simbolo.
		/// </param>
		public override bool Learn(MathTextBitmap image, MathSymbol symbol)
		{
			return false;
		}
		private void LearningProcessFailed(MathSymbol symbol)
		{
			Application.Invoke(this,
					new LearningFailedArgs(symbol),
					delegate(object sender, EventArgs a)
			                   {
				
				string msg= 
					String.Format("¡Ya hay un símbolo, «{0}», con las mismas propiedades en la base de datos!",
					              (a as LearningFailedArgs).DuplicateSymbol );
								
				LogLine(msg);
				ResetWidgets();
				
				// There were a conflict.
				conflicts++;
				
				OkDialog.Show(mainWindow, MessageType.Error,msg);
				
				PrepareForNewImage();
			});
			
		}
		/// <summary>
		/// Metodo que gestiona el evento que se provoca al hacer 
		/// click en el boton "Aprender" de la interfaz.
		/// </summary>
		private void OnBtnLearnClicked(object sender, EventArgs arg)
		{
			string errorMsg="";
			symbol=new MathSymbol();
			if(symbolLabelEditor.Label.Trim()=="")
			{
				errorMsg=".- El texto del símbolo no es válido.\n";
			}
			else
			{
				symbol.Text=symbolLabelEditor.Label.Trim();
			}
			
			if(errorMsg=="")
			{
				//NO hay errores de validación
				nextButtonsHB.Sensitive=true;
				hboxSymbolWidgets.Sensitive=false;		
				menuDatabase.Sensitive=false;				
				menuSaveAs.Sensitive=false;
				menuOpen.Sensitive=false;
				learningThread=null;
				toolbar.Sensitive=false;	
				
				
				
				learningThread = new Thread(new ThreadStart(LearnProccess));
				learningThread.Start();
				learningThread.Suspend();
				
				return;
			}
			else
			{
				//Informamos de que no podemos aprender el caracter.
				OkDialog.Show(
					mainWindow,
					MessageType.Error,
					"El símbolo no puede ser aprendido porque:\n\n{0}",
					errorMsg);				
					
				LogLine(errorMsg);
			}			
		
		}
		public LearningFailedArgs(MathSymbol symbol)
		{
			duplicateSymbol = symbol;
		}