Error when using branching in gpuArray/arrayfun

Hello,
I would like to pass a custom function into arrayfun, while only making use of supported built-in Matlab functions in element-wise operations within my custom function. When I make use of branching instructions in the custom function, I get the error message "Conversion to logical from gpuArray is not possible." The corresponding code (running excerpt):
sa = gpuArray.zeros(4,3,3);
sb = gpuArray.ones(4,3,3).*0.4;
t = gpuArray.ones(4,3,3).*1e-5;
x = sa + 0.5 .* ( sb - sa );
while ( 1 )
m = 0.5 * ( sa + sb );
tol = abs ( x ) + t;
t2 = 2.0 * tol;
%(...)
if ( abs ( x - m ) <= t2 - 0.5 * ( sb - sa ) )
break
end
%(...)
end
Already in the first place, I do not see which variable is converted by the if-statement. Further, if branching instructions are supported by arrayfun, what is the reason for the error message?
Calling the function within my main code (not quoted here), I receive the following error message: "Error using gpuArray/arrayfun Variable 'r' changed type. Consider renaming variable on left hand side of assignment"
I think that this is directly related to the previous problem (the reason why I posted the smaller example first). What can I do to make my custom function work with arrayfun?
Best,
Christoph

8 Comments

It is not clear to me from the above code what your custom function actually looks like, including what its inputs and outputs are. Can you please clarify which of the above code is (1) the data passed to arrayfun, (2) the contents of your custom function, (3) how you actually invoke arrayfun with the handle to your custom function.
Also, what version of MATLAB are you running?
Thanks for your reply! I am using MATLAB version R2013a.
Regarding the missing information you asked for: The custom function I want to transfer to arrayfun is a local minimization routine on a bounded interval. The required inputs are the boundaries of the interval, a starting value, and several parameters which are used to evaluate the function I intend to minimize. (The function value is evaluated within the code of the minimization routine, so I do not call another function out of arrayfun). While some parameters are identical for each element of the array, others are changing. So far, I pass the parameters into arrayfun by using several arrays of equal size. This implies that I simply multiply the constant parameters with a matrix of ones of the corresponding size. The whole idea is then to run the minimization routine in parallel on the GPU for every element of the array.
(1) Being more concrete, let ‘local_min’ be the custom function, a and b the boundaries, tol the tolerance level, x the starting value, and y(1),...,y(n) the variables with changing values along the entries, and z(1),...,z(m) the constant variables. The constant variables (scalars) a, b, tol,x and z(1),…,z(m) are multiplied by an array with ones such all variables take the form of an array with the same dimension, say NSxNBxNF. Finally, I have pre-allocated matrices (xsolved,res) in which I would like to store the results which are returned from the minimization routine 'local_min'. All variables are defined in the class of ‘gpuArray’.
(2) In the custom function ‘local_min’, I make use of branching and other MATLAB inbuilt functions which are eligible for arrayfun according to the documentation (see also the excerpt above).
(3) I invoke arrayfun with the following line of code:
[xsolved,res] = arrayfun(@local_min,a,b,tol,x,y(1),,y(n),z(1),,z(m));
where y(n) and z(m) are replaced by their actual variable names.
When I run the code, I get the error message: “Error using gpuArray/arrayfun Variable 'r' changed type. Consider renaming variable on left hand side of assignment.” From scaling down the problem, I arrived at the minimal example posted in my original question (see above), where branching is used and causing the error message "Conversion to logical from gpuArray is not possible", but maybe I am missing the crucial points that cause problems on the way...
Thanks again, and sorry for coming back so late to your questions.
Christoph, it would help to see the entire contents of the local_min function if it is not too long. In the code that you initially posted, I can't see where any change of type might occur. Also, for your information, you don't need to multiply your scalars by an array of ones so that all variables have the same dimension. Arrayfun on the GPU supports scalar expansion of input variables.
Sure, this is the function code:
function [ x, fx ] = local_min(a,b,eps,t,x,rM,A,Rp_eps,alfa,K,varphi,N,pinl,pil, phi,xi,eta,omega,rcb)
c = 0.5 * ( 3.0 - sqrt ( 5.0 ) );
sa = a;
sb = b;
x = sa + c .* ( b - a ); % element-wise operators
w = x;
v = w;
e = 0.0;
%function evaluation, using element-wise operators:
fx = abs(((((1-alfa).*A.*K.^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-x))-((((1-varphi).*pinl.*N-x)./(Rp_eps.*phi)).^(1./xi)))./eta).^((1-alfa-omega)./omega))-1)./eta)-rcb)-(xi.*Rp_eps.*phi.*((((1-varphi).*pinl.*N-x)./(Rp_eps.*phi)).^((xi-1)./xi)).*((((1-alfa).*A.*K.^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-x))-((((1-varphi).*pinl.*N-x)./(Rp_eps.*phi)).^(1./xi)))./eta).^((1-alfa-omega)./omega))-1)./eta)-rM-varphi.*((((1-alfa).*A.*K.^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-x))-((((1-varphi).*pinl.*N-x)./(Rp_eps.*phi)).^(1./xi)))./eta).^((1-alfa-omega)./omega))-1)./eta)-rcb)) ));
fw = fx;
fv = fw;
tol = eps * abs ( x ) + t;
d = tol;
while ( 1 )
m = 0.5 * ( sa + sb );
tol = eps * abs ( x ) + t;
t2 = 2.0 * tol;
%
% Check the stopping criterion.
%
if ( abs ( x - m ) <= t2 - 0.5 * ( sb - sa ) )
break
end
%
% Fit a parabola.
%
r = 0;
q = r;
p = q;
if ( tol < abs ( e ) )
r = ( x - w ) * ( fx - fv );
q = ( x - v ) * ( fx - fw );
p = ( x - v ) * q - ( x - w ) .* r;
q = 2.0 * ( q - r );
if ( 0.0 < q )
p = - p;
end
q = abs ( q );
r = e;
e = d;
end
if ( abs ( p ) < abs ( 0.5 * q * r ) & ...
q * ( sa - x ) < p & ...
p < q * ( sb - x ) )
%
% Take the parabolic interpolation step.
%
d = p ./ q;
u = x + d;
%
% F must not be evaluated too close to A or B.
%
if ( ( u - sa ) < t2 | ( sb - u ) < t2 )
if ( x < m )
d = tol;
else
d = - tol;
end
end
%
% A golden-section step.
%
else
if ( x < m )
e = sb - x;
else
e = sa - x;
end
d = c .* e;
end
%
% F must not be evaluated too close to X.
%
if ( tol <= abs ( d ) )
u = x + d;
elseif ( 0.0 < d )
u = x + tol;
else
u = x - tol;
end
% function evaluation at 'u'
fu = abs(((((1-alfa).*A.*K^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-u))-((((1-varphi).*pinl.*N-u)./(Rp_eps.*phi)).^(1/xi)))/eta).^((1-alfa-omega)/omega))-1)/eta)-rcb)-(xi.*Rp_eps.*phi.*((((1-varphi).*pinl.*N-u)./(Rp_eps.*phi)).^((xi-1)/xi)).*((((1-alfa).*A.*K^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-u))-((((1-varphi).*pinl.*N-u)./(Rp_eps.*phi)).^(1/xi)))/eta).^((1-alfa-omega)/omega))-1)/eta)-rM-varphi.*((((1-alfa).*A.*K^alfa.*((((1-varphi).*(pil.*N+((1-varphi).*pinl.*N-u))-((((1-varphi).*pinl.*N-u)./(Rp_eps.*phi)).^(1/xi)))/eta).^((1-alfa-omega)/omega))-1)/eta)-rcb)) ));
%
% Update A, B, V, W, and X.
%
if ( fu <= fx )
if ( u < x )
sb = x;
else
sa = x;
end
v = w;
fv = fw;
w = x;
fw = fx;
x = u;
fx = fu;
else
if ( u < x )
sa = u;
else
sb = u;
end
if ( fu <= fw | w == x )
v = w;
fv = fw;
w = u;
fw = fu;
elseif ( fu <= fv | v == x | v == w )
v = u;
fv = fu;
end
end
end % while-loop
Thanks for your helpful clarification, that arrayfun supports scalars as inputs. It is also unclear to me whether I should use element wise operators in the function, even if the operation itself should be processed on scalars only.
I don't see any compilation error in R2013a when calling your local_min via arrayfun with all double gpuArray inputs. I know there are a lot of inputs to your function, but if you can give me a sense of what their types are I may be able to reproduce the problem.
When preparing to post a replication of the input variables I succeeded in running the code. Apparently, I defined the input variables originally in 'single' precision. I did not change them into 'double' prior to defining them as gpuArray. It seems the error message addressing the change of type ("Error using gpuArray/arrayfun Variable 'r' changed type. Consider renaming variable on left hand side of assignment") was in my case related to an automatic change on the GPU from 'single' into 'double' precision, causing an internal conflict.
Jill, thank you very much for your time. I wouldn't have figured it out without your help!
No problem. I'm glad that it's sorted out. :-)

Sign in to comment.

Answers (0)

Categories

Find more on Get Started with MATLAB in Help Center and File Exchange

Asked:

on 4 Dec 2013

Commented:

on 13 Dec 2013

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!