定数係数1階線形常微分方程式
1 // <APPLET code="ODE1.class" width=500 height=500> </APPLET> 2 3 import java.applet.*; 4 import java.awt.*; 5 import java.awt.event.*; 6 7 class GraphCanvas extends Canvas { 8 9 static final boolean DEBUG = false; // true; 10 private static final String message = "graph of a function with 1 variable"; 11 // 問題に取って基本的なパラメーター 12 // 係数行列 13 private double a, b, c, d; 14 // 描画範囲 15 private double x_max = 1.0; 16 private double x_min = - 1.0; 17 private double x_margin = (x_max - x_min) / 10; 18 private double y_max = 1.0; 19 private double y_min = - 1.0; 20 private double y_margin = (y_max - y_min) / 10; 21 22 // 座標系の変換のためのパラメーター 23 private int CanvasX = 400, CanvasY = 400; 24 private double ratiox, ratioy, X0, Y0; 25 26 // コンストラクター 27 public GraphCanvas() { 28 super(); 29 } 30 public GraphCanvas(int cx, int cy) { 31 super(); 32 CanvasX = cx; CanvasY = cy; 33 } 34 35 public void compute(double A, double B, double C, double D) { 36 a = A; b = B; c = C; d = D; 37 repaint(); 38 } 39 40 private boolean IsIn(double x, double y) { 41 return (x_min <= x && x <= x_max && y_min <= y && y <= y_max); 42 } 43 // 座標変換の準備 44 private void space(double x0, double y0, double x1, double y1) { 45 X0 = x0; Y0 = y0; 46 ratiox = CanvasX / (x1 - x0); 47 ratioy = CanvasY / (y1 - y0); 48 } 49 // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) 50 private int wx(double x) { 51 return (int)(ratiox * (x - X0)); 52 } 53 // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) 54 private int wy(double y) { 55 return CanvasY - (int)(ratioy * (y - Y0)); 56 } 57 // 力学系の右辺 f=(fx, fy) 58 private double fx(double x, double y) { 59 return a * x + b * y; 60 } 61 private double fy(double x, double y) { 62 return c * x + d * y; 63 } 64 // x[], y[] の内容をグラフにする 65 private void drawGraph(Graphics g, double x0, double y0, double T) { 66 double h = 0.01 / Math.sqrt(a * a + b * b + c * c + d * d); 67 if (T < 0.0) 68 h = - h; 69 int iter = (int)Math.rint(Math.abs(T / h)); 70 double x = x0; 71 double y = y0; 72 double new_x, new_y; 73 for (int i = 0; i <= iter; i++) { 74 double k1x = h * fx(x, y); 75 double k1y = h * fy(x, y); 76 double k2x = h * fx(x + k1x / 2, y + k1y / 2); 77 double k2y = h * fy(x + k1x / 2, y + k1y / 2); 78 double k3x = h * fx(x + k2x / 2, y + k2y / 2); 79 double k3y = h * fy(x + k2x / 2, y + k2y / 2); 80 double k4x = h * fx(x + k3x, y + k3y); 81 double k4y = h * fy(x + k3x, y + k3y); 82 new_x = x + (k1x + 2 * k2x + 2 * k3x + k4x) / 6; 83 new_y = y + (k1y + 2 * k2y + 2 * k3y + k4y) / 6; 84 if (IsIn(x, y) && IsIn(new_x, new_y)) 85 g.drawLine(wx(x), wy(y), wx(new_x), wy(new_y)); 86 x = new_x; y = new_y; 87 } 88 } 89 90 public void paint(Graphics g) { 91 // 92 space(x_min - x_margin, y_min - y_margin, 93 x_max + x_margin, y_max + y_margin); 94 // 95 setBackground(Color.blue); 96 // 97 g.setColor(Color.black); 98 g.drawLine(wx(x_min), wy(0.0), wx(x_max), wy(0.0)); 99 g.drawLine(wx(0.0), wy(y_min), wx(0.0), wy(y_max)); 100 // 101 g.setColor(Color.yellow); 102 int n = 36; 103 double dt = 2 * Math.PI / n; 104 double Time = 10.0 / Math.sqrt(a * a + b * b + c * c + d * d); 105 for (int i = 0; i < n; i++) { 106 double t = i * dt; 107 drawGraph(g, Math.cos(t), Math.sin(t), Time); 108 drawGraph(g, Math.cos(t), Math.sin(t), - Time); 109 } 110 } 111 } 112 113 public class ODE1 extends Applet implements ActionListener { 114 115 private int N = 20; 116 private double lambda = 0.5; 117 private double Tmax = 0.5; 118 // ユーザーとのインターフェイス (パラメーターの入力) 119 private Label label_a, label_b, label_c, label_d; 120 private TextField input_a, input_b, input_c, input_d; 121 private double a, b, c, d; 122 private Button startB; 123 // 124 private GraphCanvas gc; 125 126 private void ReadFields() { 127 a = Double.valueOf(input_a.getText()).doubleValue(); 128 b = Double.valueOf(input_b.getText()).doubleValue(); 129 c = Double.valueOf(input_c.getText()).doubleValue(); 130 d = Double.valueOf(input_d.getText()).doubleValue(); 131 } 132 // 準備 (変数の用意と座標系の初期化など) 133 public void init() { 134 // ナル・レイアウト 135 setLayout(null); 136 // a, b, c, d を入力するためのテキスト・フィールド 137 add(label_a = new Label("a=")); label_a.setBounds(100, 30, 40, 30); 138 add(label_b = new Label("b=")); label_b.setBounds(250, 30, 40, 30); 139 add(label_c = new Label("c=")); label_c.setBounds(100, 70, 40, 30); 140 add(label_d = new Label("d=")); label_d.setBounds(250, 70, 40, 30); 141 add(input_a = new TextField("" + 1)); input_a.setBounds(150, 30, 100, 30); 142 add(input_b = new TextField("" + 0)); input_b.setBounds(300, 30, 100, 30); 143 add(input_c = new TextField("" + 0)); input_c.setBounds(150, 70, 100, 30); 144 add(input_d = new TextField("" + 1)); input_d.setBounds(300, 70, 100, 30); 145 // 再計算ボタン 146 startB = new Button("Restart"); 147 add(startB); 148 startB.setBounds(420, 45, 50, 30); 149 startB.addActionListener(this); 150 151 // キャンバス 152 gc = new GraphCanvas(); 153 add(gc); 154 gc.setBounds(50, 100, 400, 400); 155 ReadFields(); 156 gc.compute(a, b, c, d); 157 } 158 159 // ボタンを押されたら、テキスト・フィールドの内容を読み取って、再描画 160 public void actionPerformed(ActionEvent e) { 161 if (e.getSource() == startB) { 162 ReadFields(); 163 gc.compute(a, b, c, d); 164 } 165 } 166 }
Java をサポートしたブラウザーで次のページにアクセスすると実行できる。