/***************************************************************************************************
*                              C# sample for the usage of class TopoART                            *
****************************************************************************************************
*                             Created by Marko Tscherepanow, 23 July 2011                          *
***************************************************************************************************/

// Compile and run from the console: dotnet run --project TopoART_sample1.csproj

using System;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using LibTopoART;
using System.Globalization;

namespace LibTopoART_samples
{
	/// <summary>
	/// Simple clustering sample. [C#]
	/// <para>First, a datased comprised of 10 samples is learned by a TopoART network. Afterwards,
	/// the training samples are slightly modified by random values and used for predicting cluster
	/// labels.</para>
	/// </summary>
	class TopoART_sample1
	{
		private static void Main() 
		{
			// Dataset comprising two clusters, each containing 5 samples
			// Cluster 1: samples 1 to 5
			// Cluster 2: samples 6 to 10
			const string dataset		=	"../../../../../data/Simple_dataset.txt";
			// Destination directory for trained networks
			const string networkPath	=	"../../../../../results/networks/";
			const long sampleNumber		=	10;
			const long inputDimension	=	2;

			// Choose TopoART implementation (false = TopoART; true = Fast_TopoART). If true, class Fast_TopoART will be used 
			// rather than class TopoART. As a result, the computation is accelerated but less accurate. From
			// an algorithmic point of view, both implementations are equal. But Fast_TopoART uses long rather than decimal
			// for the internal represention of data.
			var useFastTopoART = false;

			var inputs = new decimal[sampleNumber][];
			ITopoART ta;

			// Set working directory to assembly directory
			Directory.SetCurrentDirectory(Path.GetDirectoryName(new Uri(Assembly.GetEntryAssembly().Location).LocalPath));

			// Load dataset
			using(var datasetFile = new StreamReader(File.OpenRead(dataset))) {
				for(long i = 0; i < sampleNumber; ++i) {
					var numbers = Regex.Split(datasetFile.ReadLine(), @"\s+");
					inputs[i] = new decimal[inputDimension]; 
					inputs[i][0] = Decimal.Parse(numbers[1], NumberStyles.Float, CultureInfo.InvariantCulture);
					inputs[i][1] = Decimal.Parse(numbers[2], NumberStyles.Float, CultureInfo.InvariantCulture);
					Console.WriteLine("Read input " + inputs[i][0] + "; " + inputs[i][1]);
				}
			}

			// Initialise a TopoART network using rho_a = 0.7 and default values for the remaining parameters
			if(useFastTopoART) 
				ta = new Fast_TopoART(inputDimension, 2, 0.70m);
			else 
				ta = new TopoART(inputDimension, 2, 0.70m);

			// Train network
			for(long i = 0; i < sampleNumber; ++i)
				ta.Learn(inputs[i]);

			// Determine clusters
			ta.ComputeClusterIDs();

			// Save network in human-readable form
			ta.SaveText(networkPath + "TopoART_Simple_dataset.txt");

			// Save network in binary form
			ta.Save(networkPath + "TopoART_Simple_dataset.ta");

			// Compute predictions for the randomly modified training data
			// (TopoART module 1 (TopoART b) creates a more detailed representation using 
			// more nodes than TopoART module 0 (TopoART a). But the number of clusters is equal.)
			var rnd = new Random();
			for(long i = 0; i < sampleNumber; ++i) {
				var xDeviation = rnd.Next(-1000, 1000) / 100000m;
				var yDeviation = rnd.Next(-1000, 1000) / 100000m;
				inputs[i][0] += xDeviation;
				inputs[i][1] += yDeviation;
				Console.WriteLine("Compute output for: {0:0.#####}; {1:0.#####}", inputs[i][0], inputs[i][1]);
				var output = ta.GetBMOutput(inputs[i]);
				Console.WriteLine("TopoART a: node {0}, cluster {1}", output[0].bm_node_ID, output[0].bm_cluster_ID);
				Console.WriteLine("TopoART b: node {0}, cluster {1}", output[1].bm_node_ID, output[1].bm_cluster_ID);
			}
		}
	}
}