2016年10月31日月曜日

数独を解く2

10月28日付けブログの数独を解くプログラムで、数独を解いてみた。連続的に解くために若干の修正をしたが、本質的には変わりない。

サンプルとして挙げた「超極・激」には、対角線指定や、変形3×4などが含まれており、それらを除いた通常のもの130題を解いたものである。

出力の冒頭を以下に示す。



問題と解答と所要時間を示した。

解答時間の平均は0.692秒 最大3.44秒であった。使用マシンのCPUはi7である。解答時間の分布は



詳細を検討してみると、checkだけで解けているものも多数あり、solveを用いて試行錯誤的にアプローチしているものも多い。solveを用いた場合、再帰の深さは結構深いのが目につく。

前回の解法アルゴリズムで、1つのグループ内に例えば5の可能性のあるマスが1つだけならばそこが5である、というアルゴリズムを最後に付け加えた。

これを拡張して、1つのグループ内に可能性が5と8だけであるマスが2つあれば、そのグループのほかのマスからは5と8の可能性が削除できる。

また、1つのグループ内に 可能性5と8を含むますが2つだけならば、その2つのマスの5と8以外は削除できる。

さらに拡張すると、1つのグループ内に例えば可能性が5と8と9だけであるマスが3つあれば、そのグループのほかのマスからは5と8と9の可能性が削除できる。この場合、この3つのマスのうちの1つは「5と8」でもよい。など。

これらについてはまだ、実装してない。

2016年10月28日金曜日

数独を解く (sudoku ナンプレとも)

Rで数独を解いてみた。その中で、R独特の機能が結構有効であったので、解説してみる。サンプルとして、Take-Shobo「ナンプレ超極・激」の30番を使用した。次のような問題である。

結果は

整形してないので見にくいが、9文字ごとに改行を入れると答えになる。もちろん先頭の[1]などは除いて。

Rのプログラムというのだろうか、ソースは以下のようなものである。

1行目、qが問題である。81文字の数字で、0は空欄を表す。q すなわち question である。

2行目、qを1文字ずつに分解し、更に数値に変換している。0~9の数字81個のベクトルである。名前bはボードの意である。
プログラムの中で、bは重要な位置を占める。
数独の問題は、視覚的には平面であるが、プログラム内では1次元ベクトルとして表現している。実は、この方がよいのである。そのことはだんだんと分かってくる。
数独のマスに順に1~81までの番号を付け、この番号を「座標」と呼ぶことにする。座標はiであらわす。

3行目から10行めはグループの指定である。
数独では各1行の中に1~9のすべての数字が入る。各1列の中にも同様である。さらに、3×3に分けた9個の各正方形の中においても同様である。この、行・列・3×3正方形の1つずつを「グループ」と呼ぶことにする。gsは各グループの座標を持つ行列である。gsはグループスの意味である。内容は次のようになる。

[1,]は1行目を表す。[10,]は1列目を表す。[19,]は左上の3×3正方形を表す。
gsを用いて、各グループに同じ数字がないことを確認するのである。実は思いがけない利用法がある、対角線上に1~9があることを条件としたり、変な形の領域に1~9があることを条件にする問題があるが、ここを変えればよいのである。
グループは27個あり、その番号はkで指定する。また、一つのグループはベクトルgで表す。

11行めから44行めの関数checkが肝である。
引数が複雑だが、外から使うときはcheck(b)のように使えばよい。このように使うと、12行めで行列sbを作る。
このsbがこのプログラムのもう一つの重要点である。サブボードのつもりでsbという名前を付けた。
ボードの各マスには1~9のいずれかの数字が入るのだが、その候補を記録するのがsbである。
sbは81行9列の行列で、各行が、各座標に入る数字の候補を記録している。
sb[i,n]は、座標iに数字nが入る可能性があれば1、なければ0をとる。
例えば1行目が 1,1,0,0,0,0,1,1,1 となっているとすると、座標1のところには、1,2,7,8,9のいずれかが入る。逆に言えば3,4,5,6は入らないことを意味する。
sbの候補をどんどん減らしていって答えを見つけるのである。
最初はすべて1である。すなわち、すべての数字の入る可能性がある。

どのように候補を絞っていくかが、そのあとに続く。

15・16行めは、ボードに数字が入っている場合、すなわち0でない場合は、その座標のsbは、その数字のところを1とし、それ以外を0とする。

b[i]は座標iの位置にある数字である。「sb[i,-b[i]]=0」はsbのi行めのうちの、「b[i]すなわち座標iの数字」以外のところを0にする。普通の言語だとループでやるところだ。こんなに簡単にできる。(簡単というのは表現の文字数が少ないという意味だ。表現の理解はそう簡単ではない)

18行めから26行め。for文を使ってしまった。applyか何かでやりたいところだが、今後の課題。
ここでは、ボード上で数字が入っていたら、その座標を含むグループのほかの座標ではその数字は使えないので、sbのその位置を0にする。もっと具体的に言うと、座標iの位置にある数字がnのとき、座標iを含むグループの他の座標jについて、sb[j,n]を0にするのだ。
プログラムに沿って解説する。
kはグループ番号で、1~27まで変わる。
k番目のグループをgとする。gは長さ9のベクトルで、k番目のグループの座標を持っている。
pはg内をポイントし、1~9変わる。
g[p]がグループgのp番目の座標なので、その位置の数字はn=b[g[p]]となる。nが0の時は数字はないので何もしない。0でないときは座標g[p]に数字nがあるので、そのグループ内のほかの座標のsbのnのところを0にしなければならない。なんとそれが、
sb[g[-p],n]=0でできてしまう。g[-p]はグループgのポイントしている以外のすべての座標からなるベクトルだ。それらの行のn番目を0にするのだ。

ここまではbの情報をもとにsbを変更した。

次の27行めから30行めは、sbをもとに、bを変更する部分である。

iはボード上の座標である。1~81の値をとる。
sb[i,]は座標iのサブボード情報である。すなわち、各数字が可能性があるかどうかを示す9つの数(0か1)からなる。
sum(sb[i,])が0だということは、その座標に入る数字がないことになる。すなわち、解(甲斐)なしである。NULLを返すこととした。
sum(sb[i,])が1だということは、座標iに入る数字が一つに決まったということである。その場合はボードに数字を書き込む。

15行めから30行目までを繰り返すと、易しい問題は解ける。繰り返しは必要で、sbからbに変更が加わるとそのbからまたsbに変更が生し、・・・ということがあるからである。13行めから42行目までがrepeatで囲まれているのはそのためである。
繰り返して、変更がなくなったらrepeatを抜けるのだが、その判断は、sbのフラグの総数の変化で調べている。sbのフラグ(1)の総数は単調減少だ。

31行めから40行めの説明は後回しにする。

43行め、返す値は、ボードbとサブボードsbのリストである。

checkだけで解ける問題は易しい問題である。checkだけでは解けない問題を試行錯誤で解くようにしたのがsolveである。
solveは最初の空欄に1~9までの数字を当てはめてcheckを繰り返す。1段階の当てはめでうまくいかない場合は、再帰的に多段階で挑戦させる。

solveの引数はl(エル)である。checkで返すリストを引数にする。リストなのでlだ。l[[1]]はボード、l[[2]]はサブボードだ。サブボードは渡さなくても計算できるが、せっかくそれまで計算したものをはじめから計算するのもどうかと思って、引数として渡すことにした。

さて、最後に残った31行めから40行めだ。
当初、これはつけないつもりでいた。試行錯誤させればよいと考えていたからだ。ところがサンプルの問題では1時間ほど動かしても答えが出ない。空欄が多い問題ではこうなるのは必然だ。

ここでやっていることは、1つのグループ内のsbのフラグをすべて見て、例えば5のフラグが1個しか立っていないならば、そこが5だ
ということを調べている。

このルーチンを付け加えたら、サンプル問題は一瞬で解けた。試行錯誤なしで、checkのみで解けた。「超極・激」というには情けない。まあ、30番だから。このあと難しいのがあるのだと思う。

このように実際の数独を解くときに使う戦略を組み込むと速度は劇的に改善する。今回Rで作ってみたが、以前に一度python3でプログラムしたことがある。その時の経験に基づいた発言である。

以上でこの稿は終わる。
しばらく、更新してなかったので、更新しなければという強迫観念で書いた。
きっと読みにくいだろうと思う。
面白いと思ってくれる人がいるのだろうか?

2016年9月1日木曜日

Print Edit ・・・FireFox アドオン

 WEBサイトを閲覧していて、ここぞというところを印刷したいことはよくある。chromeだと、選択部分の印刷ができるのだが、FireFoxの方は、アドオンを使えとつれない。

そんな中でこのアドオンに行き着いた。しかし、WEBで使い方を調べても、入口の説明しか見当たらない。で、いくらか調べてみたので、僭越ながら、紹介する。なお、アドオンのインストール方法などは割愛する。

アイコンは次のようなものである。

クリックすると

上の方にメニューが出ている。このメニューは大変長く、次のようになっている。

選択 隠す 削除 他の要素を隠す 他の要素を削除 フォーマット Text 元に戻す すべて元に戻す 保存 テキスト要素 Webスタイル プレビュー 閉じる ヘルプ ツール

この状態で、印刷したい部分(または印刷したくない部分)を選択する。下の図の赤で囲まれたところが選択された部分だ。今回は、赤い範囲の右下のあたりをクリックして選択した。

クリックして選択する以外に、ドラッグして範囲選択することもできる。ただし、ドラッグした中にすべてが含まれる要素が選択される。画像の半分とか、段落の一部とかの選択はできない(と思われる)。



印刷したい部分が選択できたら、「他の要素を削除」すると、「Restricted」「Without Flow」「Unrestricted」から一つ選ぶ。「Without Flow」を選んだのが次の図だ。なお、「Restricted」を選ぶと、左にマージンが出た。「Unrestricted」だと、フォーマットせずにべたな感じになった。



これで、プレビュー → 印刷 すればよい。

と、ここまではほかのサイトでもよく書かれている。

選択範囲が長くなると、適当なところで改ページしたい場合がある。その方法を以下に示す。

「今これがほしい」を選択して、「フォーマット」ボタンを押し、更に、赤1でプロパティを表示し、赤2で「Page Break」にチェックを入れたが次の図である。この画面では改ページされていないが、プレビューすると改ページが入ったことがわかる。



フォーマットで出てくる項目は改ページだけでではない。色やフォントやマージンなどの変更ができることがわかるだろう。

では、文字を入れたい場合はどうするか。

「甚大な被害」の写真を含むブロックを選択して、「Text」ボタンを押して、次の図。



テキストボックスに「大注目!!!」と入力した。また、その左下、「inline After」を選択した。OKすると、



選択した部分の「次」に、文字列が挿入されている。

それ以外のメニューなどを、ざっくり紹介しておこう。

左端の「選択」は、何か選択すると「選択解除」というメニューにかわる

「隠す」は選択した部分を白くする。詰めたりはしない。

「削除」は選択した部分を削除して、空間が開けばそこを詰める。

「他の要素を隠す」「他の要素を隠す」は隠す・削除を選択した以外の要素に適用する。

「フォーマット」「Text」は前述した。

「元に戻す」「すべて元に戻す」はその通りで、いろいろと試行錯誤できる。

「保存」はいろいろな形で保存できる。今のところ使う必要を感じない。

「テキスト要素」「Webスタイル」わからない。

「プレビュー」「閉じる」この通り。

「ヘルプ」マウスアクションとショートカットのヘルプ

「ツール」設定はわかるが、「Fix Page Breaks」の意味が分からない。


以上です。大変便利です。画像がぼけててすみません。

2016年8月20日土曜日

ローソク足の順序変更 その2 移動平均乖離率

 先のローソク足の順序変更で議論したものを関数化した。次のようなチャートになる。

チャート中の赤い曲線はオープンギャップ(当日始値/前日終値-1)の値である。また、ローソク足は、実際の金額ではなくて、始値からの比率とした。例えば、終値については 終値/始値-1 の値である。そのほかも同じで、始値は0となる。
オープンギャップだけではもったいないので、ほか指数でも同様にソートしてローソク足を表示するようにしてみた。
関数名はsortChartで第1引数に日足4本値データ、第2引数に指数を書く。5日移動平均からの乖離率を指数とするには次のように使う。


第2引数 lag(Delt(SMA(Cl(z),5),Cl(z))) について説明する。zは日足4本値データxts型で、Cl(z)はその終値である。SMAは移動平均を求める関数で、SMA(Cl(Z),5)で5日移動平均を求めている。Deltは比率を求める関数で、Delt(a,b)でb/a-1を計算する。Delt(SMA(Cl(z),5),Cl(z))で5日移動平均からの乖離率となる。lagを付けないとピッタリ符合するのだが、前日の終値の乖離率から判断するのだからlagが必要だ。チャートの赤い線が乖離率である。



同様に25日移動平均からの乖離率でみると


参考までにソースは次の通り

8行め中ほどのinfo(z)は私設の関数。zのコード・銘柄名・市場・業種と、次の1は貸借銘柄を意味する文字列を返す。もしも万が一このコードを動かしてみたいと思われるのならば、この部分を削除し、先頭に library(quantmod) と入れれば動くと思われる。 

9行めのコメントは10行めと取り換えると、指数をチャート内に表示するように縮尺する。

第2引数を省略するとオープンギャップを採用する。

各値がわかるように、データフレームを返すようにしてある。

ローソク足の順序変更・・・OGP オープンギャッププレー

 前日の終値と当日の始値の差をギャップというらしい。ギャップと当日の様子を比較するにはどうしたらよいかと考えるうちに、ギャップ順にソートしたローソク足を見たいと思い立った。
 xts型のデータの順序を変えてチャートを描けばよいのだが、うまくいかない。悪戦苦闘の状況を以下に記す。試してうまくいかなかったことも記録したので(こちらの方が主かもしれない)冗長である。
 コンソール出力に続いて、コメントの形でその解説という順序で記述してある。

> z
Open High Low Close Volume B
2016-08-15 734 775 732 762 107200 80887900
2016-08-16 754 805 754 783 178800 140945300
2016-08-17 768 792 726 726 177100 133505500
2016-08-18 705 712 671 676 157300 108283000
2016-08-19 666 704 651 695 226500 152292900

#zは4本値データである。

> g=Delt(lag(Cl(z)),Op(z))
> g
Delt.0.arithmetic
2016-08-15 NA
2016-08-16 -0.01049869
2016-08-17 -0.01915709
2016-08-18 -0.02892562
2016-08-19 -0.01479290

#ギャップの計算。前日終値と当日始値の差ではなくて、比率を採用した。
#具体的には g = 当日始値/前日終値-1

> order(g)
[1] 4 3 5 2 1
> z[order(g)]
Open High Low Close Volume B
2016-08-15 734 775 732 762 107200 80887900
2016-08-16 754 805 754 783 178800 140945300
2016-08-17 768 792 726 726 177100 133505500
2016-08-18 705 712 671 676 157300 108283000
2016-08-19 666 704 651 695 226500 152292900

#order(g)順に並べると、先頭は4番目のデータであるから08-18であるが、順序は変わっていない。xts型のデータの表示には自動的に日付順に並べ替えられるのだろう。ということは、zのxts属性を落とせばいいのではないか。

> as.data.frame(z)[order(g),]
Open High Low Close Volume B
2016-08-18 705 712 671 676 157300 108283000
2016-08-17 768 792 726 726 177100 133505500
2016-08-19 666 704 651 695 226500 152292900
2016-08-16 754 805 754 783 178800 140945300
2016-08-15 734 775 732 762 107200 80887900
#お、うまくいっている。

> mc0(as.data.frame(z)[order(g),])

#mc0はchartSeriesのラッパー関数だ。chartSeriesで再び日付順に並べ替えられてしまうらしい。ということは、結局、日付を変えなければだめということか。方針変更

> rank(g)
Error in if (xi == xj) 0L else if (xi > xj) 1L else -1L :
argument is of length zero

#gの順位を日付に埋め込もうと思う。またしてもgがxts型であることが問題らしい。

> rank(unclass(g))
[1] 5 4 2 1 3

#gの型をなくしたらうまくいった。

> xts(z,as.Date(rank(unclass(g))))
Open High Low Close Volume B
1970-01-02 734 775 732 762 107200 80887900
1970-01-03 754 805 754 783 178800 140945300
1970-01-04 768 792 726 726 177100 133505500
1970-01-05 705 712 671 676 157300 108283000
1970-01-06 666 704 651 695 226500 152292900

#関数xtsの第2引数は日付(時間)をとる。確かに日付は変わっているが、順序が変わっていない。zがxts型のせいだろう。

> xts(unclass(z),as.Date(rank(unclass(g))))
Open High Low Close Volume B
1970-01-02 705 712 671 676 157300 108283000
1970-01-03 768 792 726 726 177100 133505500
1970-01-04 666 704 651 695 226500 152292900
1970-01-05 754 805 754 783 178800 140945300
1970-01-06 734 775 732 762 107200 80887900

#おお、うまくいった。

> mc0(xts(unclass(z),as.Date(rank(unclass(g)))))


#これでよい。

> mc0(xts(unclass(z-as.numeric(Op(z))),as.Date(rank(unclass(g)))))

#始値をそろえてみた。左の方が前日終値より始値の方が低いので、当日は陽線が期待されるのだが、この5つの例では低いほうがさらに陰線になるという、ほんとかいなという状況である。

以下は、2132アイレップ、7203トヨタ、8411みずほの2016年について同様の操作をしたものである。


左の方が陽線が目立つ。

2016年7月18日月曜日

損切ラインと利益確定ラインについて

 私は、始値で買って、±5%程度で、指値と逆指値を入れるということを試しています。損切も利益確定も同じ幅にしています。それはなぜかというと、損切を小さく、利益確定を大きくすると損切に達する確率が高くなって、結局のところいつも損切にあってしまうのではないかとの危惧と、同じ幅にしておけば、上がると予想したことが外れたと原因がはっきりすると考えたからです。

今回この戦略をテストしてみました。対象は2132アイレップ 2015-03-13~2016-07-13です。

始値で買って、損切ラインや利益確定ラインに達すればその値段で売り、売れなかったら大引けで手仕舞うという想定です。

手元のデータは4本値だけなので、損切と利益確定の両方に達した時、どちらに先に達しているかは判別できません。

次は、損切を始値の5円下、利益確定を10円上に設定した場合です。

1行目、入力の説明をします。

culcは関数名です。

zはアイレップの4本値データ(xts)です。

続く引数の5,10は損切幅と利益確定幅の指定です。

2・3行目 出力の説明をします。

損回は損切に達した回数です。 Lo(z) <= Op(z)-5 の回数を数えています。 利回は利益確定ラインに達した回数です。 Hi(z)>= Op(z)+10 の回数を数えています。

損利両回は両方のラインに達した回数です。実際にはどちらに達しているのかわかりません。

引回は両ラインに到達せず、大引けで売った回数です。

引損益は大引けで売ったときの損益です。

損切は損切ラインの値段で売れたものと仮定しています。実際にはそれより下がることもありますが。従って損の合計は損回*-5円となります。同様に利益確定の合計は利回*10円、全計はこの2つに引損益を加えたものです。

修正計は、両ラインに達した時、損切ラインに達したものとして同様の合計を出したものです。

この場合は、損切ライン到達が160回、利益確定ラインに到達が122回、両ラインに到達したものが63回。大引けで売ったのが109回で、両方に到達しているときすべて損切ラインに到達したとすると、最終損益は-180円であるということを意味しています。

損切ラインと利益確定ラインを変えると、どうなるでしょうか。損切ラインを1~100円、利益確定ラインも1~100円にして、10000通りの組み合わせで、計算してみました。10000行表示してもいかがかと思うので、主なところを以下に示します。write.csv出力してexcelで開いた画面のハードコピーです。



最も成績の良いのが損切-18円、利益確定+57円です。

損切ライン到達が57回、損益-18*57=-1206円。利益確定ラインに到達が11回、57*11=+627円。両方に到達したケースはありませんでした。大引けまで行ったのが260回、+1201円。最終損益は802円です。

現在の終値は872円ですので、18円というのは2%にあたります。

この期間の始値292円、終値872円。単に持っていれば+580円です。

損切ラインは思いのほか小さいこと、利益確定ラインはなくてもいいくらいですが、高いところに設定しておけば、引けに向けて値下がりするときに有効なことがあるということでしょうか。勉強になりました。

ほかの銘柄で同様なことをやってみると、損切幅1円などという銘柄が多数出てきました。全体に値下がりしている銘柄はそうなるのでしょう。アイレップは右肩上がりの銘柄であったということも大きな要因かと思います。また、アイレップにしても現在大幅な下降局面に入った感があり、この戦略を今、当てはめてみようとは、思いません。なお、アイレップは2015年の11月ごろから値動きの様子が大幅に変化しました。この時期後で同じことをやってみると損切幅17円でした。

見る人もいますまいが、一応culcのソースをあげておきます。



2016年7月14日木曜日

xtsのcsv出力

zzはxts型のデータである。

これをcsv出力すると、次のようになる。

日付が消えてしまう。この場合は、write.zooを使う


Stack Overflow に出ていた。