Matlab: Multiple assignment through logical indexing - matlab

I am wondering if there is some way, how to multiple assign values to different variables according logical vector.
For example:
I have variables a, b, c and logical vector l=[1 0 1] and vector with values v but just for a and c. Vector v is changing its dimension, but everytime, it has the same size as the number of true in l.
I would like to assign just new values for a and c but b must stay unchanged.
Any ideas? Maybe there is very trivial way but I didn't figure it out.
Thanks a lot.

I think your problem is, that you stored structured data in an unstructured way. You assume a b c to have a natural order, which is pretty obvious but not represented in your code.
Replacing a b c with a vector x makes it a really easy task.
x(l)=v(l);
Assuming you want to keep your variable names, the simplest possibility I know would be to write a function:
function varargout=update(l,v,varargin)
varargout=varargin;
l=logical(l);
varargout{l}=v(l);
end
Usage would be:
[a,b,c]=update(l,v,a,b,c)

Related

Assigning values in one vector to indices in another vector?

Basically I have been trying to assign a new vector with values from another.This can be done sequentially using :
vDSP_vindex(A,B,Stride,C,Stride,Length)
So if A has 10 elements,B has 20 indices and C has 20 elements; we assign all the values in C using the elements in A at indices defined in B.
But what if I want to have the indices of C in B? to be populated with elements from A.
Hope someone can help with this.
He wants C[B[i]] = a[i] rather than C[i] = a[B[i]]. The problem with this construction is that there is no guarantee that all the elements in C are defined, or what happens when two indices in B are the same -- which one ends up in C?
Assuming these problems don't bother you, you need to transform the elements in B[i] to be the right values for the other formulation. This is just a matter of:
initialize Bprime[] to a default value for undefined.
for each i in [0,N)
Bprime[B[i]] = i;
vDSP_vindex(A,Bprime,Stride,C,Stride,N)
Whether this is worth it or not probably depends entirely on whether Bprime can be reused.

Passing values to a sparse matrix in MATLAB

Might sound too simple to you but I need some help in regrad to do all folowings in one shot instead of defining redundant variables i.e. tmp_x, tmp_y:
X= sparse(numel(find(G==0)),2);
[tmp_x, temp_y] = ind2sub(size(G), find(G == 0));
X(:)=[tmp_x, tmp_y];
(More info: G is a sparse matrix)
I tried:
X(:)=ind2sub(size(G), find(G == 0));
but that threw an error.
How can I achieve this without defining tmp_x, tmp_y?
A couple of comments with your code:
numel(find(G == 0)) is probably one of the worst ways to determine how many entries that are zero in your matrix. I would personally do numel(G) - nnz(G). numel(G) determines how many elements are in G and nnz(G) determines how many non-zero values are in G. Subtracting these both would give you the total number of elements that are zero.
What you are doing is first declaring X to be sparse... then when you're doing the final assignment in the last line to X, it reconverts the matrix to double. As such, the first statement is totally redundant.
If I understand what you are doing, you want to find the row and column locations of what is zero in G and place these into a N x 2 matrix. Currently with what MATLAB has available, this cannot be done without intermediate variables. The functions that you'd typically use (find, ind2sub, etc.) require intermediate variables if you want to capture the row and column locations. Using one output variable will give you the column locations only.
You don't have a choice but to use intermediate variables. However, if you want to make this more efficient, you don't even need to use ind2sub. Just use find directly:
[I,J] = find(~G);
X = [I,J];

Reduced row echelon matrix equivalence

I've been trying to solve whether two m-by-n matrices A and B are equivalent via
[a,ja] = rref(A,tol)
[b,jb] = rref(B,tol)
and then comparing
isequal(a,b) & isequal(ja,jb)
First, I don't really understand what ja and jb are. My problem is that the reduced row echelon form is very simple for both A and B and identical in all cases. I don't know whether this is on purpose or not. For example, I get equivalence for just
A = rand(40,3)
B = rand(40,3)
which I'm not sure is nonsense or not.
It looks like you're trying to check if the reduced row echelon forms of two matrices are element-wise equivalent. From how you've defined A and B, they are (it's effectively an overdetermined system, I believe). However, I think that you may have flipped your rows and columns. If instead you create A and B such that there are more columns than rows (i.e., an augmented matrix of an underdetermined system):
A = rand(3,40)
B = rand(3,40)
then when you run rref, you'll see a much different output and your comparison will return false as you perhaps expected.
Also, I think that it is sufficient to use the following, as two matrices that are equal element-wise will surely share the same rank (or approximation thereof):
a = rref(A,tol);
b = rref(B,tol);
isequal(a,b)

What's the most idiomatic way to create a vector with a 1 at index i?

In Matlab, suppose I would like to create a 0-vector of length L, except with a 1 at index i?
For example, something like:
>> mostlyzeros(6, 3)
ans =
0 0 1 0 0 0
The purpose is so I can use it as a 'selection' vector which I'll multiply element-wise with another vector.
The simplest way I can think of is this:
a = (1:N)==m;
where N>=m. Having said that, if you want to use the resulting vector as a "selection vector", I don't know why you'd multiply two vectors elementwise, as I would expect that to be relatively slow and inefficient. If you want to get a vector containing only the m-th value of vector v in the m-th position, this would be a more straightforward method:
b = ((1:N)==m)*v(m);
Although the most natural method would have to be this:
b(N)=0;
b(m)=v(m);
assuming that b isn't defined before this (if b is defined, you need to use zeros rather than just assigning the Nth value as zero - it has been my experience that creating a zero vector or matrix that didn't exist before that is most easily done by assigning the last element of it to be zero - it's also useful for extending a matrix or vector).
I'm having a hard time thinking of anything more sensible than:
Vec = zeros(1, L);
Vec(i) = 1;
But I'd be happy to be proven wrong!
UPDATE: The one-liner solution provided by #GlenO is very neat! However, be aware that if efficiency is the chief criteria, then a few speed tests on my machine indicate that the simple method proposed in this answer and the other two answers is 3 or 4 times faster...
NEXT UPDATE: Ah! So that's what you mean by "selection vectors". #GlenO has given a good explanation of why for this operation a vector of ones and zeros is not idiomatic Matlab - however you choose to build it.
ps Try to avoid using i as a subscript, since it is actually a matlab function.
Just for the fun of it, another one-liner:
function [out] = mostlyzeros(idx, L)
out([L, idx]) = [0 1];
I can think of:
function mostlyones(m,n)
mat=zeros(1,m);
mat(n)=1;
Also, one thing to note. In MATLAB, index starts from one and not from zero. So your function call should have been mostlyzeros(6,3)
I would simply create a zero-vector and change whatever value you like to one:
function zeroWithOne(int numOfZeros, int pos)
a = zeros(numOfZeros,1);
a(pos) = 1;
Another one line option, which should be fast is:
vec = sparse(1, ii, 1, 1, L);

Minimizing objective function by changing a variable - in Matlab?

I have a 101x82 size matrix called A. Using this variable matrix, I compute two other variables called:
1) B, a 1x1 scalar, and
2) C, a 50x6 matrix.
I compare 1) and 2) with their analogues variables 3) and 4), whose values are fixed:
3) D, a 1x1 scalar, and
4) E, a 50x6 matrix.
Now, I want to perturb/change the values of A matrix, such that:
1) ~ 3), i.e. B is nearly equal to D , and
2) ~ 4), i.e. C is nearly equal to E
Note that on perturbing A, B and C will change, but not D and E.
Any ideas how to do this? Thanks!
I can't run your code as it's demanding to load data (which I don't have) and it's not immediatly obvious how to calculate B or C.
Fortunately I may be able to answer your problem. You're describing an optimization problem, and the solution would be to use fminsearch (or something of that variety).
What you do is define a function that returns a vector with two elements:
y1 = (B - D)^weight1;
y2 = norm((C - E), weight2);
with weight being how strong you allow for variability (weight = 2 is usually sufficient).
Your function variable would be A.
From my understanding you have a few functions.
fb(A) = B
fc(A) = C
Do you know the functions listed above, that is do you know the mappings from A to each of these?
If you want to try to optimize, so that B is close to D, you need to pick:
What close means. You can look at some vector norm for the B and D case, like minimizing ||B-D||^2. The standard sum of the squares of the elements of this different will probably do the trick and is computationally nice.
How to optimize. This depends a lot on your functions, whether you want local or global mimina, etc.
So basically, now we've boiled the problem down to minimizing:
Cost = ||fb(A) - fd(A)||^2
One thing you can certainly do is to compute the gradient of this cost function with respect to the individual elements of A, and then perform minimization steps with forward Euler method with a suitable "time step". This might not be fast, but with small enough time step and well-behaved enough functions it will at least get you to a local minima.
Computing the gradient of this
grad_A(cost) = 2*||fb(A)-fd(A)||*(grad_A(fb)(A)-grad_A(fd)(A))
Where grad_A means gradient with respect to A, and grad_A(fb)(A) means gradient with respect to A of the function fb evaluated at A, etc.
Computing the grad_A(fb)(A) depends on the form of fb, but here are some pages have "Matrix calculus" identities and explanations.
Matrix calculus identities
Matrix calculus explanation
Then you simply perform gradient descent on A by doing forward Euler updates:
A_next = A_prev - timestep * grad_A(cost)