#include "stdafx.h"
#using <mscorlib.dll>
#using <DataFitXD2.dll>

using namespace System;
using namespace DataFitXD2;

//*****************************************************************
//
// This is an example of using DataFitX COM component DEMO (oedfx20d.dll) 
// from Microsoft Visual C++ .NET project in a console application.
//
//*****************************************************************

int _tmain()

{

	System::Object* ItemIndex;
	System::Array __gc* Roots;

	try
	{

		// Create the DataCollection object and import the tabbed delimited data
		// file thurber.dat. The file contains 2 columns of named data labeled
		// Density and Electron Mobility (the first non-blank line in the file
		// contains the series names). The first column is the independent
		// variable X (Density), the second column is the dependent
		// variable Y (Electron Mobility). This will add 2 DataSeries objects to
		// the DataCollection, one named "Density" the other named "Electron Mobility".
		DataCollection* dfxData = new DataCollectionClass();
		dfxData->ImportNamedSeriesFromFile(S"thurber.dat", DelimiterTypeEnum::dfxDelimiterTab, S".", S"/", S"?");
		
		// Set the RegressionKey properties for the DataCollection according to the
		// above description.
		dfxData->Item[S"Density"]->RegressionKey = "X";		
		dfxData->Item[S"Electron Mobility"]->RegressionKey = "Y";

		// The model being solved is:
		// Y = (B1+B2*x+B3*x^2+B4*x^3) / (1+B5*x+B6*x^2+B7*x^3)
		// where B1 through B7 are the fitting parameters, and X
		// is the independent variable "Density".
		// Create the model definition object so that we may define
		// a multi-line user-defined model.
		ModelDefinition* dfxDefinition = new ModelDefinitionClass();
		dfxDefinition->Description = S"Semiconductor electron mobility modeling";
		dfxDefinition->F1 = S"(B1 + B2 * x + B3 * x ^ 2 + B4 * x ^ 3)";
		dfxDefinition->F2 = S"(1 + B5 * x + B6 * x ^ 2 + B7 * x ^ 3)";
		dfxDefinition->Y = S"F1/F2";

		// Create an instance of the NonlinearRegression object
		NonlinearRegression* dfxModel = new NonlinearRegressionClass();

		// Define the multi-line user-defined model
        // according to the above definition in dfxDefinition.
        // Since we are using a ModelDefinition object to define
        // the model, use the DefineUserModelSub method.
		dfxModel->DefineUserModelSub(dfxDefinition, InputLocaleEnum::dfxLocaleEnglish);
		
		// Define the intial estimates for the model since this is a
        // user-defined model. There are seven parameters, B1 through B7.
		dfxModel->RegressionParameters->Item[S"B1"]->InitialEstimate = 1000.0;
		dfxModel->RegressionParameters->Item[S"B2"]->InitialEstimate = 1000.0;
		dfxModel->RegressionParameters->Item[S"B3"]->InitialEstimate = 400.0;
		dfxModel->RegressionParameters->Item[S"B4"]->InitialEstimate = 40.0;
		dfxModel->RegressionParameters->Item[S"B5"]->InitialEstimate = 0.7;
		dfxModel->RegressionParameters->Item[S"B6"]->InitialEstimate = 0.3;
		dfxModel->RegressionParameters->Item[S"B7"]->InitialEstimate = 0.03;

		// Set the regression solution options
		dfxModel->MaxIterations = 100;
		dfxModel->MaxUnchangedIterations = 10;
		dfxModel->RegressionTolerance = 0.0000000001;

		// Fit the model to the DataCollection dfxData
		dfxModel->FitCollection(dfxData);

		// If the model solved successfully, display some sample results. Otherwise,
        // display the solution log information to diagnose why it may have failed.
		if (dfxModel->IsSolved) {
			Console::WriteLine(S"Results for model: ");
			Console::Write(S"F1 = ");
			Console::WriteLine(dfxModel->ModelDefinition->F1);
			Console::Write(S"F2 = ");
			Console::WriteLine(dfxModel->ModelDefinition->F2);
			Console::Write(S"Y = ");
			Console::WriteLine(dfxModel->ModelDefinition->Y);
			Console::Write(S"Description: ");
			Console::WriteLine(dfxModel->ModelDefinition->Description);
			Console::WriteLine();
			Console::WriteLine(S"Data set: Thurber.dat");
			Console::WriteLine(S"Independent Variable (X): Density");
			Console::WriteLine(S"Dependent Variable (Y): Electron Mobility");
			Console::Write(S"Number of Observations = ");
			Console::WriteLine(dfxModel->NumObservations);
			Console::Write(S"XMin = ");		
			Console::WriteLine(dfxModel->ResultTables->Item[S"Density"]->Minimum);
			Console::Write(S"XMax = ");
			Console::WriteLine(dfxModel->ResultTables->Item[S"Density"]->Maximum);
			Console::Write(S"YMin = ");		
			Console::WriteLine(dfxModel->ResultTables->Item[S"Electron Mobility"]->Minimum);
			Console::Write(S"YMax = ");
			Console::WriteLine(dfxModel->ResultTables->Item[S"Electron Mobility"]->Maximum);
			Console::WriteLine();

			// Print the parameter names, values and standard errors
			int count = dfxModel->RegressionParameters->Count;
			for (long index = 1;index <= count;index++) {
				ItemIndex = __box(index);
				Console::Write(dfxModel->RegressionParameters->Item[ItemIndex]->Name); 				
				Console::Write(S" = " );
				Console::Write(dfxModel->RegressionParameters->Item[ItemIndex]->Value); 
				Console::Write(S", Standard Error = ");
				Console::WriteLine(dfxModel->RegressionParameters->Item[ItemIndex]->StandardError);				
			}
			Console::WriteLine();

			// Print goodness of fit information
			Console::Write(S"Number of Nonlinear Iterations = ");
			Console::WriteLine(dfxModel->NumIterations);
			Console::Write(S"Residual Standard Error = ");
			Console::WriteLine(dfxModel->StandardError);
			Console::Write(S"R2 Value = ");
			Console::WriteLine(dfxModel->R2);
			Console::Write(S"Regression Sum of Squares = ");
			Console::WriteLine(dfxModel->SSR);
			Console::Write(S"Residual Sum of Squares = ");
			Console::WriteLine(dfxModel->SSE);
			Console::WriteLine();

			// Other sample output

			// Single Predicted value
			Console::Write(S"Value of Y at X = 0.79: ");
			Console::WriteLine(dfxModel->PredictValue(0.79));
			Console::WriteLine();

			// Value of X at specified Y (Root)
			Console::WriteLine(S"Value(s) of X at Y = 1408.1046:");
			Roots = dfxModel->CalculateRoots(1408.1046, -5.0, 2.0, 100);
			try
			{
				for ( int i = Roots->GetLowerBound(0); i <= Roots->GetUpperBound(0); i++ )
				{
					Console::Write(S"Root at X = ");
					Console::WriteLine(Roots->GetValue(i));
					Console::WriteLine();
				}
			}
			catch (Exception* e)
			{
				Console::WriteLine(S"No Roots Found");
				Console::WriteLine(e->Message);
				Console::WriteLine();
			}

			// Derivative of Y at X = 2.1
			Console::Write(S"Derivative at X = 2.1: ");
			Console::WriteLine(dfxModel->CalculateDerivative(2.1));

			// Integration from X = -2.1 to 2.1
			Console::Write(S"Integral from -2.1 to 2.1: ");
			Console::WriteLine(dfxModel->CalculateIntegral(-2.1, 2.1));
			Console::WriteLine();

			Console::WriteLine(S"Solution successful");
					
		}
		else {

			// Solution failed, dump the log file
			dfxModel->SaveLog(S"log.txt", false);
			Console::WriteLine(S"Solution failed - see log.txt");

		}
		return 0;
	}

	catch(Exception *e)
	{
		Console::WriteLine(e->Message); 
	}


}