Bool型評価にMin/Maxを使うと配列のAND/ORを取るのに使える
以前に 配列を扱う時の便利コマンドとしてMin$
,Max$
を紹介しましたが、これを工夫すると配列でAND/ORを取れる使い方を教わったので、理解を深めつつまとめます。
概説
Max$
, Min$
は配列の要素でLoopを回しているのです。これは通常、配列の中での最大値・最小値を取るといった具合で使うものだと思っていたのですが、今回教わったのはこれをBool型の評価に使うというテクニックです。ある値は何番目の要素であるかが分からない場合、条件をかけるのにこのテクニックは有用です。
論理和・論理積など
以下のようなx
の要素0,1をビットにした配列の組み合わせ
pattern | x |
---|---|
0 | {1,1} |
1 | {1,0} |
2 | {0,1} |
3 | {0,0} |
を作り、tree
に詰めます。Scanすると
tree->Scan()
***********************************************
* Row * Instance * pattern * x *
***********************************************
* 0 * 0 * 0 * 1 *
* 0 * 1 * 0 * 1 *
* 1 * 0 * 1 * 1 *
* 1 * 1 * 1 * 0 *
* 2 * 0 * 2 * 0 *
* 2 * 1 * 2 * 1 *
* 3 * 0 * 3 * 0 *
* 3 * 1 * 3 * 0 *
***********************************************
となります。Max$(x)==1
とすると
tree->Scan("pattern","Max$(x)==1")
************************
* Row * pattern *
************************
* 0 * 0 *
* 1 * 1 *
* 2 * 2 *
************************
==> 3 selected entries
ビットの最大値が1である時にTrueを返すので、これはOR(論理和)になっています。
次にMin$(x)==1
とすると
tree->Scan("pattern","Min$(x)==1")
************************
* Row * pattern *
************************
* 0 * 0 *
************************
==> 1 selected entry
ビットの最小値が1である時にTrueを返すので、これはAND(論理積)になっています。
Max$(x)==0
はORの否定なので
tree->Scan("pattern","Max$(x)==0")
************************
* Row * pattern *
************************
* 3 * 3 *
************************
==> 1 selected entry
当然、NOR(否定論理和)になります。
同様にMin$(x)==0
はANDの否定なので
tree->Scan("pattern","Min$(x)==0")
************************
* Row * pattern *
************************
* 1 * 1 *
* 2 * 2 *
* 3 * 3 *
************************
==> 3 selected entries
と、NANDを返します。
つまり
tree->Scan("x[0]:x[1]:Min$(x)==1:Max$(x)==1:Min$(x)==0:Max$(x)==0","","colsize=10")
******************************************************************************************
* Row * x[0] * x[1] * Min$(x)==1 * Max$(x)==1 * Min$(x)==0 * Max$(x)==0 *
******************************************************************************************
* 0 * 1 * 1 * 1 * 1 * 0 * 0 *
* 1 * 1 * 0 * 0 * 1 * 1 * 0 *
* 2 * 0 * 1 * 0 * 1 * 1 * 0 *
* 3 * 0 * 0 * 0 * 0 * 1 * 1 *
******************************************************************************************
と,AND,OR,NAND,NORをそれぞれMin$, Max$
で作れるという原理です。
例
具体的な配列を用いて、例を示します。
使うデータ
このようなTreeを用意します。
#include "TTree.h"
#include "TBranch.h"
#include "TFile.h"
void makeTree_maxmin() {
TTree *tree = new TTree("tree","tree");
Int_t pattern;
Int_t x[3] = {0};
tree->Branch("pattern",&pattern,"pattern/I");
tree->Branch("x",x,"x[3]/I");
pattern = 0;
x[0] = 0; x[1] = -1; x[2] = -2;
tree->Fill();
pattern = 1;
x[0] = -1; x[1] = -2; x[2] = -3;
tree->Fill();
pattern = 2;
x[0] = 0; x[1] = 1; x[2] = 2;
tree->Fill();
pattern = 3;
x[0] = 1; x[1] = 2; x[2] = 3;
tree->Fill();
pattern = 4;
x[0] = 0; x[1] = 10; x[2] = 20;
tree->Fill();
pattern = 5;
x[0] = 10; x[1] = 100; x[2] = 1000;
tree->Fill();
TFile *file = new TFile("testTree.root","recreate");
tree->Write();
file->Close();
}
x
は配列で、パターンIDによって次のような要素が詰まれています。
pattern | x |
---|---|
0 | {0,-1,-2} |
1 | {-1,-2,-3} |
2 | {0,1,2} |
3 | {1,2,3} |
4 | {0,10,20} |
5 | {10,100,1000} |
念の為、tree->Scan()
を実行すると
root [1] tree->Scan("pattern:x")
***********************************************
* Row * Instance * pattern * x *
***********************************************
* 0 * 0 * 0 * 0 *
* 0 * 1 * 0 * -1 *
* 0 * 2 * 0 * -2 *
* 1 * 0 * 1 * -1 *
* 1 * 1 * 1 * -2 *
* 1 * 2 * 1 * -3 *
* 2 * 0 * 2 * 0 *
* 2 * 1 * 2 * 1 *
* 2 * 2 * 2 * 2 *
* 3 * 0 * 3 * 1 *
* 3 * 1 * 3 * 2 *
* 3 * 2 * 3 * 3 *
* 4 * 0 * 4 * 0 *
* 4 * 1 * 4 * 10 *
* 4 * 2 * 4 * 20 *
* 5 * 0 * 5 * 10 *
* 5 * 1 * 5 * 100 *
* 5 * 2 * 5 * 1000 *
***********************************************
(Long64_t)18
と出力されます。
Max$()==1
はORを取る
例えば、上の例で、 少なくとも1つの要素に10を含む パターンを探したい時には
tree->Scan("pattern","Max$(x==10)==1");
とすれば、
************************
* Row * pattern *
************************
* 4 * 4 *
* 5 * 5 *
************************
==> 2 selected entries
と、10を要素に含むパターン4,5が返って来ます。これは、要素の中でのORを取っていることになります。pattern4では1番め、pattern5では0番めの値ですが、区別なく条件をかけられています。
少なくとも1つの要素に10を含む の余事象は 全ての要素に10が含まれていない ですので、
tree->Scan("pattern","Max$(x==10)==0")
と表現すると
************************
* Row * pattern *
************************
* 0 * 0 *
* 1 * 1 *
* 2 * 2 *
* 3 * 3 *
************************
==> 4 selected entries
と、10が含まれていないパターン0,1,2,3が抽出できます。
少なくとも1つの要素が負である パターンは
tree->Scan("pattern","Max$(x<0)==1")
と書けば良く、その結果は
************************
* Row * pattern *
************************
* 0 * 0 *
* 1 * 1 *
************************
==> 2 selected entries
となります。
Min$()
はANDを取る
次に、 全ての要素が負である パターンは
tree->Scan("pattern","Min$(x<0)==1")
と、書きます。すると
************************
* Row * pattern *
************************
* 1 * 1 *
************************
==> 1 selected entry
と、全ての要素が負であるパターン1のみ返って来ます。これは配列の要素の中でANDを取っていることになります。
全ての要素が負である の余事象は いずれかの要素が0以上である ですので、
tree->Scan("pattern","Min$(x<0)==0")
と書けば
************************
* Row * pattern *
************************
* 0 * 0 *
* 2 * 2 *
* 3 * 3 *
* 4 * 4 *
* 5 * 5 *
************************
==> 5 selected entries
と返って来ます。
まとめ
Min$(XXX)==1
: ANDMax$(XXX)==1
: ORMin$(XXX)==0
: NANDMax$(XXX)==0
: NOR
にそれぞれ対応する。
もっと平たく言えば
- 配列要素に少なくとも1つ"XXX"が含まれている:
Max$(XXX)==1
- 配列要素が全て"XXX"である:
Min$(XXX)==1
- 配列要素が全て"XXX"でない:
Max$(XXX)==0
- 配列要素のいずれかが"XXX"でない:
Min$(XXX)==0
となるでしょうか