Combining TCuts with PyROOT

Hi,

I am trying to combine many TCut objects into a single TCut in a python script using
the logical ‘and’ operator but I am having problems. In python I get:

[code]>>> from ROOT import TCut

cut1 = TCut(“x>5”)
cut2 = TCut(“x<2”)
cut3 = cut1 and cut2
cut3.Print()
OBJ: TCut CUT x<2[/code]
whereas in a root interactive session I get:

root [0] TCut cut1("x>5") root [1] TCut cut2("x<2") root [2] TCut cut3 = cut1 && cut2 root [3] cut3.Print() OBJ: TCut CUT (x>5)&&(x<2)
Is there a problem with the logical ‘and’ operator overloading or am I missing something?

Thanks,
Guillaume

Guillaume,

the “and” in python can not be overloaded (the bit-wise & can, but so can that operator in C++, so there is a short-coming). In addition, there is currently no support in PyROOT for friend global functions (it’s on my wishlist). The easiest way to work with TCuts, then, is like so:

[code]>>> cut1 = TCut(“x>5”)

cut2 = TCut(“x<2”)
cut3 = TCut(cut1)
cut3 += cut2
cut3.Print()
OBJ: TCut CUT (x>5)&&(x<2)
[/code]
In the code above, cut1 is first copied into cut3, to prevent cut1 from being changed, then cut2 is added to cut3. The two lines execute “cut3 = TCut(cut1).iadd( cut2 )”.

HTH,
Wim

[quote=“wlav”]Guillaume,

the “and” in python can not be overloaded (the bit-wise & can, but so can that operator in C++, so there is a short-coming). In addition, there is currently no support in PyROOT for friend global functions (it’s on my wishlist). The easiest way to work with TCuts, then, is like so:

[code]>>> cut1 = TCut(“x>5”)

cut2 = TCut(“x<2”)
cut3 = TCut(cut1)
cut3 += cut2
cut3.Print()
OBJ: TCut CUT (x>5)&&(x<2)
[/code]
In the code above, cut1 is first copied into cut3, to prevent cut1 from being changed, then cut2 is added to cut3. The two lines execute “cut3 = TCut(cut1).iadd( cut2 )”.

HTH,
Wim[/quote]

How does one OR cuts together? Or negate them?

e.g. cut1 || ! cut2

Thanks,
Charles

Hi,

same problem with ‘or’ as with ‘and’ I’m afraid (it’s funny though that the TCut header explicitly has to disable a gcc warning b/c of the choice to overload operator|| and operator&& :slight_smile: ).

Best I can think of is some string manipulation:[code]>>> cut1 = TCut(“x>5”)

cut2 = TCut(“x<2”)
cut3 = TCut( cut1.GetTitle() + ’ || !’ + cut2.GetTitle() )
cut3.Print()
OBJ: TCut CUT x>5 || !x<2[/code]
Note that this string manipulation (modulo some error handling and brackets etc.) is what the implementation of the C++ operator|| is actually doing.

HTH,
Wim

[quote=“wlav”]Hi,

same problem with ‘or’ as with ‘and’ I’m afraid (it’s funny though that the TCut header explicitly has to disable a gcc warning b/c of the choice to overload operator|| and operator&& :slight_smile: ).

Best I can think of is some string manipulation:[code]>>> cut1 = TCut(“x>5”)

cut2 = TCut(“x<2”)
cut3 = TCut( cut1.GetTitle() + ’ || !’ + cut2.GetTitle() )
cut3.Print()
OBJ: TCut CUT x>5 || !x<2[/code]
Note that this string manipulation (modulo some error handling and brackets etc.) is what the implementation of the C++ operator|| is actually doing.

HTH,
Wim[/quote]

Well, that ain’t pretty, but it’ll work!

Thanks,
Charles

[quote=“wlav”]Hi,

same problem with ‘or’ as with ‘and’ I’m afraid (it’s funny though that the TCut header explicitly has to disable a gcc warning b/c of the choice to overload operator|| and operator&& :slight_smile: ).

Best I can think of is some string manipulation:[code]>>> cut1 = TCut(“x>5”)

cut2 = TCut(“x<2”)
cut3 = TCut( cut1.GetTitle() + ’ || !’ + cut2.GetTitle() )
cut3.Print()
OBJ: TCut CUT x>5 || !x<2[/code]
Note that this string manipulation (modulo some error handling and brackets etc.) is what the implementation of the C++ operator|| is actually doing.

HTH,
Wim[/quote]

cut3 = TCut ( '%s || ! (%s)' % (cut1, cut2))

Is safer (e.g., if cut2 has multiple statements).

rootpy takes care of this nicely:

https://github.com/rootpy/rootpy

See: https://github.com/rootpy/rootpy/blob/master/rootpy/tree/cut.py

>>> from rootpy.tree import Cut
>>> a = Cut("a > 2")
>>> b = Cut("b < 5")
>>> a | b
(a>2)||(b<5)
>>> a & b
(a>2)&&(b<5)
>>> 
>>> c = Cut("3 < c < 10")
>>> c
3<c&&c<10
>>> 

Noel

Similar to your suggestion of using the add-in-place operator += to “and” cuts together, couldn’t you make the multiply-in-place operator *= implement “or”?

Jean-François

That would be opposite to the standards of symbolic logic where + is OR and * is AND:

http://en.wikipedia.org/wiki/List_of_logic_symbols

rootpy currently implements it as follows:

[code]>>> from rootpy.tree import Cut

a = Cut(‘a < 10’)
b = Cut(‘b > 2’)

a.class.bases
(<class ‘ROOT.TCut’>,)
a
a<10
b
b>2
-a
!(a<10)
a * -1
(a<10)(-1)
-1 * a
(a<10)
(-1)
a-b
(a<10)-(b>2)
-a-b
(!(a<10))-(b>2)
a | -a & b + a
(a<10)||((!(a<10))&&((b>2)+(a<10)))
a += b
a
(a<10)+(b>2)
a &= b
a
((a<10)+(b>2))&&(b>2)
a |= b
a
(((a<10)+(b>2))&&(b>2))||(b>2)
a = b
a
((((a<10)+(b>2))&&(b>2))||(b>2))
(b>2)
-a
!(((((a<10)+(b>2))&&(b>2))||(b>2))*(b>2))
[/code]

You should use the &= and |= operators.

Noel