Esempio n. 1
0
def average(a, b):

    if type(a) is not hl.Expr:
        a = hl.Expr(a)

    if type(b) is not hl.Expr:
        b = hl.Expr(b)


    "hl.Expr average(hl.Expr a, hl.Expr b)"
    # Types must match.
    assert a.type() == b.type()

    # For floating point types:
    if (a.type().is_float()):
        # The '2' will be promoted to the floating point type due to
        # rule 3 above.
        return (a + b)/2


    # For integer types, we must compute the intermediate value in a
    # wider type to avoid overflow.
    narrow = a.type()
    wider = narrow.with_bits(narrow.bits() * 2)
    a = hl.cast(wider, a)
    b = hl.cast(wider, b)
    return hl.cast(narrow, (a + b)/2)
Esempio n. 2
0
 def __init__(self, r, i=None):
     if type(r) is float and type(i) is float:
         self.real = hl.Expr(r)
         self.imag = hl.Expr(i)
     elif i is not None:
         self.real = r
         self.imag = i
     else:
         self.real = r[0]
         self.imag = r[1]
Esempio n. 3
0
def test_all(vector_width, target):
    # print("target is %s " % str(target))

    W = 32
    H = 32
    input = hl.Buffer(hl.UInt(8), [W, H])
    for r in range(H):
        for c in range(W):
            input[c, r] = (c + r * W) & 0xff

    input_f = hl.Func()
    input_f[x, y] = input[x, y]

    tests = [
        (hl.BoundaryConditions.constant_exterior, check_constant_exterior),
        (hl.BoundaryConditions.repeat_edge, check_repeat_edge),
        (hl.BoundaryConditions.repeat_image, check_repeat_image),
        (hl.BoundaryConditions.mirror_image, check_mirror_image),
        (hl.BoundaryConditions.mirror_interior, check_mirror_interior),
    ]

    for bc, checker in tests:
        # print('  Testing %s:%d...' % (bc.__name__, vector_width))
        func_input_args = {'f': input_f, 'bounds': [(0, W), (0, H)]}
        image_input_args = {'f': input, 'bounds': [(0, W), (0, H)]}
        undef_min_args = {
            'f': input,
            'bounds': [(hl.Expr(), hl.Expr()), (0, H)]
        }
        undef_max_args = {
            'f': input,
            'bounds': [(0, W), (hl.Expr(), hl.Expr())]
        }
        implicit_bounds_args = {'f': input}

        if bc == hl.BoundaryConditions.constant_exterior:
            func_input_args['exterior'] = test_exterior
            image_input_args['exterior'] = test_exterior
            undef_min_args['exterior'] = test_exterior
            undef_max_args['exterior'] = test_exterior
            implicit_bounds_args['exterior'] = test_exterior

        realize_and_check(bc(**func_input_args), checker, input, test_min,
                          test_extent, test_min, test_extent, vector_width,
                          target)
        realize_and_check(bc(**image_input_args), checker, input, test_min,
                          test_extent, test_min, test_extent, vector_width,
                          target)
        realize_and_check(bc(**undef_min_args), checker, input, 0, W, test_min,
                          test_extent, vector_width, target)
        realize_and_check(bc(**undef_max_args), checker, input, test_min,
                          test_extent, 0, H, vector_width, target)
        realize_and_check(bc(**implicit_bounds_args), checker, input, test_min,
                          test_extent, test_min, test_extent, vector_width,
                          target)
Esempio n. 4
0
def gauss(input, k, rdom, name):
    blur_x = hl.Func(name + "_x")
    output = hl.Func(name)

    x, y, c, xi, yi = hl.Var("x"), hl.Var("y"), hl.Var("c"), hl.Var("xi"), hl.Var("yi")

    val = hl.Expr("val")

    if input.dimensions() == 2:
        blur_x[x, y] = hl.sum(input[x + rdom, y] * k[rdom])
        val = hl.sum(blur_x[x, y + rdom] * k[rdom])
        if input.output_types()[0] == hl.UInt(16):
            val = hl.u16(val)
        output[x, y] = val
    else:
        blur_x[x, y, c] = hl.sum(input[x + rdom, y, c] * k[rdom])
        val = hl.sum(blur_x[x, y + rdom, c] * k[rdom])
        if input.output_types()[0] == hl.UInt(16):
            val = hl.u16(val)
        output[x, y, c] = val

    blur_x.compute_at(output, x).vectorize(x, 16)

    output.compute_root().tile(x, y, xi, yi, 256, 128).vectorize(xi, 16).parallel(y)

    return output
def histogram(x, y, c, img, w, h, hist_index):
    print("GET HIST ON: ", w, h)
    histogram = hl.Func("histogram")

    # Histogram buckets start as zero.
    histogram[hist_index] = 0

    # Define a multi-dimensional reduction domain over the input image:
    r = hl.RDom([(0, w), (0, h)])

    # For every point in the reduction domain, increment the
    # histogram bucket corresponding to the intensity of the
    # input image at that point.

    histogram[hl.Expr(img[r.x, r.y])] += 1
    histogram.set_estimate(hist_index, 0, 255)

    # Get the sum of all histogram cells
    r = hl.RDom([(0,255)])
    hist_sum = hl.Func('hist_sum')
    hist_sum[()] = 0.0 # Compute the sum as a 32-bit integer
    hist_sum[()] += histogram[r.x]

    # Return each histogram as a % of total color
    pct_hist = hl.Func('pct_hist')
    pct_hist[hist_index] = histogram[hist_index] / hist_sum[()]

    return histogram
Esempio n. 6
0
def test_operator_order():
    x = hl.Var('x')
    f = hl.Func('f')
    x + 1
    1 + x
    f[x] = x**2
    f[x] + 1
    hl.Expr(1) + f[x]
    1 + f[x]
Esempio n. 7
0
def test_operator_order():

    x = hl.Var('x')
    f = hl.Func('f')
    x + 1
    1 + x
    print("x", x, ", x + 1", x + 1, ", 1 + x", 1 + x)
    f[x] = x ** 2
    f[x] + 1
    hl.Expr(1) + f[x]
    1 + f[x]

    return
Esempio n. 8
0
def test_var():
    v1 = hl.Var()
    v2 = hl.Var()
    assert len(v1.name()) > 0
    assert len(v2.name()) > 0
    assert not v1.same_as(v2)

    v1 = hl.Var.implicit(1)
    assert v1.name() == "_1"
    v2 = hl.Var("_1")
    assert v1.same_as(v2)
    v3 = hl._1
    assert v1.same_as(v3)
    v4 = hl.Var("v4")
    assert not v1.same_as(v4)

    assert v1.is_implicit()
    assert v2.is_implicit()
    assert v3.is_implicit()
    assert not v4.is_implicit()

    assert hl.Var("_1").is_implicit()
    assert not hl.Var("v4").is_implicit()

    assert v1.implicit_index() == 1
    assert v2.implicit_index() == 1
    assert v3.implicit_index() == 1
    assert v4.implicit_index() == -1

    assert hl.Var("_1").implicit_index() == 1
    assert hl.Var("v4").implicit_index() == -1

    ph = hl._
    assert ph.name() == "_"
    assert ph.is_placeholder()
    assert hl.Var.is_placeholder(ph)
    assert not v1.is_placeholder()

    outermost = hl.Var.outermost()
    assert outermost.name() == "__outermost"

    # repr() and str()
    x = hl.Var('x')
    assert str(x) == "x"
    assert repr(x) == "<halide.Var 'x'>"

    # This verifies that halide.Var is implicitly convertible to halide.Expr
    r = hl.random_int(x)

    # This verifies that halide.Var is explicitly convertible to halide.Expr
    r = hl.random_int(hl.Expr(x))
Esempio n. 9
0
def test_atomics():
    x = hl.Var('x')
    im = hl.Func('im')
    f = hl.Func('f')
    im[x] = (x * x) % 5
    r = hl.RDom([(0, 100)])
    f[x] = 0
    f[hl.Expr(im[r])] += 1
    f.compute_root().update().atomic().parallel(r)
    b = f.realize(5)

    ref = [0, 0, 0, 0, 0]
    for i in range(100):
        idx = (i * i) % 5
        ref[idx] += 1
    for i in range(5):
        assert (b[i] == ref[i])
Esempio n. 10
0
def test_float_or_int():

    x = hl.Var('x')
    i, f =  hl.Int(32), hl.Float(32)

    assert ((x//2) - 1 + 2*(x%2)).type() == i
    assert ((x/2) - 1 + 2*(x%2)).type() == i
    assert ((x/2)).type() == i
    assert ((x/2.0)).type() == f
    assert ((x//2)).type() == i
    assert ((x//2) - 1).type() == i
    assert ((x%2)).type() == i
    assert (2*(x%2)).type() == i
    assert ((x//2) - 1 + 2*(x%2)).type() == i

    assert type(x) == hl.Var
    assert (x.as_expr()).type() == i
    assert (hl.Expr(2.0)).type() == f
    assert (hl.Expr(2)).type() == i
    assert (x + 2).type() == i
    assert (2 + x).type() == i
    assert (hl.Expr(2) + hl.Expr(3)).type() == i
    assert (hl.Expr(2.0) + hl.Expr(3)).type() == f
    assert (hl.Expr(2) + 3.0).type() == f
    assert (hl.Expr(2) + 3).type() == i
    assert (x.as_expr() + 2).type() == i # yes this failed at some point
    assert (2 + x.as_expr()).type() == i
    assert (2 * (x + 2)).type() == i # yes this failed at some point
    assert (x + 0).type() == i
    assert (x % 2).type() == i
    assert (2 * x).type() == i
    assert (x * 2).type() == i
    assert (x * 2).type() == i
    assert ((x % 2)).type() == i
    assert ((x % 2) * 2).type() == i
    #assert (2 * (x % 2)).type() == i # yes this failed at some point
    assert ((x + 2) * 2).type() == i

    return
Esempio n. 11
0
def test_int_promotion():
    # Verify that (Exprlike op literal) correctly matches the type
    # of the literal to the Exprlike (rather than promoting the result to int32).
    # All types that use add_binary_operators() should be tested here.

    x = hl.Var('x')
    # All the binary ops are handled the same, so + is good enough

    # Exprlike = FuncRef
    f = hl.Func('f')
    f[x] = hl.u16(x)
    _check_is_u16(f[x] + 2)
    _check_is_u16(2 + f[x])

    # Exprlike = Expr
    e = hl.Expr(f[x])
    _check_is_u16(e + 2)
    _check_is_u16(2 + e)

    # Exprlike = Param
    p = hl.Param(hl.UInt(16))
    _check_is_u16(p + 2)
    _check_is_u16(2 + p)
Esempio n. 12
0
def test_float_or_int():
    x = hl.Var('x')
    i32, f32 = hl.Int(32), hl.Float(32)

    assert hl.Expr(x).type() == i32
    assert (x * 2).type() == i32
    assert (x / 2).type() == i32
    assert ((x // 2) - 1 + 2 * (x % 2)).type() == i32
    assert ((x / 2) - 1 + 2 * (x % 2)).type() == i32
    assert ((x / 2)).type() == i32
    assert ((x / 2.0)).type() == f32
    assert ((x // 2)).type() == i32
    assert ((x // 2) - 1).type() == i32
    assert ((x % 2)).type() == i32
    assert (2 * (x % 2)).type() == i32
    assert ((x // 2) - 1 + 2 * (x % 2)).type() == i32

    assert type(x) == hl.Var
    assert (hl.Expr(x)).type() == i32
    assert (hl.Expr(2.0)).type() == f32
    assert (hl.Expr(2)).type() == i32
    assert (x + 2).type() == i32
    assert (2 + x).type() == i32
    assert (hl.Expr(2) + hl.Expr(3)).type() == i32
    assert (hl.Expr(2.0) + hl.Expr(3)).type() == f32
    assert (hl.Expr(2) + 3.0).type() == f32
    assert (hl.Expr(2) + 3).type() == i32
    assert (hl.Expr(x) + 2).type() == i32
    assert (2 + hl.Expr(x)).type() == i32
    assert (2 * (x + 2)).type() == i32
    assert (x + 0).type() == i32
    assert (x % 2).type() == i32
    assert (2 * x).type() == i32
    assert (x * 2).type() == i32
    assert (x * 2).type() == i32
    assert ((x % 2)).type() == i32
    assert ((x % 2) * 2).type() == i32
    assert (2 * (x % 2)).type() == i32
    assert ((x + 2) * 2).type() == i32
Esempio n. 13
0
def main():

    # All Exprs have a scalar type, and all Funcs evaluate to one or
    # more scalar types. The scalar types in Halide are unsigned
    # integers of various bit widths, signed integers of the same set
    # of bit widths, floating point numbers in single and double
    # precision, and opaque handles (equivalent to void *). The
    # following array contains all the legal types.

    valid_halide_types = [
        hl.UInt(8), hl.UInt(16), hl.UInt(32), hl.UInt(64),
        hl.Int(8), hl.Int(16), hl.Int(32), hl.Int(64),
        hl.Float(32), hl.Float(64), hl.Handle() ]


    # Constructing and inspecting types.
    if True:
        # You can programmatically examine the properties of a Halide
        # type. This is useful when you write a C++ function that has
        # hl.Expr arguments and you wish to check their types:
        assert hl.UInt(8).bits() == 8
        assert hl.Int(8).is_int()


        # You can also programmatically construct Types as a function of other Types.
        t = hl.UInt(8)
        t = t.with_bits(t.bits() * 2)
        assert t == hl.UInt(16)

        # Or construct a Type from a C++ scalar type
        #assert type_of<float>() == hl.Float(32)

        # The Type struct is also capable of representing vector types,
        # but this is reserved for Halide's internal use. You should
        # vectorize code by using hl.Func::vectorize, not by attempting to
        # construct vector expressions directly. You may encounter vector
        # types if you programmatically manipulate lowered Halide code,
        # but this is an advanced topic (see hl.Func::add_custom_lowering_pass).

        # You can query any Halide hl.Expr for its type. An hl.Expr
        # representing a hl.Var has type hl.Int(32):
        x = hl.Var("x")
        assert hl.Expr(x).type() == hl.Int(32)

        # Most transcendental functions in Halide hl.cast their inputs to a
        # hl.Float(32) and return a hl.Float(32):
        assert hl.sin(x).type() == hl.Float(32)

        # You can hl.cast an hl.Expr from one Type to another using the hl.cast operator:
        assert hl.cast(hl.UInt(8), x).type() == hl.UInt(8)

        # This also comes in a template form that takes a C++ type.
        #assert hl.cast<uint8_t>(x).type() == hl.UInt(8)

        # You can also query any defined hl.Func for the types it produces.
        f1 = hl.Func("f1")
        f1[x] = hl.cast(hl.UInt(8), x)
        assert f1.output_types()[0] == hl.UInt(8)

        f2 = hl.Func("f2")
        f2[x] = (x, hl.sin(x))
        assert f2.output_types()[0] == hl.Int(32) and \
               f2.output_types()[1] == hl.Float(32)



    # Type promotion rules.
    if True:
        # When you combine Exprs of different types (e.g. using '+',
        # '*', etc), Halide uses a system of type promotion
        # rules. These differ to C's rules. To demonstrate these
        # we'll make some Exprs of each type.
        x = hl.Var("x")
        u8 = hl.cast(hl.UInt(8), x)
        u16 = hl.cast(hl.UInt(16), x)
        u32 = hl.cast(hl.UInt(32), x)
        u64 = hl.cast(hl.UInt(64), x)
        s8 = hl.cast(hl.Int(8), x)
        s16 = hl.cast(hl.Int(16), x)
        s32 = hl.cast(hl.Int(32), x)
        s64 = hl.cast(hl.Int(64), x)
        f32 = hl.cast(hl.Float(32), x)
        f64 = hl.cast(hl.Float(64), x)

        # The rules are as follows, and are applied in the order they are
        # written below.

        # 1) It is an error to hl.cast or use arithmetic operators on Exprs of type hl.Handle().

        # 2) If the types are the same, then no type conversions occur.
        for t in valid_halide_types:
            # Skip the handle type.
            if t.is_handle():
                continue
            e = hl.cast(t, x)
            assert (e + e).type() == e.type()


        # 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).
        assert (u8 + f32).type() == hl.Float(32)
        assert (f32 + s64).type() == hl.Float(32)
        assert (u16 + f64).type() == hl.Float(64)
        assert (f64 + s32).type() == hl.Float(64)

        # 4) If both types are float, then the narrower argument is
        # promoted to the wider bit-width.
        assert (f64 + f32).type() == hl.Float(64)

        # The rules above handle all the floating-point cases. The
        # following three rules handle the integer cases.

        # 5) If one of the expressions is an integer constant, then it is
        # coerced to the type of the other expression.
        assert (u32 + 3).type() == hl.UInt(32)
        assert (3 + s16).type() == hl.Int(16)

        # If this rule would cause the integer to overflow, then Halide
        # will trigger an error, e.g. uncommenting the following line
        # will cause this program to terminate with an error.
        # hl.Expr bad = u8 + 257

        # 6) If both types are unsigned integers, or both types are
        # signed integers, then the narrower argument is promoted to
        # wider type.
        assert (u32 + u8).type() == hl.UInt(32)
        assert (s16 + s64).type() == hl.Int(64)

        # 7) If one type is signed and the other is unsigned, both
        # arguments are promoted to a signed integer with the greater of
        # the two bit widths.
        assert (u8 + s32).type() == hl.Int(32)
        assert (u32 + s8).type() == hl.Int(32)

        # Note that this may silently overflow the unsigned type in the
        # case where the bit widths are the same.
        assert (u32 + s32).type() == hl.Int(32)

        if False: # evaluate<X> not yet exposed to python
            # When an unsigned hl.Expr is converted to a wider signed type in
            # this way, it is first widened to a wider unsigned type
            # (zero-extended), and then reinterpreted as a signed
            # integer. I.e. casting the hl.UInt(8) value 255 to an hl.Int(32)
            # produces 255, not -1.
            #int32_t result32 = evaluate<int>(hl.cast<int32_t>(hl.cast<uint8_t>(255)))
            assert result32 == 255

            # When a signed type is explicitly converted to a wider unsigned
            # type with the hl.cast operator (the type promotion rules will
            # never do this automatically), it is first converted to the
            # wider signed type (sign-extended), and then reinterpreted as
            # an unsigned integer. I.e. casting the hl.Int(8) value -1 to a
            # hl.UInt(16) produces 65535, not 255.
            #uint16_t result16 = evaluate<uint16_t>(hl.cast<uint16_t>(hl.cast<int8_t>(-1)))
            assert result16 == 65535


    # The type hl.Handle().
    if True:
        # hl.Handle is used to represent opaque pointers. Applying
        # type_of to any pointer type will return hl.Handle()

        #assert type_of<void *>() == hl.Handle()
        #assert type_of<const char * const **>() == hl.Handle()
        # (not clear what the proper python version would be)

        # Handles are always stored as 64-bit, regardless of the compilation
        # target.
        assert hl.Handle().bits() == 64

        # The main use of an hl.Expr of type hl.Handle is to pass
        # it through Halide to other external code.


    # Generic code.
    if True:
        # The main explicit use of Type in Halide is to write Halide
        # code parameterized by a Type. In C++ you'd do this with
        # templates. In Halide there's no need - you can inspect and
        # modify the types dynamically at C++ runtime instead. The
        # function defined below averages two expressions of any
        # equal numeric type.
        x = hl.Var("x")
        assert average(hl.cast(hl.Float(32), x), 3.0).type() == hl.Float(32)
        assert average(x, 3).type() == hl.Int(32)
        assert average(hl.cast(hl.UInt(8), x), hl.cast(hl.UInt(8), 3)).type() == hl.UInt(8)


    print("Success!")

    return 0
Esempio n. 14
0
 def maybe_mux(s):
     '''wrap multiple Exprs in mux()'''
     if len(set(s)) == 1:
         return s[0]
     else:
         return hl.mux(hl.Expr(ru), s)