fortran66のブログ

fortran について書きます。

【メモ帳】

非結合代数と浮動小数点数

浮動小数点数では結合則が成り立たないわけですが、単位元は存在し、交換則も成り立つので、可換 Loop になっています。(ただし IEEE754 では NaN とか ±∞ が引っかかりますが)

https://upload.wikimedia.org/wikipedia/commons/d/d0/Magma_to_group2.svg
ja.wikipedia.org

よって、x + (x + y) = x + (y + x) = (x + y) + x = (y + x) + x が成り立ち、x + (y + x) = (x + y) + x のような弱い結合則が成立していて flexible algebra と呼ばれるものになっているようです。

しかし、なにか易しくて良い情報はないかと可換非結合代数 (commutative non-associative algebra) で検索しても大したものは引っかかりません。例外 Lie 群で二番目に簡単な F_4 群の所で出てくる Jordan 代数がまさに可換非結合代数になっていますが、この場合上記のものに加えて (xy)(xx) = x(y(xx)) という別の弱めた結合性が成り立っているので、あまり参考にならない気がします。

コンピュータ系の代数は(離散値を扱っているし)、普通の結合則から入れてゆく(上図の右側の道筋)形で話が進み、並列化などもその上に立脚していますが、浮動小数点数結合則が成り立たないので(上図の左側の道筋)、枠組みをよく考えなければならないのじゃないかと思います。(浮動小数点数では本質的に無理だとかw)

その数式、プログラムできますか?

その数式、プログラムできますか?

From Mathematics to Generic Programming (English Edition)

From Mathematics to Generic Programming (English Edition)

プログラミング原論

プログラミング原論

Elements of Programming

Elements of Programming

  • 作者: Alexander McJones, Paul Stepanov
  • 出版社/メーカー: Addison-Wesley Professional
  • 発売日: 2009/06/09
  • メディア: ハードカバー
  • 購入: 1人 クリック: 3回
  • この商品を含むブログを見る

Will C++ be faster than Fortran?

1997年の古い論文ですが、テンプレートが導入されたので、これを使えば最適化が可能になって Fortran と同等、もしくはより速くなるという結論です。テンプレートを使わないと最適化が不可能でオーダー1桁遅いようです。

link.springer.com

【寝言】メモ帳

『林桂一』

戦前 Julius Springer から出した数表や、岩波の高等関数表で有名ですが、ネットには伝記的な情報が少ないようです。元々は土木工学の人で必要に迫られて数表・数値計算を極めたようです。九州大学はもっと顕彰して下さい。

数値計算(昭和16年)の序文によれば、元会津藩士の先生のもとで洙泗の学を志したが、途中西洋の学問に切り替えたそうです。

数値計算の理論と応用(昭和24年)には、数表を手に入れるためにした様々な苦労譚(絶版で破れた本しか手に入らず、抜けたページを大英図書館で手で書き写したとか)や Springer から出した数表には後から見ると少し誤りもあり不本意な面もあったと述懐しています。

円及双曲線函数表 (1947年)

円及双曲線函数表 (1947年)

高等函数表 (1947年)

高等函数表 (1947年)

数値計算の理論と応用 (1949年)

数値計算の理論と応用 (1949年)

数値計算と解析 (1950年)

数値計算と解析 (1950年)

ターナー ペトワース荘園

https://thecommonviewer.files.wordpress.com/2018/04/turner-petworth-park.jpg
アニメ・漫画で開発された広角レンズ的な絵画表現かと思っていたけれど、ターナーにしてすでに楕円型に曲がった表現が常用されているとは。

それにつけても伯爵様に駆け寄る犬たちがいい。屋敷の軒先でウロウロしている鹿もよろしい。地平線まで領地で動物たちに囲まれた理想的生活。
thecommonviewer.wordpress.com

大西洋同盟の破綻?

最近のトランプ政権による政策が、NATO に代表される大西洋同盟 (trans-Atlantic alliance) を破綻させると、西欧人と反トランプ的米人が喚いていますが、彼らの言うことを見てみると、もはや現実にそぐわない『戦後秩序』の幻想にしがみつく西欧(西方教会キリスト教圏)とその同調者が寝言をほざいているように見受けられます。

アメリカの民主党的なインテリw層は、自分らを西洋文明の末にいると考えて西欧人コスプレをしつつ、一般米国白人を見下し、それを補償するため有色人種(但し原住民インデアンを除く)の保護者面して、西洋諸国の幻想に合わせた作り話を騙っています。民主党なぞは元々は南部の奴隷制度賛成の大地主代表なんですが。

トランプ大統領は、一般米国人を代表して、彼らが裸の王様であると、ありのままに口に出し、共同幻想を破壊しているので罵られているようです。(そして新しい米国製の幻想を押し付けているw)

当ブログでは、今後ともイマジンブレイカートランプ大統領を応援注視してゆく所存です。

f:id:fortran66:20190302223130j:plain
Imagine Breaker Donald Trump

そもそも現今では、巨大多国籍企業が中小国よりも巨大な資産と影響力をもって、平安時代の不輸不入権みたいなのを振り回して社会資本にタダ乗りしているのが問題なので、壁を作ってでも納得いく公正さを取り戻さねばならないのに、グローバルとかを無条件に善と見なしてボロ雑巾のように利用されるだけの自殺・自傷行為は失笑ものでしょう。

次のゾンビ映画amazon 倉庫に籠城?

www.newsweekjapan.jp

別の記事では、アマゾンで生活用品を買い、アマゾン新聞(Washington Post)を読みアマゾン地獄へ行くとあって、ゆりかごから墓場までアマゾンとw 

アマゾンプライムなら三途の川の渡し賃も無料で、アマゾンの購入リストに基づいた死後の裁きがアレクサによって宣告され、アマゾンの倉庫の労働で責め苦を受けた後、次の輪廻までも優先でしょう。

www.sankei.com

 歴史家ジル・レポアは最近、ニューヨーカー誌にこう書いたという。

 〈「私たちはアマゾンの家に住んで、アマゾンの食料品を食べ、アマゾンの新聞を読んでいる」「そして死ねばアマゾン地獄へ落ちるのだろう」〉

【寝言】微妙乞食速報

HUMBLE BOOK BUNDLE: COMPUTER SCIENCE BY MERCURY LEARNING

微妙?
www.humblebundle.com

ターナー

ターナーの運動を描こうとした絵は、シャッター速度が遅すぎてイマイチ。アニメ絵のように輪郭がはっきりした高速シャッターの方が好み。

f:id:fortran66:20190227022452j:plain
ターナー

海のトリトン (オープニング)

北斎だとベタすぎるしw

ズボンをはかなくても核爆弾!

むかし毛沢東が「ズボンをはかなくても核爆弾を作る!」と言っていたが、最近の韓国が同じ調子なので興味深い。

かつて金大中が大統領だった時も、ウランの核兵器用の高濃度濃縮を試みようとして IAEA に叱られているが、しつこく北朝鮮を隠れ蓑にして核爆弾を持とうとしているようである。

なにかアパルトヘイト全盛のころの南アフリカを思い起こさせる。南アの如く韓国は国家の正統性に乏しいので、様々な滑稽な建国神話を創作しているが、南アと同じく核爆弾が精神安定剤になると思っているようである。

これまでは北朝鮮の核問題とされてきたものも、南北朝鮮はもともと胴体一つで頭が二つの罵り合ってるシャム双生児の様な存在なわけだし、核問題でも一体の懲罰対象として扱うべき。韓国が抜き難い劣等感から核兵器を渇望しているのは元々分かっていたことだが、北の核ミサイル開発の進展にともなって、あからさまに隠さなくなってきた。

文明水準を考えると、韓国人は自由主義圏を離れて経済破綻しても、たとえパンツを履かなくても、核爆弾を選ぶだろう。

【寝言】先々週の滑稽なニュース

フランスで父親・母親廃止w

>「父」「母」の呼び方を「親1」「親2」へ
この見出しを読んだ時、区別に整数1,2という順序集合を使っては、今度は順位付けでもめるだろうと思いましたが、以下の記事でもそう書いてありましたw

親薔薇・親百合とか親松茸・親アワビとかもっと詩的な名前があろうに。
www.newsweekjapan.jp

「生まれることに同意していない」両親を訴えた印度人

この見出しを読んだ時は、輪廻説を信じている印度人ならばさもありなん、天竺ならでこそと思いましたが、記事を見ると輪廻と無関係なようです。
news.livedoor.com

ミュンヘン安全保障会議

メルケル婆さんは全く信用できない。支那人を大量に呼んで話をさせている。去年までダボスダボス言っていたのに、ヨーロッパ平民が反金持ち運動を始めると、こっそり逃げ出すのが本当に姑息で見苦しい。まぁ無視すれば、それは政治センス無いがw


🇩🇪 Merkel, Pence clash on Iran deal at Munich conference | Al Jazeera English
(日本が原発を止めているせいで莫大な金がカタールに流れ込んで、これがカタールの近隣諸国への干渉の資金源となって、アルジャジーラによる宣伝戦にとどまらず、シリアのスンナ派過激派・イエメンのスンナ派反政府勢力などへの資金提供で無用な紛争の元となている。反原発の罪は重い。)

現副大統領ペンスはいいが、前副大統領アホの子バイデンがヨーロッパに世辞を売って見苦しい。基本的にアメリ東海岸のリベラルwはヨーロッパにすり寄り過ぎている。このため、歴史観などが非常に浅薄で、ヨーロッパ人のアジア・アフリカでの数百年に及ぶ植民地支配・奴隷労働・人身売買について全く見ようとしない。そしてそれに異議を申し立て、人種平等に孤軍奮闘した日本の尽力を貶めている。

Foreign Affairs

Foreign Affairs などにはそういうアメリカ人の既得権益層の寝言が詰まっていて、安っぽいカウボーイ的脳内妄想を覗けて笑える。ところが近頃、トランプ大統領に既得権や幻想を壊されて、悪口のオンパレードである。
www.foreignaffairs.com

しかしさらにひどいのが、その日本語抄録誌のフォーリン・アフェアーズ・ジャパンで、今は朝日新聞の資本が入っているため、そもそも大元が歪んでいるのにさらに記事の選択が偏っていて、そのうえまだ足りないかとばかりに記事タイトルがすげ替えられて、おかしなアブストラクトまでついて、白人の間抜けな価値観にすり寄った上に、中共擁護にまで走っている。人間としての誇りのかけらもなく、実に哀れな道化ぶりである。

ただ Foreign Affairs は外国人が書く立場の違う記事もあって、その辺は多少価値観が違って面白いこともある。

拝火教

ペンス副大統領は、イスラエルに脅威だからとイラン核合意破棄に加わるようにヨーロッパを圧迫していましたがイランと言えば拝火教

昔、NHK-FM民族音楽の時間に、イラン国営放送協会提供のイランの少数民族音楽の巻があったのですが、結構面白かった記憶があります。カスピ海とか端っこの方にいるクルド人や、少し残っている拝火教徒とか、川の中州の葦原に住んでる何某とかもいたような気もするけど記憶が混ぜこぜになっているかもしれません。最後は海に出て波の音を聞いたような。

フレディー・マーキューリーも拝火教徒の出だとか。八十日間世界一周の印度人の女も先祖がペルシアから逃れてきた拝火教徒でした。NHK の教育テレビで放送されたソ連映画で医学者イブン・シーナーの伝記ものがありましたが、奥さんが拝火教徒で、鳥に死骸を食わせていました。

拾い画像

f:id:fortran66:20190226034116j:plain
Freddy Sailor Mercury

【メモ帳】括弧積の展開と復元

Lie 代数の括弧積

Lie 代数の元の括弧積で出来た項があるとして、それを展開する方向には [X, Y]=XY-YX の定義に従って機械的にできます。しかし、展開したものを逆向きに括弧積に戻すのは、一般的には相互に打ち消しあう適当な項を付け足してやって考えねばならないので面倒です。

ところが、これを簡単に求める方法があります。各項の文字を ad( ) でくくり、項の次数で割るだけです。ただし右端の文字だけは ad される対象とします。

[X,Y]=XY-YX ⇒ ( ad(X)(Y) - ad(Y)(X) ) / 2 = ([X, Y] - [Y, X])/2 = ([X, Y] + [X, Y]) / 2 = [X, Y]

で元に戻ります。

同様に
[X, [X, Y]] = XXY - XYX - XYX + YXX

( [X, [X, Y]] - 2 [X, [Y, X]] + [Y, [X, X]] ) / 3= ( [X, [X, Y]] +2 [X, [X, Y]] + 0 ) / 3 = [X, [X, Y]]

で元に戻ります。

さらに
[X, [Y, [X, Y]]] = 2XYXY - XYYX - XXYY - 2YXYX + YYXX +XYYX
= 2XYXY - 2YXYX -X^2Y^2 + Y^2X^2
⇒2 [X, [Y, [X, Y]]] - 2 [Y, [X, [Y, X]]]

ここで [Y, [X, [Y, X]]] を展開してやると、[Y, [X, [Y, X]]] = -[X, [Y, [X, Y]]] が分かるので、右辺は 4 [X, [Y, [X, Y]]] となり 4 で割れば元に戻ります。

いま展開して元に戻しましたが、Jacobi の恒等式を用いて ad([X, Y])=[ad(X), ad(Y)] の ad と括弧の準同型を用いると展開しなくても等式変形できます。

一般の場合は準同型性を使って、数学的帰納法で示せます。

そしてこれを用いると、Baker-Campbell-Hausdorff の公式の具体的な表式が log と exp の級数展開の式からそのまま簡単に求められます。(ただし、べき展開がそもそも Lie 代数の一次の項と括弧積で表わされているはずであることは必要なので、Eichler の証明の様な物は必要。)

この導出法で、1/n の係数が出てくる意味とか、はじめて色々すっきりした気がします。

fortran66.hatenablog.com


リー代数と素粒子論

リー代数と素粒子論

リー代数素粒子論に Eichler のよりも簡単な BCH 証明と、この方法による具体的な展開式の導出が二段階で示してあります。

BCH 証明は包絡代数に依っていますが、これは詳しくはホッホシルトのリー群の構造で1章かけて説明してくれています。が、わけわかめです。

リー群の構造 (数学叢書)

リー群の構造 (数学叢書)

fortran66.hatenablog.com

八元数の虚部と例外群 G2

例外群 G_2

コンパクト Lie 群の例外群 G_2八元数スカラーのノルムを保存する変換とみなせます。特に虚部のみをみると7次元空間での制限された回転になっています。これは四元数の虚部の変換が、3次元空間での回転に対応しているのと類比されます。

SO(3) では f 電子と関係する角運動量 3 に関わる 6j symbol で選択則的に許容なのに値が 0 になるものがある事と関係しています。
\begin{Bmatrix}
5\, 5\, 3\\
3\, 3\, 3
\end{Bmatrix}=0
rank 3 のテンソル演算子が消えるので 21-(2*3+1)=14。

定義式の数値的確認

G_2=\left\{ g\in\mathrm{GL(O)}| g(uv)=g(u)g(v), \forall u, v \in\mathrm{O} \right\}

定義式から虚部を比較することにします。7次元空間での制限された回転行列の具体形は、以下の卒論から借りてくることにします。

https://www.math.hmc.edu/seniorthesis/archives/2005/rarenas/rarenas-2005-thesis.pdf

SO(7) の場合、本来 7*6/2 = 21 自由度ありますが、ここから 7 自由度減って 14 自由度の変換になっています。

実行結果

左右両辺の計算結果が一致しています。

g(u)*g(v)   0.000  -0.325   0.199   0.179   0.400  -0.041   0.540   0.204
  g(uv)     0.000  -0.325   0.199   0.179   0.400  -0.041   0.540   0.204
g(u)*g(v)   0.000   0.005   0.000   0.178   0.564  -0.298   0.434   0.214
  g(uv)     0.000   0.005   0.000   0.178   0.564  -0.298   0.434   0.214
g(u)*g(v)   0.000   0.388   0.341   0.023   0.084  -0.022   0.090   0.624
  g(uv)     0.000   0.388   0.341   0.023   0.084  -0.022   0.090   0.624
g(u)*g(v)   0.000   0.102  -0.223  -0.446   0.485  -0.349   0.199   0.129
  g(uv)     0.000   0.102  -0.223  -0.446   0.485  -0.349   0.199   0.129
g(u)*g(v)   0.000  -0.066   0.295  -0.243  -0.666  -0.171  -0.001   0.222
  g(uv)     0.000  -0.066   0.295  -0.243  -0.666  -0.171  -0.001   0.222
g(u)*g(v)   0.000  -0.467  -0.309  -0.505   0.072  -0.074  -0.121   0.279
  g(uv)     0.000  -0.467  -0.309  -0.505   0.072  -0.074  -0.121   0.279
g(u)*g(v)   0.000  -0.052  -0.089  -0.331  -0.413   0.047  -0.570  -0.232
  g(uv)     0.000  -0.052  -0.089  -0.331  -0.413   0.047  -0.570  -0.232
g(u)*g(v)   0.000   0.674  -0.099   0.068   0.331   0.019  -0.292   0.093
  g(uv)     0.000   0.674  -0.099   0.068   0.331   0.019  -0.292   0.093
g(u)*g(v)   0.000  -0.097  -0.025   0.571   0.007  -0.283   0.499  -0.086
  g(uv)     0.000  -0.097  -0.025   0.571   0.007  -0.283   0.499  -0.086
g(u)*g(v)   0.000  -0.333   0.168   0.182   0.654  -0.005   0.079   0.255
  g(uv)     0.000  -0.333   0.168   0.182   0.654  -0.005   0.079   0.255
g(u)*g(v)   0.000   0.111  -0.037  -0.200  -0.560  -0.089  -0.499   0.217
  g(uv)     0.000   0.111  -0.037  -0.200  -0.560  -0.089  -0.499   0.217
続行するには何かキーを押してください . . .

ソース・プログラム

rot_1~7 それぞれ2変換角パラメータが合計14自由度を出します。ここでは面倒なので、rot_1..rot_7 の固定順番で、乱数で決めた角度で変換して、左右両辺の結果を比較しています。

八元数の積は、非結合演算なので演算順序に注意が必要です。

    module m_comp
      implicit none
      integer, parameter :: kd = kind(0.0d0)
      
      interface operator(+) 
        procedure :: add_r, add_c, add_h, add_o
      end interface
      interface operator(*) 
        procedure :: mul_r, mul_c, mul_h, mul_o
      end interface
      interface operator(/) 
        procedure :: scale_r, scale_c, scale_h, scale_o
        procedure :: div_r, div_c, div_h, div_o
      end interface
      interface operator(-) 
        procedure :: minus_r, minus_c, minus_h, minus_o
        procedure :: sub_r, sub_c, sub_h, sub_o
      end interface
      interface operator(.cc.) 
        procedure :: conj_r, conj_c, conj_h, conj_o
      end interface
      interface conj 
        procedure :: conj_r, conj_c, conj_h, conj_o
      end interface
      interface dot 
        procedure :: dot_r, dot_c, dot_h, dot_o
      end interface
      interface cross 
        procedure :: cross_r, cross_c, cross_h, cross_o
      end interface
      interface im 
        procedure :: im_r, im_c, im_h, im_o
      end interface

      type :: t_r
        real(kd) :: re
      end type t_r    

      type :: t_c
        type(t_r) :: re, im
      end type t_c    

      type :: t_h
        type(t_c) :: re, im
      end type t_h    

      type :: t_o
        type(t_h) :: re, im
      end type t_o    

    contains  
    
      type(t_r) pure function conj_r(a) result(c)
        type(t_r), intent(in) :: a
        c%re = a%re 
      end function conj_r
      type(t_r) pure function im_r(a) result(c)
        type(t_r), intent(in) :: a
        c%re = 0.0_kd
      end function im_r
      type(t_r) pure function minus_r(a) result(c)
        type(t_r), intent(in) :: a
        c%re = -a%re 
      end function minus_r
      type(t_r) pure function add_r(a, b) result(c)
        type(t_r), intent(in) :: a, b
        c%re = a%re + b%re
      end function add_r
      type(t_r) pure function sub_r(a, b) result(c)
        type(t_r), intent(in) :: a, b
        c%re = a%re - b%re
      end function sub_r
      type(t_r) pure function div_r(a, b) result(c)
        type (t_r), intent(in) :: a, b
        c = a * conj(b) / dot(b, b)
      end function div_r
      type(t_r) pure function mul_r(a, b) result(c)
        type (t_r), intent(in) :: a, b
        c%re = a%re * b%re
      end function mul_r
      type(t_r) pure function scale_r(a, b) result(c)
        type (t_r), intent(in) :: a
        real(kd), intent(in) :: b
        c%re = a%re / b
      end function scale_r
      real(kd) pure function dot_r(a, b) result(c)
        type (t_r), intent(in) :: a, b
        c = a%re * b%re
      end function dot_r
      type(t_r) pure function cross_r(a, b) result(c)
        type (t_r), intent(in) :: a, b
        c = (conj(b) * a - conj(a) * b) / 2.0_kd
      end function cross_r

      type(t_c) pure function conj_c(a) result(c)
        type(t_c), intent(in) :: a
        c%re =  a%re 
        c%im = -a%im 
      end function conj_c
      type(t_c) pure function im_c(a) result(c)
        type(t_c), intent(in) :: a
        c%re = im(a%re)
        c%im = a%im
      end function im_c
      type(t_c) pure function minus_c(a) result(c)
        type(t_c), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_c
      type(t_c) pure function add_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function add_c
      type(t_c) pure function sub_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c%re = a%re - b%re
        c%im = a%im - b%im
      end function sub_c
      type(t_c) pure function mul_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c%re = a%re * b%re + (-b%im * a%im)
        c%im = b%im * a%re +   a%im * b%re
      end function mul_c
      type(t_c) pure function div_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c = a * conj(b) / dot(b, b)
      end function div_c
      type(t_c) pure function to_c(r0, r1)
        real(kd), intent(in) :: r0, r1
        to_c = t_c(t_r(r0), t_r(r1))
      end function to_c  
      type(t_c) pure function scale_c(a, b) result(c)
        type (t_c), intent(in) :: a
        real(kd), intent(in) :: b
        c%re = a%re / b
        c%im = a%im / b
      end function scale_c
      real(kd) pure function dot_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c = dot_r(a%re, b%re) + dot_r(a%im, b%im)
      end function dot_c
      type(t_c) pure function cross_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c = (conj(b) * a - conj(a) * b) / 2.0_kd
      end function cross_c
      
      type(t_h) pure function conj_h(a) result(c)
        type(t_h), intent(in) :: a
        c%re = conj(a%re) 
        c%im =     -a%im 
      end function conj_h
      type(t_h) pure function im_h(a) result(c)
        type(t_h), intent(in) :: a
        c%re = im(a%re)
        c%im = a%im
      end function im_h
      type(t_h) pure function minus_h(a) result(c)
        type(t_h), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_h
      type(t_h) pure function add_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function add_h
      type(t_h) pure function sub_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c%re = a%re - b%re
        c%im = a%im - b%im
      end function sub_h
      type(t_h) pure function mul_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c%re = a%re * b%re - conj(b%im) * a%im
        c%im = b%im * a%re + a%im * conj(b%re)
      end function mul_h
      type(t_h) pure function div_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c = a * conj(b) / dot(b, b)
      end function div_h
      type(t_h) pure function to_h(r0, r1, r2, r3)
        real(kd), intent(in) :: r0, r1, r2, r3
        to_h = t_h(to_c(r0, r1), to_c(r2, r3))
      end function to_h
      type(t_h) pure function scale_h(a, b) result(c)
        type (t_h), intent(in) :: a
        real(kd), intent(in) :: b
        c%re = a%re / b
        c%im = a%im / b
      end function scale_h
      real(kd) pure function dot_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c = dot_c(a%re, b%re) + dot_c(a%im, b%im)
      end function dot_h
      type(t_h) pure function cross_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c = (conj(b) * a - conj(a) * b) / 2.0_kd
      end function cross_h
      type(t_h) pure function to_h_arr(a) result(c)
        real(kd), intent(in) :: a(4)
        c = to_h(a(1), a(2), a(3), a(4))
      end function to_h_arr
      
      type(t_o) pure function conj_o(a) result(c)
        type(t_o), intent(in) :: a
        c%re = conj(a%re) 
        c%im =     -a%im 
      end function conj_o
      type(t_o) pure function im_o(a) result(c)
        type(t_o), intent(in) :: a
        c%re = im(a%re)
        c%im = a%im
      end function im_o
      type(t_o) pure function minus_o(a) result(c)
        type(t_o), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_o
      type(t_o) pure function add_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function add_o
      type(t_o) pure function sub_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c%re = a%re - b%re
        c%im = a%im - b%im
      end function sub_o
      type(t_o) pure function mul_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c%re = a%re * b%re - conj(b%im) * a%im
        c%im = b%im * a%re + a%im * conj(b%re)
      end function mul_o
      type(t_o) pure function div_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c = a * conj(b) / dot(b, b)
      end function div_o
      type(t_o) pure function scale_o(a, b) result(c)
        type (t_o), intent(in) :: a
        real(kd), intent(in) :: b
        c%re = a%re / b
        c%im = a%im / b
      end function scale_o
      type(t_o) pure function cross_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c = (conj(b) * a - conj(a) * b) / 2.0_kd
      end function cross_o
          
      type(t_o) pure function arr8_to_o(r)
        real(kd), intent(in) :: r(8)
        arr8_to_o = t_o(to_h(r(1), r(2), r(3), r(4)), to_h(r(5), r(6), r(7), r(8)))
      end function arr8_to_o

      type(t_o) pure function to_o(r0, r1, r2, r3, r4, r5, r6, r7)
        real(kd), intent(in) :: r0, r1, r2, r3, r4, r5, r6, r7
        to_o = t_o(to_h(r0, r1, r2, r3), to_h(r4, r5, r6, r7))
      end function to_o  
      type(t_o) pure function r7_to_o(a) result(b)
        real(kd), intent(in) :: a(7)
        b = t_o(to_h(0.0_kd, a(1), a(2), a(3)), to_h(a(4), a(5), a(6), a(7)))
      end function r7_to_o  
      pure function o_to_r7(a) result(b)
        type(t_o), intent(in) :: a
        real(kd) :: b(7)
        associate(hrcr=>a%re%re, hrci=>a%re%im, hicr=>a%im%re, hici=>a%im%im)
          b = [hrcr%im%re, hrci%re%re, hrci%im%re, hicr%re%re, hicr%im%re, hici%re%re, hici%im%re]
        end associate
      end function o_to_r7  
      real(kd) pure function dot_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c = dot_h(a%re, b%re) + dot_h(a%im, b%im)
      end function dot_o
      
      type (t_o) pure function associator_o(a, b, c) result(d)
        type (t_o), intent(in) :: a, b, c
        d = (a * b) * c - a * (b * c)  
      end function associator_o

    end module m_comp

    
    module m_g2
      use m_comp
      implicit none
    contains
      pure function so7_1(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) = 1.0
        r(2, 2) =  cos(x); r(2, 3) =  sin(x)
        r(3, 2) = -sin(x); r(3, 3) =  cos(x)
        r(4, 4) =  cos(x - y); r(4, 5) = -sin(x - y)
        r(5, 4) =  sin(x - y); r(5, 5) =  cos(x - y)
        r(6, 6) =  cos(y); r(6, 7) =  sin(y)
        r(7, 6) = -sin(y); r(7, 7) =  cos(y)
        b = matmul(r, a)
      end function so7_1 
      pure function so7_2(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x); r(1, 3) = -sin(x)
        r(2, 2) = 1.0
        r(3, 1) =  sin(x); r(3, 3) =  cos(x)
        r(4, 4) =  cos(- x + y); r(4, 6) = sin(- x + y)
        r(5, 5) =  cos(y); r(5, 7) = -sin(y)
        r(6, 4) = -sin(- x + y); r(6, 6) = cos(- x + y)
        r(7, 5) =  sin(y); r(7, 7) =  cos(y)
        b = matmul(r, a)
      end function so7_2 
      pure function so7_3(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x); r(1, 2) = sin(x)
        r(2, 1) = -sin(x); r(2, 2) = cos(x)
        r(3, 3) = 1.0
        r(4, 4) =  cos(- x + y); r(4, 7) = sin(- x + y)
        r(5, 5) =  cos(y); r(5, 6) = sin(y)
        r(6, 5) = -sin(y); r(6, 6) = cos(y)
        r(7, 4) = -sin(- x + y); r(7, 7) = cos(- x + y)
        b = matmul(r, a)
      end function so7_3 
      pure function so7_4(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x); r(1, 5) = -sin(x)
        r(2, 2) =  cos(- x + y); r(2, 6) = -sin(- x + y)
        r(3, 3) =  cos(y); r(3, 7) =  sin(y)
        r(4, 4) = 1.0
        r(5, 1) =  sin(x); r(5, 5) =  cos(x)
        r(6, 2) =  sin(- x + y); r(6, 6) =  cos(- x + y)
        r(7, 3) = -sin(y); r(7, 7) =  cos(y)
        b = matmul(r, a)
      end function so7_4 
      pure function so7_5(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x); r(1, 4) =  sin(x)
        r(2, 2) =  cos(x + y); r(2, 7) = sin(x + y)
        r(3, 3) =  cos(y); r(3, 6) =  sin(y)
        r(4, 1) = -sin(x); r(4, 4) =  cos(x)
        r(5, 5) = 1.0
        r(6, 3) = -sin(y); r(6, 6) =  cos(y)
        r(7, 2) = -sin(x + y); r(7, 7) =  cos(x + y)
        b = matmul(r, a)
      end function so7_5 
      pure function so7_6(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x - y); r(1, 7) = -sin(x - y)
        r(2, 2) =  cos(x); r(2, 4) =  sin(x)
        r(3, 3) =  cos(y); r(3, 5) =  sin(y)
        r(4, 2) = -sin(x); r(4, 4) =  cos(x)
        r(5, 3) = -sin(y); r(5, 5) =  cos(y)
        r(6, 6) = 1.0
        r(7, 1) =  sin(x - y); r(7, 7) =  cos(x - y)
        b = matmul(r, a)
      end function so7_6 
      pure function so7_7(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        real(kd), intent(in) :: a(7)
        real(kd) :: b(7), r(7, 7)
        r = 0.0
        r(1, 1) =  cos(x); r(1, 6) = -sin(x)
        r(2, 2) =  cos(x - y); r(2, 5) = -sin(x - y)
        r(3, 3) =  cos(y); r(3, 4) = -sin(y)
        r(4, 3) =  sin(y); r(4, 4) =  cos(y)
        r(5, 2) =  sin(x - y); r(5, 5) =  cos(x - y)
        r(6, 1) =  sin(x); r(6, 6) =  cos(x)
        r(7, 7) = 1.0
        b = matmul(r, a)
      end function so7_7 
!      
!      
      type(t_o) pure function rot_1(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_1(x, y, o_to_r7(a)))
      end function rot_1
      type(t_o) pure function rot_2(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_2(x, y, o_to_r7(a)))
      end function rot_2
      type(t_o) pure function rot_3(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_3(x, y, o_to_r7(a)))
      end function rot_3
      type(t_o) pure function rot_4(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_4(x, y, o_to_r7(a)))
      end function rot_4
      type(t_o) pure function rot_5(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_5(x, y, o_to_r7(a)))
      end function rot_5
      type(t_o) pure function rot_6(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_6(x, y, o_to_r7(a)))
      end function rot_6
      type(t_o) pure function rot_7(x, y, a) result(b)
        real(kd), intent(in) :: x, y
        type(t_o), intent(in) :: a
        b = r7_to_o(so7_7(x, y, o_to_r7(a)))
      end function rot_7
    
    end module m_g2

    
    program supercomplex
      use m_comp
      use m_g2
      implicit none
      real(kd), parameter :: pi = 4 * atan(1.0)
      real(kd) :: theta, tx(7), ty(7)
      integer :: i
      type(t_o) :: ou, ov, uv, u0, v0, uv0
      ou = to_o(0.0_kd,  2.0_kd,-1.0_kd,  1.0_kd, -2.0_kd,  2.0_kd, -1.0_kd, -2.0_kd)
      ov = to_o(0.0_kd, -1.0_kd, 1.0_kd, -2.0_kd,  1.0_kd, -1.0_kd,  2.0_kd, -1.0_kd)
      u0 = ou / sqrt(dot(ou, ou))
      v0 = ov / sqrt(dot(ov, ov))
      uv0 = u0*v0 
      do i = 1, 100
        call random_number(tx)
        call random_number(ty)
        tx = tx * pi
        ty = ty * pi
        u0 = rot_1(tx(1), ty(1), u0)
        v0 = rot_1(tx(1), ty(1), v0)
        u0 = rot_2(tx(2), ty(2), u0)
        v0 = rot_2(tx(2), ty(2), v0)
        u0 = rot_3(tx(3), ty(3), u0)
        v0 = rot_3(tx(3), ty(3), v0)
        u0 = rot_4(tx(4), ty(4), u0)
        v0 = rot_4(tx(4), ty(4), v0)
        u0 = rot_5(tx(5), ty(5), u0)
        v0 = rot_5(tx(5), ty(5), v0)
        u0 = rot_6(tx(6), ty(6), u0)
        v0 = rot_6(tx(6), ty(6), v0)
        u0 = rot_7(tx(7), ty(7), u0)
        v0 = rot_7(tx(7), ty(7), v0)
        uv0 = rot_1(tx(1), ty(1), uv0)
        uv0 = rot_2(tx(2), ty(2), uv0)
        uv0 = rot_3(tx(3), ty(3), uv0)
        uv0 = rot_4(tx(4), ty(4), uv0)
        uv0 = rot_5(tx(5), ty(5), uv0)
        uv0 = rot_6(tx(6), ty(6), uv0)
        uv0 = rot_7(tx(7), ty(7), uv0)
        print '(a, 8f8.3)', 'g(u)*g(v)', u0 * v0 + to_o(dot(u0, v0), 0.0_kd, 0.0_kd, 0.0_kd, 0.0_kd, 0.0_kd, 0.0_kd, 0.0_kd)            
        print '(a, 8f8.3)', '  g(uv)  ', uv0            
      end do  

    end program supercomplex