matlab: quick function that can produce NaN if x > 1 - matlab

I am looking for a one-line function f = #(x) {something} that produces NaN if x >= 1, and either 0 or 1 if x < 1.
Any suggestions?

Aha, I got it:
f = #(x) 0./(x<1)
yields 0 for x < 1 and NaN for x>=1.

Here's a modification of Jason's solution that works for arrays. Note that recent versions of MATLAB do not throw divide-by-zero warnings.
>> f = #(x) zeros(size(x)) ./ (x < 1)
f =
#(x)zeros(size(x))./(x<1)
>> f(0:.3:2)
ans =
0 0 0 0 NaN NaN NaN
Update: a coworker pointed out to me that Jason's original answer works just fine for arrays.
>> f = #(x) 0./(x<1)
f =
#(x)0./(x<1)
>> f(0:.3:2)
ans =
0 0 0 0 NaN NaN NaN

Here's a less obvious solution (vectorized nonetheless):
f = #(x) subsasgn(zeros(size(x)), struct('type','()','subs',{{x>=1}}), nan) + 0
Basically its equivalent to:
function v = f(x)
v = zeros(size(x));
v( x>=1 ) = nan;
The +0 at the end is to always force an output, even if f called with no output arguments (returned in ans). Example:
>> f(-2:2)
ans =
0 0 0 NaN NaN

Here's a solution that won't risk throwing any divide-by-zero warnings, since it doesn't involve any division (just the functions ONES and NAN):
f = #(x) [ones(x < 1) nan(x >= 1)];
EDIT: The above solution is made for scalar inputs. If a vectorized solution is needed (which isn't 100% clear from the question) then you could modify f like so:
f = #(x) arrayfun(#(y) [ones(y < 1) nan(y >= 1)],x);
Or apply ARRAYFUN when calling the first version of the function f:
y = arrayfun(f,x);

Related

Solving inequalities in matlab

I'm trying to solve simple inequalities using matlab and got stuck.
solve(x^2>0,x)
ans =
-1
1
solve(x^2>5,x)
ans =
5^(1/2)+1
-5^(1/2)-1
which is totally wrong. What is the problem? My matlab version is R2014b.
If you are solving an equation, e.g. x^2 == 1, then you are looking for specific points, i.e. the points x=1 and x=-1. Luckily, MATLAB returns exactly this:
>> syms x
>> solve(x^2 == 1, x)
ans =
-1
1
Now, you are looking for solutions to an inequality. You really don't want to find all points for which the inequality holds, as this are infinitely many in your case. As stated in the documentation to solve, the 'ReturnConditions' flag will make solve return the conditions under which the (in-) equality holds.
>> syms x
>> S = solve(x^2>0,x, 'ReturnConditions', true)
>> S.conditions
ans =
x < 0
0 < x
or for the second example
>> syms x
>> S = solve(x^2 > 5, x,'ReturnConditions',true)
>> S.conditions
ans =
5^(1/2) < x
x < -5^(1/2)

Matlab exp only works on the first element?

I've been trying to get a simple sigmoid function to work in matlab and it seems it only works for the first element of the matrix.
my code is:
function g = sigmoid(z)
g = zeros(size(z));
g = 1/(1 + exp(-z));
end
Now it works fine for simple values like:
>>sigmoid(0)
ans = 0.5000
but for:
`
>>k = [0; 0; 0; 0; 0];
>>sigmoid(k)`
it's giving me:
ans = 0.5000 0 0 0 0
looking into 'exp' it says its an element-wise operation, so I am not sure where I am going wrong. Any help would be appreciated. :)
A few issues here.
You don't need to pre-allocate g only to reassign it in the next line.
You need to use element-wise division ./ rather than matrix division /
So the correct function would be:
function g = sigmoid(z)
g = 1 ./ (1 + exp(-z));
end

Possible Vectorization using If Statements in MATLAB

Suppose I have the following column vectors as
res1 = -0.81 res2 = 0.61
0.1 -0.4
-0.91 0.62
0.2 -0.56
0.63 -0.72
and I have two fixed constant D = 0.5. Now suppose an element of res1 is called X and an element of res2 is called Y. I have the following conditions
if (X > D && Y < -D)
output = 1
elseif (X < -D && Y > D)
output = -1
else
output = 0
end
My question is this:
Is it possible to "vectorize" these conditions to iterate over the entire vectors res1 and res2, such that my output vector would give (for example) :
output = -1
0
-1
0
1
?
I know I can do it via a loop, but I would prefer to avoid it since these vectors are actually quite large (>10000). I have attempted to use logical indexing, but to no avail (unless I'm implementing it wrong).
Any help would be appreciated!
You can use logical arrays to replace the conditional statements and scale them with appropriate scaling factors for the final output -
%// Logical arrays corresponding to the IF and ELSEIF conditional statements
case1 = res1>D & res2<-D
case2 = res1<-D & res2>D
%// Get the final output after multiplying each case with the
%// scaling factors 1 and -1 respectively.
%// The default value of `zero` for the ELSE part is automatically taken
%// care of because we are using logical array of ones and zeros anyway
output = case1 + -1*case2 %// or simply case1 - case2
Sample run -
>> res1
res1 =
-0.8100
0.1000
-0.9100
0.2000
0.6300
>> res2
res2 =
0.6100
-0.4000
0.6200
-0.5600
-0.7200
>> output
output =
-1
0
-1
0
1

Formatting equations for linprog in MATLAB

I have to solve a simple problem using function linprog in matlab math toolbox. The problem is that I don't know how to format my equations so this function solves the problem.
This is the function I am trying to minimize (a_i are some given coefficients, x is in R^5):
x = argmax min{a1*x1 + a2*x2, a2*x2 + a3*x3 + a4*x4, a4*x4 + a5*x5}
subject to:
sum(x_i) = 3000
all x_i >= 0
This could be rephrased as:
(x, lambda) = argmin(-lambda)
subject to:
a1*x1 + a2*x2 >= lambda
a2*x2 + a3*x3 + a4*x4 >= lambda
a4*x4 + a5*x5 >= lambda
sum(x_i) = 3000
all x_i >= 0
I could only find examples of minimization of simple linear functions without min/max arguments in it. Could you give me a hint how to make my structures as arguments for linprog function?
Let's try the following
your x vector is now
[x1 x2 x3 x4 x5 lambda]
the objective vector
f = [0 0 0 0 0 -1]
equality constraint:
Aeq = [1 1 1 1 1 0] beq = 3000
Inequality constraint:
A = [-a1 -a2 0 0 0 1; 0 -a2 -a3 -a4 0 1; 0 0 0 -a4 -a5 1] b = [0;0;0]
lower bound:
lb = [0 0 0 0 0 -inf]
now try
linprog( f, A, b, Aeq, beq, lb )
up to some transposing of arguments should do the trick.
I don't believe you can pose the question as you phrased it as a linprog problem. The "MIN" operation is the problem. Since the objective function can't be phrased as
y = f'x.
Even though your constraints are linear, your objective function isn't.
Maybe with some trickery you can linearize it. But if so, that's a math problem. See: https://math.stackexchange.com/

matlab: lsqcurvefit and parameters

I'm trying to do some fitting with lsqcurvefit. I have a function like that:
function F = cdf_3p_model(a,data)
F=1-((1-a(5)-a(6)).*(exp(-abs(data)./a(1)))+((1-a(4)-a(6)).*(exp(-abs(data)./a(2))))+((1-a(4)-a(5)).*(exp(-abs(data)./a(3)))));
and
function [a residual] = cdf_fit_3p(x,y)
a0 = [10 1 0.1 0.3 0.3 0.3];
lb = [0 0 0 0 0 0];
ub = [];
curvefitoptions = optimset('Display','final','MaxFunEvals',100000,'MaxIter',50000);
[a, residual] = fmincon(#cdf_3p_model,a0,x,y,lb,ub,curvefitoptions);
end
I set the initial parameters, ub, lb but how do I also declare that:
a(1) > a(2) > a(3)
a(5) + a(6) +a(7) = 1
I think you have better chance using one of the minimization routines such as fmincon which allows you to specify constraints you might otherwise be unable to do. You can easily incorporate least-squares by taking the L2-norm of the difference between model and data
Normally I would say, "make clauses in your function that gives really terrible 'scores' when those conditions are not met." However, your conditions make the range of allowable parameters such a tiny, tiny subset of the range of possible numbers that I think you would cause lsqcurvefit to never converge if you do that. I would say lsqcurvefit is not the right solution for you.
You will have to calculate the parameters you "want" from a set of parameters that's more usable to MatLab.
For example, you can rewrite
a(1) > a(2) > a(3)
a(5) + a(6) + a(7) = 1
as
a(3) = p(1)
a(2) = p(1) + p(2)
a(1) = p(1) + p(2) + p(3)
a(4) = p(4)
a(5) = p(5)
a(6) = p(6)
a(7) = 1 - p(5) - p(6)
with
lb = [0 0 0 0 0 0]
ub = [Inf Inf Inf Inf 1 1]
Well, it's not perfect, because it allows a(7) as low as -1 instead of 0. But it includes your other constraints.