2009年12月15日火曜日

XSLT で 3元連立方程式を解いてみる

XSLT で 3元連立方程式を解いてみる。

3変数の式3本を、こんな風にXMLで表すとする。(例は手元の本とネットの数学記事から持ってきた。)
例1
x + y + z = 1
2x - y + 2z = -1
x + 2y + 3z = 0
<vec-expr>
<x>1</x><x>2</x><x>1</x>
<y>1</y><y>-1</y><y>2</y>
<z>1</z><z>2</z><z>3</z>
<p>1</p><p>-1</p><p>0</p>
</vec-expr>
例2
x + 2y + 3z = 10
4x + 7y + 8z = 12
5x + 6y + 9z = 11
<vec-expr>
<x>1</x><x>4</x><x>5</x>
<y>2</y><y>7</y><y>6</y>
<z>3</z><z>8</z><z>9</z>
<p>10</p><p>12</p><p>11</p>
</vec-expr>

この XML を読み込んで、x, y, z を求める XSLT を定義したい。解き方はクラメールの公式を使うことにする。なので行列式を計算するテンプレートが必要になるが、これを別の XSL ファイル(determinant.xsl)に分けてみる。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="calc-det-recur">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:param name="c"/>
<xsl:param name="n" select="3"/>
<xsl:choose>
<xsl:when test="0 &lt; $n">
<xsl:variable name="rec-result">
<xsl:call-template name="calc-det-recur">
<xsl:with-param name="a" select="$a"/>
<xsl:with-param name="b" select="$b"/>
<xsl:with-param name="c" select="$c"/>
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="plus-term"
select="$a[$n] * ($b[$n mod 3 +1]) * ($c[($n +1) mod 3 +1])"/>
<xsl:variable name="minus-term"
select="$a[$n] * ($b[($n +1) mod 3 +1]) * ($c[$n mod 3 +1])"/>
<xsl:value-of select="$rec-result + $plus-term - $minus-term"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

この XSLT を用いて、x, y, z それぞれの係数および右辺を表すベクトルを組み合わせて、必要な行列式を計算し、各変数の解を求める XML を、以下のように別途記述する。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="determinant.xsl"/>

<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

<xsl:template match="vec-expr">
<xsl:variable name="xyz">
<xsl:call-template name="calc-det-recur">
<xsl:with-param name="a" select="x"/>
<xsl:with-param name="b" select="y"/>
<xsl:with-param name="c" select="z"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="pyz">
<xsl:call-template name="calc-det-recur">
<xsl:with-param name="a" select="p"/>
<xsl:with-param name="b" select="y"/>
<xsl:with-param name="c" select="z"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="xpz">
<xsl:call-template name="calc-det-recur">
<xsl:with-param name="a" select="x"/>
<xsl:with-param name="b" select="p"/>
<xsl:with-param name="c" select="z"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="xyp">
<xsl:call-template name="calc-det-recur">
<xsl:with-param name="a" select="x"/>
<xsl:with-param name="b" select="y"/>
<xsl:with-param name="c" select="p"/>
</xsl:call-template>
</xsl:variable>

<xsl:text>x=</xsl:text><xsl:value-of select="$pyz div $xyz"/>
<xsl:text>&#010;</xsl:text>
<xsl:text>y=</xsl:text><xsl:value-of select="$xpz div $xyz"/>
<xsl:text>&#010;</xsl:text>
<xsl:text>z=</xsl:text><xsl:value-of select="$xyp div $xyz"/>
<xsl:text>&#010;&#010;</xsl:text>
</xsl:template>
</xsl:stylesheet>
冒頭の例を入力XMLとして与えて実行すると、以下のような結果を得る

例1例2
x=1
y=1
z=-1
x=-9.5
y=-1.2
z=7.3

0 件のコメント:

コメントを投稿