カテゴリー別アーカイブ: 未分類

[Prolog]制約論理プログラミングへの条件追加と速度の向上に関して

2週間ほど前にProject Eulerの存在を知り、面白いのでチャレンジしている。本日の時点では26問解いた。全部Prologで解いている。

Project Euler

ところどころCLPFDを使える問題があり、使っている。

制約論理プログラミングの動作の特徴?みたいなのを感じられる面白い問題があったので、紹介しようと思う。

Probrem 9 特別なピタゴラス数

この問題は、CLPFDだと探索の処理を一切書かずに以下のようにただ定義だけをずらずら書くだけで解ける。

:-use_module(library(clpfd)).

solve(Sum):-
[A,B,C] ins 1..1000,
A+B+C#=Sum,
A*A + B*B #= C*C,
A #< B,
B #< C,
label([A,B,C]),
write([A,B,C]).

問題の条件をそのまま書いただけのようなプログラムだけど、本当にこれだけで解けます。

ただ、これだと非常に処理時間がかかかる。僕のしょぼいマシンでは、
以下のように150秒かかった。

1 ?- time(solve(1000)).
[200,375,425]
% 69,897,996 inferences, 142.641 CPU in 153.188 seconds (93% CPU, 490029 Lips)
true

ネットで調べるとこのピタゴラス数の法則のようなものがいくつかヒットするのですが、そのひとつが以下の図のようなもので、

triangle

ようするにBとCの関係に関してなのですが、長さBの正方形の辺を1つづつ大きくして一回りづつ囲むように配置してゆくといつか長さCの正方形と等しくなるというもので、しかもこの大きくした分の面積はA × Aと等しいというもの。

大きくした分の面積は、N(=1,2,3..)の数列として以下のように表すことができる。
En = 2 × N × B + N × N
そして、A × A = En 。

前述のプログラムにこの条件を追加して動作させると、答えを出す速度が段違いに速くなる。

:-use_module(library(clpfd)).

solve(Sum):-
[A,B,C] ins 1..1000,
A+B+C #= Sum,
A #< B,
B #< C,
A * A + B * B #= C * C,
A*A #= 2*N*B+N*N, % 追加した条件
N in 1..1000,   % 追加した条件 
label([A,B,C]),
write([A,B,C]).

実行結果:

[4] 6 ?- time(solve(1000)).
[200,375,425]
% 14,116,046 inferences, 16.094 CPU in 16.516 seconds (97% CPU, 877114 Lips)
true

10倍近く速くなった。
多分Aの探索空間が新しい条件の数列で絞り込まれて速くなるのだと思う。

「思う」と書いたのも制約論理プログラミングの特徴といえば特徴で、条件を書くたびに大量の制約伝播用のプログラムが内部で自動的に生成されるため、厳密な動作が非常に追いずらい。ステップ実行などのデバックもしずらい(CLPFDライブラリ内部で自動的に大量のバックトラックが発生している)。

これは悪い面で、動作が見積もれないことが原因となり正確・確実な動作を期待される産業分野でなかなか採用されないかもしれない。ちゃんとした企業ほど異常動作のときなどの原因追及フェーズを徹底的に行っているので、そのときに「思う」とか「これ入れたら速くなるかも」とかは通用しないわけです。動作確認のためのログを埋め込むのも結構大変です(ライブラリに直接埋め込まないと駄目だし制約伝播状態を出力した解析困難なログになることが予想される)

ちなみに制約伝播というのは、prolog の attributed_variableの仕組みを使って変数の探索空間が変更された時点でキックされる述語が予約されていて、ドミノ倒しのように次々と他の変数の探索空間をせばめてゆくという手法です。

CLPFDのソースを読んでゆくとわかるのですが A in 1..500 などという探索空間は木構造で表現されており、探索空間の変更はこの木構造を変えることで行っている。

たとえば A の木構造が最初 左の枝が1、右の枝が500 の状態で、この状態から100~200の可能性がないことが判明した時点で、右の500の枝の部分に100..200のノードが新しく追加される感じ?

Prologの変数は基本的に再代入不可なのですが、attributed_variableは再代入可能かつ履歴情報を保持していてバックトラック時に直前の値に戻る(Prologの通常の自由変数はバックトラック時は未設定状態になるだけで履歴情報は持っていない)ようなのでこれを利用しているのでしょう。

CLPFDは非常に簡単に記述できて問題が解けるため、勉強し始めのころはまるで魔法のツールのようだと感じたが、上記のような、問題自身の性格を表す条件を入れないとすぐに処理時間が膨大になってしまうように感じる。

当たり前のことだが、問題に対する洞察・分析も非常に大切ということだろう。

[Prolog]川渡り問題を解く

ネットで見つけた以下の川渡り問題をPrologで解いてみました。

おなじみのやつですね。

Art of Prologとかm.hiroiさんのホームページでも載っていました。

問題:

ある家族がいて、舟を使って川を向こう岸へ渡ろうとしています。
この家族は父、母、息子1、息子2、娘1、娘2、メイド、犬、じっちゃん、
赤ん坊の10人家族(犬も1人と数えます)です。
舟は1艘(そう)しかなく、1度に2人まで乗ることができます。
また、この舟をこげるのは父と母とメイドとじっちゃんの4人です。

父は、母がいなくなると娘を殺してしまいます。
母は、父がいなくなると息子を殺してしまいます。
じっちゃんは、親がいないと息子や娘、赤ん坊を殺してしまいます。
息子や娘は、親がいないと赤ん坊を殺してしまいます。
犬は、メイドがいないと家族をみんな殺してしまいます。

みんなが無事に川を渡り切るには、どのような手順で渡ればよいでしょうか?

——————————————————————

プログラム解説:

盤面生成→チェック → 再帰で次の盤面生成 → チェック → … → クリアするまで繰り返し
失敗すれば バックトラックで次の選択肢を試す
Prologで何も考えずに深さ優先探索で解いています。
枝刈りを行っていず効率の悪いプログラムですが、この程度の問題だと全然問題ないようです。

現在の状態は以下の形式のcompound termで表しています。

state(左岸にいる人のリスト,船に乗っている人のリスト,右岸にいる人のリスト,船の位置(left , right , crossing のいずれか))

assertで生成したstateを登録するようにして、登録済のstateには遷移しないようにしています(意味のない行ったり来たりを防ぐ)

assertする際 順列ではなく組み合わせで登録したいため、リスト内をソートしてから登録しています。

この程度のプログラムだとあまり考えず機械的作業で量産できるようになってきた。

————————————————————————–
プログラム:

main:-
retractall(state(_,_,_,_)), % assertされた全stateの初期化
A=state([father,mother,son,son,daughter,daughter,maid,dog,granpa,baby],[],[],left), % Initial State
sort_state(A,A1),
assert(A1),
solve(A1).

% クリア
solve(state([],[],_,right)):-
write('cleared!').

% 次の盤面の生成、リストの並び替え、生成した盤面が問題ないかチェック、問題なければ登録、再帰呼び出しにより次のステップへ
solve(A):-
nextstate(A,A1),
sort_state(A1,A2),
chk(A2),
assert(A2),
solve(A2),
nl,
write(A2).

% 盤面の各リストを並び替える
sort_state(state(Left,Ship,Right,Pos),state(Left1,Ship1,Right1,Pos)):-
msort(Left,Left1),
msort(Ship,Ship1),
msort(Right,Right1).

% 盤面のチェック
chk(state(Left,Ship,Right,Pos)):-
not(state(Left,Ship,Right,Pos)),% 生成された state がまだassertされていないことを確認
not(chk_kill(Left)), % 左岸で殺される人がいないかチェック
not(chk_kill(Ship)), % 船で殺される人がいないかチェック
not(chk_kill(Right)), % 右岸で殺される人がいないかチェック
chk_ship(Ship). % 船に運転できる人が乗っているかチェック

% 父は、母がいなくなると娘を殺してしまいます。
chk_kill(List):-
memberchk(father,List),
memberchk(daughter,List),
not(memberchk(mother,List)).

% 母は、父がいなくなると息子を殺してしまいます。
chk_kill(List):-
memberchk(mother,List),
memberchk(son,List),
not(memberchk(father,List)).

% じっちゃんは、親がいないと息子や娘、赤ん坊を殺してしまいます。
chk_kill(List):-
memberchk(granpa,List),
(memberchk(son,List);memberchk(daughter,List);memberchk(baby,List)),
not(memberchk(father,List)),
not(memberchk(mother,List)).

% 息子や娘は、親がいないと赤ん坊を殺してしまいます。
chk_kill(List):-
memberchk(baby,List),
(memberchk(son,List);memberchk(daughter,List)),
not(memberchk(father,List)),
not(memberchk(mother,List)).

% 犬は、メイドがいないと家族をみんな殺してしまいます。
chk_kill(List):-
memberchk(dog,List),
not(memberchk(maid,List)),
( memberchk(son,List);
memberchk(daughter,List);
memberchk(baby,List);
memberchk(father,List);
memberchk(mother,List);
memberchk(granpa,List)
).

% この舟をこげるのは父と母とメイドとじっちゃんの4人
chk_ship([]).
chk_ship(List):-
(
memberchk(father,List);
memberchk(mother,List);
memberchk(maid,List);
memberchk(granpa,List)
).

% 左岸から2人を選んで船に乗せる
nextstate(state(Left,[],Right,left),NextState):-
select(Sel1,Left,Left1),
select(Sel2,Left1,Left2),
NextState=state(Left2,[Sel1,Sel2],Right,crossing).

% 左岸から1人を選んで船に乗せる
nextstate(state(Left,[],Right,left),NextState):-
select(Sel1,Left,Left1),
NextState=state(Left1,[Sel1],Right,crossing).

% 右岸から2人を選んで船に乗せる
nextstate(state(Left,[],Right,right),NextState):-
select(Sel1,Right,Right1),
select(Sel2,Right1,Right2),
NextState=state(Left,[Sel1,Sel2],Right2,crossing).

% 右岸から1人を選んで船に乗せる
nextstate(state(Left,[],Right,right),NextState):-
select(Sel1,Right,Right1),
NextState=state(Left,[Sel1],Right1,crossing).

% 船に乗っている人を左岸に降ろす
nextstate(state(Left,Ship,Right,crossing),NextState):-
append(Left,Ship,Left1),
NextState=state(Left1,[],Right,left).

% 船に乗っている人を右岸に降ろす
nextstate(state(Left,Ship,Right,crossing),NextState):-
append(Right,Ship,Right1),
NextState=state(Left,[],Right1,right).


—————————————————————————————–
実行結果:
(下から上に答えに近づいていきます)

4 ?- time(main).
cleared!
state([],[],[baby,daughter,daughter,dog,father,granpa,maid,mother,son,son],right)
state([],[dog,maid],[baby,daughter,daughter,father,granpa,mother,son,son],crossing)
state([dog,maid],[],[baby,daughter,daughter,father,granpa,mother,son,son],left)
state([dog],[maid],[baby,daughter,daughter,father,granpa,mother,son,son],crossing)
state([dog],[],[baby,daughter,daughter,father,granpa,maid,mother,son,son],right)
state([dog],[maid,son],[baby,daughter,daughter,father,granpa,mother,son],crossing)
state([dog,maid,son],[],[baby,daughter,daughter,father,granpa,mother,son],left)
state([son],[dog,maid],[baby,daughter,daughter,father,granpa,mother,son],crossing)
state([son],[],[baby,daughter,daughter,dog,father,granpa,maid,mother,son],right)
state([son],[father,son],[baby,daughter,daughter,dog,granpa,maid,mother],crossing)
state([father,son,son],[],[baby,daughter,daughter,dog,granpa,maid,mother],left)
state([son,son],[father],[baby,daughter,daughter,dog,granpa,maid,mother],crossing)
state([son,son],[],[baby,daughter,daughter,dog,father,granpa,maid,mother],right)
state([son,son],[father,granpa],[baby,daughter,daughter,dog,maid,mother],crossing)
state([father,granpa,son,son],[],[baby,daughter,daughter,dog,maid,mother],left)
state([father,son,son],[granpa],[baby,daughter,daughter,dog,maid,mother],crossing)
state([father,son,son],[],[baby,daughter,daughter,dog,granpa,maid,mother],right)
state([father,son,son],[dog,maid],[baby,daughter,daughter,granpa,mother],crossing)
state([dog,father,maid,son,son],[],[baby,daughter,daughter,granpa,mother],left)
state([dog,maid,son,son],[father],[baby,daughter,daughter,granpa,mother],crossing)
state([dog,maid,son,son],[],[baby,daughter,daughter,father,granpa,mother],right)
state([dog,maid,son,son],[father,granpa],[baby,daughter,daughter,mother],crossing)
state([dog,father,granpa,maid,son,son],[],[baby,daughter,daughter,mother],left)
state([father,granpa,son,son],[dog,maid],[baby,daughter,daughter,mother],crossing)
state([father,granpa,son,son],[],[baby,daughter,daughter,dog,maid,mother],right)
state([father,granpa,son,son],[baby,mother],[daughter,daughter,dog,maid],crossing)
state([baby,father,granpa,mother,son,son],[],[daughter,daughter,dog,maid],left)
state([baby,father,granpa,son,son],[mother],[daughter,daughter,dog,maid],crossing)
state([baby,father,granpa,son,son],[],[daughter,daughter,dog,maid,mother],right)
state([baby,father,granpa,son,son],[dog,maid],[daughter,daughter,mother],crossing)
state([baby,dog,father,granpa,maid,son,son],[],[daughter,daughter,mother],left)
state([baby,dog,father,maid,son,son],[granpa],[daughter,daughter,mother],crossing)
state([baby,dog,father,maid,son,son],[],[daughter,daughter,granpa,mother],right)
state([baby,dog,father,maid,son,son],[granpa,mother],[daughter,daughter],crossing)
state([baby,dog,father,granpa,maid,mother,son,son],[],[daughter,daughter],left)
state([baby,dog,father,granpa,maid,son,son],[mother],[daughter,daughter],crossing)
state([baby,dog,father,granpa,maid,son,son],[],[daughter,daughter,mother],right)
state([baby,dog,father,granpa,maid,son,son],[daughter,mother],[daughter],crossing)
state([baby,daughter,dog,father,granpa,maid,mother,son,son],[],[daughter],left)
state([baby,daughter,father,granpa,mother,son,son],[dog,maid],[daughter],crossing)
state([baby,daughter,father,granpa,mother,son,son],[],[daughter,dog,maid],right)
state([baby,daughter,father,granpa,mother,son,son],[daughter,maid],[dog],crossing)
state([baby,daughter,daughter,father,granpa,maid,mother,son,son],[],[dog],left)
state([baby,daughter,daughter,father,granpa,mother,son,son],[maid],[dog],crossing)
state([baby,daughter,daughter,father,granpa,mother,son,son],[],[dog,maid],right)
state([baby,daughter,daughter,father,granpa,mother,son,son],[dog,maid],[],crossing)
% 85,495 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 2740207 Lips)
true ;
% 32,876 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 1053711 Lips)
false.

[Prolog]演算子のカンマとそうでないカンマ、ドット演算子と演算子でないドット(ピリオド)

Prologではプログラムのほとんどの記述は演算子を用いて記述され、言語全体を通して一貫している。

例えば、以下のようなリストの長さを返す述語my_lengthがあるとする。

my_length([],0).
my_length([_|Rest],Cnt):- my_length(Rest,Cnt0),Cnt is Cnt0 + 1.

このとき、下の方のclauseを例とすると、使用されている記号

「:-」 「|」 「,」 「+」 「is」

はどれも組み込みの優先度付き演算子として定義されていて、節全体がPrologの内部表現としては下の図のような木構造で表されている。

operator_tree20161206

ここで、ボディの規則が「,」という演算子で結ばれていることがわかる。
演算子は1項及び2項なので、カンマで3つ以上の規則をつなげた規則a,規則b,規則c のような場合は、演算子の xfy の定義により

‘,’(規則a, ‘,’(規則b,規則c))

というような右方向に入れ子となる木構造として表現される。

Swi-Prologのプロンプトでの実験

6 ?- Test=(a,b,c),Test=..List.
Test = (a, b, c),
List = [',', a, (b, c)].

ここで、abc(prm1,prm2) などの compound term の引数で使われているカンマに関して考えてみると、これは実は演算子ではない。

例えば、少し無理やりですが、以下のプロンプトの実験はマッチング失敗します。

8 ?- abc(','(prm1,prm2)) = abc(prm1,prm2).
false.

しかし右辺のprm1,prm2をさらにカッコでくくるとマッチング成功します。

10 ?- abc(','(prm1,prm2))=abc((prm1,prm2)).
true.

これは(prm1,prm2)とだけ書いた表現が、「カンマ演算子の引数としてprm1、prm2を渡したもの」を表していることを意味している。

そして、[a,b,c,d,e]などのリストで使用されているカンマはそのまま演算子として使用されるのではなく、ドット演算子に変換されます。

プロンプトでの実験

7 ?- [a,b,c]=R,R=..Y.
R = [a, b, c],
Y = ['.', a, [b, c]].

はじめに紹介したmy_lengthの木構造で [_|Rest] の部分が ピリオドに変わっていますが、これもドット演算子で、ドット演算子はPrologのリストを Lisp の car と cdr のように「最初の要素」と「残りのリスト(空リスト含む)」に分けます。

プロンプトでの実験

4 ?- [First|Rest]='.'(First,Rest).
true.

5 ?- [a,b,c,d]='.'(First,Rest).
First = a,
Rest = [b, c, d].

6 ?- [a,b,c,d,e]=','(a,(b,c,d,e)).
false.

上記で分かる通り、Prologでは同じカンマでも「演算子のカンマ」と「演算子でないカンマ(term の引数のカンマ、ドット演算子に変換されるカンマ)」が混在していることになる。

誰かのブログで、Prologの構文をいじれるとしたらterm(prm1,prm2)のカンマをスペースにしたいと書いている人がいて、はじめなぜそうしたいのか意味がわからなかったけど、「演算子ではないカンマは空白にしたい」という意味として考えると、なるほど混乱を避けるためにはその方が良いかもと思うようになった。そうするとリストの要素を分けるカンマも手を付けたほうが良い?

ドット演算子と述語の終わりを意味するピリオドも同じ文字だが全然意味が違い、厳密性を考えるとこれも紛らわしいような気がする。
述語の終わりのピリオドは一体演算子なのかちょっと確認できなかったのですが、多分違うと思います(詳細を知っている方いらっしゃいましたらぜひ教えてください)

中国の安い対局時計の手番スイッチの仕組み

中国の\2000の安い対局時計を分解して手番のスイッチの仕組みを見ているんだけどボタンの接点がなく、スイッチを押したときに片側の鉄片が近づくことによる静電容量の変化を認識してるっぽい。接点がないから長持ちするのかもしれない。
(2016/04/12 訂正 3枚目の写真の透明の素子が「リードリレー」とのことで、静電容量の変化を認識しているのではなく、スイッチの片側につけられた磁石が近づくことによりON/OFFになる仕組みのようです)

自分の作った対局時計で採用しているマイコンPIC1939でも静電容量変化感知機能があってそれを使用するとタッチパネルみたいに指を近づけると反応するようなスイッチが作成できる。

ただ自分の対局時計では電池を節約するため必要な処理を行った後スリープするようにしていて、これを、

・手番ボタンの押下
・時計用水晶からの外部タイマ割り込み(0.5sec毎)

の2種類のイベントで解除するようにして電池を節約しているのですが、

静電容量が変化したときにスリープ解除するような割り込みは存在しないようだったので静電容量感知スイッチを利用するのをあきらめたのだった。

静電容量スイッチだけで作成できればスイッチが基板のパターンだけでいけるのでボタン買わずにすみ安くできる。

KIMG0644

KIMG0645

KIMG0646

KIMG0643

地球の丸さを知覚できるか

昔mixiで書いた日記なのですが、なかなか面白いと思いますのでブログに転記します。

よく観光スポットとかで「地球が丸く見える~~岬」というのがあるのですが、 自分の個人的な経験でも、本当にそういう地点に行くと地球が丸く感じられた 経験があります。

具体的には視野の左右の端の水平線は、視野の中央の水平線より
若干下がっているように見えるのです。

しかし、テレビなどで 「それは錯覚、地球が丸いという知識が前提となりそう見えているだけ。  人間の観測地点程度の高度では地球の丸みは感じられない」 ということが言われていた。

自分的には、地球が丸いという、後から学んだ知識などなくても、本当に、 裸の心で水平線を見て丸く見えたのでこのような自然な感覚が否定されている のが非常にムカついていたのです。

僕はこの水平線が丸く見えた経験を飛躍させて、 古代の人たちも実は地球が丸いということをおぼろげに気づいていたのではないか とさえ考えていた。

ただむかついているだけではしょうがないので、うまいこと計算してこの丸み が人間に知覚できるのかがんばってみました。

具体的には視野の中央と視野の端の水平線の角度(視角?)の差を求めてみました。

ちょっと説明がめんどくさいのですが大まかに説明すると、

水平線が作る円と観測地点Poとが作る円錐を考える。
水平線の任意の点をPgとする。

人間の視野角?は200度とのことなので、Pgからこの半分の100度回転させた水平線上の 点をPrとする。

円錐に接し、Po-Pgに接する平面とPoPrとのなす角が求めたい角度

いい加減にやったので80%くらい計算間違いしてると思うんですが、下記のような結果が出ました。

答え合わせもあんまりしてなくて本当にいいかげんですので信用しないでください。

計算メモとロジックをエクセルのマクロに記述したものをはっつけますので 突っ込みをお待ちしております。

100mの岬で、 0.457624909 度 と計算されました。

ちなみに「1cmの対象を1m先からみた時の視角が0.57度」ということだそうです。
海抜100mの場合は、視野の両端では1cmの対象を1m先から見たくらいの大きさよりちょっと少ないくらい水平線が下がって見えてるということかな?人間の感覚で知覚できそうな 気がしますよね。

地球の半径 半径6367.25km(赤道での直径と極での直径の中間値を採用) 人間の視野角200度として計算

観測者地点(海抜)[M] 視野の中央と端との水平線の角度の差(ラジアンではなく度)
0.1 0.014471504
0.2 0.020465797
0.3 0.02506538
0.4 0.028943007
0.5 0.032359265
0.6 0.035447799
0.7 0.038287998
0.8 0.040931592
0.9 0.043414509
1 0.04576291
1.1 0.047996544
1.2 0.050130755
1.3 0.052177744
1.4 0.054147403
1.5 0.056047886
1.6 0.057886008
1.7 0.05966753
1.8 0.061397382
1.9 0.063079813
2 0.064718522
3 0.07926367
4 0.091525794
5 0.102328939
6 0.112095726
7 0.121077211
8 0.129436971
9 0.137288628
10 0.144714907
11 0.15177826
12 0.158527208
13 0.165000334
14 0.171228923
15 0.177238758
16 0.183051385
17 0.188685031
18 0.194155278
19 0.199475567
20 0.204657594
50 0.323591172
100 0.457624909
150 0.56047117
200 0.647173371
250 0.723558481
300 0.79261494
350 0.856118026
400 0.915224438
450 0.970737622
500 1.02324257
550 1.0731809
600 1.120895712
650 1.166659854
700 1.210694552
750 1.253182127
800 1.294274953
850 1.334101918
900 1.372773203
950 1.410383873
1000 1.447016634
1050 1.482743966
1100 1.517629819
1150 1.551730945
1200 1.585097994
1250 1.617776388
1300 1.649807048
1350 1.681226996
1400 1.712069857
1450 1.742366277
1500 1.772144281
1550 1.801429579
1600 1.830245822
1650 1.858614826
1700 1.886556769
1750 1.914090352
1800 1.941232951

作成したエクセルのVBAマクロ(モジュールに貼り付けて使ってください)

CalcSikaku(地球の半径,観測地点の海抜)が角度を求める関数
ここから

Option Explicit

‘R: 地球の半径 [m]
‘h: 観測地点の地面からの距離(海抜) [m]
Public Function CalcSikaku(ByVal R As Double, ByVal h As Double) As Variant

Dim lengthPoPx As Double
Dim lengthPxPg As Double
Dim lengthPoPg As Double
Dim sita As Double
Dim naiseki As Double
Dim norm1 As Double
Dim norm2 As Double

Dim x1 As Double
Dim y1 As Double
Dim z1 As Double
Dim x2 As Double
Dim y2 As Double
Dim z2 As Double

sita = CalcSita(R, h)

lengthPoPg = CalcLengthPoPg(R, h)

lengthPoPx = lengthPoPg * Cos(sita)
lengthPxPg = lengthPoPg * Sin(sita)
x1 = 0
y1 = lengthPoPx
z1 = lengthPxPg

x2 = lengthPxPg * Cos(ToRadian(10))
y2 = -1 * lengthPxPg * Cos(ToRadian(10))
z2 = -1 * lengthPoPx

naiseki = CalcNaiseki(x1, y1, z1, x2, y2, z2)
norm1 = CalcNorm(x1, y1, z1)
norm2 = CalcNorm(x2, y2, z2)

CalcSikaku = ToDegree(myAcos(naiseki / (norm1 * norm2)))

End Function

Public Function CalcNaiseki(ByVal x1 As Double, ByVal y1 As Double, ByVal z1 As Double, ByVal x2 As
Double,

ByVal y2 As Double, ByVal z2 As Double) As Variant

CalcNaiseki = x1 * x2 + y1 * y2 + z1 * z2

End Function

Public Function CalcNorm(ByVal X As Double, ByVal y As Double, ByVal z As Double) As Variant
Dim wk As Double
wk = X * X + y * y + z * z
CalcNorm = Sqr(wk)
End Function
Public Function CalcLengthPoPg(ByVal R As Double, ByVal h As Variant) As Variant
CalcLengthPoPg = (R + h) * Cos(CalcSita(R, h))
End Function

Public Function CalcSita(ByVal R As Double, ByVal h As Variant) As Variant
CalcSita = myASin(R / (R + h))
End Function

‘度→ラジアン
Public Function ToRadian(ByVal Degrees As Double) As Double
ToRadian = (Application.WorksheetFunction.Pi / 180) * Degrees

End Function

‘ラジアン→度
Public Function ToDegree(ByVal Radian As Double) As Double
ToDegree = (180 / Application.WorksheetFunction.Pi) * Radian
End Function

Function myASin(X As Double) As Double
myASin = Atn(X / Sqr(-X * X + 1#))
End Function

Function myAcos(X As Double) As Double
myAcos = -Atn(X / Sqr(-X * X + 1#)) + (Application.WorksheetFunction.Pi / 2#)
End Function

MS-ACCESSの新規案件対応中

MS-ACCESSでの新規案件があり対応中です。

MS-ACCESSで新規アプリケーション作るのは久しぶりだな。

既存システムの改修とか修正の比率が多かったからな。

来週木曜日から来るバイトの子にはこれを手伝ってもらおうかしら…これか記帳かどっちか手伝ってもらおうか。

事務所間借り(オフィスシェア)しているアイケイシステムズさんに来ていて、インターンからバイトとして来ることになっている若者に手伝ってもらうのはどうだろうとか、アイケイシステムズの菅原社長と雑談しています。

 

mod_rewriteが効かない

WordPressのマルチサイト化(サブディレクトリ型)でエラーとなっていた問題の対応メモ(解決)

注目点は .htaccess と httpd.conf

httpd.confではAllowOverride を All にする

/usr/sbin/httpd -l の実行結果に「mod_so.c」が入っていればモジュール自体は使えるようだ(インストールなどはしなくても良い)

あとは .htaccess の内容をコメントアウトしながら実験する。

RewriteLog という命令はバージョンによりつかえないように見える。

使用OSはCentOS