private static void EasyParse_addfactor(ref Rational r, Gen::Dictionary <string, int> dic, string w, char mode) { try{ long val = long.Parse(w); if (mode == '/') { r /= val; } else { r *= val; } }catch { int exp = mode == '/'?-1:1; if (!dic.ContainsKey(w)) { dic[w] = exp; } else { if ((dic[w] += exp) == 0) { dic.Remove(w); } } } }
/// <summary> /// 行基本変形による頭の単位化を実行します。 /// </summary> /// <returns>Rank を返します。</returns> internal int _Identicalize() { int cmin = System.Math.Min(height, width); bool[] sweeped = new bool[this.height]; for (int c = 0; c < cmin; c++) { // 列 c で最大の絶対値を持つ物 l_m Rational max = -1; int l_m = -1; for (int l = 0; l < height; l++) { Rational cand = Rational.Abs(vals[l, c]); if (!sweeped[l] && Rational.Abs(vals[l, c]) > max) { max = cand; l_m = l; } } if (vals[l_m, c].IsZero) { return(c); } // pivot[l_m,c] で掃き出し if (vals[l_m, c] != Rational.One) { lines.Divide(l_m, this.vals[l_m, c]); } for (int l = 0; l < height; l++) { if (l == l_m || vals[l, c].IsZero) { continue; } lines.SubtractLine(l, l_m, vals[l, c]); } sweeped[l_m] = true; } // 並び替え for (int c = 0; c < height; c++) { for (int l = c; l < height; l++) { if (vals[l, c] == Rational.One) { lines.ExchangeLines(l, c); break; } } } return(cmin); }
/// <summary> /// <paramref name="line1"/> から <paramref name="r"/> * <paramref name="line2"/> /// を引いた結果を <paramref name="line1"/> に格納します。 /// </summary> /// <param name="line1">引かれる側の行を指定します。</param> /// <param name="line2">引く側の行を指定します。</param> /// <param name="factor">line2 に掛ける倍率を指定します。</param> public void SubtractLine(int line1, int line2, Rational factor) { if (line1 < 0 || parent.height <= line1 || line2 < 0 || parent.height <= line2) { throw new System.ArgumentOutOfRangeException("line1,line2", "行番号が正しくありません。"); } for (int column = 0; column < parent.width; column++) { parent.vals[line1, column] -= factor * parent.vals[line2, column]; } }
public void Divide(int line, Rational value) { if (line < 0 || parent.height <= line) { throw new System.ArgumentOutOfRangeException("line", "行番号が正しくありません。"); } for (int column = 0; column < parent.width; column++) { parent.vals[line, column] /= value; } }
/// <summary> /// 簡単な文字列読み取りを実行します。 /// 正しくない文字列の読み取りを実行した場合の動作は未定です。 /// </summary> /// <param name="str">各変数を空白、'*'、'/' で区切ったリストを項の表現として渡します。</param> /// <returns>読み取った結果生成した文字列を返します。</returns> public static Member EasyParse(string str) { int i = 0; char mode = '*'; string w = ""; Rational r = 1; Gen::Dictionary <string, int> dic = new Gen::Dictionary <string, int>(); while (i < str.Length) { char c = str[i++]; // 文字分類 if (c <= ' ') { c = '*'; } else if (c == ':') { c = '/'; } // 読み取り if (c == '/' || c == '*') { // 変数の登録 if (w != "") { EasyParse_addfactor(ref r, dic, w, mode); } mode = c; w = ""; } else { w += c; } } // 変数の登録 if (w != "") { EasyParse_addfactor(ref r, dic, w, mode); } // Member 生成 Variable[] vars = new Variable[dic.Count]; i = 0; foreach (Gen::KeyValuePair <string, int> pair in dic) { vars[i++] = new Variable(pair.Key, pair.Value); } return(new Member(r, vars)); }
/// <summary> /// x[n] の式を生成します。 /// </summary> private void MainEquation() { Rational f = 1; string var = string.Format("f[{0}]", ORDER - 1); string exp = var; for (int i = 1; i < ORDER; i++) { f /= (i + 1); var = "h" + var + "'"; exp += "+" + f.ToString() + " " + var; } e_f = Expression.EasyParse(exp); }
public static string Calc1() { Rational hf = new Rational(1, 2); Matrix m = new Matrix(new ksh.Rational[, ] { { 1, new Rational(1, 2), 0, -1, 1 }, { 1, -new Rational(3, 2), -1, 1, 0 }, }); int cmin = System.Math.Min(m.Height, m.Width); bool[] sweeped = new bool[m.Height]; for (int c = 0; c < cmin; c++) { // 列 c で最大の絶対値を持つ物 l_m Rational max = -1; int l_m = -1; for (int l = 0; l < m.Height; l++) { Rational cand = Rational.Abs(m[l, c]); if (!sweeped[l] && Rational.Abs(m[l, c]) > max) { max = cand; l_m = l; } } if (m[l_m, c].IsZero) { continue; } if (m[l_m, c] != Rational.One) { m.Lines.Divide(l_m, m[l_m, c]); } for (int l = 0; l < m.Height; l++) { if (l == l_m || m[l, c].IsZero) { continue; } m.Lines.SubtractLine(l, l_m, m[l, c]); } sweeped[l_m] = true; } return(m.ToHtml()); }
/// <summary> /// 指定した行の内容を交換します。 /// </summary> /// <param name="line1">交換する行の一方を指定します。</param> /// <param name="line2">交換する行の他方を指定します。</param> public void ExchangeLines(int line1, int line2) { if (line1 < 0 || parent.height <= line1 || line2 < 0 || parent.height <= line2) { throw new System.ArgumentOutOfRangeException("line1,line2", "行番号が正しくありません。"); } if (line1 == line2) { return; } for (int column = 0; column < parent.width; column++) { Rational c = parent.vals[line1, column]; parent.vals[line1, column] = parent.vals[line2, column]; parent.vals[line2, column] = c; } }
//=========================================================== // 計算 //=========================================================== /// <summary> /// 式を生成します。 /// </summary> private void InitializeEquations() { string exp = "-f[{0}]+f[{1}]"; Rational f = 1; string var = "f[{1}]"; for (int i = 1; i < ORDER; i++) { f /= i; var = "h" + var + "'"; exp += "+" + f.ToString() + " " + var; } for (int i = ORDER - 2; i >= 0; i--) { equations[i] = Expression.EasyParse(string.Format(exp, i + 1, i)); } }
/// <summary> /// 式を f[n-1]^(m) で表し直します。 /// </summary> private void UpdatePastDifferentials() { build.Append("<ul>\r\n"); string var = "f[{0}]"; for (int n = 1; n < ORDER; n++) { var = "h" + var + "'"; // 代入する式の書式文字列を生成 Rational f2 = 1; string var2 = var; string exp2 = var; for (int m = 1; m < ORDER - n; m++) { f2 /= -m; var2 = "h" + var2 + "'"; exp2 += "+" + f2.ToString() + " " + var2; } // 式を表示 for (int i = 0; i <= ORDER - 2; i++) { string varname = string.Format(var, i); Expression x = Expression.EasyParse(string.Format(exp2, i + 1)); for (int j = 0; j < equations.Length; j++) { equations[j] = equations[j].Substitute(varname, x); } //---------- build.Append("<li>"); build.Append(Expression.EasyParse(varname).ToHtml(true)); build.Append(" = "); build.Append(x.ToHtml(true)); build.Append(" + O(h<sup>" + ORDER.ToString() + "</sup>)</li>\r\n"); } } build.Append("</ul>\r\n"); }
private Member(Rational r, Variable[] vars) { this.factor = r; this.vars = vars; }
private Member(Variable v) { this.factor = 1; this.vars = new Variable[] { v }; }
public Member(Rational r) { this.factor = r; this.vars = new Variable[0]; }
/// <summary> /// 単なる有理数を値に持つ Expression を初期化します。 /// </summary> /// <param name="r">Expression の値を有理数で指定します。</param> public Expression(Rational r) : this() { this.AddMember(new Member(r)); }
public static string InverseMatrix() { Matrix m = new Matrix(new ksh.Rational[, ] { { 3, 0, 2 }, { 5, 4, 6 }, { 2, 7, -4 }, }); System.Text.StringBuilder build = new System.Text.StringBuilder(); build.Append("<h1>逆行列の求め方</h1>\r\n"); build.Append("<p>以下の行列の逆行列を求めたいと思います。</p>\r\n"); build.Append("<p>" + m.ToHtml() + "</p>\r\n"); build.Append("<p>先ず右から単位行列をくっつけます。</p>\r\n"); m |= Matrix.Identical(m.Height); build.Append("<p>" + m.ToHtml() + "</p>\r\n"); bool[] sweeped = new bool[m.Height]; for (int c = 0; c < 3; c++) { // 列 c で最大の絶対値を持つ物 l_m (既に掃き出した物は除く) Rational max = -1; int l_m = -1; for (int l = 0; l < m.Height; l++) { Rational cand = Rational.Abs(m[l, c]); if (!sweeped[l] && Rational.Abs(m[l, c]) > max) { max = cand; l_m = l; } } if (m[l_m, c].IsZero) { build.Append("<p>やっぱり何だか求められない雰囲気です...</p>"); break; } build.AppendFormat("<p>({0},{1}) 成分に注目します。これが 1 に為る様に行全体を割り算します。</p>\r\n", l_m + 1, c + 1); if (m[l_m, c] == Rational.One) { build.Append("<p>(と思ったら、元から 1 でした...)</p>\r\n"); } else { m.Lines.Divide(l_m, m[l_m, c]); build.Append("<p>" + m.ToHtml() + "</p>\r\n"); } build.AppendFormat("<p>次に ({0},{1}) 成分を使って掃き出しを実行します。</p>\r\n", l_m + 1, c + 1); bool haki = false; for (int l = 0; l < m.Height; l++) { if (l == l_m || m[l, c].IsZero) { continue; } haki = true; build.AppendFormat("<p>{0} 行目から ({1} 行目)×{2} を引き去ります</p>\r\n", l + 1, l_m + 1, m[l, c].ToHtml()); m.Lines.SubtractLine(l, l_m, m[l, c]); build.Append("<p>" + m.ToHtml() + "</p>\r\n"); } if (!haki) { build.Append("<p>と思ったら、元から掃き出された形になっているので次に進みます。</p>\r\n"); } sweeped[l_m] = true; } return(build.ToString()); }