/***************************************************************************************************
*          C# sample for the usage of class TopoART_R (approximation of a sine function)           *
****************************************************************************************************
*                           Created by Marko Tscherepanow, 11 February 2012                        *
***************************************************************************************************/

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

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

namespace LibTopoART_samples
{
	/// <summary>
	/// Regression sample using TopoART-R. (simplified version) [C#]
	/// <para>
	/// This sample trains a TopoART-R network with 100 points sampled from a sine function.
	/// Then, sine values are predicted for 25 random values.
	/// </para>
	/// <para>The predicted results can be visualised using the script <c>ShowTopoARTRResults</c> provided 
	/// for R and MATLAB in the subfolder <c>visualisation</c>.
	/// </para>
	/// </summary>
	class TopoART_R_sample1
	{
		private static void Main()
		{
			// Destination directory for the regression results
			const string resultPath = "../../../../../results/regression/";

			// Input and output dimensions
			const long iLen = 1;	// number of independent variables (input dimensions)
			const long dLen = 1;	// number of dependent variables (output dimensions)

			// Training data
			const long trainingSampleNum = 100; 
			var trainingSamples = new decimal[trainingSampleNum][];

			// Test data
			const long testSampleNum = 25; 

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

			// Create training samples (sine function)
			// In this sample, input vectors holding the independent and the dependent variable are applied.
			for(long i = 0; i < trainingSampleNum; ++i) {
				trainingSamples[i]		=	new decimal[iLen + dLen];

				// Set the independent variable
				trainingSamples[i][0]	=	i * (decimal)Math.PI * 2.0m / (trainingSampleNum - 1);

				// Set the dependent variable
				trainingSamples[i][1]	=	((decimal)Math.Sin((double)trainingSamples[i][0]) + 1.0m) / 2.0m;

				// Normalisation of the independent variable
				trainingSamples[i][0]	/=	((decimal)Math.PI * 2.0m);
			}

			// Create TopoART-R network using rho_a = 0.99 and default values for the remaining parameters
			var tar = new TopoART_R(iLen, dLen, 2, 0.99m);

			// Disable topology learning
			tar.SkipEdgeLearning = true;

			// Create file for the results and write the training data
			using(var writer = new StreamWriter(File.Open(resultPath + "TopoART-R_sine_regression_results.csv", 
				FileMode.Create)))
			{
				writer.WriteLine("   {0,6:D},   {1,6:D}", trainingSampleNum, testSampleNum);

				// Training with a common array for the independent variables and the dependent variables 
				Console.WriteLine("Train TopoART-R network with {0} samples", trainingSampleNum);
				for(long i = 0; i < trainingSampleNum; ++i) {
					tar.Learn(trainingSamples[i]);

					// Write denormalised training data
					writer.WriteLine("   {0},   {1}", 
					 	(trainingSamples[i][0] * (decimal)Math.PI * 2.0m).ToString(" 0.000;-0.000", CultureInfo.InvariantCulture), 
					 	((trainingSamples[i][1] - 0.5m) * 2.0m).ToString(" 0.000;-0.000", CultureInfo.InvariantCulture));
				}

				// Prediction without using a mask vector (all independent variables are required to be present) 
				var iVecRandom = new decimal[iLen];
				var rnd = new Random();
				Console.WriteLine("Predict sine function for 25 random values");
				for(long i = 0; i < testSampleNum; ++i) {
					iVecRandom[0] = (decimal)rnd.NextDouble();
					var prediction = tar.Predict(iVecRandom);
					writer.WriteLine("   {0},   {1}",
						(iVecRandom[0] * (decimal)Math.PI * 2.0m).ToString(" 0.000;-0.000", CultureInfo.InvariantCulture), 
						((prediction[0] - 0.5m) * 2.0m).ToString(" 0.000;-0.000", CultureInfo.InvariantCulture)); 
				}
			}
		}
	}
}