Option Explicit On Option Strict On Public Class Form1 Private Structure SAKUZU '作図用データ構造体 Dim sxjiku As String 'x軸名 Dim syjiku As String 'y軸名 Dim xmin As Double 'x軸最小値 Dim xmax As Double 'x軸最大値 Dim dx As Double 'x軸増分 Dim ymin As Double 'y軸最小値 Dim ymax As Double 'y軸最大値 Dim dy As Double 'y軸増分 Dim kxi0 As Integer 'x軸最小値座標(px) Dim kxf0 As Integer 'x軸最大値座標(px) Dim kyi0 As Integer 'y軸最小値座標(px) Dim kyf0 As Integer 'y軸最大値座標(px) Dim HSIZE As Integer '画像横寸法 Dim DHL As Integer '画像左余白(縦軸描画スペース:px) Dim DHR As Integer '画像右余白(px) Dim VSIZE As Integer '画像縦サイズ(px) Dim DVL As Integer '画像下余白(横軸描画スペース:px) Dim DVU As Integer '画像上余白(px) End Structure Private Sub ToolStripButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click Call main() End Sub Private Sub main() 'Simplex法による任意曲線回帰 Dim fname As String '入力データファイルの一部指定 Dim fname1 As String = "" '入力データファイル名 Dim fname2 As String = "" '回帰係数出力データファイル名 Dim fname3 As String = "" '画像出力データファイル名 Dim scom As String = "" 'データファイルコメント Dim NDATA As Integer 'データ個数−1 Dim datax(0) As Double 'データx値 Dim datay(0) As Double 'データy値 Dim MPARA As Integer '回帰係数の数 Dim parameter() As Double '回帰係数 Dim iteration As Integer '繰り返し回数(上限は10万回) Dim iflag As Integer '収束・未収束判定(収束:0,未収束:1) Dim pltdata As SAKUZU '作図用データ構造体 'pltdata初期化 pltdata.sxjiku = "" 'x軸名 pltdata.syjiku = "" 'y軸名 pltdata.xmin = 0.0 'x軸最小値 pltdata.xmax = 0.0 'x軸最大値 pltdata.dx = 0.0 'x軸増分 pltdata.ymin = 0.0 'y軸最小値 pltdata.ymax = 0.0 'y軸最大値 pltdata.dy = 0.0 'y軸増分 pltdata.kxi0 = 0 'x軸最小値座標(px) pltdata.kxf0 = 0 'x軸最大値座標(px) pltdata.kyi0 = 0 'y軸最小値座標(px) pltdata.kyf0 = 0 'y軸最大値座標(px) pltdata.HSIZE = 0 '画像横寸法 pltdata.DHL = 0 '画像左余白(縦軸描画スペース:px) pltdata.DHR = 0 '画像右余白(px) pltdata.VSIZE = 0 '画像縦サイズ(px) pltdata.DVL = 0 '画像下余白(横軸描画スペース:px) pltdata.DVU = 0 '画像上余白(px) '******************************************************* '入力ファイル名指定 '******************************************************* MPARA = MPARA_SET() '回帰係数の数 ReDim parameter(MPARA - 1) OpenFileDialog1.InitialDirectory = System.IO.Directory.GetCurrentDirectory() If OpenFileDialog1.ShowDialog() = DialogResult.OK Then fname1 = OpenFileDialog1.FileName If SaveFileDialog1.ShowDialog() = DialogResult.OK Then fname2 = SaveFileDialog1.FileName fname = System.IO.Path.GetFileNameWithoutExtension(fname2) fname3 = System.IO.Path.GetDirectoryName(fname2) & "\" & fname & ".png" 'データ入力 Call INPDAT(fname1, scom, pltdata, NDATA, datax, datay) '回帰係数計算 Call Simplex(NDATA, datax, datay, MPARA, parameter, iteration, iflag) '回帰係数出力 Call OUTDAT(fname2, scom, iflag, iteration, MPARA, parameter) '画像出力 Call OUTFIG(fname3, scom, pltdata, NDATA, datax, datay, parameter) 'MessageBoxへの回帰係数の表示 Call OUTVIEW(scom, iflag, iteration, MPARA, parameter) End Sub Private Function MPARA_SET() As Integer '***************************************************** 'パラメータ数:MPARA(ここでは変数MPARA_SET)のセット '***************************************************** MPARA_SET = 5 'MPARA_SET = 4 End Function Private Function Vfunc(ByVal x As Double, ByRef parameter() As Double) As Double '********************************************** '関数値Vfuncの定義・計算 'parameter(i):回帰係数(i=0〜MPARA-1) '********************************************** 'パソコンによるデータ解析入門p236(MPARA = 5) Dim gamma2 As Double Dim dx As Double gamma2 = parameter(1) * parameter(1) dx = x - parameter(0) Vfunc = parameter(2) * gamma2 / (dx * dx + gamma2) + parameter(3) + parameter(4) * x '減衰振動(MPARA=4) 'Vfunc = parameter(0) * Math.Exp(-parameter(1) * x) * Math.Sin(parameter(2) * x + parameter(3)) End Function Private Sub INIVAL(ByVal MPARA As Integer, ByRef vertex(,) As Double, ByRef stepsize() As Double, ByRef tolerance() As Double) '******************************************* '解析パラメ-タ初期値等入力(0〜MPARA-1) 'vertex:初期値 'stepsize:初期の検索ステップ 'tolerance:収束判定基準 '******************************************* Dim j As Integer For j = 0 To MPARA - 1 vertex(0, j) = 1.0 : stepsize(j) = 0.1 * vertex(0, j) : tolerance(j) = 0.000001 Next j End Sub Private Sub INPDAT(ByVal fname1 As String, ByRef scom As String, ByRef pltdata As SAKUZU, _ ByRef NDATA As Integer, ByRef datax() As Double, ByRef datay() As Double) Dim sr As System.IO.StreamReader Dim dat As String Dim sbuf() As String Dim delim() As Char = {","c} sr = New System.IO.StreamReader(fname1, System.Text.Encoding.Default) dat = sr.ReadLine() : sbuf = dat.Split(delim) : scom = sbuf(0) dat = sr.ReadLine() : sbuf = dat.Split(delim) : pltdata.sxjiku = sbuf(0) : pltdata.syjiku = sbuf(1) dat = sr.ReadLine() : sbuf = dat.Split(delim) : pltdata.HSIZE = CInt(sbuf(0)) : pltdata.DHL = CInt(sbuf(1)) : pltdata.DHR = CInt(sbuf(2)) dat = sr.ReadLine() : sbuf = dat.Split(delim) : pltdata.VSIZE = CInt(sbuf(0)) : pltdata.DVL = CInt(sbuf(1)) : pltdata.DVU = CInt(sbuf(2)) dat = sr.ReadLine() : sbuf = dat.Split(delim) : pltdata.xmin = CDbl(sbuf(0)) : pltdata.xmax = CDbl(sbuf(1)) : pltdata.dx = CDbl(sbuf(2)) dat = sr.ReadLine() : sbuf = dat.Split(delim) : pltdata.ymin = CDbl(sbuf(0)) : pltdata.ymax = CDbl(sbuf(1)) : pltdata.dy = CDbl(sbuf(2)) dat = sr.ReadLine() : sbuf = dat.Split(delim) : NDATA = CInt(sbuf(0)) - 1 ReDim datax(NDATA) ReDim datay(NDATA) For i = 0 To NDATA dat = sr.ReadLine() : sbuf = dat.Split(delim) datax(i) = CDbl(sbuf(0)) datay(i) = CDbl(sbuf(1)) Next i sr.Close() End Sub Private Sub OUTDAT(ByVal fname2 As String, ByVal scom As String, _ ByVal iflag As Integer, ByVal iteration As Integer, _ ByVal MPARA As Integer, ByRef parameter() As Double) Dim sw As System.IO.StreamWriter sw = New System.IO.StreamWriter(fname2, False, System.Text.Encoding.Default) sw.WriteLine(scom) sw.WriteLine("iflag=," & CStr(iflag)) sw.WriteLine("iteration=," & CStr(iteration)) sw.WriteLine("MPARA=," & CStr(MPARA)) For i = 0 To MPARA - 1 sw.WriteLine("parameter(" & CInt(i) & ")=," & parameter(i).ToString("E6")) Next i sw.Close() End Sub Private Sub OUTVIEW(ByVal scom As String, ByVal iflag As Integer, ByVal iteration As Integer, _ ByVal MPARA As Integer, ByRef parameter() As Double) Dim dat As String dat = scom & ControlChars.CrLf dat = dat & "iflag=" & CStr(iflag) & ControlChars.CrLf dat = dat & "iteration=" & CStr(iteration) & ControlChars.CrLf dat = dat & "MPARA=" & CStr(MPARA) & ControlChars.CrLf For i = 0 To MPARA - 1 dat = dat & "parameter(" & CInt(i) & ")=" & parameter(i).ToString("E6") & ControlChars.CrLf Next i MessageBox.Show(dat, "計算結果表示") End Sub Private Sub Simplex(ByVal NDATA As Integer, ByRef datax() As Double, ByRef datay() As Double, _ ByVal MPARA As Integer, ByRef parameter() As Double, ByRef iteration As Integer, ByRef iflag As Integer) Dim vertex(MPARA, MPARA - 1) As Double Dim criterion(MPARA) As Double Dim stepsize(MPARA - 1) As Double Dim tolerance(MPARA - 1) As Double Dim s As Double Dim v1 As Double Dim v2 As Double Dim cr As Double Dim v As Double Dim vmax As Double Dim vmin As Double Dim vsum As Double Dim p As Double Dim x As Double Dim y As Double Dim i As Integer Dim j As Integer Dim k As Integer Dim kworst As Integer Dim kbest As Integer Dim ks As Integer Call INIVAL(MPARA, vertex, stepsize, tolerance) s = Math.Sqrt(0.5) v1 = s * (Math.Sqrt(CDbl(MPARA + 1)) - 1.0) / CDbl(MPARA) For j = 0 To MPARA - 1 v2 = vertex(0, j) + v1 * stepsize(j) For k = 1 To MPARA vertex(k, j) = v2 Next k vertex(j + 1, j) = v2 + s * stepsize(j) Next j For k = 0 To MPARA For j = 0 To MPARA - 1 parameter(j) = vertex(k, j) Next j cr = 0 'Vcrit-Start For i = 0 To NDATA x = datax(i) y = Vfunc(x, parameter) cr = cr + (y - datay(i)) * (y - datay(i)) Next i 'Vcrit-End criterion(k) = cr Next k iteration = 0 Do While iteration <= 100000 iteration = iteration + 1 kworst = 0 : kbest = 0 For k = 1 To MPARA If criterion(k) > criterion(kworst) Then kworst = k If criterion(k) < criterion(kbest) Then kbest = k Next k iflag = 0 For j = 0 To MPARA - 1 vmax = vertex(0, j) : vmin = vmax For k = 1 To MPARA v = vertex(k, j) If v >= vmax Then vmax = v If v < vmin Then vmin = v Next k If vmax - vmin > tolerance(j) Then iflag = 1 Next j If iflag = 0 Then Exit Do For j = 0 To MPARA - 1 vsum = 0 For k = 0 To MPARA If k <> kworst Then vsum = vsum + vertex(k, j) Next k parameter(j) = 2 * vsum / MPARA - vertex(kworst, j) Next j cr = 0 'Vcrit-Start For i = 0 To NDATA x = datax(i) y = Vfunc(x, parameter) cr = cr + (y - datay(i)) * (y - datay(i)) Next i 'Vcrit-End If cr < criterion(kbest) Then ks = 0 If criterion(kbest) <= cr And cr <= criterion(kworst) Then ks = 1 If criterion(kworst) < cr Then ks = 2 Select Case ks Case 0 For j = 0 To MPARA - 1 p = 1.5 * parameter(j) - 0.5 * vertex(kworst, j) vertex(kworst, j) = parameter(j) parameter(j) = p Next j criterion(kworst) = cr cr = 0 'Vcrit-Start For i = 0 To NDATA x = datax(i) y = Vfunc(x, parameter) cr = cr + (y - datay(i)) * (y - datay(i)) Next i 'Vcrit-End If cr < criterion(kworst) Then For j = 0 To MPARA - 1 'REPLACE-Start vertex(kworst, j) = parameter(j) Next j criterion(kworst) = cr 'REPLACE-End End If Case 1 For j = 0 To MPARA - 1 'REPLACE-Start vertex(kworst, j) = parameter(j) Next j criterion(kworst) = cr 'REPLACE-End Case 2 For j = 0 To MPARA - 1 parameter(j) = 0.75 * vertex(kworst, j) + 0.25 * parameter(j) Next j cr = 0 'Vcrit-Start For i = 0 To NDATA x = datax(i) y = Vfunc(x, parameter) cr = cr + (y - datay(i)) * (y - datay(i)) Next i 'Vcrit-End If cr < criterion(kworst) Then For j = 0 To MPARA - 1 'REPLACE-Start vertex(kworst, j) = parameter(j) Next j criterion(kworst) = cr 'REPLACE-End Else For k = 0 To MPARA If k <> kbest Then For j = 0 To MPARA - 1 parameter(j) = 0.5 * (vertex(k, j) + vertex(kbest, j)) vertex(k, j) = parameter(j) Next j cr = 0 'Vcrit-Start For i = 0 To NDATA x = datax(i) y = Vfunc(x, parameter) cr = cr + (y - datay(i)) * (y - datay(i)) Next i 'Vcrit-End criterion(k) = cr End If Next k End If End Select Loop For j = 0 To MPARA - 1 parameter(j) = vertex(kbest, j) Next j End Sub Private Sub OUTFIG(ByVal fname3 As String, ByVal scom As String, ByRef pltdata As SAKUZU, _ ByVal NDATA As Integer, ByRef datax() As Double, ByRef datay() As Double, _ ByRef parameter() As Double) Dim i As Integer Dim bmp As Bitmap Dim g As Graphics Dim nd As Integer Dim kpt As Integer Dim thePicBox As PictureBox = PictureBox1 nd = NDATA 'プロット領域定義 pltdata.kxi0 = pltdata.DHL pltdata.kxf0 = pltdata.HSIZE - pltdata.DHR pltdata.kyi0 = pltdata.DVU pltdata.kyf0 = pltdata.VSIZE - pltdata.DVL For i = 0 To 1 Select Case i Case 0 '画面出力 kpt = 1 thePicBox = PictureBox1 thePicBox.Visible = True Case 1 '画像出力(ファイル:fname3,png形式) kpt = 2 thePicBox = PictureBox2 thePicBox.Visible = False End Select thePicBox.Size = New Size(kpt * pltdata.HSIZE, kpt * pltdata.VSIZE) bmp = New Bitmap(thePicBox.Width, thePicBox.Height) thePicBox.Image = bmp g = Graphics.FromImage(thePicBox.Image) g.FillRectangle(Brushes.White, 0, 0, thePicBox.Width, thePicBox.Height) Call PLOT(g, kpt, pltdata, nd, datax, datay, parameter, scom) g.Dispose() Next i PictureBox1.Left = 0 PictureBox1.Top = ToolStrip1.Height Me.ClientSize = New Size(PictureBox1.Width, PictureBox1.Height + ToolStrip1.Height) PictureBox2.Image.Save(fname3, System.Drawing.Imaging.ImageFormat.Png) End Sub Private Sub PLOT(ByVal g As Graphics, ByVal kpt As Integer, ByVal pltdata As SAKUZU, _ ByVal nd As Integer, ByRef datax() As Double, ByRef datay() As Double, ByRef parameter() As Double, _ ByVal scom As String) Dim i As Integer Dim kxi As Integer : Dim kxf As Integer Dim kyi As Integer : Dim kyf As Integer Dim xx As Double : Dim yy As Double Dim kxx As Integer : Dim kyy As Integer Dim kxx1 As Integer : Dim kyy1 As Integer Dim kxx2 As Integer : Dim kyy2 As Integer Dim str As String Dim dc As Integer Dim f As New Font("MS ゴシック", kpt * 10) Dim TextSize1 As New System.Drawing.SizeF Dim TextSize2 As New System.Drawing.SizeF kxi = kpt * pltdata.kxi0 : kxf = kpt * pltdata.kxf0 kyi = kpt * pltdata.kyi0 : kyf = kpt * pltdata.kyf0 '普通座標軸 Dim LPen As New System.Drawing.Pen(System.Drawing.Color.Black) LPen.DashStyle = Drawing2D.DashStyle.Dot Call DRN_XJIKU(g, f, LPen, kpt, pltdata.xmin, pltdata.xmax, pltdata.dx, kxi, kxf, kyi, kyf) Call DRN_YJIKU(g, f, LPen, kpt, pltdata.ymin, pltdata.ymax, pltdata.dy, kxi, kxf, kyi, kyf) '枠線描画 g.DrawRectangle(New Pen(Color.Black, 2), kxi, kyi, kxf - kxi, kyf - kyi) 'コメント描画 str = scom TextSize1 = g.MeasureString(str, f) g.DrawString(str, f, Brushes.Black, kxf - TextSize1.Width - kpt * 2, kyi - TextSize1.Height - 2 * kpt) 'y軸名描画 str = pltdata.syjiku TextSize1 = g.MeasureString("-1.0", f) TextSize2 = g.MeasureString(str, f) kxx = CInt(kxi - kpt * 15 - TextSize1.Width - TextSize2.Height) kyy = CInt((kyi + kyf) / 2 + TextSize2.Width / 2) Call INC_STR(g, f, str, kxx, kyy, -90) 'x軸名描画 str = pltdata.sxjiku TextSize2 = g.MeasureString(str, f) kxx = CInt((kxi + kxf) / 2 - TextSize2.Width / 2) kyy = CInt(kyf + kpt * 10 + TextSize1.Height) Call INC_STR(g, f, str, kxx, kyy, 0) 'データプロット If kyf - kyi < kxf - kxi Then dc = CInt(kpt * (kyf - kyi) / 100) Else dc = CInt(kpt * (kxf - kxi) / 100) End If For i = 0 To nd xx = datax(i) yy = datay(i) kxx = kxi + CInt((xx - pltdata.xmin) * (kxf - kxi) / (pltdata.xmax - pltdata.xmin)) - CInt(dc / 2) kyy = kyf - CInt((yy - pltdata.ymin) * (kyf - kyi) / (pltdata.ymax - pltdata.ymin)) - CInt(dc / 2) g.DrawEllipse(New Pen(Color.Red, 2), kxx, kyy, dc, dc) Next '回帰曲線 Dim nn As Integer = 100 xx = pltdata.xmin yy = Vfunc(xx, parameter) kxx1 = kxi + CInt((xx - pltdata.xmin) * (kxf - kxi) / (pltdata.xmax - pltdata.xmin)) kyy1 = kyf - CInt((yy - pltdata.ymin) * (kyf - kyi) / (pltdata.ymax - pltdata.ymin)) For i = 1 To nn xx = pltdata.xmin + (pltdata.xmax - pltdata.xmin) / CDbl(nn) * CDbl(i) yy = Vfunc(xx, parameter) kxx2 = kxi + CInt((xx - pltdata.xmin) * (kxf - kxi) / (pltdata.xmax - pltdata.xmin)) kyy2 = kyf - CInt((yy - pltdata.ymin) * (kyf - kyi) / (pltdata.ymax - pltdata.ymin)) g.DrawLine(New Pen(Color.Blue, 1), kxx1, kyy1, kxx2, kyy2) kxx1 = kxx2 kyy1 = kyy2 Next i f.Dispose() End Sub Private Sub INC_STR(ByVal g As Graphics, ByVal f As System.Drawing.Font, ByVal str As String, _ ByVal kxx As Integer, ByVal kyy As Integer, ByVal ang As Single) '軸名描画 g.ScaleTransform(1.0, 1.0) '横・縦の表示比率を設定 g.TranslateTransform(kxx, kyy) '表示位置の設定(表示位置を原点とする座標移動) g.RotateTransform(ang) '表示角度を指定 g.DrawString(str, f, Brushes.Black, 0, 0) '描画実行 g.ResetTransform() '単位行列にリセット End Sub Private Sub DRN_XJIKU(ByVal g As Graphics, ByVal f As System.Drawing.Font, ByVal LPen As System.Drawing.Pen, _ ByVal kpt As Integer, _ ByVal xmin As Double, ByVal xmax As Double, ByVal dx As Double, _ ByVal kxi As Integer, ByVal kxf As Integer, _ ByVal kyi As Integer, ByVal kyf As Integer) Dim i As Integer Dim ix As Integer Dim xx As Double Dim wv As Double Dim str As String Dim kxx As Integer Dim TextSize1 As New System.Drawing.SizeF '普通x軸描画 ix = CInt((xmax - xmin) / dx) For i = 0 To ix xx = xmin + CDbl(i) * dx kxx = kxi + CInt((xx - xmin) * (kxf - kxi) / (xmax - xmin)) wv = xmin + CDbl(i) * dx str = wv.ToString("0") If CInt(dx * 1000.0) Mod 10 <> 0 Then str = wv.ToString("0.000") If CInt(dx * 1000.0) Mod 10 = 0 And CInt(dx * 100.0) Mod 10 <> 0 Then str = wv.ToString("0.00") If (CInt(dx * 1000.0) Mod 10 = 0 And CInt(dx * 100.0) Mod 10 = 0) And CInt(dx * 10.0) Mod 10 <> 0 Then str = wv.ToString("0.0") TextSize1 = g.MeasureString(str, f) g.DrawLine(LPen, kxx, kyi, kxx, kyf) g.DrawString(str, f, Brushes.Black, kxx - TextSize1.Width / 2, kyf + kpt * 3) Next i End Sub Private Sub DRN_YJIKU(ByVal g As Graphics, ByVal f As System.Drawing.Font, ByVal LPen As System.Drawing.Pen, _ ByVal kpt As Integer, _ ByVal ymin As Double, ByVal ymax As Double, ByVal dy As Double, _ ByVal kxi As Integer, ByVal kxf As Integer, _ ByVal kyi As Integer, ByVal kyf As Integer) Dim i As Integer Dim iy As Integer Dim yy As Double Dim wv As Double Dim str As String Dim kyy As Integer Dim TextSize1 As New System.Drawing.SizeF '普通y軸描画 iy = CInt((ymax - ymin) / dy) For i = 0 To iy yy = ymin + CDbl(i) * dy kyy = kyf - CInt((yy - ymin) * (kyf - kyi) / (ymax - ymin)) wv = ymin + CDbl(i) * dy str = wv.ToString("0") If CInt(dy * 1000.0) Mod 10 <> 0 Then str = wv.ToString("0.000") If CInt(dy * 1000.0) Mod 10 = 0 And CInt(dy * 100.0) Mod 10 <> 0 Then str = wv.ToString("0.00") If (CInt(dy * 1000.0) Mod 10 = 0 And CInt(dy * 100.0) Mod 10 = 0) And CInt(dy * 10.0) Mod 10 <> 0 Then str = wv.ToString("0.0") TextSize1 = g.MeasureString(str, f) g.DrawLine(LPen, kxi, kyy, kxf, kyy) g.DrawString(str, f, Brushes.Black, kxi - TextSize1.Width - kpt * 2, kyy - TextSize1.Height / 2) Next i End Sub End Class