From 268604ea2ce8c72590f11c3dc553bbb7a8833763 Mon Sep 17 00:00:00 2001 From: siliataider Date: Fri, 3 Oct 2025 11:53:36 +0200 Subject: [PATCH 1/2] Fix TH2 and TH3 arithmetic operators in Python --- hist/hist/inc/TH2.h | 64 +++++++++++++++++++++++++++++++++++++---- hist/hist/inc/TH3.h | 69 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 11 deletions(-) diff --git a/hist/hist/inc/TH2.h b/hist/hist/inc/TH2.h index 84b3200261dd1..93ff389aa6cce 100644 --- a/hist/hist/inc/TH2.h +++ b/hist/hist/inc/TH2.h @@ -166,7 +166,7 @@ class TH2C : public TH2, public TArrayC { TH2C& operator=(const TH2C &h1); friend TH2C operator*(Float_t c1, TH2C const &h1); - friend TH2C operator*(TH2C const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH2C operator*(TH2C const &h1, Float_t c1); friend TH2C operator+(TH2C const &h1, TH2C const &h2); friend TH2C operator-(TH2C const &h1, TH2C const &h2); friend TH2C operator*(TH2C const &h1, TH2C const &h2); @@ -179,6 +179,15 @@ class TH2C : public TH2, public TArrayC { ClassDefOverride(TH2C,4) //2-Dim histograms (one char per channel) }; +TH2C operator*(Float_t c1, TH2C const &h1); +inline TH2C operator*(TH2C const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH2C operator+(TH2C const &h1, TH2C const &h2); +TH2C operator-(TH2C const &h1, TH2C const &h2); +TH2C operator*(TH2C const &h1, TH2C const &h2); +TH2C operator/(TH2C const &h1, TH2C const &h2); //______________________________________________________________________________ @@ -208,7 +217,7 @@ class TH2S : public TH2, public TArrayS { TH2S& operator=(const TH2S &h1); friend TH2S operator*(Float_t c1, TH2S const &h1); - friend TH2S operator*(TH2S const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH2S operator*(TH2S const &h1, Float_t c1); friend TH2S operator+(TH2S const &h1, TH2S const &h2); friend TH2S operator-(TH2S const &h1, TH2S const &h2); friend TH2S operator*(TH2S const &h1, TH2S const &h2); @@ -221,6 +230,15 @@ class TH2S : public TH2, public TArrayS { ClassDefOverride(TH2S,4) //2-Dim histograms (one short per channel) }; +TH2S operator*(Float_t c1, TH2S const &h1); +inline TH2S operator*(TH2S const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH2S operator+(TH2S const &h1, TH2S const &h2); +TH2S operator-(TH2S const &h1, TH2S const &h2); +TH2S operator*(TH2S const &h1, TH2S const &h2); +TH2S operator/(TH2S const &h1, TH2S const &h2); //______________________________________________________________________________ @@ -250,7 +268,7 @@ class TH2I : public TH2, public TArrayI { TH2I& operator=(const TH2I &h1); friend TH2I operator*(Float_t c1, TH2I const &h1); - friend TH2I operator*(TH2I const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH2I operator*(TH2I const &h1, Float_t c1); friend TH2I operator+(TH2I const &h1, TH2I const &h2); friend TH2I operator-(TH2I const &h1, TH2I const &h2); friend TH2I operator*(TH2I const &h1, TH2I const &h2); @@ -263,6 +281,16 @@ class TH2I : public TH2, public TArrayI { ClassDefOverride(TH2I,4) //2-Dim histograms (one 32 bit integer per channel) }; +TH2I operator*(Float_t c1, TH2I const &h1); +inline TH2I operator*(TH2I const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH2I operator+(TH2I const &h1, TH2I const &h2); +TH2I operator-(TH2I const &h1, TH2I const &h2); +TH2I operator*(TH2I const &h1, TH2I const &h2); +TH2I operator/(TH2I const &h1, TH2I const &h2); + //______________________________________________________________________________ class TH2L : public TH2, public TArrayL64 { @@ -289,7 +317,7 @@ class TH2L : public TH2, public TArrayL64 { void SetBinsLength(Int_t n=-1) override; TH2L& operator=(const TH2L &h1); friend TH2L operator*(Float_t c1, TH2L const &h1); - friend TH2L operator*(TH2L const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH2L operator*(TH2L const &h1, Float_t c1); friend TH2L operator+(TH2L const &h1, TH2L const &h2); friend TH2L operator-(TH2L const &h1, TH2L const &h2); friend TH2L operator*(TH2L const &h1, TH2L const &h2); @@ -302,6 +330,16 @@ class TH2L : public TH2, public TArrayL64 { ClassDefOverride(TH2L,0) //2-Dim histograms (one 64 bit integer per channel) }; +TH2L operator*(Float_t c1, TH2L const &h1); +inline TH2L operator*(TH2L const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH2L operator+(TH2L const &h1, TH2L const &h2); +TH2L operator-(TH2L const &h1, TH2L const &h2); +TH2L operator*(TH2L const &h1, TH2L const &h2); +TH2L operator/(TH2L const &h1, TH2L const &h2); + //______________________________________________________________________________ class TH2F : public TH2, public TArrayF { @@ -350,6 +388,12 @@ class TH2F : public TH2, public TArrayF { ClassDefOverride(TH2F,4) //2-Dim histograms (one float per channel) }; +TH2F operator*(Float_t c1, TH2F const &h1); +TH2F operator*(TH2F const &h1, Float_t c1); +TH2F operator+(TH2F const &h1, TH2F const &h2); +TH2F operator-(TH2F const &h1, TH2F const &h2); +TH2F operator*(TH2F const &h1, TH2F const &h2); +TH2F operator/(TH2F const &h1, TH2F const &h2); //______________________________________________________________________________ @@ -385,7 +429,7 @@ class TH2D : public TH2, public TArrayD { TH2D& operator=(const TH2D &h1); friend TH2D operator*(Float_t c1, TH2D const &h1); - friend TH2D operator*(TH2D const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH2D operator*(TH2D const &h1, Float_t c1); friend TH2D operator+(TH2D const &h1, TH2D const &h2); friend TH2D operator-(TH2D const &h1, TH2D const &h2); friend TH2D operator*(TH2D const &h1, TH2D const &h2); @@ -398,4 +442,14 @@ class TH2D : public TH2, public TArrayD { ClassDefOverride(TH2D,4) //2-Dim histograms (one double per channel) }; +TH2D operator*(Float_t c1, TH2D const &h1); +inline TH2D operator*(TH2D const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH2D operator+(TH2D const &h1, TH2D const &h2); +TH2D operator-(TH2D const &h1, TH2D const &h2); +TH2D operator*(TH2D const &h1, TH2D const &h2); +TH2D operator/(TH2D const &h1, TH2D const &h2); + #endif diff --git a/hist/hist/inc/TH3.h b/hist/hist/inc/TH3.h index 62eea0c55cabc..9ebde9afe8ef1 100644 --- a/hist/hist/inc/TH3.h +++ b/hist/hist/inc/TH3.h @@ -191,7 +191,7 @@ class TH3C : public TH3, public TArrayC { TH3C& operator=(const TH3C &h1); friend TH3C operator*(Float_t c1, TH3C const &h1); - friend TH3C operator*(TH3C const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3C operator*(TH3C const &h1, Float_t c1); friend TH3C operator+(TH3C const &h1, TH3C const &h2); friend TH3C operator-(TH3C const &h1, TH3C const &h2); friend TH3C operator*(TH3C const &h1, TH3C const &h2); @@ -204,6 +204,15 @@ class TH3C : public TH3, public TArrayC { ClassDefOverride(TH3C,4) //3-Dim histograms (one char per channel) }; +TH3C operator*(Float_t c1, TH3C const &h1); +inline TH3C operator*(TH3C const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3C operator+(TH3C const &h1, TH3C const &h2); +TH3C operator-(TH3C const &h1, TH3C const &h2); +TH3C operator*(TH3C const &h1, TH3C const &h2); +TH3C operator/(TH3C const &h1, TH3C const &h2); //________________________________________________________________________ class TH3S : public TH3, public TArrayS { @@ -230,7 +239,7 @@ class TH3S : public TH3, public TArrayS { TH3S& operator=(const TH3S &h1); friend TH3S operator*(Float_t c1, TH3S const &h1); - friend TH3S operator*(TH3S const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3S operator*(TH3S const &h1, Float_t c1); friend TH3S operator+(TH3S const &h1, TH3S const &h2); friend TH3S operator-(TH3S const &h1, TH3S const &h2); friend TH3S operator*(TH3S const &h1, TH3S const &h2); @@ -243,6 +252,16 @@ class TH3S : public TH3, public TArrayS { ClassDefOverride(TH3S,4) //3-Dim histograms (one short per channel) }; +TH3S operator*(Float_t c1, TH3S const &h1); +inline TH3S operator*(TH3S const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3S operator+(TH3S const &h1, TH3S const &h2); +TH3S operator-(TH3S const &h1, TH3S const &h2); +TH3S operator*(TH3S const &h1, TH3S const &h2); +TH3S operator/(TH3S const &h1, TH3S const &h2); + //________________________________________________________________________ class TH3I : public TH3, public TArrayI { @@ -269,7 +288,7 @@ class TH3I : public TH3, public TArrayI { TH3I& operator=(const TH3I &h1); friend TH3I operator*(Float_t c1, TH3I const &h1); - friend TH3I operator*(TH3I const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3I operator*(TH3I const &h1, Float_t c1); friend TH3I operator+(TH3I const &h1, TH3I const &h2); friend TH3I operator-(TH3I const &h1, TH3I const &h2); friend TH3I operator*(TH3I const &h1, TH3I const &h2); @@ -282,6 +301,15 @@ class TH3I : public TH3, public TArrayI { ClassDefOverride(TH3I,4) //3-Dim histograms (one 32 bit integer per channel) }; +TH3I operator*(Float_t c1, TH3I const &h1); +inline TH3I operator*(TH3I const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3I operator+(TH3I const &h1, TH3I const &h2); +TH3I operator-(TH3I const &h1, TH3I const &h2); +TH3I operator*(TH3I const &h1, TH3I const &h2); +TH3I operator/(TH3I const &h1, TH3I const &h2); //________________________________________________________________________ @@ -307,7 +335,7 @@ class TH3L : public TH3, public TArrayL64 { void SetBinsLength(Int_t n=-1) override; TH3L& operator=(const TH3L &h1); friend TH3L operator*(Float_t c1, TH3L const &h1); - friend TH3L operator*(TH3L const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3L operator*(TH3L const &h1, Float_t c1); friend TH3L operator+(TH3L const &h1, TH3L const &h2); friend TH3L operator-(TH3L const &h1, TH3L const &h2); friend TH3L operator*(TH3L const &h1, TH3L const &h2); @@ -320,6 +348,15 @@ class TH3L : public TH3, public TArrayL64 { ClassDefOverride(TH3L,0) //3-Dim histograms (one 64 bit integer per channel) }; +TH3L operator*(Float_t c1, TH3L const &h1); +inline TH3L operator*(TH3L const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3L operator+(TH3L const &h1, TH3L const &h2); +TH3L operator-(TH3L const &h1, TH3L const &h2); +TH3L operator*(TH3L const &h1, TH3L const &h2); +TH3L operator/(TH3L const &h1, TH3L const &h2); //________________________________________________________________________ @@ -353,7 +390,7 @@ class TH3F : public TH3, public TArrayF { TH3F& operator=(const TH3F &h1); friend TH3F operator*(Float_t c1, TH3F const &h1); - friend TH3F operator*(TH3F const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3F operator*(TH3F const &h1, Float_t c1); friend TH3F operator+(TH3F const &h1, TH3F const &h2); friend TH3F operator-(TH3F const &h1, TH3F const &h2); friend TH3F operator*(TH3F const &h1, TH3F const &h2); @@ -366,6 +403,16 @@ class TH3F : public TH3, public TArrayF { ClassDefOverride(TH3F,4) //3-Dim histograms (one float per channel) }; +TH3F operator*(Float_t c1, TH3F const &h1); +inline TH3F operator*(TH3F const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3F operator+(TH3F const &h1, TH3F const &h2); +TH3F operator-(TH3F const &h1, TH3F const &h2); +TH3F operator*(TH3F const &h1, TH3F const &h2); +TH3F operator/(TH3F const &h1, TH3F const &h2); + //________________________________________________________________________ class TH3D : public TH3, public TArrayD { @@ -397,7 +444,7 @@ class TH3D : public TH3, public TArrayD { TH3D& operator=(const TH3D &h1); friend TH3D operator*(Float_t c1, TH3D const &h1); - friend TH3D operator*(TH3D const &h1, Float_t c1) {return operator*(c1,h1);} + friend TH3D operator*(TH3D const &h1, Float_t c1); friend TH3D operator+(TH3D const &h1, TH3D const &h2); friend TH3D operator-(TH3D const &h1, TH3D const &h2); friend TH3D operator*(TH3D const &h1, TH3D const &h2); @@ -417,4 +464,14 @@ class TH3D : public TH3, public TArrayD { ClassDefOverride(TH3D,4) //3-Dim histograms (one double per channel) }; +TH3D operator*(Float_t c1, TH3D const &h1); +inline TH3D operator*(TH3D const &h1, Float_t c1) +{ + return operator*(c1, h1); +} +TH3D operator+(TH3D const &h1, TH3D const &h2); +TH3D operator-(TH3D const &h1, TH3D const &h2); +TH3D operator*(TH3D const &h1, TH3D const &h2); +TH3D operator/(TH3D const &h1, TH3D const &h2); + #endif From f5d10bd88429e39a7e2645e3354af8bc02950833 Mon Sep 17 00:00:00 2001 From: siliataider Date: Fri, 3 Oct 2025 12:01:31 +0200 Subject: [PATCH 2/2] Add tests for TH2 and TH3 arithmetic operations --- .../pyroot/pythonizations/test/CMakeLists.txt | 1 + bindings/pyroot/pythonizations/test/th2.py | 39 +++++++++++++++- bindings/pyroot/pythonizations/test/th3.py | 44 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 bindings/pyroot/pythonizations/test/th3.py diff --git a/bindings/pyroot/pythonizations/test/CMakeLists.txt b/bindings/pyroot/pythonizations/test/CMakeLists.txt index 2940e1bf95962..267df1c3431c3 100644 --- a/bindings/pyroot/pythonizations/test/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/test/CMakeLists.txt @@ -55,6 +55,7 @@ ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree_branch ttree_branch.py PYTHON_DEPS numpy) ROOT_ADD_PYUNITTEST(pyroot_pyz_th1_operators th1_operators.py) ROOT_ADD_PYUNITTEST(pyroot_pyz_th1_fillN th1_fillN.py PYTHON_DEPS numpy) ROOT_ADD_PYUNITTEST(pyroot_pyz_th2 th2.py) +ROOT_ADD_PYUNITTEST(pyroot_pyz_th3 th3.py) # TGraph, TGraph2D and error subclasses pythonizations ROOT_ADD_PYUNITTEST(pyroot_pyz_tgraph_getters tgraph_getters.py) diff --git a/bindings/pyroot/pythonizations/test/th2.py b/bindings/pyroot/pythonizations/test/th2.py index 5eb834a1033f4..97b13dc0acf8b 100644 --- a/bindings/pyroot/pythonizations/test/th2.py +++ b/bindings/pyroot/pythonizations/test/th2.py @@ -17,5 +17,42 @@ def test_GetBinError(self): self.assertEqual(h.GetBinErrorLow(1, 1), 2) -if __name__ == '__main__': +class TH2Operations(unittest.TestCase): + """ + Test TH2D arithmetic operations + """ + + def setUp(self): + self.h1 = ROOT.TH2D("h1", "h1", 2, 0, 2, 2, 0, 2) + self.h2 = ROOT.TH2D("h2", "h2", 2, 0, 2, 2, 0, 2) + + self.h1.Fill(0.5, 0.5, 2.0) + self.h2.Fill(0.5, 0.5, 3.0) + + def test_addition(self): + hsum = self.h1 + self.h2 + self.assertAlmostEqual(hsum.GetBinContent(1, 1), 5.0) + + def test_subtraction(self): + hdiff = self.h2 - self.h1 + self.assertAlmostEqual(hdiff.GetBinContent(1, 1), 1.0) + + def test_multiplication(self): + hprod = self.h1 * self.h2 + self.assertAlmostEqual(hprod.GetBinContent(1, 1), 6.0) + + def test_division(self): + hdiv = self.h2 / self.h1 + self.assertAlmostEqual(hdiv.GetBinContent(1, 1), 1.5) + + def test_scalar_multiplication_left(self): + hscaled = 2.0 * self.h1 + self.assertAlmostEqual(hscaled.GetBinContent(1, 1), 4.0) + + def test_scalar_multiplication_right(self): + hscaled = self.h1 * 2.0 + self.assertAlmostEqual(hscaled.GetBinContent(1, 1), 4.0) + + +if __name__ == "__main__": unittest.main() diff --git a/bindings/pyroot/pythonizations/test/th3.py b/bindings/pyroot/pythonizations/test/th3.py new file mode 100644 index 0000000000000..6e5672070b9ce --- /dev/null +++ b/bindings/pyroot/pythonizations/test/th3.py @@ -0,0 +1,44 @@ +import unittest + +import ROOT + + +class TH3Operations(unittest.TestCase): + """ + Test TH3D arithmetic operations + """ + + def setUp(self): + self.h1 = ROOT.TH3D("h1", "h1", 2, 0, 2, 2, 0, 2, 2, 0, 2) + self.h2 = ROOT.TH3D("h2", "h2", 2, 0, 2, 2, 0, 2, 2, 0, 2) + + self.h1.Fill(0.5, 0.5, 0.5, 2.0) + self.h2.Fill(0.5, 0.5, 0.5, 3.0) + + def test_addition(self): + hsum = self.h1 + self.h2 + self.assertAlmostEqual(hsum.GetBinContent(1, 1, 1), 5.0) + + def test_subtraction(self): + hdiff = self.h2 - self.h1 + self.assertAlmostEqual(hdiff.GetBinContent(1, 1, 1), 1.0) + + def test_multiplication(self): + hprod = self.h1 * self.h2 + self.assertAlmostEqual(hprod.GetBinContent(1, 1, 1), 6.0) + + def test_division(self): + hdiv = self.h2 / self.h1 + self.assertAlmostEqual(hdiv.GetBinContent(1, 1, 1), 1.5) + + def test_scalar_multiplication_left(self): + hscaled = 2.0 * self.h1 + self.assertAlmostEqual(hscaled.GetBinContent(1, 1, 1), 4.0) + + def test_scalar_multiplication_right(self): + hscaled = self.h1 * 2.0 + self.assertAlmostEqual(hscaled.GetBinContent(1, 1, 1), 4.0) + + +if __name__ == "__main__": + unittest.main()