using System;
using System.Drawing;
using System.Windows.Forms;
using Steema.TeeChart.Functions;
using Steema.TeeChart.Styles;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 포인트 시리즈
/// </summary>
private Points points;
/// <summary>
/// Y 예측값 배열
/// </summary>
private double[] yHatArray;
/// <summary>
/// 계수 배열
/// </summary>
private double[] coefficientArray;
/// <summary>
/// 라인 시리즈
/// </summary>
private Line line;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
#region 포인트 시리즈를 생성한다.
this.points = new Points();
this.points.Title = "Source";
this.points.Pointer.Brush.Color = Color.FromArgb(115, 141, 192);
this.points.Pointer.Pen.Color = Color.FromArgb(69, 85, 115);
this.points.Pointer.Style = PointerStyles.Rectangle;
#endregion
#region 라인 시리즈를 생성한다.
this.line = new Line();
this.line.Title = "Fitted";
this.line.Color = Color.Orange;
#endregion
#region 티차트를 설정한다.
this.tChart.Series.Add(this.points);
this.tChart.Series.Add(this.line);
#endregion
this.points.Add(1.1 , 1 );
this.points.Add(1.2 , 2.5);
this.points.Add(1.25, 4 );
this.points.Add(1.3 , 3 );
this.points.Add(1.9 , 5.5);
this.points.Add(2.1 , 6.2);
this.points.Add(2.2 , 6.6);
this.points.Add(2.4 , 7.2);
this.points.Add(3 , 8 );
this.points.Add(3.5 , 12 );
Load += Form_Load;
this.modelComboBox.SelectedIndexChanged += modelComboBox_SelectedIndexChanged;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 폼 로드시 처리하기 - Form_Load(sender, e)
/// <summary>
/// 폼 로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Form_Load(object sender, EventArgs e)
{
this.modelComboBox.SelectedIndex = 0;
}
#endregion
#region 모델 콤보 박스 선택 인덱스 변경시 처리하기 - modelComboBox_SelectedIndexChanged(sender, e)
/// <summary>
/// 모델 콤보 박스 선택 인덱스 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void modelComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
this.yHatArray = new double[this.points.XValues.Count];
this.line.Clear();
if(FitModel(points, ref this.yHatArray, out this.coefficientArray, this.modelComboBox.SelectedIndex))
{
this.line.XValues.Count = this.points.XValues.Count;
this.line.XValues.Value = this.points.XValues.Value;
this.line.YValues.Count = this.points.XValues.Count;
this.line.YValues.Value = this.yHatArray;
switch(this.modelComboBox.SelectedIndex)
{
case 0 :
this.tChart.Header.Text = "y = a * Exp(b * x)\r\na = " + this.coefficientArray[0].ToString("0.00")+" b = "+this.coefficientArray[1].ToString("0.00");
break;
case 1 :
this.tChart.Header.Text = "y = a x ^ b\r\na = " + this.coefficientArray[0].ToString("0.00") + " b = " + this.coefficientArray[1].ToString("0.00");
break;
case 2 :
this.tChart.Header.Text = "y = b * ln(x) + a\r\na =" + this.coefficientArray[0].ToString("0.00") + " b = " + this.coefficientArray[1].ToString("0.00");
break;
}
}
this.line.Repaint();
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 모델 맞추기 - FitModel(source, yHatArray, coeffientArray, modelIndex)
/// <summary>
/// 모델 맞추기
/// </summary>
/// <param name="source">소스 시리즈</param>
/// <param name="yHatArray">Y 예측값 배열</param>
/// <param name="coeffientArray">계수 배열</param>
/// <param name="modelIndex">모델 인덱스</param>
/// <returns>처리 결과</returns>
private bool FitModel(Series source, ref double[] yHatArray, out double[] coeffientArray, int modelIndex)
{
double[] yArray = new double[source.Count];
double[] xArray = new double[source.Count];
double[] wArray = new double[source.Count];
bool validModel = true;
switch(modelIndex)
{
case 0 :
// y(x) = a * Exp(b * x)
// linear model : ln(y) = b * x + ln(a)
for(int i = 0; i < source.Count; i++)
{
xArray[i] = source.notMandatory[i];
yArray[i] = Math.Log(source.mandatory[i]);
wArray[i] = source.mandatory[i] * source.mandatory[i];
}
Regression.LinearRegression(source.Count, xArray, yArray, wArray, out coeffientArray);
coeffientArray[0] = Math.Exp(coeffientArray[0]);
for(int i = 0; i < source.Count; i++)
{
yHatArray[i] = coeffientArray[0] * Math.Exp(coeffientArray[1] * xArray[i]);
}
break;
case 1 :
// Power model y = a * x ^ b
// linear model : ln(y) = b * ln(x) + ln(a)
for(int i = 0; i < source.Count; i++)
{
xArray[i] = Math.Log(source.notMandatory[i]);
yArray[i] = Math.Log(source.mandatory[i]);
wArray[i] = source.mandatory[i] * source.mandatory[i];
}
Regression.LinearRegression(source.Count, xArray, yArray, wArray, out coeffientArray);
coeffientArray[0] = Math.Exp(coeffientArray[0]);
for(int i = 0; i < source.Count; i++)
{
yHatArray[i] = coeffientArray[0] * Math.Pow(source.notMandatory[i], coeffientArray[1]);
}
break;
case 2 :
// Logarithmic model y = b * ln(x) + a
for(int i = 0; i < source.Count; i++)
{
xArray[i] = Math.Log(source.notMandatory[i]);
yArray[i] = source.mandatory[i];
wArray[i] = source.mandatory[i] * source.mandatory[i];
}
Regression.LinearRegression(source.Count, xArray, yArray, wArray, out coeffientArray);
for(int i = 0; i < source.Count; i++)
{
yHatArray[i] = coeffientArray[1] * Math.Log(source.notMandatory[i]) + coeffientArray[0];
}
break;
default :
coeffientArray = new double[0];
break;
}
return validModel;
}
#endregion
}
}