/***************************************************************************************************
*          C# sample for the usage of TopoART-C (classes TopoART_C, Fast_TopoART_C) and            *
*          Hypersphere TopoART-C (class Hypersphere_TopoART_C)                                     *
****************************************************************************************************
*                            Created by Marko Tscherepanow, 17 April 2017                          *
***************************************************************************************************/

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

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

namespace LibTopoART_samples
{
	/// <summary>
	/// Classification sample using more complex synthetic two-dimensional data with associated class IDs. [C#]
	/// <para>
	/// Train TopoART-C 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 which were mixed randomly. The samples are divided into two classes. Each sample belonging 
	/// to one of the six clusters is assigned a class ID depending on its position. In contrast, noise samples receive 
	/// a random class ID. 
	/// </para>
	/// <para>The resulting neural network can be visualised using the script <c>ShowTopoARTCResults</c> 
	/// or the script <c>ShowHypersphereTopoARTCResults</c>, respectively. Both scripts are provided for R and MATLAB
	/// in the subfolder <c>visualisation</c>.
	/// </para>
	/// </summary>
	class TopoART_C_sample2
	{
		enum Selector {
			USE_TopoART_C,
			USE_Fast_TopoART_C,
			USE_Hypersphere_TopoART_C
		};

		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-C implementation (see enum Selector above)
			var sel = Selector.USE_Fast_TopoART_C;

			ITopoART_C tac = null;
			string filePrefix = null;
			string fileSuffix = null;
			var inputs = new decimal[sampleNumber][];
			var classIDs = new long[sampleNumber];
			var rnd = new Random();

			// 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 entries = Regex.Split(datasetFile.ReadLine(), @"\s+");
					inputs[i] = new decimal[inputDimension]; 
					inputs[i][0] = Decimal.Parse(entries[1], NumberStyles.Float, CultureInfo.InvariantCulture);
					inputs[i][1] = Decimal.Parse(entries[2], NumberStyles.Float, CultureInfo.InvariantCulture);

					// Compute class IDs of cluster samples depending on their x coordinate
					if(entries[3] != "NOISE")
						classIDs[i] = (inputs[i][0] > 0.5m) ? 1 : 2;
					// Assign a random class ID to noise samples
					else
						classIDs[i] = rnd.Next(1, 3);
				}
			}

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

			// Initialise a TopoART network with appropriate parameter values
			switch(sel) {
				case Selector.USE_TopoART_C:
						tac = new TopoART_C(inputDimension, 2, 0.92m);
						tac.Beta_sbm	=	0.65m;
						filePrefix 		=	"TopoART-C";
						fileSuffix		=	"tac";
					break;
				case Selector.USE_Fast_TopoART_C:
						tac = new Fast_TopoART_C(inputDimension, 2, 0.92m);
						tac.Beta_sbm	=	0.65m;
						filePrefix 		=	"Fast_TopoART-C";
						fileSuffix		=	"ftac";
					break;
				case Selector.USE_Hypersphere_TopoART_C:
						tac = new Hypersphere_TopoART_C(inputDimension, 2, 0.90m);
						tac.Beta_sbm	=	0.60m;
						filePrefix 		=	"Hypersphere_TopoART-C";
						fileSuffix		=	"htac";
					break;
			}

			// Set remaining common parameters
			tac.Phi	= 5;
			tac.Tau	= 250;

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

			// Determine clusters
			tac.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
			tac.SaveText(networkPath + filePrefix + "_AIL12-like_dataset.txt");

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