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: AND
  • Max$(XXX)==1: OR
  • Min$(XXX)==0: NAND
  • Max$(XXX)==0: NOR

にそれぞれ対応する。

もっと平たく言えば

  • 配列要素に少なくとも1つ"XXX"が含まれている: Max$(XXX)==1
  • 配列要素が全て"XXX"である: Min$(XXX)==1
  • 配列要素が全て"XXX"でない: Max$(XXX)==0
  • 配列要素のいずれかが"XXX"でない: Min$(XXX)==0

となるでしょうか

Shoichiro Masuoka

CNS, the Univ. of Tokyo. Dcotoral student

関連項目