/***************************************************************************************************
*             C# sample for the usage of TopoART (classes TopoART and Fast_TopoART) and            *
*             Hypersphere TopoART (class Hypersphere_TopoART)                                      *
****************************************************************************************************
*                           Created by Marko Tscherepanow, 30 December 2012                        *
***************************************************************************************************/

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

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

namespace LibTopoART_samples
{
	/// <summary>
	/// Clustering sample using more complex synthetic two-dimensional data. [C#]
	/// <para>
	/// Train TopoART or Hypersphere TopoART with a two-dimensional dataset similar to the one used in "Marko 
	/// Tscherepanow and Sören Riechers (2012). An Incremental On-line Classifier for Imbalanced, Incomplete, and Noisy 
	/// Data. In Proceedings of the European Conference on Artificial Intelligence (ECAI), Workshop on Active and 
	/// Incremental Learning (AIL), pp. 18-23. Montpellier, France." This dataset comprises six clusters (each 
	/// containing 15,000 samples) as well as 10,000 noise samples. These samples were mixed randomly.
	/// </para>
	/// <para>The resulting neural network can be visualised using the script <c>ShowTopoARTResults</c> or the 
	/// script <c>ShowHypersphereTopoARTResults.R</c>, respectively. Both scripts are provided for R and MATLAB
	/// in the subfolder <c>visualisation</c>.
	/// </para>
	/// </summary>
	class TopoART_sample2
	{
		enum Selector {
			USE_TopoART,
			USE_Fast_TopoART,
			USE_Hypersphere_TopoART
		};

		private static void Main()
		{
			// Dataset
			const string dataset 		=	"../../../../../data/AIL12-like_dataset.txt";
			// Destination directory for trained networks
			const string networkPath	=	"../../../../../results/networks/";

			const long sampleNumber		=	100000;
			const long inputDimension	=	2;

			// Choose TopoART implementation (see enum Selector above)
			var sel = Selector.USE_Fast_TopoART;

			ITopoART ta = null;
			string filePrefix = null;
			string fileSuffix = null;
			var inputs = new decimal[sampleNumber][];

			// 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);
				}
			}

			// Start time measuring
			var start = DateTime.Now;

			// Initialise a TopoART network with appropriate parameter values
			switch(sel) {
				case Selector.USE_TopoART:
						ta = new TopoART(inputDimension, 2, 0.92m);
						ta.Beta_sbm	=	0.65m;
						filePrefix 	=	"TopoART";
						fileSuffix	=	"ta";
					break;
				case Selector.USE_Fast_TopoART:
						ta = new Fast_TopoART(inputDimension, 2, 0.92m);
						ta.Beta_sbm	=	0.65m;
						filePrefix 	=	"Fast_TopoART";
						fileSuffix	=	"fta";
					break;
				case Selector.USE_Hypersphere_TopoART:
						ta = new Hypersphere_TopoART(inputDimension, 2, 0.90m);
						ta.Beta_sbm	=	0.60m;
						filePrefix 	=	"Hypersphere_TopoART";
						fileSuffix	=	"hta";
					break;
			}

			// Set remaining common parameters
			ta.Phi = 5;
			ta.Tau = 200;

			// Train network
			for(long i = 0; i < sampleNumber; ++i) {
				ta.Learn(inputs[i]);
				if(i % 2000 == 0) 
					Console.Write(".");
			}
			Console.WriteLine("");

			// Determine clusters
			ta.ComputeClusterIDs();

			// Stop time measuring
			var end = DateTime.Now;

			// Output the required time
			var time = end - start;
			Console.WriteLine("Time for computation: " + time);

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

			// Save network in binary form
			ta.Save(networkPath + filePrefix + "_AIL12-like_dataset." + fileSuffix);
		}
	}
}