//libNS.java

import java.io.*;
import java.util.Random;
import java.awt.*;
import java.awt.event.*;

class sygmoid //Класс, описывающий функцию сигмойд и производную от нее.
{
	double beta; //Коэффициент бетта
	public sygmoid(double b) { beta = b;} //Конструктор с подстановкой коэффициента
	public double f(double x) {	return (1/(1+Math.exp(-beta*x))); } //Возвращает значение сигмойда
	public double fD(double x) { return (beta*(1-f(x))*f(x)); } //Возвращает значение производной
	public void setBeta(double b) {	beta = b;} // Меняет коэффициент
}
class Neiro_Layer1  //Класс содержащий веса первого слоя
{
	double w[][] = new double[3][3]; //Массив содержащий текущие коэффициенты первого слоя
	public Neiro_Layer1 (double w10, double w11, double w12, double w20, double w21, double w22,double w30, double w31, double w32) //Конструктор
	{
		w[0][0] = w10;	//W10 первого нейрона
		w[0][1] = w11;	//W11 первого нейрона
		w[0][2] = w12;	//W12 первого нейрона
		w[1][0] = w20;	//W20 второго нейрона
		w[1][1] = w21;	//W21 второго нейрона
		w[1][2] = w22;	//W22 второго нейрона
		w[2][0] = w30;  //W30 третьего нейрона
		w[2][1] = w31;  //w31 третьего нейрона
		w[2][1] = w32;  //w32 третьего нейрона
	}
	public Neiro_Layer1 (double ww) //Конструктор устанавливает все веса одинаковыми
	{
		for (int i=0; i<3; i++)
			for (int j=0; j<3; j++)
				w[i][j] = ww;
	}
	public void setWeight (int i, int j, double ww) { w[i][j] = ww;	} //Устанавливает вес
	public double getWeight (int i, int j) {return w[i][j]; } //Возвращает вес
	public double doUi(int i, double x1, double x2) {return (w[i-1][0]+w[i-1][1]*x1+w[i-1][2]*x2);} //Сумматор нейрона i
}

class Neiro_Layer2 //Класс содержащий веса второго слоя
{
	double w[] = new double[4]; //Массив весов
	public Neiro_Layer2(double w0, double w1, double w2,double w3) //Конструктор
	{
		w[0] = w0; // Установка весов
		w[1] = w1;
		w[2] = w2;
		w[3] = w3;
	}
	public Neiro_Layer2 (double ww) //Конструктор устанавливает все веса одинаковыми
	{
		for (int i=0; i<4; i++) w[i] = ww;
	}
	public void setWeight (int i, double ww) { w[i] = ww;}//Устанавливает вес
	public double getWeight (int i) {return w[i];}//Возвращает вес
	public double doU (double v1, double v2, double v3) {return (w[0]+w[1]*v1+w[2]*v2+w[3]*v3 );}//Сумматор нейрона
}

class Neiro_Net
{
	static sygmoid sigm; //Создаём ссылку на объект типа
	public Neiro_Layer1 s1 = new Neiro_Layer1(1,1,1,1,-1,1,-1,1,1); //Создаём первый слой
	public Neiro_Layer2 s2 = new Neiro_Layer2(1); //Создаём второй слой
	static double eta; //Параметр обучения
	public Neiro_Net  (sygmoid f1, double et) //Конструктор класса
	{
		sigm = f1;
		eta = et;
	}
	public double getEta() //Возвращает параметр обучения
	{
		return(eta);
	}
	public void setEta(double et) //Устанавливает параметр обучения
	{
		eta = et;
	}
	public double getY (double x1, double x2) //Возвращает занчение выхода вторго слоя, на точке (x1,x2)
	{
		return (sigm.f(s2.doU(sigm.f(s1.doUi(1, x1, x2)), sigm.f(s1.doUi(2, x1, x2)),sigm.f(s1.doUi(3, x1, x2)))));
	}

//	--------------------------------
	public void teach(double x1, double x2, double eps) //Алгоритм обучения (x1,x2) - координаты точки eps - истиное значение выходного сигнала
	{	//Иницициализация первого слоя
		double x[] = new double[3]; //Массив входов первого слоя
		x[0] = 1; x[1] = x1; x[2] = x2; //Инициализация входных сигналов первого слоя
		double u[] = new double[3]; //Выходы сумматоров нейронов первого слоя
		double v[] = new double[4]; //Входы нейрона второго(третьего) слоя
		double delta1[] = new double[3]; //Промежуточная переменная дельта1
		for (int i=0; i<3; i++) //Инициализация
					{
					u[i] = s1.doUi(i+1, x1, x2);
					v[i+1] = sigm.f(u[i]);
					}
		double delta2; //Промежуточная переменна дельта2
		//Инициализация второго слоя
		v[0] = 1; //Инициализируем сигнал нулевого входа нейрона второго слоя
		double u2 = s2.doU(v[1], v[2],v[3]); //Инициализируем выход сумматора второго слоя
		delta2 = (getY(x1, x2)-eps)*sigm.fD(u2); // Находим дельта2
		for (int i=0; i<3; i++) //Находим дельта1 для нейронов первого слоя
			delta1[i] = delta2*s2.getWeight(i+1)*sigm.fD(u[i]);
		double[] dwj = new double[4]; // Поправки весов второго слоя
		double[][] dwij = new double[3][3]; //Поправки весов первого слоя
		for (int i=0; i<4; i++) //Считаем поправки второго слоя
			dwj[i] = (-eta)*delta2*v[i];
		for (int i=0; i<3; i++) //Считаем поправки первого слоя
			for (int j=0; j<3; j++)
				dwij[i][j] = delta1[i]*x[j]*(-eta);
		for (int i=0; i<4; i++) //Меняем веса во втором слое
			s2.setWeight(i, s2.getWeight(i)+dwj[i]);
		for (int i=0; i<3; i++) //Меняем веса в первом слое
			for (int j=0; j<3; j++)
				s1.setWeight(i, j, s1.getWeight(i, j)+dwij[i][j]);
		}
}

//Основной Класс программы
public class libNS extends Frame implements WindowListener, ActionListener
{	static double betta = 2; //Коэффициент
	static double eta = 0.05; //Параметр обучения
	static int mods_number = 2; //
	static sygmoid f1 = new sygmoid(betta);//Создание нового сигмоида
	//Хранилища данных
	static double[] x = new double[100000]; //Хранилище координат генерируемых точек
	static double[] y = new double[100000];
	static byte[] clas = new byte[100000]; //Принадлежность соответствующих точек классам
	static double[] w0 = new double[200]; //Веса, для прослеживания динамики их изменения
	static double[] w1 = new double[200];
	static double[] w2 = new double[200];
	static double[] w3 = new double[200];

	static double[] w00 = new double[200];
	static double[] w01 = new double[200];
	static double[] w02 = new double[200];

	static double[] w10 = new double[200];
	static double[] w11 = new double[200];
	static double[] w12 = new double[200];

	static double[] w20 = new double[200];
	static double[] w21 = new double[200];
	static double[] w22 = new double[200];

	static Random r = new Random(); //Создание объекта класса рандом для генерации случайных значений
	static double[] p = new double[mods_number]; //Хранилище вероятностей попадания в моду
	static Neiro_Net  ns = new Neiro_Net (f1, eta); //Создаём нейросеть с параметром обучения
	static double[] mx = new double[mods_number]; //Матиматическое ожидание по оси x
	static double[] my = new double[mods_number]; //Матиматическое ожидание по оси y
	static double[] dx = new double[mods_number]; //Дисперсия ожидание по оси x
	static double[] dy = new double[mods_number]; //Дисперсия ожидание по оси y

	static double mstx=0, msty=0; //Переменные масштаба
	static double minx=0, miny=0, maxx=0, maxy=0; //Минимум и максимум из точек для нахождения масштаба
	static boolean flag = false; //Флаг выбора пункта меню Тюнинг

	public void windowOpened(WindowEvent e) {}
	public void windowClosed(WindowEvent e) {}
	public void windowIconified(WindowEvent e) {}
	public void windowDeiconified(WindowEvent e) {}
	public void windowActivated(WindowEvent e) {}
	public void windowDeactivated(WindowEvent e) {}

	public void windowClosing(WindowEvent e) {
		dispose();
		System.exit(1);
		}

	public void actionPerformed(ActionEvent e) {
		int i, j=0;
		int right=0;
		String arg = (String) e.getActionCommand();
		if (arg.equals("Values")) {
			Correction corr = new Correction(this,true,true);
			corr.setVisible(true);
			};
		if (arg.equals("Eta")) {
			Correction corr1 = new Correction(this,true, false);
			corr1.setVisible(true);
			}
		if (arg.equals("Teach")) {
			generate();
			for (i =0; i<100000; i++) {
				ns.teach(x[i],y[i],clas[i]);
				j++;
				if (j==500) {
					w0[(int) (i)/500] = ns.s2.getWeight(0);
					w1[(int) (i)/500] = ns.s2.getWeight(1);
					w2[(int) (i)/500] = ns.s2.getWeight(2);
					w3[(int) (i)/500] = ns.s2.getWeight(3);

					w00[(int) (i)/500] = ns.s1.getWeight(0,0);
					w01[(int) (i)/500] = ns.s1.getWeight(0,1);
					w02[(int) (i)/500] = ns.s1.getWeight(0,2);

					w10[(int) (i)/500] = ns.s1.getWeight(1,0);
					w11[(int) (i)/500] = ns.s1.getWeight(1,1);
					w12[(int) (i)/500] = ns.s1.getWeight(1,2);

					w20[(int) (i)/500] = ns.s1.getWeight(2,0);
					w21[(int) (i)/500] = ns.s1.getWeight(2,1);
					w22[(int) (i)/500] = ns.s1.getWeight(2,2);

					j = 0;
					}
				}
			}
		if (arg.equals("Check")) {
			generate();
			for (i=0; i<100000; i++) {
				/*int d =(int) Math.round(ns.getY(x[i],y[i])-clas[i]);
				if (d <=0) right++;*/
				if((ns.getY(x[i],y[i])-clas[i])<=0) right++;
				}
			Message mes = new Message(this,"Right decisions - "+right+", wrong decisions - "+(100000-right));
			mes.setVisible(true);
			}
		if (arg.equals("New")) {
			ns.s1.setWeight(0,0,-1);
			ns.s1.setWeight(0,1,1);
			ns.s1.setWeight(0,2,0);

			ns.s1.setWeight(1,0,-1);
			ns.s1.setWeight(1,1,2);
			ns.s1.setWeight(1,2,0);

			ns.s1.setWeight(2,0,-1);
			ns.s1.setWeight(2,1,1);
			ns.s1.setWeight(1,2,1);

			ns.s2.setWeight(0,1/2);
			ns.s2.setWeight(1,-1);
			ns.s2.setWeight(2,1);
			ns.s2.setWeight(3,1);

			}
		if (arg.equals("Tuning")) flag = true;

		repaint();
		}
/*
	public static byte[] min(double[] a) {
		double aa[] = new double[4];
		double mi=0;
		int i, j;
		byte[] k = new byte[4];
		byte c=0;
		for (i=0; i<4; i++) {
			k[i] = (byte) i;
			aa[i] = a[i];
			}
		for (i=0; i<4; i++)
			for (j=i+1; j<4; j++)
				if (aa[j]<aa[i]) {
					mi = aa[j]; c = k[j];
					aa[j] = aa[i]; k[j] = k[i];						aa[i] = mi; k[i] = c;
					}
		return k;
		}
*/
	public static double gauss (double mo, double d) {
		return (r.nextGaussian()*Math.sqrt(d)+mo);
		}

	public static byte moda(){
		double pp = r.nextDouble();
		//byte t[] = new byte[4];
		//t = min (p);
		if (pp<p[0]) return(0);
			else return(1);

		}

	public static void generate () {
		int i;
		byte j;
		for (i=0; i<100000; i++) {
			j=moda();
			x[i] = gauss(mx[j], dx[j]);
			y[i] = gauss(my[j], dy[j]);
			if (j==0) clas[i] = 1;
				else clas[i] = 0;
			}
		}

	public static void scale() {
		int i;
		double xma = x[0], xmi = x[0];
		double yma = y[0], ymi = y[0];
		for(i=0; i<100000; i++) {
			if (x[i]>xma) xma=x[i];
			if (x[i]<xmi) xmi=x[i];
			if (y[i]>yma) yma=y[i];
			if (y[i]<ymi) ymi=y[i];
			}
		mstx = 400/(xma-xmi);
		maxx = xma; minx = xmi;
		msty = 400/(yma-ymi);
		maxy = yma; miny = ymi;
		}

	public static void DrawClass(Graphics g, Frame frm) {
		double y1=0, y2=0;
		int xa=0, xb=0, i, k=0;

		scale();
		g.drawRect(100, 100, 400, 400); //прямоугольник вывода

		for (i=0; i<400; i++) {
			if (ns.s1.getWeight(0,2)!=0) {
				y1 = -(ns.s1.getWeight(0,0) + ns.s1.getWeight(0,1)*((i/mstx)+minx))/ns.s1.getWeight(0,2);
				if ((y1<=maxy)&(y1>=miny)) {
					if(Math.abs(y1-miny)>=Math.abs(maxy-y1)) y1=maxy;
						else y1=miny;

					xa = i;
					i = 400;
					}
				}
			else {
				y1 = 400;
				xa = (int)Math.round((-ns.s1.getWeight(0,0)/ns.s1.getWeight(0,1)-minx)*mstx);
				i = 400;
				}
			}
		for (i=400; i>0; i--) {
			if (ns.s1.getWeight(0,2)!=0) {
				y2 = -(ns.s1.getWeight(0,0) + ns.s1.getWeight(0,1)*((i/mstx)+minx))/ns.s1.getWeight(0,2);
				if ((y2<=maxy)&(y2>=miny)) {
					if(Math.abs(y2-miny)>=Math.abs(maxy-y2)) y2=maxy;
						else y2=miny;
					xb = i;
					i = 0;
					}
				}
			else {
				y2 = 100;
				xb = xa;
				i = 0;
				}
			}

		g.setColor(Color.blue);
		g.drawLine(xa+100, 500- (int)Math.round((y1-miny)*msty), xb+100, 500- (int)Math.round((y2-miny)*msty));//1-й нейрон

		for (i=0; i<400; i++) {
					if (ns.s1.getWeight(1,2)!=0) {
						y1 = -(ns.s1.getWeight(1,0) + ns.s1.getWeight(1,1)*((i/mstx)+minx))/ns.s1.getWeight(1,2);
						if ((y1<=maxy)&(y1>=miny)) {
							if(Math.abs(y1-miny)>=Math.abs(maxy-y1)) y1=maxy;
								else y1=miny;
							xa = i;
							i = 400;
							}
						}
					else {
						y1 = maxy;
						xa = (int)Math.round((-ns.s1.getWeight(1,0)/ns.s1.getWeight(1,1)-minx)*mstx);
						i = 400;
						}
					}
				for (i=400; i>0; i--) {
					if (ns.s1.getWeight(1,2)!=0) {
						y2 = -(ns.s1.getWeight(1,0) + ns.s1.getWeight(1,1)*((i/mstx)+minx))/ns.s1.getWeight(1,2);
						if ((y2<maxy)&(y2>miny)) {
							if(Math.abs(y2-miny)>=Math.abs(maxy-y2)) y2=maxy;
								else y2=miny;
							xb = i;
							i = 0;
							}
						}
					else {
						y2 = miny;
						xb = xa;
						i = 0;
						}
					}
				g.setColor(Color.green);
		g.drawLine(xa+100, 500- (int)Math.round((y1-miny)*msty), xb+100, 500- (int)Math.round((y2-miny)*msty));//2-й нейрон

		for (i=0; i<400; i++) {
					if (ns.s1.getWeight(2,2)!=0) {
						y1 = -(ns.s1.getWeight(2,0) + ns.s1.getWeight(2,1)*((i/mstx)+minx))/ns.s1.getWeight(2,2);
						if ((y1<=maxy)&(y1>=miny)) {
							if(Math.abs(y1-miny)>=Math.abs(maxy-y1)) y1=maxy;
								else y1=miny;

							xa = i;
							i = 400;
							}
						}
					else {
						y1 = maxy;
						xa = (int)Math.round((-ns.s1.getWeight(2,0)/ns.s1.getWeight(2,1)-minx)*mstx);
						i = 400;
						}
					}
				for (i=400; i>0; i--) {
					if (ns.s1.getWeight(2,2)!=0) {
						y2 = -(ns.s1.getWeight(2,0) + ns.s1.getWeight(2,1)*((i/mstx)+minx))/ns.s1.getWeight(2,2);
						if ((y2<=maxy)&(y2>=miny)) {
							if(Math.abs(y2-miny)>=Math.abs(maxy-y2)) y2=maxy;
								else y2=miny;
							xb = i;
							i = 0;
							}
						}
					else {
						y2 = miny;
						xb = xa;
						i = 0;
						}
			}
			g.setColor(Color.yellow);
		g.drawLine(xa+100, 500- (int)Math.round((y1-miny)*msty), xb+100, 500- (int)Math.round((y2-miny)*msty));//3-й нейрон





//рисуем множества
		for (i=0; i<100000; i++) {
			if (clas[i]==1) g.setColor(Color.black);
				else g.setColor(Color.red);
			if ((x[i]>maxx)|(x[i]<minx)) k++;

			g.drawLine(100+(int) Math.round((x[i]-minx)*mstx), 500-(int)Math.round((y[i]-miny)*msty), 100+(int)Math.round((x[i]-minx)*mstx), 500-(int)Math.round((y[i]-miny)*msty));
			}
		}

	public void makeMenu () {
		MenuBar mb = new MenuBar();
		setMenuBar(mb);
		Menu file = new Menu("Settings");
		mb.add(file);
		MenuItem item5 = new MenuItem("New");
		file.add(item5);
		MenuItem item1 = new MenuItem("Values");
		file.add(item1);
		MenuItem item2 = new MenuItem("Eta");
		file.add(item2);
		Menu actions = new Menu("Actions");
		mb.add(actions);
		MenuItem item3 = new MenuItem ("Teach");
		MenuItem item4 = new MenuItem ("Check");
		MenuItem item6 = new MenuItem ("Tuning");
		actions.add(item3);
		actions.add(item4);
		actions.add(item6);
		item1.addActionListener(this);
		item2.addActionListener(this);
		item3.addActionListener(this);
		item4.addActionListener(this);
		item5.addActionListener(this);
		item6.addActionListener(this);
		}

	public void paint (Graphics g) {
		DrawClass(g,this);
		if (flag) {
			mTune mtu = new mTune(w0, w1, w2, w3, w00, w01, w02, w10, w11, w12, w20, w21, w22);
			mtu.setVisible(true);
			}
		flag = false;
		}

	public libNS() {
		super("Neiro Set'");
		addWindowListener(this);

			dx[0] = 1;
			dx[1] = 5;
			dy[0] = 1;
			dy[1] = 5;

			p[0] = 0.5;
			p[1] = 0.5;

		mx[0] = 3;
		mx[1] = 3;

		my[0] = 3;
		my[1] = 3;


		ns.s1.setWeight(0,0,-1);
		ns.s1.setWeight(0,1,1);
		ns.s1.setWeight(0,2,0);

		ns.s1.setWeight(1,0,-1);
		ns.s1.setWeight(1,1,2);
		ns.s1.setWeight(1,2,0);

		ns.s1.setWeight(2,0,-1);
		ns.s1.setWeight(2,1,1);
		ns.s1.setWeight(1,2,1);

		ns.s2.setWeight(0,1/2);
		ns.s2.setWeight(1,-1);
		ns.s2.setWeight(2,1);
		ns.s2.setWeight(3,1);

		makeMenu();
		generate();
		scale();
		setSize(800, 600);
		setVisible(true);
		setResizable(true);
		}

	public static void main(String args[]) {
		libNS kn = new libNS();
		}
	}//end of libNS

class Message extends Dialog implements ActionListener {

	StringBuffer st;

	public Message(Frame frm, String str) {
		super(frm, "Attention!! Message:", true);
		StringBuffer st1 = new StringBuffer(str);
		st = st1;
		setSize(300, 100);
		setLayout(new FlowLayout(FlowLayout.CENTER));
		add(new Label(str));
		Button but=new Button("  OK  ");
		add (but);
		but.addActionListener(this);
		}

	public void actionPerformed (ActionEvent e) {
		dispose();
		}
	}//end of message

//класс диалогового окна, производящий корректировку.
class Correction extends Dialog implements ActionListener {
	TextField p1, p2, mx1, mx2,  my1, my2,  dx1, dx2, dy1, dy2,  eta;
	boolean wh;
	libNS kNS;
	Neiro_Net  ns1 = libNS.ns;

	public void actionPerformed(ActionEvent e) {
		if (wh==false) ns1.setEta(new Double (eta.getText()).doubleValue());
			else {
				libNS.p[0] = new Double (p1.getText()).doubleValue();
				libNS.p[1] = new Double (p2.getText()).doubleValue();
				//libNS.p[2] = new Double (p3.getText()).doubleValue();
				//libNS.p[3] = new Double (p4.getText()).doubleValue();
				libNS.mx[0] = new Double (mx1.getText()).doubleValue();
				libNS.mx[1] = new Double (mx2.getText()).doubleValue();
				//libNS.mx[2] = new Double (mx3.getText()).doubleValue();
				//libNS.mx[3] = new Double (mx4.getText()).doubleValue();
				libNS.my[0] = new Double (my1.getText()).doubleValue();
				libNS.my[1] = new Double (my2.getText()).doubleValue();
				//libNS.my[2] = new Double (my3.getText()).doubleValue();
				//libNS.my[3] = new Double (my4.getText()).doubleValue();
				libNS.dx[0] = new Double (dx1.getText()).doubleValue();
				libNS.dx[1] = new Double (dx2.getText()).doubleValue();
				//libNS.dx[2] = new Double (dx3.getText()).doubleValue();
				//libNS.dx[3] = new Double (dx4.getText()).doubleValue();
				libNS.dy[0] = new Double (dy1.getText()).doubleValue();
				libNS.dy[1] = new Double (dy2.getText()).doubleValue();
				//libNS.dy[2] = new Double (dy3.getText()).doubleValue();
				//libNS.dy[3] = new Double (dy4.getText()).doubleValue();
				libNS.generate();
				libNS.scale();
				this.getOwner().repaint();
				}
		dispose();
		}

	public Correction (Frame parentFrm, boolean modal, boolean what) {
		super(parentFrm, " Correction ", modal);
		setSize(350,350);
		setLayout(new FlowLayout(FlowLayout.LEFT, 35, 5)) ;
		wh=what;
		if (what) {

//1 вероятности:
			add(new Label ("p11"));
			p1 = new TextField();
			p1.setText(Double.toString(libNS.p[0]));
			add(p1);
//2
			add(new Label ("p12"));
			p2 = new TextField();
			p2.setText(Double.toString(libNS.p[1]));
			add(p2);

//5 мат ожидания по x:
			add(new Label ("mx11"));
			mx1 = new TextField();
			mx1.setText(Double.toString(libNS.mx[0]));
			add(mx1);
//6
			add(new Label ("mx12"));
			mx2 = new TextField();
			mx2.setText(Double.toString(libNS.mx[1]));
			add(mx2);

//9 мат ожидания по у:
			add(new Label ("my11"));
			my1 = new TextField();
			my1.setText(Double.toString(libNS.my[0]));
			add(my1);
//10
			add(new Label ("my12"));
			my2 = new TextField();
			my2.setText(Double.toString(libNS.my[1]));
			add(my2);

//13 дисперсии по x:
			add(new Label ("dx11"));
			dx1 = new TextField();
			dx1.setText(Double.toString(libNS.dx[0]));
			add(dx1);
//14
			add(new Label ("dx12"));
			dx2 = new TextField();
			dx2.setText(Double.toString(libNS.dx[1]));
			add(dx2);

//17 дисперсии по у:
			add(new Label ("dy11"));
			dy1 = new TextField();
			dy1.setText(Double.toString(libNS.dy[0]));
			add(dy1);
//18
			add(new Label ("dy12"));
			dy2 = new TextField();
			dy2.setText(Double.toString(libNS.dy[1]));
			add(dy2);

			};

		if (what==false) {
//Корректируем только значение параметра
//обучения "эта":
			add(new Label ("eta"));
			eta = new TextField();
			eta.setText(Double.toString(ns1.getEta()));
			add(eta);
			};


		Button mb = new Button (" OK ");				add(mb);
		mb.addActionListener(this);
		}//end of constructor
	}//end of Correction



class mTune extends Frame implements WindowListener {

	static double max, min, mst;
	double[] w0 = new double[200];
	double[] w1 = new double[200];
	double[] w2 = new double[200];
	double[] w3 = new double[200];
	double[] w00 = new double[200];
	double[] w01 = new double[200];
	double[] w02 = new double[200];
	double[] w10 = new double[200];
	double[] w11 = new double[200];
	double[] w12 = new double[200];
	double[] w20 = new double[200];
	double[] w21 = new double[200];
	double[] w22 = new double[200];


	public void windowOpened(WindowEvent e) {}
	public void windowClosed(WindowEvent e) {
		System.out.println("cam close");
		System.exit(0);
		}
	public void windowIconified(WindowEvent e) {}
	public void windowDeiconified(WindowEvent e) {}
	public void windowActivated(WindowEvent e) {}
	public void windowDeactivated(WindowEvent e) {}

	public void windowClosing(WindowEvent e) {
		setVisible(false);
		}


	public mTune(double[] v0, double[] v1, double[] v2, double[] v3, double[] v00, double[] v01, double[] v02, double[] v10, double[] v11, double[] v12, double[] v20,double[] v21, double[] v22) {
		super("Tuning Process!");
		addWindowListener(this);
		int i = 0;
		max = v0[0];
		min = v0[0];


		for (i = 0; i<w0.length; i++) {
			if (v0[i] > max) max = v0[i];
			if (v1[i] > max) max = v1[i];
			if (v2[i] > max) max = v2[i];
			if (v3[i] > max) max = v3[i];

			if (v00[i] > max) max = v00[i];
			if (v01[i] > max) max = v01[i];
			if (v02[i] > max) max = v02[i];
			if (v10[i] > max) max = v10[i];
			if (v11[i] > max) max = v11[i];
			if (v12[i] > max) max = v12[i];
			if (v20[i] > max) max = v20[i];
			if (v21[i] > max) max = v21[i];
			if (v22[i] > max) max = v22[i];
			if (v0[i] < min) min = v0[i];
			if (v1[i] < min) min = v1[i];
			if (v2[i] < min) min = v2[i];
			if (v3[i] < min) min = v3[i];

			if (v00[i] < min) min = v00[i];
			if (v01[i] < min) min = v01[i];
			if (v02[i] < min) min = v02[i];
			if (v10[i] < min) min = v10[i];
			if (v11[i] < min) min = v11[i];
			if (v12[i] < min) min = v12[i];

			if (v20[i] < min) min = v20[i];
			if (v21[i] < min) min = v21[i];
			if (v22[i] < min) min = v22[i];
			w0[i] = v0[i];
			w1[i] = v1[i];
			w2[i] = v2[i];
			w3[i] = v3[i];
			w00[i] = v00[i];
			w01[i] = v01[i];
			w02[i] = v02[i];
			w10[i] = v10[i];
			w11[i] = v11[i];
			w12[i] = v12[i];
			w20[i] = v20[i];
			w21[i] = v21[i];
			w22[i] = v22[i];
			}
		mst = 75/(max - min);
		setSize(500, 750);
		setVisible(true);
		setResizable(true);
		}

	public void paint(Graphics g) {
		int i = 0;
		g.drawRect(0, 25, 200, 75);
		g.drawRect(0, 125, 200, 75);
		g.drawRect(0, 225, 200, 75);
		g.drawRect(0, 325, 200, 75);

		g.drawRect(300, 25, 200, 75);
		g.drawRect(300, 100, 200, 75);
		g.drawRect(300, 175, 200, 75);

		g.drawRect(300, 250, 200, 75);
		g.drawRect(300, 325, 200, 75);
		g.drawRect(300, 400, 200, 75);

		g.drawRect(300, 475, 200, 75);
		g.drawRect(300, 550, 200, 75);
		g.drawRect(300, 625, 200, 75);

		g.setColor(Color.red);
		for(i = 0; i<200; i++) {
			g.drawLine(i, 100- (int)Math.round((w0[i]-min)*mst),i , 100- (int)Math.round((w0[i]-min)*mst));
			g.drawLine(i, 200- (int)Math.round((w1[i]-min)*mst),i , 200- (int)Math.round((w1[i]-min)*mst));
			g.drawLine(i, 300- (int)Math.round((w2[i]-min)*mst),i , 300- (int)Math.round((w2[i]-min)*mst));
			g.drawLine(i, 400- (int)Math.round((w3[i]-min)*mst),i , 400- (int)Math.round((w3[i]-min)*mst));
       			g.drawLine(i+300, 100- (int)Math.round((w00[i]-min)*mst), i+300, 100- (int)Math.round((w00[i]-min)*mst));
       			g.drawLine(i+300, 175- (int)Math.round((w01[i]-min)*mst), i+300, 175- (int)Math.round((w01[i]-min)*mst));
       			g.drawLine(i+300, 250- (int)Math.round((w02[i]-min)*mst), i+300, 250- (int)Math.round((w02[i]-min)*mst));
       			g.drawLine(i+300, 325- (int)Math.round((w10[i]-min)*mst), i+300, 325- (int)Math.round((w10[i]-min)*mst));
       			g.drawLine(i+300, 400- (int)Math.round((w11[i]-min)*mst), i+300, 400- (int)Math.round((w11[i]-min)*mst));
       			g.drawLine(i+300, 475- (int)Math.round((w12[i]-min)*mst), i+300, 475- (int)Math.round((w12[i]-min)*mst));

       			g.drawLine(i+300, 550- (int)Math.round((w20[i]-min)*mst), i+300, 550- (int)Math.round((w20[i]-min)*mst));
				g.drawLine(i+300, 625- (int)Math.round((w21[i]-min)*mst), i+300, 625- (int)Math.round((w21[i]-min)*mst));
       			g.drawLine(i+300, 700- (int)Math.round((w22[i]-min)*mst), i+300, 700- (int)Math.round((w22[i]-min)*mst));
			}
		}
	}//end of mTune