Skip to content

Unrolling pow with integer powers in Python #8676

@rtzam

Description

@rtzam

Here's an example:

from halide import Expr

df = Expr(2.0)

# 2.0 ** 3
df.__pow__(3)
# expected pow_f32(2.0, 3.0)
# actual:
# <halide.Expr of type float32: ((2.000000f*2.000000f)*2.000000f)>

# 3 ** 2.0
df.__rpow__(3)
# expected pow_f32(3.0, 2.0)
# <halide.Expr of type float32: ((2.000000f*2.000000f)*2.000000f)>

Furthermore, this also occurs when the literal 3 is explicitly cast to be an Expr:

df ** Expr(3)

For reproduction purposes, this is a local build of main (freshly pulled a few minutes ago) on MacOS.

I would like to raise two issues.

The first is that __pow__ and __rpow__ call the same C++ code when instead they
should have their arguments swapped. This is obvious from the source code on line 176
in Halide/python_bindings/src/halide/halide_/PyBinaryOperators.h:

// Halide::pow() has only an Expr, Expr variant
const auto pow_wrap = [](const Expr &self, const Expr &other) -> decltype(Halide::pow(self, other)) {
    return Halide::pow(self, other);
};
class_instance
    .def("__pow__", pow_wrap, py::is_operator())
    .def("__rpow__", pow_wrap, py::is_operator());

The second issue seems deeper. There seems to be loop unrolling instead of a simple call to Halide::pow. Is this expected behavior when raising to an integer power? I can raise an expression to large power and get a truly enormous AST.
Lastly, with respect to Halides type casting rules from the published tutorials:

// 3) If one type is a float but the other is not, then the
// non-float argument is promoted to a float (possibly causing a
// loss of precision for large integers).

and

// 5) If one of the arguments is an C++ int, and the other is
// a Halide::Expr, then the int is coerced to the type of the
// expression.

which means the arguments to power should be cast to floats first and then
passed to pow_f32.
The unrolling seems entirely at odds with the typing rules of the language.

Metadata

Metadata

Assignees

Labels

pythonIssues related to Halide/Python interop

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions