| 情報学部 | 菅沼ホーム | 目次 | 索引 | 
/****************************/ /* back propagation model */ /* coded by Y.Suganuma */ /****************************/ #include#include #include #include #include "MT.h" /******************************************************/ /* バックプロパゲーションの制御(クラス BackControl) */ /******************************************************/ class BackControl { protected: double alpha, eata; //重み及びバイアス修正パラメータ double eps; // 許容誤差 unsigned long seed; // 乱数の初期値; int order; // 入力パターンの与え方(=0:順番,=1:ランダム) int p_type; // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // (負の時は,認識結果と重みをファイルへも出力) char o_file[100]; // 出力ファイル名 public: BackControl(char *); // コンストラクタ }; /*****************************************************/ /* バックプロパゲーションのデータ(クラス BackData) */ /*****************************************************/ class BackData { int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int noip; // 入力パターンの数 double **iptn; // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 double **optn; // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 public: BackData(char *); // コンストラクタ ~BackData(); // デストラクタ friend class Backpr; }; /*******************************************/ /* バックプロパゲーション(クラス Backpr) */ /*******************************************/ class Backpr : BackControl { char **con; // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 int f_type; // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int *nohu; // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl int nolvl; // 隠れユニットの階層数 int nou; // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ // ットには最も上の出力ユニットから,隠れ層の各ユニット, // 及び,入力ユニットに至る一連のユニット番号が付けられ // る) double *dp; // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 double *op; // op[i] : ユニット(i+1)の出力 i=0,nou-1 double *theta; //theta[i] : ユニット(i+1)のバイアス i=0,nou double **w; // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 public: Backpr(char *, char *); // コンストラクタ ~Backpr(); // デストラクタ void Err_back(double *); // 重みの修正 void Forward(); // 誤差の計算 void Learn(BackData &, int); // 学習 int Recog(BackData &, int, int); // 認識と学習 }; /*************************************/ /* クラスBackControlのコンストラクタ */ /* name : 入力データファイル名 */ /*************************************/ BackControl::BackControl(char *name) { FILE *in; in = fopen(name, "r"); fscanf(in, "%*s %lf %*s %d", &eps, &p_type); if (p_type < 0) fscanf(in, "%*s %s", o_file); fscanf(in, "%*s %d %*s %lf %*s %lf", &order, &eata, &alpha); fclose(in); seed = (unsigned long)time(NULL); } /************************************/ /* クラスBackDataのコンストラクタ */ /* name : 入力データファイル名 */ /************************************/ BackData::BackData(char *name) { int i1, i2; FILE *in; in = fopen(name, "r"); /* 入力パターン数等 */ fscanf(in, "%*s %d %*s %d %*s %d", &noip, &noiu, &noou); /* 領域の確保 */ iptn = new double * [noip]; for (i1 = 0; i1 < noip; i1++) iptn[i1] = new double [noiu]; optn = new double * [noip]; for (i1 = 0; i1 < noip; i1++) optn[i1] = new double [noou]; /* 入力パターン及び各入力パターンに対する出力パターンの入力 */ for (i1 = 0; i1 < noip; i1++) { fscanf(in, "%*s"); for (i2 = 0; i2 < noiu; i2++) fscanf(in, "%lf", &(iptn[i1][i2])); fscanf(in, "%*s"); for (i2 = 0; i2 < noou; i2++) fscanf(in, "%lf", &(optn[i1][i2])); } fclose(in); } /**************************/ /* BackDataのデストラクタ */ /**************************/ BackData::~BackData() { int i1; for (i1 = 0; i1 < noip; i1++) delete [] iptn[i1]; delete [] iptn; for (i1 = 0; i1 < noip; i1++) delete [] optn[i1]; delete [] optn; } /************************************************/ /* クラスBackprのコンストラクタ */ /* name_c : 制御データ用入力ファイル名 */ /* name_s : ネットワーク記述入力ファイル名 */ /************************************************/ Backpr::Backpr(char *name_c, char *name_s) : BackControl(name_c) { double x1, x2; int i0, i1, i2, id, k, k1, k2, k3, k4, l1, l2, n, sw; FILE *in; in = fopen(name_s, "r"); /* 乱数の初期化 */ init_genrand(seed); /* 入力ユニット,出力ユニットの数,関数タイプ */ fscanf(in, "%*s %d %*s %d %*s %d", &noiu, &noou, &f_type); nou = noiu + noou; // 入力ユニットと出力ユニットの和 /* 隠れユニットの階層数と各階層のユニット数 */ fscanf(in, "%*s %d", &nolvl); nohu = new int [nolvl+1]; nohu[nolvl] = noou; // 出力ユニットの数 if (nolvl > 0) { fscanf(in, "%*s"); for (i1 = 0; i1 < nolvl; i1++) { fscanf(in, "%d", &(nohu[i1])); nou += nohu[i1]; } } /* 領域の確保 */ con = new char * [nou]; for (i1 = 0; i1 < nou; i1++) { con[i1] = new char [nou]; for (i2 = 0; i2 < nou; i2++) con[i1][i2] = (i1 == i2) ? -1 : 0; } w = new double * [nou]; for (i1 = 0; i1 < nou; i1++) { w[i1] = new double [nou]; for (i2 = 0; i2 < nou; i2++) w[i1][i2] = 0.0; } dp = new double [nou]; op = new double [nou]; theta = new double [nou]; for (i1 = 0; i1 < nou; i1++) theta[i1] = 0.2 * genrand_real3() - 0.1; /* 各ユニットのバイアスとユニット間の接続関係 */ // バイアス // バイアスデータの数 fscanf(in, "%*s %d", &n); fscanf(in, "%*s %*s %*s"); if (n > 0) { // バイアスデータの処理 for (i0 = 0; i0 < n; i0++) { // ユニット番号 fscanf(in, "%d", &k1); // 不適当なユニット番号のチェック if (k1 < 1 || k1 > (nou-noiu)) { printf("***error ユニット番号 %d が不適当\n", k1); exit(1); } // バイアスの与え方 k1--; fscanf(in, "%d", &id); con[k1][k1] = id; // バイアスの初期設定 switch (con[k1][k1]) { case -1: fscanf(in, "%lf %lf", &x1, &x2); theta[k1] = (x2 - x1) * genrand_real3() + x1; break; case -2: fscanf(in, "%lf", &(theta[k1])); break; case -3: fscanf(in, "%lf", &(theta[k1])); break; default: printf("***error バイアスの与え方が不適当\n"); exit(1); } } } // 接続方法 // 接続データの数 fscanf(in, "%*s %d", &n); fscanf(in, "%*s %*s %*s"); if (n > 0) { // 接続データの処理 for (i0 = 0; i0 < n; i0++) { // 接続情報 fscanf(in, "%d %d %d %d", &k1, &k2, &k3, &k4); // 不適切な接続のチェック sw = 0; if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1) sw = 1; else { if (k1 > nou || k2 > nou || k3 > nou || k4 > nou) sw = 1; else { if (k1 > k2 || k3 > k4) sw = 1; else { if (k4 >= k1) sw = 1; else { l1 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l1 < 0; i1--) { k += nohu[i1]; if (k1 <= k) l1 = i1; } l2 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l2 < 0; i1--) { k += nohu[i1]; if (k4 <= k) l2 = i1; } if (l2 <= l1) sw = 1; } } } } if (sw > 0) { printf("***error ユニット番号が不適当(%d %d %d %d)\n", k1, k2, k3, k4); exit(1); } // 重みの初期値の与え方 k1--; k2--; k3--; k4--; fscanf(in, "%d", &id); if (id == 1) fscanf(in, "%lf %lf", &x1, &x2); else { if (id > 1) fscanf(in, "%lf", &x1); else { if (id != 0) { printf("***error 接続方法が不適当\n"); exit(1); } } } // 重みの初期値の設定 for (i1 = k3; i1 <= k4; i1++) { for (i2 = k1; i2 <= k2; i2++) { con[i1][i2] = id; switch (id) { case 0: w[i1][i2] = 0.0; break; case 1: w[i1][i2] = (x2 - x1) * genrand_real3() + x1; break; case 2: w[i1][i2] = x1; break; case 3: w[i1][i2] = x1; break; } } } } } fclose(in); } /************************/ /* Backprのデストラクタ */ /************************/ Backpr::~Backpr() { int i1; for (i1 = 0; i1 < nou; i1++) delete [] con[i1]; delete [] con; for (i1 = 0; i1 < nou; i1++) delete [] w[i1]; delete [] w; delete [] nohu; delete [] dp; delete [] op; delete [] theta; } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[i1] : 出力パターン */ /******************************************/ void Backpr::Err_back(double *ptn) { double x1; int i1, i2; for (i1 = 0; i1 < nou-noiu; i1++) { // 誤差の計算 if (i1 < noou) { if (f_type == 0) dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]); else dp[i1] = 0.5 * (ptn[i1] - op[i1]) * (op[i1] - 1.0) * (op[i1] + 1.0); } else { x1 = 0.0; for (i2 = 0; i2 < i1; i2++) { if (con[i2][i1] > 0) x1 += dp[i2] * w[i2][i1]; } if (f_type == 0) dp[i1] = op[i1] * (1.0 - op[i1]) * x1; else dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1; } // 重みの修正 for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] == 1 || con[i1][i2] == 2) { x1 = eata * dp[i1] * op[i2] + alpha * w[i2][i1]; w[i2][i1] = x1; w[i1][i2] += x1; } } // バイアスの修正 if (con[i1][i1] >= -2) { x1 = eata * dp[i1] + alpha * w[i1][i1]; w[i1][i1] = x1; theta[i1] += x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ void Backpr::Forward() { double sum; int i1, i2; for (i1 = nou-noiu-1; i1 >= 0; i1--) { sum = -theta[i1]; for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] > 0) sum -= w[i1][i2] * op[i2]; } op[i1] = (f_type == 0) ? 1.0 / (1.0 + exp(sum)) : 1.0 - 2.0 / (1.0 + exp(sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ void Backpr::Learn(BackData &p, int m_tri) { int i1, i2, k0 = -1, k1; /* エラーチェック */ if (noiu != p.noiu || noou != p.noou) { printf("***error 入力または出力ユニットの数が違います\n"); exit(1); } for (i1 = 0; i1 < m_tri; i1++) { /* パターンを与える順番の決定 */ if (order == 0) { // 順番 k0++; if (k0 >= p.noip) k0 = 0; } else { // ランダム k0 = (int)(genrand_real3() * p.noip); if (k0 >= p.noip) k0 = p.noip - 1; } /* 出力ユニットの結果を計算 */ k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[k0][i2]; Forward(); /* 重みとバイアスの修正 */ Err_back(&(p.optn[k0][0])); } } /***********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =0 : 出力を行わない */ /* =1 : 出力を行う */ /* =2 : 出力を行う(未学習パターン) */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /***********************************************/ int Backpr::Recog(BackData &p, int pr, int tri) { int i1, i2, k1, No = 0, ln, sw; FILE *out = NULL; /* ファイルのオープン */ if (p_type < 0 && pr > 0) { if (pr == 1) { out = fopen(o_file, "w"); fprintf(out, "***学習パターン***\n\n"); } else { out = fopen(o_file, "a"); fprintf(out, "\n***未学習パターン***\n\n"); } } /* 各パターンに対する出力 */ for (i1 = 0; i1 < p.noip; i1++) { // 入力パターンの設定 k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[i1][i2]; // 出力の計算 Forward(); // 結果の表示 if (p_type != 0 && pr > 0) { printf("入力パターン%4d ", i1+1); for (i2 = 0; i2 < noiu; i2++) { printf("%5.2f", op[k1+i2]); if (i2 == noiu-1) printf("\n"); else { if(((i2+1) % 10) == 0) printf("\n "); } } printf("\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { printf("%10.3f", p.optn[i1][i2]); if (i2 == noou-1) printf("\n"); else { if(((i2+1) % 5) == 0) printf("\n "); } } } sw = 0; if (p_type != 0 && pr > 0) printf(" (実際) "); for (i2 = 0; i2 < noou; i2++) { if (p_type != 0 && pr > 0) { printf("%10.3f", op[i2]); if (i2 == noou-1) printf("\n"); else { if(((i2+1) % 5) == 0) printf("\n "); } } if (fabs(op[i2]-p.optn[i1][i2]) > eps) sw = 1; } if (sw > 0) No++; if (p_type < 0 && pr > 0) { fprintf(out, "入力パターン%4d ", i1+1); for (i2 = 0; i2 < noiu; i2++) { fprintf(out, "%5.2f", op[k1+i2]); if (i2 == noiu-1) fprintf(out, "\n"); else { if(((i2+1) % 10) == 0) fprintf(out, "\n "); } } fprintf(out, "\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { fprintf(out, "%10.3f", p.optn[i1][i2]); if (i2 == noou-1) fprintf(out, "\n"); else { if(((i2+1) % 5) == 0) fprintf(out, "\n "); } } fprintf(out, " (実際) "); for (i2 = 0; i2 < noou; i2++) { fprintf(out, "%10.3f", op[i2]); if (i2 == noou-1) fprintf(out, "\n"); else { if(((i2+1) % 5) == 0) fprintf(out, "\n "); } } } if (p_type != 0 && pr > 0) { getchar(); if (i1 == 0) getchar(); } } /* 重みの出力 */ if ((p_type < -1 || p_type > 1) && pr == 1) { printf(" 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { printf(" to%4d from ", i1+1); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else printf("\n "); } printf("%4d%11.3f", i2+1, w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } printf("\n"); } printf("\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { printf("%4d%11.3f", i1+1, theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; printf("\n "); } } if (ln != 0) printf("\n"); getchar(); } if (p_type < 0 && pr == 1) { fprintf(out, " 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { fprintf(out, " to%4d from ", i1+1); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else fprintf(out, "\n "); } fprintf(out, "%4d%11.3f", i2+1, w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } fprintf(out, "\n"); } fprintf(out, "\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { fprintf(out, "%4d%11.3f", i1+1, theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; fprintf(out, "\n "); } } if (ln != 0) fprintf(out, "\n"); } if (p_type < 0 && pr > 0) fclose(out); return No; } /****************/ /* main program */ /****************/ int main(int argc, char *argv[]) { int conv; // 収束確認回数 int m_tri; // 最大学習回数 int max = 0, no = 1, sw, tri; char f_name[100]; // エラー if (argc != 3) { printf("***error 入力データファイル名を指定して下さい\n"); exit(1); } else { // ネットワークの定義 Backpr net(argv[1], argv[2]); // 学習パターン等の入力 printf("学習回数は? "); scanf("%d", &m_tri); printf("何回毎に収束を確認しますか? "); scanf("%d", &conv); printf("学習パターンのファイル名は? "); scanf("%s", f_name); BackData dt1(f_name); // 学習 while (max < m_tri && no > 0) { tri = ((max + conv) < m_tri) ? conv : m_tri - max; max += tri; net.Learn(dt1, tri); // 学習 no = net.Recog(dt1, 0, max); // 学習対象の認識 printf(" 回数 %d 誤って認識したパターン数 %d\n", max, no); } no = net.Recog(dt1, 1, max); // 学習対象の認識と出力 // 未学習パターンの認識 printf("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "); scanf("%d", &sw); if (sw > 0) { printf("未学習パターンのファイル名は? "); scanf("%s", f_name); BackData dt2(f_name); no = net.Recog(dt2, 2, max); // 未学習対象の認識と出力 } } return 0; } /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include " // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti > 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk > 1) ^ mag01[y & 0x1UL]; } for (;kk > 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */ 
/****************************/
/* back propagation model   */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.StringTokenizer;
class Test {
	/****************/
	/* main program */
	/****************/
	public static void main(String args[]) throws IOException, FileNotFoundException
	{
		int conv;   // 収束確認回数
		int m_tri;   // 最大学習回数
		int max = 0, no = 1, sw, tri;
		String f_name;
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
					// エラー
		if (args.length != 2) {
			System.out.print("***error   入力データファイル名を指定して下さい\n");
			System.exit(1);
		}
		else {
					// ネットワークの定義
			Backpr net = new Backpr (args[0], args[1]);
					// 学習パターン等の入力
			System.out.print("学習回数は? ");
			m_tri = Integer.parseInt(in.readLine());
			System.out.print("何回毎に収束を確認しますか? ");
			conv = Integer.parseInt(in.readLine());
			System.out.print("学習パターンのファイル名は? ");
			f_name = in.readLine();
			BackData dt1 = new BackData(f_name);
					// 学習
			while (max < m_tri && no > 0) {
				tri  = ((max + conv) < m_tri) ? conv : m_tri - max;
				max += tri;
				net.Learn(dt1, tri);   // 学習
				no = net.Recog(dt1, 0, max);   // 学習対象の認識
				System.out.println("   回数 " + max + " 誤って認識したパターン数 " + no);
			}
			no = net.Recog(dt1, 1, max);   // 学習対象の認識と出力
					// 未学習パターンの認識
			System.out.print("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ");
			sw = Integer.parseInt(in.readLine());
			if (sw > 0) {
				System.out.print("未学習パターンのファイル名は? ");
				f_name = in.readLine();
				BackData dt2 = new BackData(f_name);
				no = net.Recog(dt2, 2, max);   // 未学習対象の認識と出力
			}
		}
		in.close();
	}
}
/******************************************************/
/* バックプロパゲーションの制御(クラス BackControl) */
/******************************************************/
class BackControl {
	protected double alpha, eata;   //重み及びバイアス修正パラメータ
	protected double eps;   // 許容誤差
	protected int order;   // 入力パターンの与え方(=0:順番,=1:ランダム)
	protected int p_type;   // 出力先・方法の指定
                            //   =0 : 誤って認識した数だけ出力
                            //   =1 : 認識結果を出力
                            //   =2 : 認識結果と重みを出力
                            //        (負の時は,認識結果と重みをファイルへも出力)
	protected int c_size;   // 円の大きさ(直径,0のときは画面を表示しない)
	protected int f_size;   // フォントサイズ(0のときはユニット番号を表示しない)
	protected int width;   // 画面の幅
	protected int hight;   // 画面の高さ
	protected String o_file;   // 出力ファイル名
	/*************************************/
	/* クラスBackControlのコンストラクタ */
	/*      name : 入力データファイル名  */
	/*************************************/
	BackControl(String name) throws IOException, FileNotFoundException
	{
		StringTokenizer str;
		BufferedReader in = new BufferedReader(new FileReader(name));
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		eps = Double.parseDouble(str.nextToken());
		str.nextToken();
		p_type = Integer.parseInt(str.nextToken());
		if (p_type < 0) {
			str.nextToken();
			o_file = str.nextToken();
		}
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		order = Integer.parseInt(str.nextToken());
		str.nextToken();
		eata = Double.parseDouble(str.nextToken());
		str.nextToken();
		alpha = Double.parseDouble(str.nextToken());
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		c_size = Integer.parseInt(str.nextToken());
		if (c_size > 0) {
			f_size = Integer.parseInt(str.nextToken());
			width  = Integer.parseInt(str.nextToken());
			hight  = Integer.parseInt(str.nextToken());
		}
		in.close();
	}
}
/*****************************************************/
/* バックプロパゲーションのデータ(クラス BackData) */
/*****************************************************/
class BackData {
	int noiu;   // 入力ユニットの数
	int noou;   // 出力ユニットの数
	int noip;   // 入力パターンの数
	double iptn[][];   // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
                       //              入力ユニットの入力値
                       //                i=0,noip-1  j=0,noiu-1
	double optn[][];   // optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
                       //              番目の出力ユニットの目標出力値
                       //                i=0,noip-1  j=0,noou-1
	/************************************/
	/* クラスBackDataのコンストラクタ   */
	/*      name : 入力データファイル名 */
	/************************************/
	BackData(String name) throws IOException, FileNotFoundException
	{
		int i1, i2;
		StringTokenizer str;
		BufferedReader in = new BufferedReader(new FileReader(name));
	/*
	    入力パターン数等
	*/
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		noip = Integer.parseInt(str.nextToken());
		str.nextToken();
		noiu = Integer.parseInt(str.nextToken());
		str.nextToken();
		noou = Integer.parseInt(str.nextToken());
	/*
	     領域の確保
	*/
		iptn = new double [noip][noiu];
		optn = new double [noip][noou];
	/*
	     入力パターン及び各入力パターンに対する出力パターンの入力
	*/
		for (i1 = 0; i1 < noip; i1++) {
			str = new StringTokenizer(in.readLine(), " ");
			str.nextToken();
			for (i2 = 0; i2 < noiu; i2++)
				iptn[i1][i2] = Double.parseDouble(str.nextToken());
			str = new StringTokenizer(in.readLine(), " ");
			str.nextToken();
			for (i2 = 0; i2 < noou; i2++)
				optn[i1][i2] = Double.parseDouble(str.nextToken());
		}
		in.close();
	}
}
/*******************************************/
/* バックプロパゲーション(クラス Backpr) */
/*******************************************/
class Backpr extends BackControl {
	private byte con[][];   // con[i][j] : 各ユニットに対するバイアスの与え方,及び,
                            // 接続方法
                            //   [i][i] : ユニット(i+1)のバイアスの与え方
                            //     =-3 : 入力値で固定
                            //     =-2 : 入力値を初期値として,学習により変更
                            //     =-1 : 乱数で初期値を設定し,学習により変更
                            //   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
                            //     =0 : 接続しない
                            //     =1 : 接続する(重みの初期値を乱数で設定し,学習)
                            //     =2 : 接続する(重みの初期値を入力で与え,学習)
                            //     =3 : 接続する(重みを入力値に固定)
                            //            i=0,nou-1  j=0,nou-1
	private int f_type;   // シグモイド関数のタイプ
                          //   0 : [0,1]
                          //   1 : [-1,1])
	private int noiu;   // 入力ユニットの数
	private int noou;   // 出力ユニットの数
	private int nohu[];   // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
                          //           には下から順に番号が付けられ,出力層はレ
                          //           ベル(nolvl+1)の隠れ層とも見做される)
                          //             i=0,nolvl
	private int nolvl;   // 隠れユニットの階層数
	private int nou;   // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ
                       // ットには最も上の出力ユニットから,隠れ層の各ユニット,
                       // 及び,入力ユニットに至る一連のユニット番号が付けられ
                       // る)
	private double dp[];   // dp[i] : ユニット(i+1)の誤差  i=0,nou-1
	private double op[];   // op[i] : ユニット(i+1)の出力  i=0,nou-1
	private double theta[];   //theta[i] : ユニット(i+1)のバイアス  i=0,nou
	private double w[][];   // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
                            // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
                            // w[i][i] : ユニット(i+1)のバイアスの前回修正量
                            //   i=0,nou-1  j=0,nou-1
	private Random rn;   // 乱数
	/************************************************/
	/* クラスBackprのコンストラクタ                 */
	/*      name_c : 制御データ用入力ファイル名     */
	/*      name_s : ネットワーク記述入力ファイル名 */
	/************************************************/
	Backpr(String name_c, String name_s) throws IOException, FileNotFoundException
	{
		super(name_c);
		double x1, x2;
		int i0, i1, i2, id, k, k1, k2, k3, k4, l1, l2, n, sw;
		StringTokenizer str;
		BufferedReader in = new BufferedReader(new FileReader(name_s));
	/*
	     乱数の初期化
	*/
		rn  = new Random();   // 乱数の初期設定
	/*
	     入力ユニット,出力ユニットの数,関数タイプ
	*/
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		noiu = Integer.parseInt(str.nextToken());
		str.nextToken();
		noou = Integer.parseInt(str.nextToken());
		str.nextToken();
		f_type = Integer.parseInt(str.nextToken());
		nou = noiu + noou;   // 入力ユニットと出力ユニットの和
	/*
	     隠れユニットの階層数と各階層のユニット数
	*/
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		nolvl = Integer.parseInt(str.nextToken());
		nohu        = new int [nolvl+1];
		nohu[nolvl] = noou;   // 出力ユニットの数
		if (nolvl > 0) {
			str.nextToken();
			for (i1 = 0; i1 < nolvl; i1++) {
				nohu[i1]  = Integer.parseInt(str.nextToken());
				nou      += nohu[i1];
			}
		}
	/*
	     領域の確保
	*/
		con = new byte [nou][nou];
		for (i1 = 0; i1 < nou; i1++) {
			for (i2 = 0; i2 < nou; i2++)
				con[i1][i2] =  (i1 == i2) ? (byte)-1 : (byte)0;
		}
		w = new double [nou][nou];
		for (i1 = 0; i1 < nou; i1++) {
			for (i2 = 0; i2 < nou; i2++)
				w[i1][i2] = 0.0;
		}
		dp    = new double [nou];
		op    = new double [nou];
		theta = new double [nou];
		for (i1 = 0; i1 < nou; i1++)
			theta[i1] = 0.2 * rn.nextDouble() - 0.1;
	/*
	     各ユニットのバイアスとユニット間の接続関係
	*/
					// バイアス
						// バイアスデータの数
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		n = Integer.parseInt(str.nextToken());
		in.readLine();
		in.readLine();
		in.readLine();
		if (n > 0) {
						// バイアスデータの処理
			for (i0 = 0; i0 < n; i0++) {
							// ユニット番号
				str = new StringTokenizer(in.readLine(), " ");
				k1 = Integer.parseInt(str.nextToken());
							// 不適当なユニット番号のチェック
				if (k1 < 1 || k1 > (nou-noiu)) {
					System.out.print("***error  ユニット番号 " + k1 + " が不適当\n");
					System.exit(1);
				}
							// バイアスの与え方
				k1--;
				id = Integer.parseInt(str.nextToken());
				con[k1][k1] = (byte)id;
							// バイアスの初期設定
				switch (con[k1][k1]) {
					case -1:
						x1 = Double.parseDouble(str.nextToken());
						x2 = Double.parseDouble(str.nextToken());
						theta[k1] = (x2 - x1) * rn.nextDouble() + x1;
						break;
					case -2:
						theta[k1] = Double.parseDouble(str.nextToken());
						break;
					case -3:
						theta[k1] = Double.parseDouble(str.nextToken());
						break;
					default:
						System.out.print("***error  バイアスの与え方が不適当\n");
						System.exit(1);
				}
			}
		}
					// 接続方法
						// 接続データの数
		str = new StringTokenizer(in.readLine(), " ");
		str.nextToken();
		n = Integer.parseInt(str.nextToken());
		in.readLine();
		in.readLine();
		in.readLine();
		if (n > 0) {
						// 接続データの処理
			for (i0 = 0; i0 < n; i0++) {
							// 接続情報
				str = new StringTokenizer(in.readLine(), " ");
				k1 = Integer.parseInt(str.nextToken());
				k2 = Integer.parseInt(str.nextToken());
				k3 = Integer.parseInt(str.nextToken());
				k4 = Integer.parseInt(str.nextToken());
							// 不適切な接続のチェック
				sw = 0;
				if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1)
					sw = 1;
				else {
					if (k1 > nou || k2 > nou || k3 > nou || k4 > nou)
						sw = 1;
					else {
						if (k1 > k2 || k3 > k4)
							sw = 1;
						else {
							if (k4 >= k1)
								sw = 1;
							else {
								l1 = -1;
								k  = 0;
								for (i1 = nolvl; i1 >= 0 && l1 < 0; i1--) {
									k += nohu[i1];
									if (k1 <= k)
										l1 = i1;
								}
								l2 = -1;
								k  = 0;
								for (i1 = nolvl; i1 >= 0 && l2 < 0; i1--) {
									k += nohu[i1];
									if (k4 <= k)
										l2 = i1;
								}
								if (l2 <= l1)
									sw = 1;
							}
						}
					}
				}
				if (sw > 0) {
					System.out.print("***error  ユニット番号が不適当("
                                       + k1 + " " + k2 + " " + k3 + " " + k4 + ")\n");
					System.exit(1);
				}
							// 重みの初期値の与え方
				k1--;
				k2--;
				k3--;
				k4--;
				id = Integer.parseInt(str.nextToken());
				x1 = 0.0;
				x2 = 0.0;
				if (id == 1) {
					x1 = Double.parseDouble(str.nextToken());
					x2 = Double.parseDouble(str.nextToken());
				}
				else {
					if (id > 1)
						x1 = Double.parseDouble(str.nextToken());
					else {
						if (id != 0) {
							System.out.print("***error  接続方法が不適当\n");
							System.exit(1);
						}
					}
				}
							// 重みの初期値の設定
				for (i1 = k3; i1 <= k4; i1++) {
					for (i2 = k1; i2 <= k2; i2++) {
						con[i1][i2] = (byte)id;
						switch (id) {
							case 0:
								w[i1][i2] = 0.0;
								break;
							case 1:
								w[i1][i2] = (x2 - x1) * rn.nextDouble() + x1;
								break;
							case 2:
								w[i1][i2] = x1;
								break;
							case 3:
								w[i1][i2] = x1;
								break;
						}
					}
				}
			}
		}
		in.close();
	/*
	     画面表示
	*/
		Win win;
		if (c_size > 0)
			win = new Win("Network Structure", c_size, f_size, width, hight,
                          noiu, nohu, nolvl, con);
	}
	/******************************************/
	/* 誤差の計算,及び,重みとバイアスの修正 */
	/*      ptn[i1] : 出力パターン            */
	/******************************************/
	void Err_back(double ptn[])
	{
		double x1;
		int i1, i2;
		for (i1 = 0; i1 < nou-noiu; i1++) {
					// 誤差の計算
			if (i1 < noou) {
				if (f_type == 0)
					dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]);
				else
					dp[i1] = 0.5 * (ptn[i1] - op[i1]) * 
                             (op[i1] - 1.0) * (op[i1] + 1.0);
			}
			else {
				x1 = 0.0;
				for (i2 = 0; i2 < i1; i2++) {
					if (con[i2][i1] > 0)
						x1 += dp[i2] * w[i2][i1];
				}
				if (f_type == 0)
					dp[i1] = op[i1] * (1.0 - op[i1]) * x1;
				else
					dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1;
			}
					// 重みの修正
			for (i2 = i1+1; i2 < nou; i2++) {
				if (con[i1][i2] == 1 || con[i1][i2] == 2) {
					x1         = eata * dp[i1] * op[i2] + alpha * w[i2][i1];
					w[i2][i1]  = x1;
					w[i1][i2] += x1;
				}
			}
					// バイアスの修正
			if (con[i1][i1] >= -2) {
				x1         = eata * dp[i1] + alpha * w[i1][i1];
				w[i1][i1]  = x1;
				theta[i1] += x1;
			}
		}
	}
	/********************************************************/
	/* 与えられた入力パターンに対する各ユニットの出力の計算 */
	/********************************************************/
	void Forward()
	{
		double sum;
		int i1, i2;
		for (i1 = nou-noiu-1; i1 >= 0; i1--) {
			sum = -theta[i1];
			for (i2 = i1+1; i2 < nou; i2++) {
				if (con[i1][i2] > 0)
					sum -= w[i1][i2] * op[i2];
			}
			op[i1] = (f_type == 0) ? 1.0 / (1.0 + Math.exp(sum)) :
                                     1.0 - 2.0 / (1.0 + Math.exp(sum));
		}
	}
	/*****************************/
	/* 学習の実行                */
	/*      p : 認識パターン     */
	/*      m_tri : 最大学習回数 */
	/*****************************/
	void Learn(BackData p, int m_tri)
	{
		int i1, i2, k0 = -1, k1;
	/*
	     エラーチェック
	*/
		if (noiu != p.noiu || noou != p.noou) {
			System.out.print("***error  入力または出力ユニットの数が違います\n");
			System.exit(1);
		}
		for (i1 = 0; i1 < m_tri; i1++) {
	/*
	     パターンを与える順番の決定
	*/
			if (order == 0) {       // 順番
				k0++;
				if (k0 >= p.noip)
					k0 = 0;
			}
			else {                  // ランダム
				k0 = (int)(rn.nextDouble() * p.noip);
				if (k0 >= p.noip)
					k0 = p.noip - 1;
			}
	/*
	     出力ユニットの結果を計算
	*/
			k1 = nou - noiu;
			for (i2 = 0; i2 < noiu; i2++)
				op[k1+i2] = p.iptn[k0][i2];
			Forward();
	/*
	     重みとバイアスの修正
	*/
			Err_back(p.optn[k0]);
		}
	}
	/***********************************************/
	/* 与えられた対象の認識と出力                  */
	/*      p : 認識パターン                       */
	/*      pr : =0 : 出力を行わない               */
	/*           =1 : 出力を行う                   */
	/*           =2 : 出力を行う(未学習パターン) */
	/*      tri : 現在の学習回数                   */
	/*      return : 誤って認識したパターンの数    */
	/***********************************************/
	int Recog(BackData p, int pr, int tri) throws IOException, FileNotFoundException
	{
		int i1, i2, k1, No = 0, ln, sw;
		String next;
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	/*
	     ファイルのオープン
	*/
		PrintStream out = null;
		if (p_type < 0 && pr > 0) {
			if (pr == 1) {
				out = new PrintStream(new FileOutputStream(o_file));
				out.print("***学習パターン***\n\n");
			}
			else {
				out = new PrintStream(new FileOutputStream(o_file, true));
				out.print("\n***未学習パターン***\n\n");
			}
		}
	/*
	     各パターンに対する出力
	*/
		for (i1 = 0; i1 < p.noip; i1++) {
					// 入力パターンの設定
			k1 = nou - noiu;
			for (i2 = 0; i2 < noiu; i2++)
				op[k1+i2] = p.iptn[i1][i2];
					// 出力の計算
			Forward();
					// 結果の表示
			if (p_type != 0 && pr > 0) {
				System.out.print("入力パターン" + (i1+1) + "   ");
				for (i2 = 0; i2 < noiu; i2++) {
					System.out.print(" " + op[k1+i2]);
					if (i2 == noiu-1)
						System.out.print("\n");
					else {
						if(((i2+1) % 10) == 0)
							System.out.print("\n                   ");
					}
				}
				System.out.print("\n    出力パターン(理想)  ");
				for (i2 = 0; i2 < noou; i2++) {
					System.out.print(" " + p.optn[i1][i2]);
					if (i2 == noou-1)
						System.out.print("\n");
					else {
						if(((i2+1) % 5) == 0)
							System.out.print("\n                        ");
					}
				}
			}
			sw = 0;
			if (p_type != 0 && pr > 0)
				System.out.print("                (実際)  ");
			for (i2 = 0; i2 < noou; i2++) {
				if (p_type != 0 && pr > 0) {
					System.out.print(" " + op[i2]);
					if (i2 == noou-1)
						System.out.print("\n");
					else {
						if(((i2+1) % 5) == 0)
							System.out.print("\n                        ");
					}
				}
				if (Math.abs(op[i2]-p.optn[i1][i2]) > eps)
					sw = 1;
			}
			if (sw > 0)
				No++;
			if (p_type < 0 && pr > 0) {
				out.print("入力パターン" + (i1+1) + "   ");
				for (i2 = 0; i2 < noiu; i2++) {
					out.print(" " + op[k1+i2]);
					if (i2 == noiu-1)
						out.print("\n");
					else {
						if(((i2+1) % 10) == 0)
							out.print("\n                   ");
					}
				}
				out.print("\n    出力パターン(理想)  ");
				for (i2 = 0; i2 < noou; i2++) {
					out.print(" " + p.optn[i1][i2]);
					if (i2 == noou-1)
						out.print("\n");
					else {
						if(((i2+1) % 5) == 0)
							out.print("\n                        ");
					}
				}
				out.print("                (実際)  ");
				for (i2 = 0; i2 < noou; i2++) {
					out.print(" " + op[i2]);
					if (i2 == noou-1)
						out.print("\n");
					else {
						if(((i2+1) % 5) == 0)
							out.print("\n                        ");
					}
				}
			}
			if (p_type != 0 && pr > 0)
				next = in.readLine();
		}
	/*
	     重みの出力
	*/
		if ((p_type < -1 || p_type > 1) && pr == 1) {
			System.out.print("    重み\n");
			for (i1 = 0; i1 < nou-noiu; i1++) {
				System.out.print("      to " + (i1+1) + " from  ");
				ln = -1;
				for (i2 = 0; i2 < nou; i2++) {
					if (con[i1][i2] > 0) {
						if (ln <= 0) {
							if (ln < 0)
								ln = 0;
							else
								System.out.print("\n                   ");
						}
						System.out.print(" " + (i2+1) + " " + w[i1][i2]);
						ln += 1;
						if (ln == 4)
							ln = 0;
					}
				}
				System.out.print("\n");
			}
			System.out.print("\n    バイアス  ");
			ln = 0;
			for (i1 = 0; i1 < nou-noiu; i1++) {
				System.out.print(" " + (i1+1) + " " + theta[i1]);
				ln += 1;
				if (ln == 4 && i1 != nou-noiu-1) {
					ln = 0;
					System.out.print("\n              ");
				}
			}
			if (ln != 0)
				System.out.print("\n");
			next = in.readLine();
		}
		if (p_type < 0 && pr == 1) {
			out.print("    重み\n");
			for (i1 = 0; i1 < nou-noiu; i1++) {
				out.print("      to " + (i1+1) + " from  ");
				ln = -1;
				for (i2 = 0; i2 < nou; i2++) {
					if (con[i1][i2] > 0) {
						if (ln <= 0) {
							if (ln < 0)
								ln = 0;
							else
								out.print("\n                   ");
						}
						out.print(" " + (i2+1) + " " + w[i1][i2]);
						ln += 1;
						if (ln == 4)
							ln = 0;
					}
				}
				out.print("\n");
			}
			out.print("\n    バイアス  ");
			ln = 0;
			for (i1 = 0; i1 < nou-noiu; i1++) {
				out.print(" " + (i1+1) + " " + theta[i1]);
				ln += 1;
				if (ln == 4 && i1 != nou-noiu-1) {
					ln = 0;
					out.print("\n              ");
				}
			}
			if (ln != 0)
				out.print("\n");
		}
		if (p_type < 0 && pr > 0)
			out.close();
		return No;
	}
}
/*******************/
/* クラスWinの定義 */
/*******************/
class Win extends Frame {
	byte con[][];   // 接続関係
	int nohu[];   // 各層のユニット数(入力層から出力層)
	int nolvl;   // 層の数
	int nou;   // ユニット数
	int c_size;   // 円の大きさ(直径)
	int f_size;   // フォントサイズ
	int width;   // 画面の幅
	int height;   // 画面の高さ
	int x[], y[];   // ユニットの位置
	/**************************************************/
	/* コンストラクタ                                 */
	/*      name : Windowのタイトル                   */
	/*      c_size_i : 円の大きさ(直径)             */
	/*      f_size_i : フォントサイズ                 */
	/*      width_i : 画面の幅                        */
	/*      height_i : 画面の高さ                     */
	/*      noiu_i : 入力層のユニット数               */
	/*      nohu_i : 各層のユニット数(入力層を除く) */
	/*      nolvl_i : 層の数(入力層を除く)          */
	/*      con_i : 接続関係                          */
	/**************************************************/
	Win (String name, int c_size_i, int f_size_i, int width_i, int height_i,
         int noiu_i, int nohu_i[], int nolvl_i, byte con_i[][])
	{
					// Frameクラスのコンストラクタ(Windowのタイトルを引き渡す)
		super(name);
					// データの設定
		int i1, i2;
		c_size = c_size_i;
		f_size = f_size_i;
		width  = width_i;
		height = height_i;
		nou = noiu_i;
		for (i1 = 0; i1 <= nolvl_i; i1++)
			nou += nohu_i[i1];
		nolvl = nolvl_i + 2;
		nohu  = new int [nolvl];
		for (i1 = 0; i1 <= nolvl_i; i1++)
			nohu[i1+1] = nohu_i[i1];
		nohu[0] = noiu_i;
		con = new byte [nou][nou];
		for (i1 = 0; i1 < nou; i1++) {
			for (i2 = 0; i2 < nou; i2++)
				con[i1][i2] = con_i[i1][i2];
		}
		x = new int [nou];
		y = new int [nou];
					// Windowの大きさ
		setSize(width, height);
					// ウィンドウを表示
		setVisible(true);
					// イベントアダプタ
		addWindowListener(new WinEnd());
	}
	/********/
	/* 描画 */
	/********/
	public void paint (Graphics g)
	{
						// 初期設定
		int y_s = (f_size > 25) ? 25 + f_size : 50;
		int y_e = (c_size > 20 ) ? height - c_size - 10 : height - 30;
		int c_x, c_y = y_s;
		int i1, i2, k = 0;
		int x_step, y_step = (y_e - y_s) / (nolvl - 1);
		Font f;
						// フォントサイズ
		if (f_size > 0) {
			f = new Font("TimesRoman", Font.PLAIN, f_size);
			g.setFont(f);
		}
						// 各ユニットを描く
		for (i1 = nolvl-1; i1 >= 0; i1--) {
			x_step = width / nohu[i1];
			c_x    = x_step / 2;
			for (i2 = 0; i2 < nohu[i1]; i2++) {
				x[k] = c_x;
				y[k] = c_y;
				g.fillOval(x[k], y[k], c_size, c_size);
				if (f_size > 0)
					g.drawString(Integer.toString(k+1), x[k]-f_size/2, y[k]);
				c_x += x_step;
				k++;
			}
			c_y += y_step;
		}
						// 接続関係を描く
		k = c_size / 2;
		for (i1 = 0; i1 < nou-nohu[0]; i1++) {
			for (i2 = i1+1; i2 < nou; i2++ ) {
				if (con[i1][i2] != 0)
					g.drawLine(x[i1]+k, y[i1]+k, x[i2]+k, y[i2]+k);
			}
		}
	}
	/************/
	/* 終了処理 */
	/************/
	class WinEnd extends WindowAdapter
	{
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	}
}
/*
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
*/
			
<!DOCTYPE HTML>
<HTML>
<HEAD>
	<TITLE>back propagation model</TITLE>
	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
	<SCRIPT TYPE="text/javascript">
		res = "";
		net = null;
		dt1 = null;
		dt2 = null;
		/****************/
		/* main program */
		/****************/
		function main()
		{
			let m_tri = parseInt(document.getElementById("m_tri").value);
					// ネットワークの定義
			net = new Backpr();
					// 学習パターンの入力
			dt1 = new BackData("ptn1");
					// 学習
			net.Learn(dt1, m_tri);   // 学習
			let no = net.Recog(dt1, 1, m_tri);   // 学習対象の認識
			res += ("\n+++学習終了 回数 " + m_tri + " 誤って認識したパターン数 " + no + "\n\n");
					// 未学習パターンの認識
			dt2 = new BackData("ptn2");
			no  = net.Recog(dt2, 2, m_tri);   // 未学習対象の認識と出力
			document.getElementById("result").value = res;
		}
		/********************************/
		/* BackDataオブジェクト         */
		/*      name : テキストエリア名 */
		/********************************/
		function BackData(name)
		{
			let lines = (document.getElementById(name).value).split('\n');
					//
					// 入力パターン数等
					//
			let str   = lines[0].split(' ').filter(function(e){return e.length > 0;});
			this.noip = parseInt(str[1]);   // 入力ユニットの数
			this.noiu = parseInt(str[3]);   // 出力ユニットの数
			this.noou = parseInt(str[5]);   // 入力パターンの数
					//
					// 領域の確保
					//
			this.iptn = new Array(this.noip);
                         // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
                         //              入力ユニットの入力値
                         //                i=0,noip-1  j=0,noiu-1
			this.optn = new Array(this.noip);
                         // optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
                         //              番目の出力ユニットの目標出力値
                         //                i=0,noip-1  j=0,noou-1
			for (let i1 = 0; i1 < this.noip; i1++) {
				this.iptn[i1] = new Array(this.noiu);
				this.optn[i1] = new Array(this.noou);
			}
					//
					// 入力パターン及び各入力パターンに対する出力パターンの入力
					//
			for (let i1 = 0; i1 < this.noip; i1++) {
				let k = 2 * i1 + 1;
				str   = lines[k].split(' ').filter(function(e){return e.length > 0;});
				for (let i2 = 0; i2 < this.noiu; i2++)
					this.iptn[i1][i2] = parseFloat(str[i2+1]);
				str = lines[k+1].split(' ').filter(function(e){return e.length > 0;});
				for (let i2 = 0; i2 < this.noou; i2++)
					this.optn[i1][i2] = parseFloat(str[i2+1]);
			}
		}
		/**********************/
		/* Backprオブジェクト */
		/**********************/
		function Backpr()
		{
					//
					// 制御用データ
					//
			let lines = (document.getElementById("data1").value).split('\n');
						// 1 行目
			let str     = lines[0].split(' ').filter(function(e){return e.length > 0;});
			this.eps    = parseFloat(str[1]);   // 許容誤差
			this.p_type = parseInt(str[3]);   // 出力先・方法の指定
                                              //   =0 : 誤って認識した数だけ出力
                                              //   =1 : 認識結果を出力
                                              //   =2 : 認識結果と重みを出力
						// 2 行目
			str        = lines[1].split(' ').filter(function(e){return e.length > 0;});
			this.order = parseInt(str[1]);   // 入力パターンの与え方(=0:順番,=1:ランダム)
			this.eata  = parseFloat(str[3]);   //重み及びバイアス修正パラメータ
			this.alpha = parseFloat(str[5]);   //重み及びバイアス修正パラメータ
					//
					// 入力ユニット,出力ユニットの数,関数タイプ
					//
			lines = (document.getElementById("data2").value).split('\n');
			str         = lines[0].split(' ').filter(function(e){return e.length > 0;});
			this.noiu   = parseInt(str[1]);   // 入力ユニットの数
			this.noou   = parseInt(str[3]);   // 出力ユニットの数
			this.f_type = parseInt(str[5]);   // シグモイド関数のタイプ
                                              //   0 : [0,1]
                                              //   1 : [-1,1])
			this.nou    = this.noiu + this.noou;   // 入力ユニットと出力ユニットの和
					//
					// 隠れユニットの階層数と各階層のユニット数
					//
			str         = lines[1].split(' ').filter(function(e){return e.length > 0;});
			this.nolvl  = parseInt(str[1]);   // 隠れユニットの階層数
			this.nohu   = new Array(this.nolvl+1);
                             // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
                             //           には下から順に番号が付けられ,出力層はレ
                             //           ベル(nolvl+1)の隠れ層とも見做される)
                             //             i=0,nolvl
			this.nohu[this.nolvl] = this.noou;   // 出力ユニットの数
		
			if (this.nolvl > 0) {
				for (let i1 = 0; i1 < this.nolvl; i1++) {
					this.nohu[i1]  = parseInt(str[i1+3]);
					this.nou      += this.nohu[i1];
				}
			}
					//
					// 領域の確保
					//
			this.con = new Array(this.nou);
                     // con[i][j] : 各ユニットに対するバイアスの与え方,及び,
                     // 接続方法
                     //   [i][i] : ユニット(i+1)のバイアスの与え方
                     //     =-3 : 入力値で固定
                     //     =-2 : 入力値を初期値として,学習により変更
                     //     =-1 : 乱数で初期値を設定し,学習により変更
                     //   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
                     //     =0 : 接続しない
                     //     =1 : 接続する(重みの初期値を乱数で設定し,学習)
                     //     =2 : 接続する(重みの初期値を入力で与え,学習)
                     //     =3 : 接続する(重みを入力値に固定)
                     //            i=0,nou-1  j=0,nou-1
			for (let i1 = 0; i1 < this.nou; i1++) {
				this.con[i1] = new Array(this.nou);
				for (let i2 = 0; i2 < this.nou; i2++)
					this.con[i1][i2] =  (i1 == i2) ? -1 : 0;
			}
		
			this.w = new Array(this.nou);
                    // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
                    // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
                    // w[i][i] : ユニット(i+1)のバイアスの前回修正量
                    //   i=0,nou-1  j=0,nou-1
			for (let i1 = 0; i1 < this.nou; i1++) {
				this.w[i1] = new Array(this.nou);
				for (let i2 = 0; i2 < this.nou; i2++)
					this.w[i1][i2] = 0.0;
			}
		
			this.dp    = new Array(this.nou);   // dp[i] : ユニット(i+1)の誤差  i=0,nou-1
			this.op    = new Array(this.nou);   // op[i] : ユニット(i+1)の出力  i=0,nou-1
			this.theta = new Array(this.nou);   //theta[i] : ユニット(i+1)のバイアス  i=0,nou
		
			for (let i1 = 0; i1 < this.nou; i1++)
				this.theta[i1] = 0.2 * Math.random() - 0.1;
					//
					// 各ユニットのバイアスとユニット間の接続関係
					//
						// バイアス
							// バイアスデータの数
			str    = lines[2].split(' ').filter(function(e){return e.length > 0;});
			let nb = parseInt(str[1]);
			if (nb > 0) {
							// バイアスデータの処理
				for (let i0 = 0; i0 < nb; i0++) {
								// ユニット番号
					str    = lines[i0+6].split(' ').filter(function(e){return e.length > 0;});
					let k1 = parseInt(str[0]);
								// 不適当なユニット番号のチェック
					if (k1 < 1 || k1 > (this.nou-this.noiu))
						alert("***error  ユニット番号 " + k1 + " が不適当");
								// バイアスの与え方
					k1--;
					let id           = parseInt(str[1]);
					this.con[k1][k1] = id;
								// バイアスの初期設定
					switch (this.con[k1][k1]) {
						case -1:
							let x1 = parseFloat(str[2]);
							let x2 = parseFloat(str[3]);
							this.theta[k1] = (x2 - x1) * Math.random() + x1;
							break;
						case -2:
							this.theta[k1] = parseFloat(str[2]);
							break;
						case -3:
							this.theta[k1] = parseFloat(str[2]);
							break;
						default:
							alert("***error  バイアスの与え方が不適当");
							break;
					}
				}
			}
						// 接続方法
							// 接続データの数
			str   = lines[nb+6].split(' ').filter(function(e){return e.length > 0;});
			let n = parseInt(str[1]);
		
			if (n > 0) {
							// 接続データの処理
				for (let i0 = 0; i0 < n; i0++) {
								// 接続情報
					str    = lines[nb+10+i0].split(' ').filter(function(e){return e.length > 0;});
					let k1 = parseInt(str[0]);
					let k2 = parseInt(str[1]);
					let k3 = parseInt(str[2]);
					let k4 = parseInt(str[3]);
								// 不適切な接続のチェック
					let sw = 0;
					if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1)
						sw = 1;
					else {
						if (k1 > this.nou || k2 > this.nou || k3 > this.nou || k4 > this.nou)
							sw = 1;
						else {
							if (k1 > k2 || k3 > k4)
								sw = 1;
							else {
								if (k4 >= k1)
									sw = 1;
								else {
									let l1 = -1;
									let k  = 0;
									for (let i1 = this.nolvl; i1 >= 0 && l1 < 0; i1--) {
										k += this.nohu[i1];
										if (k1 <= k)
											l1 = i1;
									}
									let l2 = -1;
									k      = 0;
									for (let i1 = this.nolvl; i1 >= 0 && l2 < 0; i1--) {
										k += this.nohu[i1];
										if (k4 <= k)
											l2 = i1;
									}
									if (l2 <= l1)
										sw = 1;
								}
							}
						}
					}
		
					if (sw > 0)
						alert("***error  ユニット番号が不適当("
                               + k1 + " " + k2 + " " + k3 + " " + k4 + ")");
								// 重みの初期値の与え方
					k1--;
					k2--;
					k3--;
					k4--;
		
					let id = parseInt(str[4]);
					let x1 = 0.0;
					let x2 = 0.0;
		
					if (id == 1) {
						x1 = parseFloat(str[5]);
						x2 = parseFloat(str[6]);
					}
					else {
						if (id > 1)
							x1 = parseFloat(str[5]);
						else {
							if (id != 0)
								alert("***error  接続方法が不適当");
						}
					}
								// 重みの初期値の設定
					for (let i1 = k3; i1 <= k4; i1++) {
						for (let i2 = k1; i2 <= k2; i2++) {
							this.con[i1][i2] = id;
							switch (id) {
								case 0:
									this.w[i1][i2] = 0.0;
									break;
								case 1:
									this.w[i1][i2] = (x2 - x1) * Math.random() + x1;
									break;
								case 2:
									this.w[i1][i2] = x1;
									break;
								case 3:
									this.w[i1][i2] = x1;
									break;
							}
						}
					}
				}
			}
		}
		/******************************************/
		/* 誤差の計算,及び,重みとバイアスの修正 */
		/*      ptn[i1] : 出力パターン            */
		/******************************************/
		Backpr.prototype.Err_back = function(ptn)
		{
			for (let i1 = 0; i1 < net.nou-net.noiu; i1++) {
						// 誤差の計算
				if (i1 < net.noou) {
					if (net.f_type == 0)
						net.dp[i1] = (ptn[i1] - net.op[i1]) * net.op[i1] * (1.0 - net.op[i1]);
					else
						net.dp[i1] = 0.5 * (ptn[i1] - net.op[i1]) * (net.op[i1] - 1.0) * (net.op[i1] + 1.0);
				}
				else {
					let x1 = 0.0;
					for (let i2 = 0; i2 < i1; i2++) {
						if (net.con[i2][i1] > 0)
							x1 += net.dp[i2] * net.w[i2][i1];
					}
					if (net.f_type == 0)
						net.dp[i1] = net.op[i1] * (1.0 - net.op[i1]) * x1;
					else
						net.dp[i1] = 0.5 * (net.op[i1] - 1.0) * (net.op[i1] + 1.0) * x1;
				}
						// 重みの修正
				for (let i2 = i1+1; i2 < net.nou; i2++) {
					if (net.con[i1][i2] == 1 || net.con[i1][i2] == 2) {
						let x1  = net.eata * net.dp[i1] * net.op[i2] + net.alpha * net.w[i2][i1];
						net.w[i2][i1]  = x1;
						net.w[i1][i2] += x1;
					}
				}
						// バイアスの修正
				if (net.con[i1][i1] >= -2) {
					let x1  = net.eata * net.dp[i1] + net.alpha * net.w[i1][i1];
					net.w[i1][i1]  = x1;
					net.theta[i1] += x1;
				}
			}
		}
		/********************************************************/
		/* 与えられた入力パターンに対する各ユニットの出力の計算 */
		/********************************************************/
		Backpr.prototype.Forward = function()
		{
			for (let i1 = net.nou-net.noiu-1; i1 >= 0; i1--) {
				let sum = -net.theta[i1];
				for (let i2 = i1+1; i2 < net.nou; i2++) {
					if (net.con[i1][i2] > 0)
						sum -= net.w[i1][i2] * net.op[i2];
				}
				net.op[i1] = (net.f_type == 0) ? 1.0 / (1.0 + Math.exp(sum)) :
                                                 1.0 - 2.0 / (1.0 + Math.exp(sum));
			}
		}
		/*****************************/
		/* 学習の実行                */
		/*      p : 認識パターン     */
		/*      m_tri : 最大学習回数 */
		/*****************************/
		Backpr.prototype.Learn = function(p, m_tri)
		{
					//
					// エラーチェック
					//
			if (net.noiu != p.noiu || net.noou != p.noou)
				alert("***error  入力または出力ユニットの数が違います");
			let k0 = -1;
			for (let i1 = 0; i1 < m_tri; i1++) {
					//
					// パターンを与える順番の決定
					//
				if (net.order == 0) {       // 順番
					k0++;
					if (k0 >= p.noip)
						k0 = 0;
				}
				else {                  // ランダム
					k0 = Math.floor(Math.random() * p.noip);
					if (k0 >= p.noip)
						k0 = p.noip - 1;
				}
					//
					// 出力ユニットの結果を計算
					//
				let k1 = net.nou - net.noiu;
				for (let i2 = 0; i2 < net.noiu; i2++)
					net.op[k1+i2] = p.iptn[k0][i2];
				net.Forward();
					//
					// 重みとバイアスの修正
					//
				net.Err_back(p.optn[k0]);
			}
		}
		/********************************************/
		/* 与えられた対象の認識と出力               */
		/*      p : 認識パターン                    */
		/*      pr : =1 : 学習パターン              */
		/*           =2 : 未学習パターン            */
		/*      tri : 現在の学習回数                */
		/*      return : 誤って認識したパターンの数 */
		/********************************************/
		Backpr.prototype.Recog = function(p, pr, tri)
		{
			if (pr == 1)
				res = "***学習パターン***\n";
			else
				res += "***未学習パターン***\n";
					//
					// 各パターンに対する出力
					//
			let No = 0;
			for (let i1 = 0; i1 < p.noip; i1++) {
						// 入力パターンの設定
				let k1 = net.nou - net.noiu;
				for (let i2 = 0; i2 < net.noiu; i2++)
					net.op[k1+i2] = p.iptn[i1][i2];
						// 出力の計算
				net.Forward();
						// 結果の表示
				if (net.p_type != 0 && pr > 0) {
					res += ("入力パターン" + (i1+1) + "   ");
					for (let i2 = 0; i2 < net.noiu; i2++) {
						res += (" " + net.op[k1+i2]);
						if (i2 == net.noiu-1)
							res += "\n";
						else {
							if(((i2+1) % 10) == 0) {
								res += "\n";
								res += "                   ";
							}
						}
					}
					res += "\n";
					res += ("    出力パターン(理想)  ");
					for (let i2 = 0; i2 < net.noou; i2++) {
						res += (" " + p.optn[i1][i2]);
						if (i2 == net.noou-1)
							res += "\n";
						else {
							if(((i2+1) % 5) == 0) {
								res += "\n";
								res += "                        ";
							}
						}
					}
				}
				let sw = 0;
				if (net.p_type != 0 && pr > 0)
					res += ("                (実際)  ");
				for (let i2 = 0; i2 < net.noou; i2++) {
					if (net.p_type != 0 && pr > 0) {
						res += (" " + net.op[i2]);
						if (i2 == net.noou-1)
							res += "\n";
						else {
							if(((i2+1) % 5) == 0) {
								res += "\n";
								res += "                        ";
							}
						}
					}
					if (Math.abs(net.op[i2]-p.optn[i1][i2]) > net.eps)
						sw = 1;
				}
				if (sw > 0)
					No++;
			}
					//
					// 重みの出力
					//
			let ln;
			if ((net.p_type < -1 || net.p_type > 1) && pr == 1) {
				res += ("    重み");
				for (let i1 = 0; i1 < net.nou-net.noiu; i1++) {
					res += ("      to " + (i1+1) + " from  ");
					ln   = -1;
					for (let i2 = 0; i2 < net.nou; i2++) {
						if (net.con[i1][i2] > 0) {
							if (ln <= 0) {
								if (ln < 0)
									ln = 0;
								else {
									res += "\n";
									res += ("                   ");
								}
							}
							res += (" " + (i2+1) + " " + net.w[i1][i2]);
							ln += 1;
							if (ln == 4)
								ln = 0;
						}
					}
					res += "\n";
				}
				res += "\n";
				res += ("    バイアス  ");
				ln   = 0;
				for (let i1 = 0; i1 < net.nou-net.noiu; i1++) {
					res += (" " + (i1+1) + " " + net.theta[i1]);
					ln  += 1;
					if (ln == 4 && i1 != net.nou-net.noiu-1) {
						ln = 0;
						res += "\n";
						res += ("              ");
					}
				}
				if (ln != 0)
					res += "\n";
			}
			return No;
		}
	</SCRIPT>
</HEAD>
<BODY STYLE="font-size: 130%; text-align:center; background-color: #eeffee;">
	<H2><B>back propagation model</B></H2>
	学習回数:<INPUT ID="m_tri" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="5000"> 
	<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="return main()">実行</BUTTON><BR>
	<DIV STYLE="width: 800px; margin-right: auto; margin-left: auto">
		<DIV STYLE="text-align:center; float: right; width: 400px">
			<DIV STYLE="text-align:center">構造データ</DIV>
			<TEXTAREA ID="data2" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px">
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.1 0.1
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
			</TEXTAREA>
		</DIV>
		<DIV STYLE="text-align:center; width: 400px">
			<DIV STYLE="text-align:center">制御データ</DIV>
			<TEXTAREA ID="data1" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px">
誤差 0.1 出力 2 出力ファイル kekka
順番 0 η 0.5 α 0.8
			</TEXTAREA>
		</DIV>
		<DIV STYLE="text-align:center; float: right; width: 400px">
			<DIV STYLE="text-align:center">未学習パターン</DIV>
			<TEXTAREA ID="ptn2" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px">
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
			</TEXTAREA>
		</DIV>
		<DIV STYLE="text-align:center; width: 400px">
			<DIV STYLE="text-align:center">学習パターン</DIV>
			<TEXTAREA ID="ptn1" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px">
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
			</TEXTAREA>
		</DIV>
		<DIV STYLE="text-align:center">結果</DIV>
		<TEXTAREA ID="result" COLS="70" ROWS="10" STYLE="font-size: 100%;">
		</TEXTAREA>
	</DIV>
</BODY>
</HTML>
			
<?php
/****************************/
/* back propagation model   */
/*      coded by Y.Suganuma */
/****************************/
/******************************************************/
/* バックプロパゲーションの制御(クラス BackControl) */
/******************************************************/
class BackControl {
	protected $alpha;   //重み及びバイアス修正パラメータ
	protected $eata;
	protected $eps;   // 許容誤差
	protected $order;   // 入力パターンの与え方(=0:順番,=1:ランダム)
	protected $p_type;   // 出力先・方法の指定
                         //   =0 : 誤って認識した数だけ出力
                         //   =1 : 認識結果を出力
                         //   =2 : 認識結果と重みを出力
                         //        (負の時は,認識結果と重みをファイルへも出力)
	protected $o_file;   // 出力ファイル名
	/*************************************/
	/* クラスBackControlのコンストラクタ */
	/*      name : 入力データファイル名  */
	/*************************************/
    function BackControl($name)
    {
    	$in = fopen($name, "rb");
	
		$str = trim(fgets($in));
		strtok($str, " ");
		$this->eps = floatval(strtok(" "));
		strtok(" ");
		$this->p_type = intval(strtok(" "));
		if ($this->p_type < 0) {
			strtok(" ");
			$this->o_file = strtok(" ");
		}
    	fscanf($in, "%*s %d %*s %lf %*s %lf", $this->order, $this->eata, $this->alpha);
   
		fclose($in);
    }
}
/*****************************************************/
/* バックプロパゲーションのデータ(クラス BackData) */
/*****************************************************/
class BackData {
	public $noiu;   // 入力ユニットの数
	public $noou;   // 出力ユニットの数
	public $noip;   // 入力パターンの数
	public $iptn;   // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
                    //              入力ユニットの入力値
                    //                i=0,noip-1  j=0,noiu-1
	public $optn;   // optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
                    //              番目の出力ユニットの目標出力値
                    //                i=0,noip-1  j=0,noou-1
	/************************************/
	/* クラスBackDataのコンストラクタ   */
	/*      name : 入力データファイル名 */
	/************************************/
	function BackData($name)
    {
    	$in = fopen($name, "rb");
    /*
        入力パターン数等
	*/
		fscanf($in, "%*s %d %*s %d %*s %d", $this->noip, $this->noiu, $this->noou);
	/*
	     領域の確保
	*/
		$this->iptn = array($this->noip);
    	for ($i1 = 0; $i1 < $this->noip; $i1++)
    		$this->iptn[$i1] = array($this->noiu);
    
    	$this->optn = array($this->noip);
		for ($i1 = 0; $i1 < $this->noip; $i1++)
			$this->optn[$i1] = array($this->noou);
	/*
	     入力パターン及び各入力パターンに対する出力パターンの入力
	*/
		for ($i1 = 0; $i1 < $this->noip; $i1++) {
			$str = trim(fgets($in));
			strtok($str, " ");
    		for ($i2 = 0; $i2 < $this->noiu; $i2++)
 				$this->iptn[$i1][$i2] = intval(strtok(" "));
			$str = trim(fgets($in));
			strtok($str, " ");
			for ($i2 = 0; $i2 < $this->noou; $i2++)
 				$this->optn[$i1][$i2] = intval(strtok(" "));
		}
		fclose($in);
	}
}
/*******************************************/
/* バックプロパゲーション(クラス Backpr) */
/*******************************************/
class Backpr extends BackControl {
	public $con;   // con[i][j] : 各ユニットに対するバイアスの与え方,及び,
                   // 接続方法
                   //   [i][i] : ユニット(i+1)のバイアスの与え方
                   //     =-3 : 入力値で固定
                   //     =-2 : 入力値を初期値として,学習により変更
                   //     =-1 : 乱数で初期値を設定し,学習により変更
                   //   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
                   //     =0 : 接続しない
                   //     =1 : 接続する(重みの初期値を乱数で設定し,学習)
                   //     =2 : 接続する(重みの初期値を入力で与え,学習)
                   //     =3 : 接続する(重みを入力値に固定)
                   //            i=0,nou-1  j=0,nou-1
	public $f_type;   // シグモイド関数のタイプ
                      //   0 : [0,1]
                      //   1 : [-1,1])
	public $noiu;   // 入力ユニットの数
	public $noou;   // 出力ユニットの数
	public $nohu;   // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
                    //           には下から順に番号が付けられ,出力層はレ
                    //           ベル(nolvl+1)の隠れ層とも見做される)
                    //             i=0,nolvl
	public $nolvl;   // 隠れユニットの階層数
	public $nou;   // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ
                   // ットには最も上の出力ユニットから,隠れ層の各ユニット,
                   // 及び,入力ユニットに至る一連のユニット番号が付けられ
                   // る)
	public $dp;   // dp[i] : ユニット(i+1)の誤差  i=0,nou-1
	public $op;   // op[i] : ユニット(i+1)の出力  i=0,nou-1
	public $theta;   //theta[i] : ユニット(i+1)のバイアス  i=0,nou
	public $w;   // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
                 // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
                 // w[i][i] : ユニット(i+1)のバイアスの前回修正量
                 //   i=0,nou-1  j=0,nou-1
	/************************************************/
    /* クラスBackprのコンストラクタ                 */
    /*      name_c : 制御データ用入力ファイル名     */
    /*      name_s : ネットワーク記述入力ファイル名 */
    /************************************************/
    function Backpr($name_c, $name_s)
    {
    	parent::BackControl($name_c);
    
    	$in = fopen($name_s, "rb");
    /*
         乱数の初期化
	*/
    	mt_srand();
    /*
	     入力ユニット,出力ユニットの数,関数タイプ
	*/
		fscanf($in, "%*s %d %*s %d %*s %d", $this->noiu, $this->noou, $this->f_type);
    	$this->nou = $this->noiu + $this->noou;   // 入力ユニットと出力ユニットの和
    /*
         隠れユニットの階層数と各階層のユニット数
	*/
		$str = trim(fgets($in));
		strtok($str, " ");
		$this->nolvl = intval(strtok(" "));
   
    	$this->nohu               = array($this->nolvl+1);
    	$this->nohu[$this->nolvl] = $this->noou;   // 出力ユニットの数
	
		if ($this->nolvl > 0) {
			strtok(" ");
			for ($i1 = 0; $i1 < $this->nolvl; $i1++) {
				$this->nohu[$i1] = intval(strtok(" "));
    			$this->nou      += $this->nohu[$i1];
    		}
		}
    /*
         領域の確保
    */
    	$this->con = array($this->nou);
    	for ($i1 = 0; $i1 < $this->nou; $i1++) {
    		$this->con[$i1] = array($this->nou);
    		for ($i2 = 0; $i2 < $this->nou; $i2++)
    			$this->con[$i1][$i2] =  ($i1 == $i2) ? -1 : 0;
    	}
    
    	$this->w = array($this->nou);
		for ($i1 = 0; $i1 < $this->nou; $i1++) {
    		$this->w[$i1] = array($this->nou);
    		for ($i2 = 0; $i2 < $this->nou; $i2++)
				$this->w[$i1][$i2] = 0.0;
		}
	
    	$this->dp    = array($this->nou);
    	$this->op    = array($this->nou);
    	$this->theta = array($this->nou);
	
		for ($i1 = 0; $i1 < $this->nou; $i1++)
    		$this->theta[$i1] = 0.2 * mt_rand() / mt_getrandmax() - 0.1;
    /*
         各ユニットのバイアスとユニット間の接続関係
	*/
						// バイアス
							// バイアスデータの数
		fscanf($in, "%*s %d", $n);
    	fgets($in);
    	fgets($in);
    	fgets($in);
    
    	if ($n > 0) {
							// バイアスデータの処理
    		for ($i0 = 0; $i0 < $n; $i0++) {
 				$str = trim(fgets($in));
   							// ユニット番号
    			$k1 = intval(strtok($str, " "));
   							// 不適当なユニット番号のチェック
    			if ($k1 < 1 || $k1 > ($this->nou-$this->noiu))
    				exit("***error  ユニット番号 ".$k1." が不適当\n");
    							// バイアスの与え方
    			$k1--;
    			$id = intval(strtok(" "));
				$this->con[$k1][$k1] = $id;
    							// バイアスの初期設定
    			switch ($this->con[$k1][$k1]) {
					case -1:
						$x1 = floatval(strtok(" "));
						$x2 = floatval(strtok(" "));
						$this->theta[$k1] = ($x2 - $x1) * mt_rand() / mt_getrandmax() + $x1;
    					break;
    				case -2:
    					$this->theta[$k1] = floatval(strtok(" "));
						break;
					case -3:
    					$this->theta[$k1] = floatval(strtok(" "));
    					break;
    				default:
						exit("***error  バイアスの与え方が不適当\n");
				}
			}
    	}
    					// 接続方法
    						// 接続データの数
		fscanf($in, "%*s %d", $n);
    	fgets($in);
    	fgets($in);
    	fgets($in);
    
    	if ($n > 0) {
    						// 接続データの処理
    		for ($i0 = 0; $i0 < $n; $i0++) {
 				$str = trim(fgets($in));
    							// 接続情報
     			$k1 = intval(strtok($str, " "));
     			$k2 = intval(strtok(" "));
     			$k3 = intval(strtok(" "));
      			$k4 = intval(strtok(" "));
   							// 不適切な接続のチェック
    			$sw = 0;
    			if ($k1 < 1 || $k2 < 1 || $k3 < 1 || $k4 < 1)
    				$sw = 1;
				else {
    				if ($k1 > $this->nou || $k2 > $this->nou || $k3 > $this->nou || $k4 > $this->nou)
    					$sw = 1;
					else {
						if ($k1 > $k2 || $k3 > $k4)
							$sw = 1;
    					else {
    						if ($k4 >= $k1)
    							$sw = 1;
							else {
								$l1 = -1;
    							$k  = 0;
    							for ($i1 = $this->nolvl; $i1 >= 0 && $l1 < 0; $i1--) {
    								$k += $this->nohu[$i1];
									if ($k1 <= $k)
										$l1 = $i1;
								}
								$l2 = -1;
    							$k  = 0;
    							for ($i1 = $this->nolvl; $i1 >= 0 && $l2 < 0; $i1--) {
    								$k += $this->nohu[$i1];
									if ($k4 <= $k)
    									$l2 = $i1;
    							}
    							if ($l2 <= $l1)
    								$sw = 1;
    						}
    					}
    				}
    			}
    
    			if ($sw > 0)
    				exit("***error  ユニット番号が不適当(".$k1." ".$k2." ".$k3." ".$k4."\n");
								// 重みの初期値の与え方
				$k1--;
				$k2--;
    			$k3--;
    			$k4--;
    
      			$id = intval(strtok(" "));
	
    			if ($id == 1) {
					$x1 = floatval(strtok(" "));
					$x2 = floatval(strtok(" "));
				}
    			else {
					if ($id > 1)
						$x1 = floatval(strtok(" "));
					else {
						if ($id != 0)
    						exit("***error  接続方法が不適当\n");
					}
    			}
    							// 重みの初期値の設定
    			for ($i1 = $k3; $i1 <= $k4; $i1++) {
    				for ($i2 = $k1; $i2 <= $k2; $i2++) {
    					$this->con[$i1][$i2] = $id;
    					switch ($id) {
    						case 0:
    							$this->w[$i1][$i2] = 0.0;
								break;
    						case 1:
    							$this->w[$i1][$i2] = ($x2 - $x1) * mt_rand() / mt_getrandmax() + $x1;
    							break;
							case 2:
    							$this->w[$i1][$i2] = $x1;
    							break;
							case 3:
								$this->w[$i1][$i2] = $x1;
								break;
    					}
    				}
    			}
			}
		}
    
    	fclose($in);
    }
	
	/******************************************/
	/* 誤差の計算,及び,重みとバイアスの修正 */
	/*      ptn[$i1] : 出力パターン            */
    /******************************************/
    function Err_back($k0, $ptn)
    {
		for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) {
    					// 誤差の計算
    		if ($i1 < $this->noou) {
    			if ($this->f_type == 0)
    				$this->dp[$i1] = ($ptn[$i1] - $this->op[$i1]) * $this->op[$i1] * (1.0 - $this->op[$i1]);
    			else
    				$this->dp[$i1] = 0.5 * ($ptn[$i1] - $this->op[$i1]) * ($this->op[$i1] - 1.0) * ($this->op[$i1] + 1.0);
    		}
    		else {
    			$x1 = 0.0;
    			for ($i2 = 0; $i2 < $i1; $i2++) {
					if ($this->con[$i2][$i1] > 0)
    					$x1 += $this->dp[$i2] * $this->w[$i2][$i1];
    			}
				if ($this->f_type == 0)
					$this->dp[$i1] = $this->op[$i1] * (1.0 - $this->op[$i1]) * $x1;
				else
    				$this->dp[$i1] = 0.5 * ($this->op[$i1] - 1.0) * ($this->op[$i1] + 1.0) * $x1;
    		}
    					// 重みの修正
			for ($i2 = $i1+1; $i2 < $this->nou; $i2++) {
				if ($this->con[$i1][$i2] == 1 || $this->con[$i1][$i2] == 2) {
    				$x1                 = $this->eata * $this->dp[$i1] * $this->op[$i2] + $this->alpha * $this->w[$i2][$i1];
    				$this->w[$i2][$i1]  = $x1;
    				$this->w[$i1][$i2] += $x1;
				}
			}
						// バイアスの修正
			if ($this->con[$i1][$i1] >= -2) {
    			$x1                = $this->eata * $this->dp[$i1] + $this->alpha * $this->w[$i1][$i1];
    			$this->w[$i1][$i1] = $x1;
    			$this->theta[$i1] += $x1;
			}
    	}
    }
    
    /********************************************************/
    /* 与えられた入力パターンに対する各ユニットの出力の計算 */
    /********************************************************/
    function Forward()
    {
    	for ($i1 = $this->nou-$this->noiu-1; $i1 >= 0; $i1--) {
    
    		$sum = -$this->theta[$i1];
	
    		for ($i2 = $i1+1; $i2 < $this->nou; $i2++) {
    			if ($this->con[$i1][$i2] > 0)
					$sum -= $this->w[$i1][$i2] * $this->op[$i2];
			}
	
    		$this->op[$i1] = ($this->f_type == 0) ? 1.0 / (1.0 + exp($sum)) : 1.0 - 2.0 / (1.0 + exp($sum));
    	}
	}
	
    /*****************************/
    /* 学習の実行                */
    /*      p : 認識パターン     */
	/*      m_tri : 最大学習回数 */
	/*****************************/
	function Learn($p, $m_tri)
	{
    	$k0 = -1;
    /*
         エラーチェック
	*/
    	if ($this->noiu != $p->noiu || $this->noou != $p->noou)
    		exit("***error  入力または出力ユニットの数が違います\n");
    
    	for ($i1 = 0; $i1 < $m_tri; $i1++) {
    /*
         パターンを与える順番の決定
    */
    		if ($this->order == 0) {       // 順番
    			$k0 += 1;
				if ($k0 >= $p->noip)
    				$k0 = 0;
    		}
			else {                  // ランダム
				$k0 = intval(mt_rand() / mt_getrandmax() * $p->noip);
				if ($k0 >= $p->noip)
    				$k0 = $p->noip - 1;
    		}
   /*
	     出力ユニットの結果を計算
	*/
    		$k1 = $this->nou - $this->noiu;
    		for ($i2 = 0; $i2 < $this->noiu; $i2++)
    			$this->op[$k1+$i2] = $p->iptn[$k0][$i2];
	
			$this->Forward();
	/*
	     重みとバイアスの修正
    */
    		$this->Err_back($k0, $p->optn[$k0]);
    	}
	}
    
    /***********************************************/
    /* 与えられた対象の認識と出力                  */
    /*      p : 認識パターン                       */
    /*      pr : =0 : 出力を行わない               */
    /*           =1 : 出力を行う                   */
    /*           =2 : 出力を行う(未学習パターン) */
    /*      tri : 現在の学習回数                   */
    /*      return : 誤って認識したパターンの数    */
    /***********************************************/
    function Recog($p, $pr, $tri)
	{
    	$No = 0;
    /*
	     ファイルのオープン
	*/
		if ($this->p_type < 0 && $pr > 0) {
    		if ($pr == 1) {
    			$out = fopen($this->o_file, "wb");
    			fwrite($out, "***学習パターン***\n\n");
			}
			else {
    			$out = fopen($this->o_file, "ab");
    			fwrite($out, "\n***未学習パターン***\n\n");
    		}
		}
	/*
	     各パターンに対する出力
	*/
    	for ($i1 = 0; $i1 < $p->noip; $i1++) {
    					// 入力パターンの設定
    		$k1 = $this->nou - $this->noiu;
			for ($i2 = 0; $i2 < $this->noiu; $i2++)
    			$this->op[$k1+$i2] = $p->iptn[$i1][$i2];
    					// 出力の計算
    		$this->Forward();
    					// 結果の表示
    		if ($this->p_type != 0 && $pr > 0) {
    
    			printf("入力パターン%4d    ", $i1+1);
    			for ($i2 = 0; $i2 < $this->noiu; $i2++) {
    				printf("%5.2f", $this->op[$k1+$i2]);
    				if ($i2 == $this->noiu-1)
    					printf("\n");
					else {
    					if((($i2+1) % 10) == 0)
    						printf("\n                    ");
					}
				}
	
    			printf("\n    出力パターン(理想)   ");
    			for ($i2 = 0; $i2 < $this->noou; $i2++) {
    				printf("%10.3f", $p->optn[$i1][$i2]);
					if ($i2 == $this->noou-1)
						printf("\n");
    				else {
    					if((($i2+1) % 5) == 0)
    						printf("\n                         ");
					}
				}
			}
	
    		$sw = 0;
    		if ($this->p_type != 0 && $pr > 0)
    			printf("                (実際)   ");
			for ($i2 = 0; $i2 < $this->noou; $i2++) {
    			if ($this->p_type != 0 && $pr > 0) {
    				printf("%10.3f", $this->op[$i2]);
    				if ($i2 == $this->noou-1)
    					printf("\n");
    				else {
    					if((($i2+1) % 5) == 0)
    						printf("\n                         ");
    				}
    			}
    			if (abs($this->op[$i2]-$p->optn[$i1][$i2]) > $this->eps)
    				$sw = 1;
			}
    
    		if ($sw > 0)
				$No++;
	
			if ($this->p_type < 0 && $pr > 0) {
    
    			$str = "入力パターン".($i1+1)."    ";
    			for ($i2 = 0; $i2 < $this->noiu; $i2++) {
					$str = $str." ".$this->op[$k1+$i2];
					if ($i2 == $this->noiu-1)
    					$str = $str."\n";
    				else {
    					if((($i2+1) % 10) == 0)
							$str = $str."\n                    ";
					}
				}
				fwrite($out, $str);
	
    			$str = "\n    出力パターン(理想)   ";
    			for ($i2 = 0; $i2 < $this->noou; $i2++) {
    				$str = $str." ".$p->optn[$i1][$i2];
					if ($i2 == $this->noou-1)
    					$str = $str."\n";
    				else {
    					if((($i2+1) % 5) == 0)
    						$str = $str."\n                         ";
    				}
    			}
				fwrite($out, $str);
    
    			$str = "                (実際)   ";
    			for ($i2 = 0; $i2 < $this->noou; $i2++) {
    				$str = $str." ".$this->op[$i2];
    				if ($i2 == $this->noou-1)
						$str = $str."\n";
    				else {
    					if((($i2+1) % 5) == 0)
							$str = $str."\n                         ";
					}
				}
				fwrite($out, $str);
    		}
    
    		if ($this->p_type != 0 && $pr > 0) {
				fgets(STDIN);
				if ($i1 == 0)
    				fgets(STDIN);
    		}
    	}
	/*
	     重みの出力
	*/
		if (($this->p_type < -1 || $this->p_type > 1) && $pr == 1) {
    
    		printf("    重み\n");
    		for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) {
				printf("      to%4d from   ", $i1+1);
    			$ln = -1;
    			for ($i2 = 0; $i2 < $this->nou; $i2++) {
    				if ($this->con[$i1][$i2] > 0) {
    					if ($ln <= 0) {
    						if ($ln < 0)
    							$ln = 0;
    						else
    							printf("\n                    ");
    					}
    					printf("%4d%11.3f", $i2+1, $this->w[$i1][$i2]);
    					$ln += 1;
						if ($ln == 4)
    						$ln = 0;
    				}
				}
	
				printf("\n");
    		}
    
    		printf("\n    バイアス   ");
			$ln = 0;
			for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) {
    			printf("%4d%11.3f", $i1+1, $this->theta[$i1]);
    			$ln += 1;
    			if ($ln == 4 && $i1 != $this->nou-$this->noiu-1) {
					$ln = 0;
					printf("\n               ");
				}
			}
    
    		if ($ln != 0)
    			printf("\n");
	
    		fgets(STDIN);
    	}
    
    	if ($this->p_type < 0 && $pr == 1) {
    
    		$str = "    重み\n";
    		for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) {
    			$str = $str."      to ".( $i1+1)." from   ";
    			$ln = -1;
    			for ($i2 = 0; $i2 < $this->nou; $i2++) {
    				if ($this->con[$i1][$i2] > 0) {
						if ($ln <= 0) {
    						if ($ln < 0)
    							$ln = 0;
							else
								$str = $str."\n                    ";
						}
    					$str = $str.($i2+1)." ".$this->w[$i1][$i2];
    					$ln += 1;
    					if ($ln == 4)
							$ln = 0;
					}
    			}
    			$str = $str."\n";
			}
			fwrite($out, $str);
	
			$str = "\n    バイアス   ";
			$ln = 0;
    		for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) {
    			$str = $str.($i1+1)." ".$this->theta[$i1];
    			$ln += 1;
				if ($ln == 4 && $i1 != $this->nou-$this->noiu-1) {
    				$ln = 0;
    				$str = $str."\n               ";
    			}
    		}
    
    		if ($ln != 0)
    			$str = $str."\n";
  			fwrite($out, $str);
  	}
    
    	if ($this->p_type < 0 && $pr > 0)
    		fclose($out);
	
    	return $No;
    }
}
	
/****************/
/* main program */
/****************/
	$max = 0;
	$no  = 1;
					// エラー
	if (count($argv) != 3)
		exit("***error   入力データファイル名を指定して下さい\n");
   	else {
					// ネットワークの定義
  		$net = new Backpr($argv[1], $argv[2]);
   					// 学習パターン等の入力
   		printf("学習回数は? ");
   		fscanf(STDIN, "%d", $m_tri);   // 最大学習回数
   		printf("何回毎に収束を確認しますか? ");
   		fscanf(STDIN, "%d", $conv);   // 収束確認回数
   		printf("学習パターンのファイル名は? ");
   		fscanf(STDIN, "%s", $f_name);
   		$dt1 = new BackData($f_name);
					// 学習
   		while ($max < $m_tri && $no > 0) {
			$tri  = (($max + $conv) < $m_tri) ? $conv : $m_tri - $max;
			$max += $tri;
   			$net->Learn($dt1, $tri);   // 学習
   			$no = $net->Recog($dt1, 0, $max);   // 学習対象の認識
			printf("   回数 %d 誤って認識したパターン数 %d\n", $max, $no);
   		}
   		$no = $net->Recog($dt1, 1, $max);   // 学習対象の認識と出力
					// 未学習パターンの認識
		printf("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ");
		fscanf(STDIN, "%d", $sw);
   		if ($sw > 0) {
    
   			printf("未学習パターンのファイル名は? ");
			fscanf(STDIN, "%s", $f_name);
			$dt2 = new BackData($f_name);
			$no = $net->Recog($dt2, 2, $max);   // 未学習対象の認識と出力
		}
	}
/*
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
*/
?>
			
##########################
# back propagation model
#      coded by Y.Suganuma
##########################
######################################################
# バックプロパゲーションの制御(クラス BackControl)
######################################################
class BackControl
	
	####################################
	# クラスBackControlのコンストラクタ
	#      name : 入力データファイル名
	####################################
	
	def initialize(name)
	
		f        = open(name, "r")
		s        = f.gets().split(" ")
		@_eps    = Float(s[1])   # 許容誤差
		@_p_type = Integer(s[3])   # 出力先・方法の指定
	                               #   =0 : 誤って認識した数だけ出力
	                               #   =1 : 認識結果を出力
	                               #   =2 : 認識結果と重みを出力
	                               #        (負の時は,認識結果と重みをファイルへも出力)
		if @_p_type < 0
			@_o_file = s[5]   # 出力ファイル名
		end
		s       = f.gets().split(" ")
		@_order = Integer(s[1])   # 入力パターンの与え方(=0:順番,=1:ランダム)
		@_eata  = Float(s[3])   # 重み及びバイアス修正パラメータ
		@_alpha = Float(s[5])   # 重み及びバイアス修正パラメータ
		f.close()
		srand()
	end
end
	
######################################################
# バックプロパゲーションのデータ(クラス BackData)
######################################################
class BackData
	
	####################################
	# クラスBackDataのコンストラクタ
	#      name : 入力データファイル名
	####################################
	
	def initialize(name)
				# 入力パターン数等
		f      = open(name, "r")
		s      = f.gets().split(" ")
		@_noip = Integer(s[1])   # 入力パターンの数
		@_noiu = Integer(s[3])   # 入力ユニットの数
		@_noou = Integer(s[5])   # 出力ユニットの数
				# 領域の確保
		@_iptn = Array.new(@_noip)
		for i1 in 0 ... @_noip
			@_iptn[i1] = Array.new(@_noiu)
		end
	                      # iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
	                      #              入力ユニットの入力値
	                      #                i=0,noip-1  j=0,noiu-1
		@_optn = Array.new(@_noip)
		for i1 in 0 ... @_noip
			@_optn[i1] = Array.new(@_noou)
		end
	                      # optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
	                      #              番目の出力ユニットの目標出力値
	                      #                i=0,noip-1  j=0,noou-1
				# 入力パターン及び各入力パターンに対する出力パターンの入力
		for i1 in 0 ... @_noip
			s = f.gets().split(" ")
			for i2 in 0 ... @_noiu
				@_iptn[i1][i2] = Float(s[i2+1])
			end
			s = f.gets().split(" ")
			for i2 in 0 ... @_noou
				@_optn[i1][i2] = Float(s[i2+1])
			end
		end
		f.close()
	end
	attr_accessor("_noip", "_noiu", "_noou", "_iptn", "_optn")
end
###########################################
# バックプロパゲーション(クラス Backpr)
###########################################
class Backpr < BackControl
	
	################################################
	# クラスBackprのコンストラクタ
	#      name_c : 制御データ用入力ファイル名
	#      name_s : ネットワーク記述入力ファイル名
	################################################
	
	def initialize(name_c, name_s)
	
		super(name_c)   # 親のコンストラクタ
		f = open(name_s, "r")
				# 入力ユニット,出力ユニットの数,関数タイプ
		s        = f.gets().split(" ")
		@_noiu   = Integer(s[1])   # 入力ユニットの数
		@_noou   = Integer(s[3])   # 出力ユニットの数
		@_f_type = Integer(s[5])   # シグモイド関数のタイプ,0 : [0,1],1 : [-1,1]
		@_nou    = @_noiu + @_noou   # 入力ユニットと出力ユニットの和
	                                 # 各ユニットには最も上の出力ユニットから,
	                                 # 隠れ層の各ユニット,及び,入力ユニットに至る
	                                 # 一連のユニット番号が付けられる
				# 隠れユニットの階層数と各階層のユニット数
		s       = f.gets().split(" ")
		@_nolvl = Integer(s[1])   # 隠れユニットの階層数
		@_nohu  = Array.new(@_nolvl+1)
	                 # nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
	                 #           には下から順に番号が付けられ,出力層はレ
	                 #           ベル(nolvl+1)の隠れ層とも見做される)
	                 #             i=0,nolvl
		@_nohu[@_nolvl] = @_noou
	
		if @_nolvl > 0
			for i1 in 0 ... @_nolvl
				@_nohu[i1]  = Integer(s[i1+3])
				@_nou      += @_nohu[i1]
			end
		end
				# 領域の確保
		@_con = Array.new(@_nou)
		for i1 in 0 ... @_nou
			@_con[i1] = Array.new(@_nou)
		end
		for i1 in 0 ... @_nou
			for i2 in 0 ... @_nou
				if i1 == i2
					@_con[i1][i2] = -1
				else
					@_con[i1][i2] = 0
	              # con[i][j] : 各ユニットに対するバイアスの与え方,及び,接続方法
	              #   [i][i] : ユニット(i+1)のバイアスの与え方
	              #     =-3 : 入力値で固定
	              #     =-2 : 入力値を初期値として,学習により変更
	              #     =-1 : 乱数で初期値を設定し,学習により変更
	              #   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
	              #     =0 : 接続しない
	              #     =1 : 接続する(重みの初期値を乱数で設定し,学習)
	              #     =2 : 接続する(重みの初期値を入力で与え,学習)
	              #     =3 : 接続する(重みを入力値に固定)
	              #            i=0,nou-1  j=0,nou-1
				end
			end
		end
	
		@_w = Array.new(@_nou)
		for i1 in 0 ... @_nou
			@_w[i1] = Array.new(@_nou)
		end
		for i1 in 0 ... @_nou
			for i2 in 0 ... @_nou
				@_w[i1][i2] = 0.0
	              # w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
	              # w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
	              # w[i][i] : ユニット(i+1)のバイアスの前回修正量
	              #   i=0,nou-1  j=0,nou-1
			end
		end
	
		@_dp    = Array.new(@_nou)   # ユニット(i+1)の誤差  i=0,nou-1
		@_op    = Array.new(@_nou)   # ユニット(i+1)の出力  i=0,nou-1
		@_theta = Array.new(@_nou)   # ユニット(i+1)のバイアス  i=0,nou
		for i1 in 0 ... @_nou
			@_theta[i1] = 0.2 * rand(0) - 0.1
		end
				# 各ユニットのバイアスとユニット間の接続関係
						# バイアス
							# バイアスデータの数
		s = f.gets().split(" ")
		n = Integer(s[1])
		f.gets()
		f.gets()
		f.gets()
	
		if n > 0
							# バイアスデータの処理
			for i0 in 0 ... n
				s = f.gets().split(" ")
								# ユニット番号
				k1 = Integer(s[0])
								# 不適当なユニット番号のチェック
				if k1 < 1 or k1 > (@_nou-@_noiu)
					print("***error  ユニット番号 " + String(k1) + " が不適当" + "\n")
				end
								# バイアスの与え方
				k1            -= 1
				id             = Integer(s[1])
				@_con[k1][k1]  = id
								# バイアスの初期設定
				if @_con[k1][k1] == -1
					x1          = Float(s[2])
					x2          = Float(s[3])
					@_theta[k1] = (x2 - x1) * rand(0) + x1
				elsif @_con[k1][k1] == -2 or @_con[k1][k1] == -3
					@_theta[k1] = Float(s[2])
				else
					print("***error  バイアスの与え方が不適当\n")
				end
			end
		end
						# 接続方法
							# 接続データの数
		s = f.gets().split(" ")
		n = Integer(s[1])
		f.gets()
		f.gets()
		f.gets()
	
		if n > 0
							# 接続データの処理
			for i0 in 0 ... n
				s  = f.gets().split(" ")
								# 接続情報
				k1 = Integer(s[0])
				k2 = Integer(s[1])
				k3 = Integer(s[2])
				k4 = Integer(s[3])
								# 不適切な接続のチェック
				sw = 0
				if k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1
					sw = 1
				else
					if k1 > @_nou or k2 > @_nou or k3 > @_nou or k4 > @_nou
						sw = 1
					else
						if k1 > k2 or k3 > k4
							sw = 1
						else
							if k4 >= k1
								sw = 1
							else
								l1 = -1
								k  = 0
								i1 = @_nolvl
								while i1 > -1
									k += @_nohu[i1]
									if k1 <= k
										l1 = i1
										break
									end
									i1 -= 1
								end
								l2 = -1
								k  = 0
								i1 = @_nolvl
								while i1 > -1
									k += @_nohu[i1]
									if k4 <= k
										l2 = i1
										break
									end
									i1 -= 1
								end
								if l2 <= l1
									sw = 1
								end
							end
						end
					end
				end
	
				if sw > 0
					print("***error  ユニット番号が不適当(" + String(k1) + " " + String(k2) + " " + String(k3) + " " + String(k4) + ")\n")
				end
								# 重みの初期値の与え方
				k1 -= 1
				k2 -= 1
				k3 -= 1
				k4 -= 1
	
				id = Integer(s[4])
	
				if id == 1
					x1  = Float(s[5])
					x2  = Float(s[6])
				else
					if id > 1
						x1  = Float(s[5])
					else
						if id != 0
							print("***error  接続方法が不適当\n")
						end
					end
				end
								# 重みの初期値の設定
				for i1 in k3 ... k4+1
					for i2 in k1 ... k2+1
						@_con[i1][i2] = id
						if id == 0
							@_w[i1][i2] = 0.0
						elsif id == 1
							@_w[i1][i2] = (x2 - x1) * rand(0) + x1
						elsif id == 2
							@_w[i1][i2] = x1
						elsif id == 3
							@_w[i1][i2] = x1
						end
					end
				end
			end
		end
	
		f.close()
	end
	
	##########################################
	# 誤差の計算,及び,重みとバイアスの修正
	#      ptn[i1] : 出力パターン
	##########################################
	
	def Err_back(ptn)
	
		for i1 in 0 ... @_nou-@_noiu
						# 誤差の計算
			if i1 < @_noou
				if @_f_type == 0
					@_dp[i1] = (ptn[i1] - @_op[i1]) * @_op[i1] * (1.0 - @_op[i1])
				else
					@_dp[i1] = 0.5 * (ptn[i1] - @_op[i1]) * (@_op[i1] - 1.0) * (@_op[i1] + 1.0)
				end
			else
				x1 = 0.0
				for i2 in 0 ... i1
					if @_con[i2][i1] > 0
						x1 += @_dp[i2] * @_w[i2][i1]
					end
				end
				if @_f_type == 0
					@_dp[i1] = @_op[i1] * (1.0 - @_op[i1]) * x1
				else
					@_dp[i1] = 0.5 * (@_op[i1] - 1.0) * (@_op[i1] + 1.0) * x1
				end
			end
						# 重みの修正
			for i2 in i1+1 ... @_nou
				if @_con[i1][i2] == 1 or @_con[i1][i2] == 2
					x1           = @_eata * @_dp[i1] * @_op[i2] + @_alpha * @_w[i2][i1]
					@_w[i2][i1]  = x1
					@_w[i1][i2] += x1
				end
			end
						# バイアスの修正
			if @_con[i1][i1] >= -2
				x1           = @_eata * @_dp[i1] + @_alpha * @_w[i1][i1]
				@_w[i1][i1]  = x1
				@_theta[i1] += x1
			end
		end
	end
	
	########################################################
	# 与えられた入力パターンに対する各ユニットの出力の計算
	########################################################
	
	def Forward()
	
		i1 = @_nou - @_noiu - 1
		while i1 > -1
	
			sum = -@_theta[i1]
	
			for i2 in i1+1 ... @_nou
				if @_con[i1][i2] > 0
					sum -= @_w[i1][i2] * @_op[i2]
				end
			end
	
			if @_f_type == 0
				@_op[i1] = 1.0 / (1.0 + Math.exp(sum))
			else
				@_op[i1] = 1.0 - 2.0 / (1.0 + Math.exp(sum))
			end
			i1 -= 1
		end
	end
	
	#############################
	# 学習の実行
	#      p : 認識パターン
	#      m_tri : 最大学習回数
	#############################
	
	def Learn(p, m_tri)
	
		k0 = -1
				# エラーチェック
		if @_noiu != p._noiu or @_noou != p._noou
			print("***error  入力または出力ユニットの数が違います\n")
		end
	
		for i1 in 0 ... m_tri
				# パターンを与える順番の決定
			if @_order == 0   # 順番
				k0 += 1
				if k0 >= p._noip
					k0 = 0
				end
			else   # ランダム
				k0 = Integer(rand(0) * p._noip)
				if k0 >= p._noip
					k0 = p._noip - 1
				end
			end
				# 出力ユニットの結果を計算
			k1 = @_nou - @_noiu
			for i2 in 0 ... @_noiu
				@_op[k1+i2] = p._iptn[k0][i2]
			end
	
			Forward()
				# 重みとバイアスの修正
			Err_back(p._optn[k0])
		end
	end
	
	################################################
	# 与えられた対象の認識と出力
	#      p : 認識パターン
	#      pr : =0 : 出力を行わない
	#           =1 : 出力を行う
	#           =2 : 出力を行う(未学習パターン)
	#      tri : 現在の学習回数
	#      return : 誤って認識したパターンの数
	################################################
	
	def Recog(p, pr, tri)
	
		no = 0
				# ファイルのオープン
		if @_p_type < 0 and pr > 0
			if pr == 1
				out = open(@_o_file, "w")
				out.print("***学習パターン***\n\n")
			else
				out = open(@_o_file, "a")
				out.print("\n***未学習パターン***\n\n")
			end
		end
				# 各パターンに対する出力
		for i1 in 0 ... p._noip
						# 入力パターンの設定
			k1 = @_nou - @_noiu
			for i2 in 0 ... @_noiu
				@_op[k1+i2] = p._iptn[i1][i2]
			end
						# 出力の計算
			Forward()
						# 結果の表示
			if @_p_type != 0 and pr > 0
	
				printf("入力パターン%4d    ", (i1+1))
				for i2 in 0 ... @_noiu
					printf("%5.2f", @_op[k1+i2])
					if i2 == @_noiu-1
						print("\n")
					else
						if ((i2+1) % 10) == 0
							print("\n                    ")
						end
					end
				end
	
				print("\n    出力パターン(理想)   ")
				for i2 in 0 ... @_noou
					printf("%10.3f", p._optn[i1][i2])
					if i2 == @_noou-1
						print("\n")
					else
						if ((i2+1) % 5) == 0
							print("\n                         ")
						end
					end
				end
			end
	
			sw = 0
			if @_p_type != 0 and pr > 0
				print("                (実際)   ")
			end
			for i2 in 0 ... @_noou
				if @_p_type != 0 and pr > 0
					printf("%10.3f", @_op[i2])
					if i2 == @_noou-1
						print("\n")
					else
						if ((i2+1) % 5) == 0
							print("\n                         ")
						end
					end
				end
				if (@_op[i2]-p._optn[i1][i2]).abs() > @_eps
					sw = 1
				end
			end
	
			if sw > 0
				no += 1
			end
	
			if @_p_type < 0 and pr > 0
	
				out.printf("入力パターン%4d    ", (i1+1))
				for i2 in 0 ... @_noiu
					out.printf("%5.2f", @_op[k1+i2])
					if i2 == @_noiu-1
						out.print("\n")
					else
						if ((i2+1) % 10) == 0
							out.print("\n                    ")
						end
					end
				end
	
				out.print("\n    出力パターン(理想)   ")
				for i2 in 0 ... @_noou
					out.printf("%10.3f", p._optn[i1][i2])
					if i2 == @_noou-1
						out.print("\n")
					else
						if ((i2+1) % 5) == 0
							out.print("\n                         ")
						end
					end
				end
	
				out.print("                (実際)   ")
				for i2 in 0 ... @_noou
					out.printf("%10.3f", @_op[i2])
					if i2 == @_noou-1
						out.print("\n")
					else
						if ((i2+1) % 5) == 0
							out.print("\n                         ")
						end
					end
				end
			end
	
			if @_p_type != 0 and pr > 0
				$stdin.gets()
			end
		end
				# 重みの出力
		if (@_p_type < -1 or @_p_type > 1) and pr == 1
	
			print("    重み")
			for i1 in 0 ... @_nou-@_noiu
				printf("      to%4d from   ", (i1+1))
				ln = -1
				for i2 in 0 ... @_nou
					if @_con[i1][i2] > 0
						if ln <= 0
							if ln < 0
								ln = 0
							else
								print("\n                    ")
							end
						end
						printf("%4d%11.3f", i2+1, @_w[i1][i2])
						ln += 1
						if ln == 4
							ln = 0
						end
					end
				end
	
				print("\n")
			end
	
			print("\n    バイアス   ")
			ln = 0
			for i1 in 0 ... @_nou-@_noiu
				printf("%4d%11.3f", i1+1, @_theta[i1])
				ln += 1
				if ln == 4 and i1 != @_nou-@_noiu-1
					ln = 0
					print("\n               ")
				end
			end
			print("\n")
	
			$stdin.gets()
		end
	
		if @_p_type < 0 and pr == 1
	
			out.print("    重み\n")
			for i1 in 0 ... @_nou-@_noiu
				out.printf("      to%4d from   ", (i1+1))
				ln = -1
				for i2 in 0 ... @_nou
					if @_con[i1][i2] > 0
						if ln <= 0
							if ln < 0
								ln = 0
							else
								out.print("\n                    ")
							end
						end
						out.printf("%4d%11.3f", i2+1, @_w[i1][i2])
						ln += 1
						if ln == 4
							ln = 0
						end
					end
				end
	
				out.print("\n")
			end
	
			out.print("\n    バイアス   ")
			ln = 0
			for i1 in 0 ... @_nou-@_noiu
				out.printf("%4d%11.3f", i1+1, @_theta[i1])
				ln += 1
				if ln == 4 and i1 != @_nou-@_noiu-1
					ln = 0
					out.print("\n               ")
				end
			end
	
			if ln != 0
				out.print("\n")
			end
		end
	
		if @_p_type < 0 and pr > 0
			out.close()
		end
	
		return no
	end
end
ct = 0
no = 1
				# エラー
if ARGV.length != 2
	print("***error   入力データファイル名を指定して下さい\n")
else
				# ネットワークの定義
	net   = Backpr.new(ARGV[0], ARGV[1])
				# 学習パターン等の入力
	print("学習回数は? ")
	m_tri = Integer($stdin.gets())
	print("何回毎に収束を確認しますか? ")
	conv = Integer($stdin.gets())
	print("学習パターンのファイル名は? ")
	f_name = $stdin.gets().strip()
	dt1    = BackData.new(f_name)
				# 学習
	while ct < m_tri and no > 0
		if (ct + conv) < m_tri
			tri = conv
		else
			tri = m_tri - ct
		end
		ct += tri
		net.Learn(dt1, tri)   # 学習
		no = net.Recog(dt1, 0, ct)   # 学習対象の認識
		print("   回数 " + String(ct) + " 誤って認識したパターン数 " + String(no) + "\n")
	end
	no = net.Recog(dt1, 1, ct)   # 学習対象の認識と出力
				# 未学習パターンの認識
	print("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ")
	sw = Integer($stdin.gets())
	if sw > 0
		print("未学習パターンのファイル名は? ")
		f_name = $stdin.gets().strip()
		dt2    = BackData.new(f_name)
		no     = net.Recog(dt2, 2, ct)   # 未学習対象の認識と出力
	end
end
=begin
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
=end
			
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
from random import *
######################################################
# バックプロパゲーションの制御(クラス BackControl)
######################################################
class BackControl :
	
	####################################
	# クラスBackControlのコンストラクタ
	#      name : 入力データファイル名
	####################################
	
	def __init__(self, name) :
	
		f           = open(name, "r")
		s           = f.readline().split()
		self.eps    = float(s[1])   # 許容誤差
		self.p_type = int(s[3])   # 出力先・方法の指定
	                  #   =0 : 誤って認識した数だけ出力
	                  #   =1 : 認識結果を出力
	                  #   =2 : 認識結果と重みを出力
	                  #        (負の時は,認識結果と重みをファイルへも出力)
		if self.p_type < 0 :
			self.o_file = s[5]   # 出力ファイル名
		s          = f.readline().split()
		self.order = int(s[1])   # 入力パターンの与え方(=0:順番,=1:ランダム)
		self.eata  = float(s[3])   # 重み及びバイアス修正パラメータ
		self.alpha = float(s[5])   # 重み及びバイアス修正パラメータ
		f.close()
		seed()
	
######################################################
# バックプロパゲーションのデータ(クラス BackData)
######################################################
class BackData :
	
	####################################
	# クラスBackDataのコンストラクタ
	#      name : 入力データファイル名
	####################################
	
	def __init__(self, name) :
				# 入力パターン数等
		f         = open(name, "r")
		s         = f.readline().split()
		self.noip = int(s[1])   # 入力パターンの数
		self.noiu = int(s[3])   # 入力ユニットの数
		self.noou = int(s[5])   # 出力ユニットの数
				# 領域の確保
		self.iptn = np.empty((self.noip, self.noiu), np.float)
	                      # iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
	                      #              入力ユニットの入力値
	                      #                i=0,noip-1  j=0,noiu-1
		self.optn = np.empty((self.noip, self.noou), np.float)
	                      # optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
	                      #              番目の出力ユニットの目標出力値
	                      #                i=0,noip-1  j=0,noou-1
				# 入力パターン及び各入力パターンに対する出力パターンの入力
		for i1 in range(0, self.noip) :
			s = f.readline().split()
			for i2 in range(0, self.noiu) :
				self.iptn[i1][i2] = float(s[i2+1])
			s = f.readline().split()
			for i2 in range(0, self.noou) :
				self.optn[i1][i2] = float(s[i2+1])
		f.close()
###########################################
# バックプロパゲーション(クラス Backpr)
###########################################
class Backpr(BackControl) :
	
	################################################
	# クラスBackprのコンストラクタ
	#      name_c : 制御データ用入力ファイル名
	#      name_s : ネットワーク記述入力ファイル名
	################################################
	
	def __init__(self, name_c, name_s) :
	
		BackControl.__init__(self, name_c)   # 親のコンストラクタ
		f = open(name_s, "r")
				# 入力ユニット,出力ユニットの数,関数タイプ
		s           = f.readline().split()
		self.noiu   = int(s[1])   # 入力ユニットの数
		self.noou   = int(s[3])   # 出力ユニットの数
		self.f_type = int(s[5])   # シグモイド関数のタイプ,0 : [0,1],1 : [-1,1]
		self.nou    = self.noiu + self.noou   # 入力ユニットと出力ユニットの和
	                  # 各ユニットには最も上の出力ユニットから,
	                  # 隠れ層の各ユニット,及び,入力ユニットに至る
	                  # 一連のユニット番号が付けられる
				# 隠れユニットの階層数と各階層のユニット数
		s          = f.readline().split()
		self.nolvl = int(s[1])   # 隠れユニットの階層数
		self.nohu  = np.empty(self.nolvl+1, np.int)
	                 # nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
	                 #           には下から順に番号が付けられ,出力層はレ
	                 #           ベル(nolvl+1)の隠れ層とも見做される)
	                 #             i=0,nolvl
		self.nohu[self.nolvl] = self.noou
	
		if self.nolvl > 0 :
			for i1 in range(0, self.nolvl) :
				self.nohu[i1]  = int(s[i1+3])
				self.nou      += self.nohu[i1]
				# 領域の確保
		self.con = np.empty((self.nou, self.nou), np.int)
		for i1 in range(0, self.nou) :
			for i2 in range(0, self.nou) :
				if i1 == i2 :
					self.con[i1][i2] = -1
				else :
					self.con[i1][i2] = 0
	              # con[i][j] : 各ユニットに対するバイアスの与え方,及び,接続方法
	              #   [i][i] : ユニット(i+1)のバイアスの与え方
	              #     =-3 : 入力値で固定
	              #     =-2 : 入力値を初期値として,学習により変更
	              #     =-1 : 乱数で初期値を設定し,学習により変更
	              #   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
	              #     =0 : 接続しない
	              #     =1 : 接続する(重みの初期値を乱数で設定し,学習)
	              #     =2 : 接続する(重みの初期値を入力で与え,学習)
	              #     =3 : 接続する(重みを入力値に固定)
	              #            i=0,nou-1  j=0,nou-1
	
		self.w = np.empty((self.nou, self.nou), np.float)
		for i1 in range(0, self.nou) :
			for i2 in range(0, self.nou) :
				self.w[i1][i2] = 0.0
	              # w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
	              # w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
	              # w[i][i] : ユニット(i+1)のバイアスの前回修正量
	              #   i=0,nou-1  j=0,nou-1
	
		self.dp    = np.empty(self.nou, np.float)   # ユニット(i+1)の誤差  i=0,nou-1
		self.op    = np.empty(self.nou, np.float)   # ユニット(i+1)の出力  i=0,nou-1
		self.theta = np.empty(self.nou, np.float)   # ユニット(i+1)のバイアス  i=0,nou
		for i1 in range(0, self.nou) :
			self.theta[i1] = 0.2 * random() - 0.1
				# 各ユニットのバイアスとユニット間の接続関係
						# バイアス
							# バイアスデータの数
		s = f.readline().split()
		n = int(s[1])
		f.readline()
		f.readline()
		f.readline()
	
		if n > 0 :
							# バイアスデータの処理
			for i0 in range(0, n) :
				s = f.readline().split()
								# ユニット番号
				k1 = int(s[0])
								# 不適当なユニット番号のチェック
				if k1 < 1 or k1 > (self.nou-self.noiu) :
					print("***error  ユニット番号 " + str(k1) + " が不適当")
								# バイアスの与え方
				k1 -= 1
				id  = int(s[1])
				self.con[k1][k1] = id
								# バイアスの初期設定
				if self.con[k1][k1] == -1 :
					x1  = float(s[2])
					x2  = float(s[3])
					self.theta[k1] = (x2 - x1) * random() + x1
				elif self.con[k1][k1] == -2 or self.con[k1][k1] == -3 :
					self.theta[k1] = float(s[2])
				else :
					print("***error  バイアスの与え方が不適当")
						# 接続方法
							# 接続データの数
		s = f.readline().split()
		n = int(s[1])
		f.readline()
		f.readline()
		f.readline()
	
		if n > 0 :
							# 接続データの処理
			for i0 in range(0, n) :
				s  = f.readline().split()
								# 接続情報
				k1 = int(s[0])
				k2 = int(s[1])
				k3 = int(s[2])
				k4 = int(s[3])
								# 不適切な接続のチェック
				sw = 0
				if k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1 :
					sw = 1
				else :
					if k1 > self.nou or k2 > self.nou or k3 > self.nou or k4 > self.nou :
						sw = 1
					else :
						if k1 > k2 or k3 > k4 :
							sw = 1
						else :
							if k4 >= k1 :
								sw = 1
							else :
								l1 = -1
								k  = 0
								for i1 in range(self.nolvl, -1, -1) :
									k += self.nohu[i1]
									if k1 <= k :
										l1 = i1
										break
								l2 = -1
								k  = 0
								for i1 in range(self.nolvl, -1, -1) :
									k += self.nohu[i1]
									if k4 <= k :
										l2 = i1
										break
								if l2 <= l1 :
									sw = 1
	
				if sw > 0 :
					print("***error  ユニット番号が不適当(" + str(k1) + " " + str(k2) + " " + str(k3) + " " + str(k4) + ")")
								# 重みの初期値の与え方
				k1 -= 1
				k2 -= 1
				k3 -= 1
				k4 -= 1
	
				id = int(s[4])
	
				if id == 1 :
					x1  = float(s[5])
					x2  = float(s[6])
				else :
					if id > 1 :
						x1  = float(s[5])
					else :
						if id != 0 :
							print("***error  接続方法が不適当")
								# 重みの初期値の設定
				for i1 in range(k3, k4+1) :
					for i2 in range(k1, k2+1) :
						self.con[i1][i2] = id
						if id == 0 :
							self.w[i1][i2] = 0.0
						elif id == 1 :
							self.w[i1][i2] = (x2 - x1) * random() + x1
						elif id == 2 :
							self.w[i1][i2] = x1
						elif id == 3 :
							self.w[i1][i2] = x1
	
		f.close()
	
	##########################################
	# 誤差の計算,及び,重みとバイアスの修正
	#      ptn[i1] : 出力パターン
	##########################################
	
	def Err_back(self, ptn) :
	
		for i1 in range(0, self.nou-self.noiu) :
						# 誤差の計算
			if i1 < self.noou :
				if self.f_type == 0 :
					self.dp[i1] = (ptn[i1] - self.op[i1]) * self.op[i1] * (1.0 - self.op[i1])
				else :
					self.dp[i1] = 0.5 * (ptn[i1] - self.op[i1]) * (self.op[i1] - 1.0) * (self.op[i1] + 1.0)
			else :
				x1 = 0.0
				for i2 in range(0, i1) :
					if self.con[i2][i1] > 0 :
						x1 += self.dp[i2] * self.w[i2][i1]
				if self.f_type == 0 :
					self.dp[i1] = self.op[i1] * (1.0 - self.op[i1]) * x1
				else :
					self.dp[i1] = 0.5 * (self.op[i1] - 1.0) * (self.op[i1] + 1.0) * x1
						# 重みの修正
			for i2 in range(i1+1, self.nou) :
				if self.con[i1][i2] == 1 or self.con[i1][i2] == 2 :
					x1 = self.eata * self.dp[i1] * self.op[i2] + self.alpha * self.w[i2][i1]
					self.w[i2][i1]  = x1
					self.w[i1][i2] += x1
						# バイアスの修正
			if self.con[i1][i1] >= -2 :
				x1 = self.eata * self.dp[i1] + self.alpha * self.w[i1][i1]
				self.w[i1][i1]  = x1
				self.theta[i1] += x1
	
	########################################################
	# 与えられた入力パターンに対する各ユニットの出力の計算
	########################################################
	
	def Forward(self) :
	
		for i1 in range(self.nou-self.noiu-1, -1, -1) :
	
			sum = -self.theta[i1]
	
			for i2 in range(i1+1, self.nou) :
				if self.con[i1][i2] > 0 :
					sum -= self.w[i1][i2] * self.op[i2]
	
			if self.f_type == 0 :
				self.op[i1] = 1.0 / (1.0 + exp(sum))
			else :
				self.op[i1] = 1.0 - 2.0 / (1.0 + exp(sum))
	
	#############################
	# 学習の実行
	#      p : 認識パターン
	#      m_tri : 最大学習回数
	#############################
	
	def Learn(self, p, m_tri) :
	
		k0 = -1
				# エラーチェック
		if self.noiu != p.noiu or self.noou != p.noou :
			print("***error  入力または出力ユニットの数が違います")
	
		for i1 in range(0, m_tri) :
				# パターンを与える順番の決定
			if self.order == 0 :   # 順番
				k0 += 1
				if k0 >= p.noip :
					k0 = 0
			else :   # ランダム
				k0 = int(random() * p.noip)
				if k0 >= p.noip :
					k0 = p.noip - 1
				# 出力ユニットの結果を計算
			k1 = self.nou - self.noiu
			for i2 in range(0, self.noiu) :
				self.op[k1+i2] = p.iptn[k0][i2]
	
			self.Forward()
				# 重みとバイアスの修正
			self.Err_back(p.optn[k0])
	
	################################################
	# 与えられた対象の認識と出力
	#      p : 認識パターン
	#      pr : =0 : 出力を行わない
	#           =1 : 出力を行う
	#           =2 : 出力を行う(未学習パターン)
	#      tri : 現在の学習回数
	#      return : 誤って認識したパターンの数
	################################################
	
	def Recog(self, p, pr, tri) :
	
		No = 0
				# ファイルのオープン
		if self.p_type < 0 and pr > 0 :
			if pr == 1 :
				out = open(self.o_file, "w")
				out.write("***学習パターン***\n\n")
			else :
				out = open(self.o_file, "a")
				out.write("\n***未学習パターン***\n\n")
				# 各パターンに対する出力
		for i1 in range(0, p.noip) :
						# 入力パターンの設定
			k1 = self.nou - self.noiu
			for i2 in range(0, self.noiu) :
				self.op[k1+i2] = p.iptn[i1][i2]
						# 出力の計算
			self.Forward()
						# 結果の表示
			if self.p_type != 0 and pr > 0 :
	
				print("入力パターン{0:4d}    ".format(i1+1), end="")
				for i2 in range(0, self.noiu) :
					print("{0:5.2f}".format(self.op[k1+i2]), end="")
					if i2 == self.noiu-1 :
						print("")
					else :
						if ((i2+1) % 10) == 0 :
							print("\n                    ", end="")
	
				print("\n    出力パターン(理想)   ", end="")
				for i2 in range(0, self.noou) :
					print("{0:10.3f}".format(p.optn[i1][i2]), end="")
					if i2 == self.noou-1 :
						print("")
					else :
						if ((i2+1) % 5) == 0 :
							print("\n                         ", end="")
	
			sw = 0
			if self.p_type != 0 and pr > 0 :
				print("                (実際)   ", end="")
			for i2 in range(0, self.noou) :
				if self.p_type != 0 and pr > 0 :
					print("{0:10.3f}".format(self.op[i2]), end="")
					if i2 == self.noou-1 :
						print("\n")
					else :
						if ((i2+1) % 5) == 0 :
							print("\n                         ", end="")
				if abs(self.op[i2]-p.optn[i1][i2]) > self.eps :
					sw = 1
	
			if sw > 0 :
				No += 1
	
			if self.p_type < 0 and pr > 0 :
	
				out.write("入力パターン{0:4d}    ".format(i1+1))
				for i2 in range(0, self.noiu) :
					out.write("{0:5.2f}".format(self.op[k1+i2]))
					if i2 == self.noiu-1 :
						out.write("\n")
					else :
						if ((i2+1) % 10) == 0 :
							out.write("\n                    ")
	
				out.write("\n    出力パターン(理想)   ")
				for i2 in range(0, self.noou) :
					out.write("{0:10.3f}".format(p.optn[i1][i2]))
					if i2 == self.noou-1 :
						out.write("\n")
					else :
						if ((i2+1) % 5) == 0 :
							out.write("\n                         ")
	
				out.write("                (実際)   ")
				for i2 in range(0, self.noou) :
					out.write("{0:10.3f}".format(self.op[i2]))
					if i2 == self.noou-1 :
						out.write("\n")
					else :
						if ((i2+1) % 5) == 0 :
							out.write("\n                         ")
	
			if self.p_type != 0 and pr > 0 :
				input("")
				# 重みの出力
		if (self.p_type < -1 or self.p_type > 1) and pr == 1 :
	
			print("    重み")
			for i1 in range(0, self.nou-self.noiu) :
				print("      to{0:4d} from   ".format(i1+1), end="")
				ln = -1
				for i2 in range(0, self.nou) :
					if self.con[i1][i2] > 0 :
						if ln <= 0 :
							if ln < 0 :
								ln = 0
							else :
								print("\n                    ", end="")
						print("{0:4d}{1:11.3f}".format(i2+1, self.w[i1][i2]), end="")
						ln += 1
						if ln == 4 :
							ln = 0
	
				print("")
	
			print("\n    バイアス   ", end="")
			ln = 0
			for i1 in range(0, self.nou-self.noiu) :
				print("{0:4d}{1:11.3f}".format(i1+1, self.theta[i1]), end="")
				ln += 1
				if ln == 4 and i1 != self.nou-self.noiu-1 :
					ln = 0
					print("\n               ", end="")
			print("")
	
			input("")
	
		if self.p_type < 0 and pr == 1 :
	
			out.write("    重み\n")
			for i1 in range(0, self.nou-self.noiu) :
				out.write("      to{0:4d} from   ".format(i1+1))
				ln = -1
				for i2 in range(0, self.nou) :
					if self.con[i1][i2] > 0 :
						if ln <= 0 :
							if ln < 0 :
								ln = 0
							else :
								out.write("\n                    ")
						out.write("{0:4d}{1:11.3f}".format(i2+1, self.w[i1][i2]))
						ln += 1
						if ln == 4 :
							ln = 0
	
				out.write("\n")
	
			out.write("\n    バイアス   ")
			ln = 0
			for i1 in range(0, self.nou-self.noiu) :
				out.write("{0:4d}{1:11.3f}".format(i1+1, self.theta[i1]))
				ln += 1
				if ln == 4 and i1 != self.nou-self.noiu-1 :
					ln = 0
					out.write("\n               ")
	
			if ln != 0 :
				out.write("\n")
	
		if self.p_type < 0 and pr > 0 :
			out.close()
	
		return No
##########################
# back propagation model
#      coded by Y.Suganuma
##########################
ct = 0
no = 1
				# エラー
if len(sys.argv) != 3 :
	print("***error   入力データファイル名を指定して下さい")
else :
				# ネットワークの定義
	net = Backpr(sys.argv[1], sys.argv[2])
				# 学習パターン等の入力
	m_tri  = int(input("学習回数は? "))
	conv   = int(input("何回毎に収束を確認しますか? "))
	f_name = input("学習パターンのファイル名は? ")
	dt1    = BackData(f_name)
				# 学習
	while ct < m_tri and no > 0 :
		if (ct + conv) < m_tri :
			tri = conv
		else :
			tri = m_tri - ct
		ct += tri
		net.Learn(dt1, tri)   # 学習
		no = net.Recog(dt1, 0, ct)   # 学習対象の認識
		print("   回数 " + str(ct) + " 誤って認識したパターン数 " + str(no))
	no = net.Recog(dt1, 1, ct)   # 学習対象の認識と出力
				# 未学習パターンの認識
	sw = int(input("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "))
	if sw > 0 :
		f_name = input("未学習パターンのファイル名は? ")
		dt2    = BackData(f_name)
		no     = net.Recog(dt2, 2, ct)   # 未学習対象の認識と出力
"""
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
"""
"""
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
"""
			
/****************************/
/* back propagation model   */
/*      coded by Y.Suganuma */
/****************************/
using System;
using System.IO;
class Program
{
	/****************/
	/* main program */
	/****************/
	static void Main(String[] args)
	{
					// エラー
		if (args.Length != 2) {
			Console.WriteLine("***error   入力データファイル名を指定して下さい");
			Environment.Exit(1);
		}
		else {
					// ネットワークの定義
			Backpr net = new Backpr (args[0], args[1]);
					// 学習パターン等の入力
			Console.Write("学習回数は? ");
			int m_tri = int.Parse(Console.ReadLine());   // 最大学習回数
			Console.Write("何回毎に収束を確認しますか? ");
			int conv = int.Parse(Console.ReadLine());   // 収束確認回数
			Console.Write("学習パターンのファイル名は? ");
			String f_name = Console.ReadLine();
			BackData dt1 = new BackData(f_name);
					// 学習
			int max = 0, no = 1;
			while (max < m_tri && no > 0) {
				int tri = ((max + conv) < m_tri) ? conv : m_tri - max;
				max    += tri;
				net.Learn(dt1, tri);   // 学習
				no = net.Recog(dt1, 0, max);   // 学習対象の認識
				Console.WriteLine("   回数 " + max + " 誤って認識したパターン数 " + no);
			}
			no = net.Recog(dt1, 1, max);   // 学習対象の認識と出力
					// 未学習パターンの認識
			Console.Write("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ");
			int sw = int.Parse(Console.ReadLine());
			if (sw > 0) {
				Console.Write("未学習パターンのファイル名は? ");
				f_name = Console.ReadLine();
				BackData dt2 = new BackData(f_name);
				no = net.Recog(dt2, 2, max);   // 未学習対象の認識と出力
			}
		}
	}
}
/******************************************************/
/* バックプロパゲーションの制御(クラス BackControl) */
/******************************************************/
class BackControl {
	protected double alpha, eata;   //重み及びバイアス修正パラメータ
	protected double eps;   // 許容誤差
	protected int order;   // 入力パターンの与え方(=0:順番,=1:ランダム)
	protected int p_type;   // 出力先・方法の指定
                            //   =0 : 誤って認識した数だけ出力
                            //   =1 : 認識結果を出力
                            //   =2 : 認識結果と重みを出力
                            //        (負の時は,認識結果と重みをファイルへも出力)
	protected String o_file;   // 出力ファイル名
	/*************************************/
	/* クラスBackControlのコンストラクタ */
	/*      name : 入力データファイル名  */
	/*************************************/
	public BackControl(String name)
	{
		char[] charSep = new char[] {' '};
		String[] lines = File.ReadAllLines(name);
		String[] str   = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		eps            = double.Parse(str[1]);
		p_type         = int.Parse(str[3]);
		if (p_type < 0)
			o_file = str[5];
		str   = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		order = int.Parse(str[1]);
		eata  = double.Parse(str[3]);
		alpha = double.Parse(str[5]);
	}
}
/*****************************************************/
/* バックプロパゲーションのデータ(クラス BackData) */
/*****************************************************/
class BackData {
	public int noiu;   // 入力ユニットの数
	public int noou;   // 出力ユニットの数
	public int noip;   // 入力パターンの数
	public double[][] iptn;   // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の
                              //              入力ユニットの入力値
                              //                i=0,noip-1  j=0,noiu-1
	public double[][] optn;   // optn[i][j] : (i+1)番目の入力パターンに対する(j+1)
                              //              番目の出力ユニットの目標出力値
                              //                i=0,noip-1  j=0,noou-1
	/************************************/
	/* クラスBackDataのコンストラクタ   */
	/*      name : 入力データファイル名 */
	/************************************/
	public BackData(String name)
	{
		char[] charSep = new char[] {' '};
		String[] lines = File.ReadAllLines(name);
				//
				// 入力パターン数等
				//
		String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		noip         = int.Parse(str[1]);
		noiu         = int.Parse(str[3]);
		noou         = int.Parse(str[5]);
				//
				// 領域の確保
				//
		iptn = new double [noip][];
		optn = new double [noip][];
		for (int i1 = 0; i1 < noip; i1++) {
			iptn[i1] = new double [noiu];
			optn[i1] = new double [noou];
		}
				//
				// 入力パターン及び各入力パターンに対する出力パターンの入力
				//
		for (int i1 = 0; i1 < noip; i1++) {
			int k = 2 * i1 + 1;
			str = lines[k].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
			for (int i2 = 0; i2 < noiu; i2++)
				iptn[i1][i2] = double.Parse(str[i2+1]);
			str = lines[k+1].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
			for (int i2 = 0; i2 < noou; i2++)
				optn[i1][i2] = double.Parse(str[i2+1]);
		}
	}
}
/*******************************************/
/* バックプロパゲーション(クラス Backpr) */
/*******************************************/
class Backpr : BackControl {
	sbyte[][] con;   // con[i][j] : 各ユニットに対するバイアスの与え方,及び,
                     // 接続方法
                     //   [i][i] : ユニット(i+1)のバイアスの与え方
                     //     =-3 : 入力値で固定
                     //     =-2 : 入力値を初期値として,学習により変更
                     //     =-1 : 乱数で初期値を設定し,学習により変更
                     //   [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i)
                     //     =0 : 接続しない
                     //     =1 : 接続する(重みの初期値を乱数で設定し,学習)
                     //     =2 : 接続する(重みの初期値を入力で与え,学習)
                     //     =3 : 接続する(重みを入力値に固定)
                     //            i=0,nou-1  j=0,nou-1
	int f_type;   // シグモイド関数のタイプ
                  //   0 : [0,1]
                  //   1 : [-1,1])
	int noiu;   // 入力ユニットの数
	int noou;   // 出力ユニットの数
	int[] nohu;   // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層
                  //           には下から順に番号が付けられ,出力層はレ
                  //           ベル(nolvl+1)の隠れ層とも見做される)
                  //             i=0,nolvl
	int nolvl;   // 隠れユニットの階層数
	int nou;   // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ
               // ットには最も上の出力ユニットから,隠れ層の各ユニット,
               // 及び,入力ユニットに至る一連のユニット番号が付けられ
               // る)
	double[] dp;   // dp[i] : ユニット(i+1)の誤差  i=0,nou-1
	double[] op;   // op[i] : ユニット(i+1)の出力  i=0,nou-1
	double[] theta;   //theta[i] : ユニット(i+1)のバイアス  i=0,nou
	double[][] w;   // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i)
                    // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i)
                    // w[i][i] : ユニット(i+1)のバイアスの前回修正量
                    //   i=0,nou-1  j=0,nou-1
	Random rn;   // 乱数
	/************************************************/
	/* クラスBackprのコンストラクタ                 */
	/*      name_c : 制御データ用入力ファイル名     */
	/*      name_s : ネットワーク記述入力ファイル名 */
	/************************************************/
	public Backpr(String name_c, String name_s) : base(name_c)
	{
		char[] charSep = new char[] {' '};
		String[] lines = File.ReadAllLines(name_s);
				//
				// 乱数の初期化
				//
		rn  = new Random();   // 乱数の初期設定
				//
				// 入力ユニット,出力ユニットの数,関数タイプ
				//
		String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		noiu         = int.Parse(str[1]);
		noou         = int.Parse(str[3]);
		f_type       = int.Parse(str[5]);
		nou          = noiu + noou;   // 入力ユニットと出力ユニットの和
				//
				// 隠れユニットの階層数と各階層のユニット数
				//
		str         = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		nolvl       = int.Parse(str[1]);
		nohu        = new int [nolvl+1];
		nohu[nolvl] = noou;   // 出力ユニットの数
		if (nolvl > 0) {
			for (int i1 = 0; i1 < nolvl; i1++) {
				nohu[i1]  = int.Parse(str[i1+3]);
				nou      += nohu[i1];
			}
		}
				//
				// 領域の確保
				//
		con = new sbyte [nou][];
		for (int i1 = 0; i1 < nou; i1++) {
			con[i1] = new sbyte [nou];
			for (int i2 = 0; i2 < nou; i2++)
				con[i1][i2] =  (i1 == i2) ? (sbyte)-1 : (sbyte)0;
		}
		w = new double [nou][];
		for (int i1 = 0; i1 < nou; i1++) {
			w[i1] = new double [nou];
			for (int i2 = 0; i2 < nou; i2++)
				w[i1][i2] = 0.0;
		}
		dp    = new double [nou];
		op    = new double [nou];
		theta = new double [nou];
		for (int i1 = 0; i1 < nou; i1++)
			theta[i1] = 0.2 * rn.NextDouble() - 0.1;
				//
				// 各ユニットのバイアスとユニット間の接続関係
				//
					// バイアス
						// バイアスデータの数
		str    = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		int nb = int.Parse(str[1]);
		if (nb > 0) {
						// バイアスデータの処理
			for (int i0 = 0; i0 < nb; i0++) {
							// ユニット番号
				str    = lines[i0+6].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
				int k1 = int.Parse(str[0]);
							// 不適当なユニット番号のチェック
				if (k1 < 1 || k1 > (nou-noiu)) {
					Console.WriteLine("***error  ユニット番号 " + k1 + " が不適当");
					Environment.Exit(1);
				}
							// バイアスの与え方
				k1--;
				int id      = int.Parse(str[1]);
				con[k1][k1] = (sbyte)id;
							// バイアスの初期設定
				switch (con[k1][k1]) {
					case -1:
						double x1 = double.Parse(str[2]);
						double x2 = double.Parse(str[3]);
						theta[k1] = (x2 - x1) * rn.NextDouble() + x1;
						break;
					case -2:
						theta[k1] = double.Parse(str[2]);
						break;
					case -3:
						theta[k1] = double.Parse(str[2]);
						break;
					default:
						Console.WriteLine("***error  バイアスの与え方が不適当");
						Environment.Exit(1);
						break;
				}
			}
		}
					// 接続方法
						// 接続データの数
		str   = lines[nb+6].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
		int n = int.Parse(str[1]);
		if (n > 0) {
						// 接続データの処理
			for (int i0 = 0; i0 < n; i0++) {
							// 接続情報
				str    = lines[nb+10+i0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
				int k1 = int.Parse(str[0]);
				int k2 = int.Parse(str[1]);
				int k3 = int.Parse(str[2]);
				int k4 = int.Parse(str[3]);
							// 不適切な接続のチェック
				int sw = 0;
				if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1)
					sw = 1;
				else {
					if (k1 > nou || k2 > nou || k3 > nou || k4 > nou)
						sw = 1;
					else {
						if (k1 > k2 || k3 > k4)
							sw = 1;
						else {
							if (k4 >= k1)
								sw = 1;
							else {
								int l1 = -1;
								int k  = 0;
								for (int i1 = nolvl; i1 >= 0 && l1 < 0; i1--) {
									k += nohu[i1];
									if (k1 <= k)
										l1 = i1;
								}
								int l2 = -1;
								k      = 0;
								for (int i1 = nolvl; i1 >= 0 && l2 < 0; i1--) {
									k += nohu[i1];
									if (k4 <= k)
										l2 = i1;
								}
								if (l2 <= l1)
									sw = 1;
							}
						}
					}
				}
				if (sw > 0) {
					Console.WriteLine("***error  ユニット番号が不適当("
                                       + k1 + " " + k2 + " " + k3 + " " + k4 + ")");
					Environment.Exit(1);
				}
							// 重みの初期値の与え方
				k1--;
				k2--;
				k3--;
				k4--;
				int id    = int.Parse(str[4]);
				double x1 = 0.0;
				double x2 = 0.0;
				if (id == 1) {
					x1 = double.Parse(str[5]);
					x2 = double.Parse(str[6]);
				}
				else {
					if (id > 1)
						x1 = double.Parse(str[5]);
					else {
						if (id != 0) {
							Console.WriteLine("***error  接続方法が不適当");
							Environment.Exit(1);
						}
					}
				}
							// 重みの初期値の設定
				for (int i1 = k3; i1 <= k4; i1++) {
					for (int i2 = k1; i2 <= k2; i2++) {
						con[i1][i2] = (sbyte)id;
						switch (id) {
							case 0:
								w[i1][i2] = 0.0;
								break;
							case 1:
								w[i1][i2] = (x2 - x1) * rn.NextDouble() + x1;
								break;
							case 2:
								w[i1][i2] = x1;
								break;
							case 3:
								w[i1][i2] = x1;
								break;
						}
					}
				}
			}
		}
	}
	/******************************************/
	/* 誤差の計算,及び,重みとバイアスの修正 */
	/*      ptn[i1] : 出力パターン            */
	/******************************************/
	void Err_back(double[] ptn)
	{
		for (int i1 = 0; i1 < nou-noiu; i1++) {
					// 誤差の計算
			if (i1 < noou) {
				if (f_type == 0)
					dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]);
				else
					dp[i1] = 0.5 * (ptn[i1] - op[i1]) * 
                             (op[i1] - 1.0) * (op[i1] + 1.0);
			}
			else {
				double x1 = 0.0;
				for (int i2 = 0; i2 < i1; i2++) {
					if (con[i2][i1] > 0)
						x1 += dp[i2] * w[i2][i1];
				}
				if (f_type == 0)
					dp[i1] = op[i1] * (1.0 - op[i1]) * x1;
				else
					dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1;
			}
					// 重みの修正
			for (int i2 = i1+1; i2 < nou; i2++) {
				if (con[i1][i2] == 1 || con[i1][i2] == 2) {
					double x1  = eata * dp[i1] * op[i2] + alpha * w[i2][i1];
					w[i2][i1]  = x1;
					w[i1][i2] += x1;
				}
			}
					// バイアスの修正
			if (con[i1][i1] >= -2) {
				double x1  = eata * dp[i1] + alpha * w[i1][i1];
				w[i1][i1]  = x1;
				theta[i1] += x1;
			}
		}
	}
	/********************************************************/
	/* 与えられた入力パターンに対する各ユニットの出力の計算 */
	/********************************************************/
	void Forward()
	{
		for (int i1 = nou-noiu-1; i1 >= 0; i1--) {
			double sum = -theta[i1];
			for (int i2 = i1+1; i2 < nou; i2++) {
				if (con[i1][i2] > 0)
					sum -= w[i1][i2] * op[i2];
			}
			op[i1] = (f_type == 0) ? 1.0 / (1.0 + Math.Exp(sum)) :
                                     1.0 - 2.0 / (1.0 + Math.Exp(sum));
		}
	}
	/*****************************/
	/* 学習の実行                */
	/*      p : 認識パターン     */
	/*      m_tri : 最大学習回数 */
	/*****************************/
	public void Learn(BackData p, int m_tri)
	{
				//
				// エラーチェック
				//
		if (noiu != p.noiu || noou != p.noou) {
			Console.WriteLine("***error  入力または出力ユニットの数が違います");
			Environment.Exit(1);
		}
		int k0 = -1;
		for (int i1 = 0; i1 < m_tri; i1++) {
				//
				// パターンを与える順番の決定
				//
			if (order == 0) {       // 順番
				k0++;
				if (k0 >= p.noip)
					k0 = 0;
			}
			else {                  // ランダム
				k0 = (int)(rn.NextDouble() * p.noip);
				if (k0 >= p.noip)
					k0 = p.noip - 1;
			}
				//
				// 出力ユニットの結果を計算
				//
			int k1 = nou - noiu;
			for (int i2 = 0; i2 < noiu; i2++)
				op[k1+i2] = p.iptn[k0][i2];
			Forward();
				//
				// 重みとバイアスの修正
				//
			Err_back(p.optn[k0]);
		}
	}
	/***********************************************/
	/* 与えられた対象の認識と出力                  */
	/*      p : 認識パターン                       */
	/*      pr : =0 : 出力を行わない               */
	/*           =1 : 出力を行う                   */
	/*           =2 : 出力を行う(未学習パターン) */
	/*      tri : 現在の学習回数                   */
	/*      return : 誤って認識したパターンの数    */
	/***********************************************/
	public int Recog(BackData p, int pr, int tri)
	{
				//
				// ファイルのオープン
				//
		StreamWriter OUT = null;
		if (p_type < 0 && pr > 0) {
			OUT = new StreamWriter(o_file, true); 
			if (pr == 1) {
				OUT.WriteLine("***学習パターン***");
				OUT.WriteLine();
			}
			else {
				OUT.WriteLine();
				OUT.WriteLine("***未学習パターン***");
				OUT.WriteLine();
			}
		}
				//
				// 各パターンに対する出力
				//
		int No = 0;
		for (int i1 = 0; i1 < p.noip; i1++) {
					// 入力パターンの設定
			int k1 = nou - noiu;
			for (int i2 = 0; i2 < noiu; i2++)
				op[k1+i2] = p.iptn[i1][i2];
					// 出力の計算
			Forward();
					// 結果の表示
			if (p_type != 0 && pr > 0) {
				Console.Write("入力パターン" + (i1+1) + "   ");
				for (int i2 = 0; i2 < noiu; i2++) {
					Console.Write(" " + op[k1+i2]);
					if (i2 == noiu-1)
						Console.WriteLine();
					else {
						if(((i2+1) % 10) == 0) {
							Console.WriteLine();
							Console.Write("                   ");
						}
					}
				}
				Console.WriteLine();
				Console.Write("    出力パターン(理想)  ");
				for (int i2 = 0; i2 < noou; i2++) {
					Console.Write(" " + p.optn[i1][i2]);
					if (i2 == noou-1)
						Console.WriteLine();
					else {
						if(((i2+1) % 5) == 0) {
							Console.WriteLine();
							Console.Write("                        ");
						}
					}
				}
			}
			int sw = 0;
			if (p_type != 0 && pr > 0)
				Console.Write("                (実際)  ");
			for (int i2 = 0; i2 < noou; i2++) {
				if (p_type != 0 && pr > 0) {
					Console.Write(" " + op[i2]);
					if (i2 == noou-1)
						Console.WriteLine();
					else {
						if(((i2+1) % 5) == 0) {
							Console.WriteLine();
							Console.Write("                        ");
						}
					}
				}
				if (Math.Abs(op[i2]-p.optn[i1][i2]) > eps)
					sw = 1;
			}
			if (sw > 0)
				No++;
			if (p_type < 0 && pr > 0) {
				OUT.Write("入力パターン" + (i1+1) + "   ");
				for (int i2 = 0; i2 < noiu; i2++) {
					OUT.Write(" " + op[k1+i2]);
					if (i2 == noiu-1)
						OUT.WriteLine();
					else {
						if(((i2+1) % 10) == 0) {
							OUT.WriteLine();
							OUT.Write("                   ");
						}
					}
				}
				OUT.WriteLine();
				OUT.Write("    出力パターン(理想)  ");
				for (int i2 = 0; i2 < noou; i2++) {
					OUT.Write(" " + p.optn[i1][i2]);
					if (i2 == noou-1)
						OUT.WriteLine();
					else {
						if(((i2+1) % 5) == 0) {
							OUT.WriteLine();
							OUT.Write("                        ");
						}
					}
				}
				OUT.Write("                (実際)  ");
				for (int i2 = 0; i2 < noou; i2++) {
					OUT.Write(" " + op[i2]);
					if (i2 == noou-1)
						OUT.WriteLine();
					else {
						if(((i2+1) % 5) == 0) {
							OUT.WriteLine();
							OUT.Write("                        ");
						}
					}
				}
			}
			if (p_type != 0 && pr > 0)
				Console.ReadLine();
		}
				//
				// 重みの出力
				//
		int ln;
		if ((p_type < -1 || p_type > 1) && pr == 1) {
			Console.WriteLine("    重み");
			for (int i1 = 0; i1 < nou-noiu; i1++) {
				Console.Write("      to " + (i1+1) + " from  ");
				ln = -1;
				for (int i2 = 0; i2 < nou; i2++) {
					if (con[i1][i2] > 0) {
						if (ln <= 0) {
							if (ln < 0)
								ln = 0;
							else {
								Console.WriteLine();
								Console.Write("                   ");
							}
						}
						Console.Write(" " + (i2+1) + " " + w[i1][i2]);
						ln += 1;
						if (ln == 4)
							ln = 0;
					}
				}
				Console.WriteLine();
			}
			Console.WriteLine();
			Console.Write("    バイアス  ");
			ln = 0;
			for (int i1 = 0; i1 < nou-noiu; i1++) {
				Console.Write(" " + (i1+1) + " " + theta[i1]);
				ln += 1;
				if (ln == 4 && i1 != nou-noiu-1) {
					ln = 0;
					Console.WriteLine();
					Console.Write("              ");
				}
			}
			if (ln != 0)
				Console.WriteLine();
			Console.ReadLine();
		}
		if (p_type < 0 && pr == 1) {
			OUT.WriteLine("    重み");
			for (int i1 = 0; i1 < nou-noiu; i1++) {
				OUT.Write("      to " + (i1+1) + " from  ");
				ln = -1;
				for (int i2 = 0; i2 < nou; i2++) {
					if (con[i1][i2] > 0) {
						if (ln <= 0) {
							if (ln < 0)
								ln = 0;
							else {
								OUT.WriteLine();
								OUT.Write("                   ");
							}
						}
						OUT.Write(" " + (i2+1) + " " + w[i1][i2]);
						ln += 1;
						if (ln == 4)
							ln = 0;
					}
				}
				OUT.WriteLine();
			}
			OUT.WriteLine();
			OUT.Write("    バイアス  ");
			ln = 0;
			for (int i1 = 0; i1 < nou-noiu; i1++) {
				OUT.Write(" " + (i1+1) + " " + theta[i1]);
				ln += 1;
				if (ln == 4 && i1 != nou-noiu-1) {
					ln = 0;
					OUT.WriteLine();
					OUT.Write("\n              ");
				}
			}
			if (ln != 0)
				OUT.WriteLine();
		}
		if (p_type < 0 && pr > 0)
			OUT.Close();
		return No;
	}
}
/*
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
*/
			
'**************************'
' back propagation model   '
'      coded by Y.Suganuma '
'**************************'
Imports System.IO
Imports System.Text.RegularExpressions
Module Test
	Sub Main(args() As String)
					' エラー
		If args.Length <> 2
			Console.WriteLine("***error   入力データファイル名を指定して下さい")
			Environment.Exit(1)
		Else
					' ネットワークの定義
			Dim net As Backpr = new Backpr(args(0), args(1))
					' 学習パターン等の入力
			Console.Write("学習回数は? ")
			Dim m_tri As Integer = Integer.Parse(Console.ReadLine())   ' 最大学習回数
			Console.Write("何回毎に収束を確認しますか? ")
			Dim conv As Integer = Integer.Parse(Console.ReadLine())   ' 収束確認回数
			Console.Write("学習パターンのファイル名は? ")
			Dim f_name As String = Console.ReadLine()
			Dim dt1 As BackData = new BackData(f_name)
					' 学習
			Dim max As Integer = 0
			Dim no As Integer  = 1
			Do While max < m_tri and no > 0
				Dim tri As Integer
				If (max + conv) < m_tri
					tri = conv
				Else
					tri = m_tri - max
				End If
				max += tri
				net.Learn(dt1, tri)   ' 学習
				no = net.Recog(dt1, 0, max)   ' 学習対象の認識
				Console.WriteLine("   回数 " & max & " 誤って認識したパターン数 " & no)
			Loop
			no = net.Recog(dt1, 1, max)   ' 学習対象の認識と出力
					' 未学習パターンの認識
			Console.Write("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ")
			Dim sw As Integer = Integer.Parse(Console.ReadLine())
			If sw > 0
				Console.Write("未学習パターンのファイル名は? ")
				f_name = Console.ReadLine()
				Dim dt2 As BackData = new BackData(f_name)
				no = net.Recog(dt2, 2, max)   ' 未学習対象の認識と出力
			End If
		End If
	End Sub
	'****************************************************'
	' バックプロパゲーションの制御(クラス BackControl) '
	'****************************************************'
	Class BackControl
		Protected alpha As Double   '重み及びバイアス修正パラメータ
		Protected eata As Double   '重み及びバイアス修正パラメータ
		Protected eps As Double   ' 許容誤差
		Protected order As Integer   ' 入力パターンの与え方(=0:順番,=1:ランダム)
		Protected p_type As Integer   ' 出力先・方法の指定
	                                  '   =0 : 誤って認識した数だけ出力
	                                  '   =1 : 認識結果を出力
	                                  '   =2 : 認識結果と重みを出力
	                                  '  (負の時は,認識結果と重みをファイルへも出力)
		Protected o_file As String   ' 出力ファイル名
		'***********************************'
		' クラスBackControlのコンストラクタ '
		'      name : 入力データファイル名  '
		'***********************************'
		Public Sub New(name As String)
			Dim inp As StreamReader = New StreamReader(name)
			Dim MS As Regex         = New Regex("\s+") 
			Dim str() As String     = MS.Split(inp.ReadLine().Trim())
			eps                     = Double.Parse(str(1))
			p_type                  = Integer.Parse(str(3))
			If p_type < 0
				o_file = str(5)
			End If
			str   = MS.Split(inp.ReadLine().Trim())
			order = Integer.Parse(str(1))
			eata  = Double.Parse(str(3))
			alpha = Double.Parse(str(5))
			inp.Close()
		End Sub
	End Class
	'***************************************************'
	' バックプロパゲーションのデータ(クラス BackData) '
	'***************************************************'
	Class BackData
		Public noiu As Integer   ' 入力ユニットの数
		Public noou As Integer   ' 出力ユニットの数
		Public noip As Integer   ' 入力パターンの数
		Public iptn(,) As Double   ' iptn(i,j) : (i+1)番目の入力パターンの(j+1)番目の
	                               '              入力ユニットの入力値
	                               '                i=0,noip-1  j=0,noiu-1
		Public optn(,) As Double   ' optn(i,j) : (i+1)番目の入力パターンに対する(j+1)
	                               '              番目の出力ユニットの目標出力値
	                               '                i=0,noip-1  j=0,noou-1
	
		'**********************************'
		' クラスBackDataのコンストラクタ   '
		'      name : 入力データファイル名 '
		'**********************************'
		Public Sub New(name As String)
			Dim MS As Regex         = New Regex("\s+") 
			Dim inp As StreamReader = New StreamReader(name)
					'
					' 入力パターン数等
					'
			Dim str() As String = MS.Split(inp.ReadLine().Trim())
			noip                = Integer.Parse(str(1))
			noiu                = Integer.Parse(str(3))
			noou                = Integer.Parse(str(5))
					'
					' 領域の確保
					'
			ReDim iptn(noip,noiu)
			ReDim optn(noip,noou)
					'
					' 入力パターン及び各入力パターンに対する出力パターンの入力
					'
			For i1 As Integer = 0 To noip-1
				str = MS.Split(inp.ReadLine().Trim())
				For i2 As Integer = 0 To noiu-1
					iptn(i1,i2) = Double.Parse(str(i2+1))
				Next
				str = MS.Split(inp.ReadLine().Trim())
				For i2 As Integer = 0 To noou-1
					optn(i1,i2) = Double.Parse(str(i2+1))
				Next
			Next
			inp.Close()
		End Sub
	End Class
	'*****************************************'
	' バックプロパゲーション(クラス Backpr) '
	'*****************************************'
	Class Backpr
		Inherits BackControl   ' クラス BackControl を継承
		Private con(,) As Integer   ' バイアスの与え方,及び,接続方法
	                                '   (i,i) : ユニット(i+1)のバイアスの与え方
	                                '     =-3 : 入力値で固定
	                                '     =-2 : 入力値を初期値として,学習により変更
	                                '     =-1 : 乱数で初期値を設定し,学習により変更
	                                '   (i,j) : ユニット(i+1)と(j+1)の接続方法(j>i)
	                                '     =0 : 接続しない
	                                '     =1 : 接続する(重みの初期値を乱数で設定し,学習)
	                                '     =2 : 接続する(重みの初期値を入力で与え,学習)
	                                '     =3 : 接続する(重みを入力値に固定)
	                                '            i=0,nou-1  j=0,nou-1
		Private f_type As Integer   ' シグモイド関数のタイプ
	                                '   0 : (0,1)
	                                '   1 : (-1,1))
		Private noiu As Integer   ' 入力ユニットの数
		Private noou As Integer   ' 出力ユニットの数
		Private nohu() As Integer   ' nohu(i) : レベル(i+1)の隠れ層のユニット数(隠れ層
	                                '           には下から順に番号が付けられ,出力層はレ
	                                '           ベル(nolvl+1)の隠れ層とも見做される)
	                                '             i=0,nolvl
		Private nolvl As Integer   ' 隠れユニットの階層数
		Private nou As Integer   ' 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ
	                             ' ットには最も上の出力ユニットから,隠れ層の各ユニット,
	                             ' 及び,入力ユニットに至る一連のユニット番号が付けられ
	                             ' る)
		Private dp() As Double   ' dp(i) : ユニット(i+1)の誤差  i=0,nou-1
		Private op() As Double   ' op(i) : ユニット(i+1)の出力  i=0,nou-1
		Private theta() As Double   'theta(i) : ユニット(i+1)のバイアス  i=0,nou
		Private w(,) As Double   ' w(i,j) : ユニット(i+1)から(j+1)への重み(j>i)
	                             ' w(j,i) : (i+1)から(j+1)への重みの前回修正量(j>i)
	                             ' w(i,i) : ユニット(i+1)のバイアスの前回修正量
	                             '   i=0,nou-1  j=0,nou-1
		 Private rn As Random   ' 乱数
	
		'**********************************************'
		' クラスBackprのコンストラクタ                 '
		'      name_c : 制御データ用入力ファイル名     '
		'      name_s : ネットワーク記述入力ファイル名 '
		'**********************************************'
		Public Sub New(name_c As String, name_s As String)
			MyBase.new(name_c)   ' 基底クラスのコンストラクタ
			Dim MS As Regex         = New Regex("\s+") 
			Dim inp As StreamReader = New StreamReader(name_s)
					'
					' 乱数の初期化
					'
			rn  = new Random()   ' 乱数の初期設定
					'
					' 入力ユニット,出力ユニットの数,関数タイプ
					'
			Dim str() As String = MS.Split(inp.ReadLine().Trim())
			noiu                = Integer.Parse(str(1))
			noou                = Integer.Parse(str(3))
			f_type              = Integer.Parse(str(5))
			nou                 = noiu + noou   ' 入力ユニットと出力ユニットの和
					'
					' 隠れユニットの階層数と各階層のユニット数
					'
			str   = MS.Split(inp.ReadLine().Trim())
			nolvl = Integer.Parse(str(1))
			ReDim nohu(nolvl+1)
			nohu(nolvl) = noou   ' 出力ユニットの数
	
			If nolvl > 0
				For i1 As Integer = 0 To nolvl-1
					nohu(i1)  = Integer.Parse(str(i1+3))
					nou      += nohu(i1)
				Next
			End If
					'
					' 領域の確保
					'
			ReDim con(nou,nou)
			For i1 As Integer = 0 To nou-1
				For i2 As Integer = 0 To nou-1
					If i1 = i2
						con(i1,i2) =  -1
					Else
						con(i1,i2) = 0
					End If
				Next
			Next
	
			ReDim w(nou,nou)
			For i1 As Integer = 0 To nou-1
				For i2 As Integer = 0 To nou-1
					w(i1,i2) = 0.0
				Next
			Next
	
			ReDim dp(nou)
			ReDim op(nou)
			ReDim theta(nou)
	
			For i1 As Integer = 0 To nou-1
				theta(i1) = 0.2 * rn.NextDouble() - 0.1
			Next
					'
					' 各ユニットのバイアスとユニット間の接続関係
					'
						' バイアス
							' バイアスデータの数
			str               = MS.Split(inp.ReadLine().Trim())
			Dim nb As Integer = Integer.Parse(str(1))
			inp.ReadLine()
			inp.ReadLine()
			inp.ReadLine()
			If nb > 0
							' バイアスデータの処理
				For i0 As Integer = 0 To nb-1
								' ユニット番号
					str               = MS.Split(inp.ReadLine().Trim())
					Dim k1 As Integer = Integer.Parse(str(0))
								' 不適当なユニット番号のチェック
					If k1 < 1 or k1 > (nou-noiu)
						Console.WriteLine("***error  ユニット番号 " & k1 & " が不適当")
						Environment.Exit(1)
					End If
								' バイアスの与え方
					k1 -= 1
					Dim id As Integer = Integer.Parse(str(1))
					con(k1,k1)        = id
								' バイアスの初期設定
					Select Case con(k1,k1)
						Case -1
							Dim x1 As Double = Double.Parse(str(2))
							Dim x2 As Double = Double.Parse(str(3))
							theta(k1) = (x2 - x1) * rn.NextDouble() + x1
						Case -2
							theta(k1) = Double.Parse(str(2))
						Case -3
							theta(k1) = Double.Parse(str(2))
						Case Else
							Console.WriteLine("***error  バイアスの与え方が不適当")
							Environment.Exit(1)
					End Select
				Next
			End If
						' 接続方法
							' 接続データの数
			str              = MS.Split(inp.ReadLine().Trim())
			Dim n As Integer = Integer.Parse(str(1))
			inp.ReadLine()
			inp.ReadLine()
			inp.ReadLine()
	
			If n > 0
							' 接続データの処理
				For i0 As Integer = 0 To n-1
								' 接続情報
					str               = MS.Split(inp.ReadLine().Trim())
					Dim k1 As Integer = Integer.Parse(str(0))
					Dim k2 As Integer = Integer.Parse(str(1))
					Dim k3 As Integer = Integer.Parse(str(2))
					Dim k4 As Integer = Integer.Parse(str(3))
								' 不適切な接続のチェック
					Dim sw As Integer = 0
					If k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1
						sw = 1
					Else
						If k1 > nou or k2 > nou or k3 > nou or k4 > nou
							sw = 1
						Else
							If k1 > k2 or k3 > k4
								sw = 1
							Else
								If k4 >= k1
									sw = 1
								Else
									Dim l1 As Integer  = -1
									Dim k As Integer   = 0
									Dim i1t As Integer = nolvl
									Do While i1t >= 0 and l1 < 0
										k += nohu(i1t)
										If k1 <= k
											l1 = i1t
										End If
										i1t -= 1
									Loop
									Dim l2 As Integer = -1
									k                 = 0
									i1t               = nolvl
									Do While i1t >= 0 and l2 < 0
										k += nohu(i1t)
										If k4 <= k
											l2 = i1t
										End If
										i1t -= 1
									Loop
									If l2 <= l1
										sw = 1
									End If
								End If
							End If
						End If
					End If
	
					If sw > 0
						Console.WriteLine("***error  ユニット番号が不適当(" &
						                   k1 & " " & k2 & " " & k3 & " " & k4 & ")")
						Environment.Exit(1)
					End If
								' 重みの初期値の与え方
					k1 -= 1
					k2 -= 1
					k3 -= 1
					k4 -= 1
	
					Dim id As Integer = Integer.Parse(str(4))
					Dim x1 As Double  = 0.0
					Dim x2 As Double  = 0.0
	
					If id = 1
						x1 = Double.Parse(str(5))
						x2 = Double.Parse(str(6))
					Else
						If (id > 1)
							x1 = Double.Parse(str(5))
						Else
							If id <> 0
								Console.WriteLine("***error  接続方法が不適当")
								Environment.Exit(1)
							End If
						End If
					End If
								' 重みの初期値の設定
					For i1 As Integer = k3 To k4
						For i2 As Integer = k1 To k2
							con(i1,i2) = id
							Select Case id
								Case 0
									w(i1,i2) = 0.0
								Case 1
									w(i1,i2) = (x2 - x1) * rn.NextDouble() + x1
								Case 2
									w(i1,i2) = x1
								Case 3
									w(i1,i2) = x1
							End Select
						Next
					Next
				Next
			End If
			inp.Close()
		End Sub
		'***************************'
		' 学習の実行                '
		'      p : 認識パターン     '
		'      m_tri : 最大学習回数 '
		'***************************'
		Public Sub Learn(p As BackData, m_tri As Integer)
					'
					' エラーチェック
					'
			If noiu <> p.noiu or noou <> p.noou
				Console.WriteLine("***error  入力または出力ユニットの数が違います")
				Environment.Exit(1)
			End If
	
			Dim k0 As Integer = -1
			For i1 As Integer = 0 To m_tri-1
					'
					' パターンを与える順番の決定
					'
				If order = 0   ' 順番
					k0 += 1
					If k0 >= p.noip
						k0 = 0
					End If
				Else   ' ランダム
					k0 = Math.Floor(rn.NextDouble() * p.noip)
					If k0 >= p.noip
						k0 = p.noip - 1
					End If
				End If
					'
					' 出力ユニットの結果を計算
					'
				Dim k1 As Integer = nou - noiu
				For i2 As Integer = 0 To noiu-1
					op(k1+i2) = p.iptn(k0,i2)
				Next
	
				Forward()
					'
					' 重みとバイアスの修正
					'
				Dim ptn(noou) As Double
				For i2 As Integer = 0 To noou-1
					ptn(i2) = p.optn(k0,i2)
				Next
				Err_back(ptn)
			Next
		End Sub
		'******************************************************'
		' 与えられた入力パターンに対する各ユニットの出力の計算 '
		'******************************************************'
		Sub Forward()
			For i1 As Integer = nou-noiu-1 To 0 Step -1
	
				Dim sum As Double = -theta(i1)
	
				For i2 As Integer = i1+1 To nou-1
					If con(i1,i2) > 0
						sum -= w(i1,i2) * op(i2)
					End If
				Next
	
				If f_type = 0
					op(i1) = 1.0 / (1.0 + Math.Exp(sum)) :
				Else
					op(i1) = 1.0 - 2.0 / (1.0 + Math.Exp(sum))
				End If
			Next
		End Sub
		'****************************************'
		' 誤差の計算,及び,重みとバイアスの修正 '
		'      ptn(i1) : 出力パターン            '
		'****************************************'
		Sub Err_back(ptn() As Double)
			For i1 As Integer = 0 To nou-noiu-1
						' 誤差の計算
				If i1 < noou
					If f_type = 0
						dp(i1) = (ptn(i1) - op(i1)) * op(i1) * (1.0 - op(i1))
					Else
						dp(i1) = 0.5 * (ptn(i1) - op(i1)) * (op(i1) - 1.0) * (op(i1) + 1.0)
					End If
				Else
					Dim x1 As Double = 0.0
					For i2 As Integer = 0 To i1-1
						If con(i2,i1) > 0
							x1 += dp(i2) * w(i2,i1)
						End If
					Next
					If f_type = 0
						dp(i1) = op(i1) * (1.0 - op(i1)) * x1
					Else
						dp(i1) = 0.5 * (op(i1) - 1.0) * (op(i1) + 1.0) * x1
					End If
				End If
						' 重みの修正
				For i2 As Integer = i1+1 To nou-1
					If con(i1,i2) = 1 or con(i1,i2) = 2
						Dim x1 As Double = eata * dp(i1) * op(i2) + alpha * w(i2,i1)
						w(i2,i1)  = x1
						w(i1,i2) += x1
					End If
				Next
						' バイアスの修正
				If con(i1,i1) >= -2
					Dim x1 As Double = eata * dp(i1) + alpha * w(i1,i1)
					w(i1,i1)   = x1
					theta(i1) += x1
				End If
			Next
		End Sub
		'*********************************************'
		' 与えられた対象の認識と出力                  '
		'      p : 認識パターン                       '
		'      pr : =0 : 出力を行わない               '
		'           =1 : 出力を行う                   '
		'           =2 : 出力を行う(未学習パターン) '
		'      tri : 現在の学習回数                   '
		'      return : 誤って認識したパターンの数    '
		'*********************************************'
		Public Function Recog(p As BackData, pr As Integer, tri As Integer)
					'
					' ファイルのオープン
					'
			Dim Out As StreamWriter
			If p_type < 0 and pr > 0
				OUT = new StreamWriter(o_file, true) 
				If pr = 1
					OUT.WriteLine("***学習パターン***")
					OUT.WriteLine()
				Else
					OUT.WriteLine()
					OUT.WriteLine("***未学習パターン***")
					OUT.WriteLine()
				End If
			End If
					'
					' 各パターンに対する出力
					'
			Dim No As Integer = 0
	
			For i1 As Integer = 0 To p.noip-1
						' 入力パターンの設定
				Dim k1 As Integer = nou - noiu
				For i2 As Integer = 0 To noiu-1
					op(k1+i2) = p.iptn(i1,i2)
				Next
						' 出力の計算
				Forward()
						' 結果の表示
				If p_type <> 0 and pr > 0
	
					Console.Write("入力パターン" & (i1+1) & "   ")
					For i2 As Integer = 0 To noiu-1
						Console.Write(" " & op(k1+i2))
						If i2 = noiu-1
							Console.WriteLine()
						Else
							If ((i2+1) Mod 10) = 0
								Console.WriteLine()
								Console.Write("                   ")
							End If
						End If
					Next
	
					Console.WriteLine()
					Console.Write("    出力パターン(理想)  ")
					For i2 As Integer = 0 To noou-1
						Console.Write(" " & p.optn(i1,i2))
						If i2 = noou-1
							Console.WriteLine()
						Else
							If((i2+1) Mod 5) = 0
								Console.WriteLine()
								Console.Write("                        ")
							End If
						End If
					Next
				End If
	
				Dim sw As Integer = 0
				If p_type <> 0 and pr > 0
					Console.Write("                (実際)  ")
				End If
				For i2 As Integer = 0 To noou-1
					If p_type <> 0 and pr > 0
						Console.Write(" " & op(i2))
						If i2 = noou-1
							Console.WriteLine()
						Else
							If ((i2+1) Mod 5) = 0
								Console.WriteLine()
								Console.Write("                        ")
							End If
						End If
					End If
					If Math.Abs(op(i2)-p.optn(i1,i2)) > eps
						sw = 1
					End If
				Next
	
				If sw > 0
					No += 1
				End If
	
				If p_type < 0 and pr > 0
	
					OUT.Write("入力パターン" & (i1+1) & "   ")
					For i2 As Integer = 0 To noiu-1
						OUT.Write(" " & op(k1+i2))
						If i2 = noiu-1
							OUT.WriteLine()
						Else
							If ((i2+1) Mod 10) = 0
								OUT.WriteLine()
								OUT.Write("                   ")
							End If
						End If
					Next
	
					OUT.WriteLine()
					OUT.Write("    出力パターン(理想)  ")
					For i2 As Integer = 0 To noou-1
						OUT.Write(" " & p.optn(i1,i2))
						If i2 = noou-1
							OUT.WriteLine()
						Else
							If ((i2+1) Mod 5) = 0
								OUT.WriteLine()
								OUT.Write("                        ")
							End If
						End If
					Next
	
					OUT.Write("                (実際)  ")
					For i2 As Integer = 0 To noou-1
						OUT.Write(" " & op(i2))
						If i2 = noou-1
							OUT.WriteLine()
						Else
							If ((i2+1) Mod 5) = 0
								OUT.WriteLine()
								OUT.Write("                        ")
							End If
						End If
					Next
				End If
	
				If p_type <> 0 and pr > 0
					Console.ReadLine()
				End If
			Next
					'
					' 重みの出力
					'
			Dim ln As Integer
			If (p_type < -1 or p_type > 1) and pr = 1
	
				Console.WriteLine("    重み")
				For i1 As Integer = 0 To nou-noiu-1
					Console.Write("      to " & (i1+1) & " from  ")
					ln = -1
					For i2 As Integer = 0 To nou-1
						If con(i1,i2) > 0
							If ln <= 0
								If ln < 0
									ln = 0
								Else
									Console.WriteLine()
									Console.Write("                   ")
								End If
							End If
							Console.Write(" " & (i2+1) & " " & w(i1,i2))
							ln += 1
							If ln = 4
								ln = 0
							End If
						End If
					Next
	
					Console.WriteLine()
				Next
	
				Console.WriteLine()
				Console.Write("    バイアス  ")
				ln = 0
				For i1 As Integer = 0 To nou-noiu-1
					Console.Write(" " & (i1+1) & " " & theta(i1))
					ln += 1
					If ln = 4 and i1 <> nou-noiu-1
						ln = 0
						Console.WriteLine()
						Console.Write("              ")
					End If
				Next
	
				If ln <> 0
					Console.WriteLine()
				End If
	
				Console.ReadLine()
			End If
	
			If p_type < 0 and pr = 1
	
				OUT.WriteLine("    重み")
				For i1 As Integer = 0 To nou-noiu-1
					OUT.Write("      to " & (i1+1) & " from  ")
					ln = -1
					For i2 As Integer = 0 To nou-1
						If con(i1,i2) > 0
							If ln <= 0
								If ln < 0
									ln = 0
								Else
									OUT.WriteLine()
									OUT.Write("                   ")
								End If
							End If
							OUT.Write(" " & (i2+1) & " " & w(i1,i2))
							ln += 1
							If ln = 4
								ln = 0
							End If
						End If
					Next
	
					OUT.WriteLine()
				Next
	
				OUT.WriteLine()
				OUT.Write("    バイアス  ")
				ln = 0
				For i1 As Integer = 0 To nou-noiu-1
					OUT.Write(" " & (i1+1) & " " & theta(i1))
					ln += 1
					If ln = 4 and i1 <> nou-noiu-1
						ln = 0
						OUT.WriteLine()
						OUT.WriteLine()
						OUT.Write("              ")
					End If
				Next
	
				If ln <> 0
					OUT.WriteLine()
				End If
			End If
	
			If p_type < 0 and pr > 0
				OUT.Close()
			End If
	
			Return No
		End Function
	End Class
End Module
/*
------------------------制御データ----------------
誤差 0.1 出力 -2 出力ファイル kekka
順番 0 η 0.5 α 0.8
画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300
------------------------構造データ----------------
入力ユニット数 2 出力ユニット数 1 関数タイプ 0
隠れ層の数 1 各隠れ層のユニット数(下から) 1
バイアス入力ユニット数 1
 ユニット番号:出力ユニットから順に番号付け
 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1]))
 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限)
1 -1 -0.05 0.05
接続方法の数 2
 ユニット番号:ユニットk1からk2を,k3からk4に接続
 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定
 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限)
3 4 1 2 1 -0.1 0.1
2 2 1 1 1 -0.1 0.1
------------------------学習データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
------------------------認識データ----------------
パターンの数 4 入力ユニット数 2 出力ユニット数 1
入力1 0 0
 出力1 0
入力2 0 1
 出力2 1
入力3 1 0
 出力3 1
入力4 1 1
 出力4 0
*/
			
| 情報学部 | 菅沼ホーム | 目次 | 索引 |