Combining multiple halide functions but keeping the dimensions same - halide

I have three Halide functions which have the following output dimensions:
40 x 40 x 64
40 x 40 x 128
40 x 40 x 64
I want to combine them into a single function so that I get a function handle for later use. So for here , the resulting function should have a dimension of
40 x 40 x 256
I am using Halide::select but it results in 4 dimensions
concat(x,y,z,c)=Halide::select(c == 0, func_1(x, y, z), c == 1, func_2(x, y, z), func_3(x, y, z));
Is there any way to produce a merged 3D function?

You may want to return a Pipeline object instead of a Func. Pipelines compile to functions with multiple output parameters, which can be buffers of different shapes.
If you do want a single Func, you want something like:
concat(x, y, z) =
Halide::select(z < 64, func_1(x, y, clamp(z, 0, 63)),
z < 192, func_2(x, y, clamp(z - 64, 0, 127)),
func_3(x, y, clamp(z - 192, 0, 63)));

You can use a Tuple. It's a little complicated by the different size of the 3rd dimension since the members of a Tuple have to be the same size. This complication exists for your 4d solution as well.
result(x, y, z) = Tuple
( func_1(x, y, z)
, func_2(x, y, z * 2 + 0) // Even z
, func_2(x, y, z * 2 + 1) // Odd z
, func_3(x, y, z)
);
If you keep the 4d solution, add unroll(c) to the schedule and the 3 (now 4) functions will be evaluated sequentially inside the innermost loop.
Rather than concatenating the three functions in the third dimension, adding another dimension or using a Tuple is the better way to go, IMHO.
Edit: Besides unroll(c), you'll need reorder(c,x,y,z) to change the loop order.

Related

How would scanline fill algorithm iterate the pixel positions on the following image in an optimised way?

Can anyone explain me how would scanline fill algorithm turn the blue positions into pink? I wanted to know how the iterations will change when an obstruction is observed. Take for example in the third row, the algorithm will easily consider positions 40 to 46 being part of the same group. But how and when will the algorithm iterate the positions 52 to 59?
If possible, please explain from left to right instead of top to bottom. Also mention an optimised method to iterate.
Here is the simple code from wikipedia:
fn fill(x, y):
if not Inside(x, y) then return
let s = new empty stack or queue
add (x, y) to s
while s is not empty:
Remove an (x, y) from s
let lx = x
while Inside(lx - 1, y):
Set(lx - 1, y)
lx = lx - 1
while Inside(x, y):
Set(x, y)
x = x + 1
scan(lx, x - 1, y + 1, s)
scan(lx, x - 1, y - 1, s)
fn scan(lx, rx, y, s):
let added = false
for x in lx .. rx:
if not Inside(x, y):
added = false
else if not added:
Add (x, y) to s
added = true
So "s" is a seed list, basically you put some random point (must be empty) to start off the algorithm.
while s is not empty:
Remove an (x, y) from s
This is a basic loop where we are consuming seeds and when there are no seeds left in "s" then the algorithm is finished.
let lx = x
while Inside(lx - 1, y):
Set(lx - 1, y)
lx = lx - 1
while Inside(x, y):
Set(x, y)
x = x + 1
This is keeping track of the current scan line where lx is the leftmost empty pixel and (x-1) is the rightmost empty pixel (note as this may be confusing, x will be incremented at least once no matter what since all seed points are assured to be inside points). The first loop steps to the left and decrements lx every time it finds an empty pixel. The second loop steps to the right and increments x every time it finds an empty pixel. You can set pixel by pixel as stated, but depending on your library (if drawing lines is cheaper than pixel by pixel editing) you can instead draw a line after passing both of these loops, extending the line between (lx,y) and (x-1,y).
scan(lx, x - 1, y + 1, s)
scan(lx, x - 1, y - 1, s)
This is the "re-seeding" step. Basically the above steps consume seeds, this is the step that produces new seeds based on the results of the seed that was just consumed. "y+1" and "y-1" are single pixel offsets above and below the line that was just drawn, while "lx" and "x-1" describe the line that was just computed this step.
fn scan(lx, rx, y, s):
let added = false
for x in lx .. rx:
if not Inside(x, y):
added = false
else if not added:
Add (x, y) to s
added = true
All that is happening here is that any empty pixels on the scan line (remember this is above and below the last line checked based on arguments) is being added to the seed array to be later tested (this is not incrementing forward and backwards but exhaustively searching every point along the line). Keep in mind that s needs to be a byref argument here since you will be editing it.
One additional note: when I say "empty pixel" I mean two things (though they generally are handled the same in this aglo): 1 the pixel is not an edge point, 2 the pixel has not already be filled by the algo.
As can be seen in the graphic below, any seed can be pulled from the seed list in any order and the algo still functions properly.

How does the power function work

This is My First Logic Programming Language course so this is a really Dumb Question But I cannot for the life of me figure out how does this power predicate work I've tried making a search tree to trace it But I still cannot understand how is it working
mult(_ , 0 ,0).
mult(X , Y, Z):-
Y > 0,
Y1 is Y - 1,
mult(X,Y1,Z1),
Z is Z1 + X.
exp2(_ ,0 , 1).
exp2(X,Y,Z):-
Y > 0,
Y1 is Y - 1,
exp2(X , Y1 , Z1),
mult(X,Z1,Z).
I so far get that I'm going to call the exp2 predicate till I reach the point where the Y is going to be Zero then I'm going to start multiplying from there, but At the last call when it's at exp2(2 , 1 , Z) what is the Z value and how does the predicate work from there?
Thank you very much =)
EDIT: I'm really sorry for the Late reply I had some problems and couldn't access my PC
I'll walk through mult/3 in more detail here, but I'll leave exp2/3 to you as an exercise. It's similar..
As I mentioned in my comment, you want to read a Prolog predicate as a rule.
mult(_ , 0 ,0).
This rule says 0 is the result of multiplying anything (_) by 0. The variable _ is an anonymous variable, meaning it is not only a variable, but you don't care what its value is.
mult(X, Y, Z) :-
This says, Z is the result of multiplying X by Y if....
Y > 0,
Establish that Y is greater than 0.
Y1 is Y - 1,
And that Y1 has the value of Y minus 1.
mult(X, Y1, Z1),
And that Z1 is the result of multiplying X by Y1.
Z is Z1 + X.
And Z is the value of Z1 plus X.
Or reading the mult(X, Y, Z) rule altogether:
Z is the result of multiplying X by Y if Y is greater than 0, and Y1 is Y-1, and Z1 is the result of multiplying X by Y1, and Z is the result of adding Z1 to X.
Now digging a little deeper, you can see this is a recursive definition, as in the multiplication of two numbers is being defined by another multiplication. But what is being multiplied is important. Mathematically, it's using the fact that x * y is equal to x * (y - 1) + x. So it keeps reducing the second multiplicand by 1 and calling itself on the slightly reduced problem. When does this recursive reduction finally end? Well, as shown above, the second rule says Y must be greater than 0. If Y is 0, then the first rule, mult(_, 0, 0) applies and the recursion finally comes back with a 0.
If you are not sure how recursion works or are unfamiliar with it, I highly recommend Googling it to understand it. That is, indeed, a concept that applies to many computer languages. But you need to be careful about learning Prolog via comparison with other languages. Prolog is fundamentally different in it's behavior from procedural/imperative languages like Java, Python, C, C++, etc. It's best to get used to interpreting Prolog rules and facts as I have described above.
Say you want to compute 2^3 as assign result to R.
For that you will call exp2(2, 3, R).
It will recursively call exp2(2, 2, R1) and then exp2(2, 1, R2) and finally exp(2, 0, R3).
At this point exp(_, 0, 1) will match and R3 will be assigned to 1.
Then when call stack unfolds 1 will be multiplied by 2 three times.
In Java this logic would be encoded as follows. Execution would go pretty much the same route.
public static int Exp2(int X, int Y) {
if (Y == 0) { // exp2(_, 0, 1).
return 1;
}
if (Y > 0) { // Y > 0
int Y1 = Y - 1; // Y1 is Y - 1
int Z1 = Exp2(X, Y1); // exp2(X, Y1, Z1);
return X * Z1; // mult(X, Z1, Z).
}
return -1; // this should never happen.
}

How to make a prolog program return the value it computed

(I'm not sur if return is the right word to describe it, but that's the best one I could find.)
I am trying to write a small program in prolog that uses the function add to do multiplications. When I run add by itself or even when it is called by the function test the result is "Z = the sum" ex: if I run add(2,3,Z) it will display Z=5.
My problem is that I can't get it to do the same thing when I call mult. The only solution that I found is to use write, but that's not the same thing. I tried a lot of stuff but most of it wasn't even compiling and the rest didn't change anything. Does anybody know how I could make it do that ("Z = the product")? What would be the way to make it do that (return) for a program in general?
Thank You
add(X,Y,Z) :-
Z is X + Y.
mult(X,Y,Z1):-
multiply(X,Y,0).
multiply(_,0,_):-
write(0).
multiply(0,_,Z):-
write(Z).
multiply(X,Y,Z):-
X > 0,
add(Y,Z,Z1),
X1 is X - 1,
multiply(X1,Y,Z1).
multiply(X,Y,Z):-
Y < 0,
X1 is abs(X),
Y1 is abs(Y),
multiply(X1,Y1,Z).
multiply(X,Y,Z):-
Y1 is Y * -1,
add(Y1,Z,Z1),
X1 is X + 1,
multiply(X1,Y,Z1).
test(X,Y,Z1):-
add(X,Y,Z1).
I managed to get it working by adding a 4th parameter. I don't know if it is the right way to do it but it works.
mult(X,Y,Z):-
multiply(X,Y,0,Z).
multiply(_,0,_,Z):-
Z is 0.
multiply(0,_,Z1,Z):-
Z is Z1.
multiply(X,Y,Z1,Z):-
X > 0,
add(Y,Z1,Z2),
X1 is X - 1,
multiply(X1,Y,Z2,Z).
multiply(X,Y,Z1,Z):-
Y < 0,
X1 is abs(X),
Y1 is abs(Y),
multiply(X1,Y1,Z1,Z).
multiply(X,Y,Z1,Z):-
Y1 is Y * -1,
add(Y1,Z1,Z2),
X1 is X + 1,
multiply(X1,Y,Z2,Z).

Fixing arguments when using pmap in Julia

I have defined a function f(x, y, z) in Julia and I want to parallely compute f for many values of x, holding y and z fixed. What is the "best practices" way to do this using pmap?
It would be nice if it was something like pmap(f, x, y = 5, z = 8), which is how the apply family handles fixed arguments in R, but it doesn't appear to be as simple as that. I have devised solutions, but I find them inelegant and I doubt that they will generalize nicely for my purposes.
I can wrap f in a function g where g(x) = f(x, y = 5, z = 8). Then I simply call pmap(g, x). This is less parsimonious than I would like.
I can set 5 and 8 as default values for y and z when f is defined and then call pmap(f, x). This makes me uncomfortable in the case where I want to fix y at the value of some variable a, where a has (for good reason) not been defined at the time that f is defined, but will be by the time f is called. It works, but it kind of spooks me.
A good solution, which turns your apparently inflexible first option into a flexible one, is to use an anonymous function, e.g.
g(y, z) = x -> f(x, y, z)
pmap(g(5, 8), x)
or just
pmap(x -> f(x, 5, 8), x)
In Julia 0.4, anonymous functions have a performance penalty, but this will be gone in 0.5.

Working with tuples in Halide

I want to extract one channel in Halide,
Halide::Image<uint8_t> input = load_image("images/rgb.png");
Halide::Var x, y;
Halide::Func green;
green(x,y)= {0, input(x, y, 1), 0};
Halide::Image<uint8_t> output =
green.realize(input.width(), input.height());
gives
Can only cast single-element realizations to buffers or images
it must be simple
It sounds like you want a three channel output in which two are all zero and one is the content of the corresponding channel of the input image. To do this, try:
green(x, y, c) = select(c == 1, input(x, y, 1), 0);
If this is unrolled and bounded, there will be no conditional evaluation in the execution.
I think you want:
green(x, y) = input(x, y, 1);
The thing you have creates a tuple of three output images, two of which are zero.

Resources