(elisp) Elements of vectors of vectors - emacs

I build a 2-dimensional array (a matrix) consisting of a vector of vectors:
(setq zero-row [0 0 0 0 0])
=> [0 0 0 0 0]
(setq zero-mat (make-vector 4 zero-row))
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
I'll set the element in row 2, column 3 (0-indexed) to 42 by replacing row 2 with a vector containing the changed element:
(aset zero-mat 2 [0 0 0 42 0])
=> [0 0 0 42 0]
zero-mat
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 42 0] [0 0 0 0 0]]
It works.
Next I try to build a function which takes this approach to set the (i,j)-th element in such a 2-dimensional array:
(defun matrix-set (mat i j elt)
"Set the (i, j)-th element of mat to elt. mat is a vector of the row vectors. Indexing is 0-based in each component."
(let ((vect (aref mat i)))
(aset vect j elt)
(aset mat i vect)
mat))
But this doesn't work:
(setq zero-row [0 0 0 0 0])
=> [0 0 0 0 0]
(setq zero-mat (make-vector 4 zero-row))
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
(matrix-set zero-mat 2 3 42)
=> [[0 0 0 42 0] [0 0 0 42 0] [0 0 0 42 0] [0 0 0 42 0]]
It looks like all the rows of the array are linked to the same vector, so changing that vector changes all the rows.
So two questions: (1) Why is this happening in the second case, but not the first? (2) How can I fix this (so I can access the (i, j)-th entry of a 2-dim. array represented this way)?
(I was originally writing a little routine to add two matrices, represented as vectors of vectors as above, and ran into the same problem. I think the stripped-down example above may make the problem clearer.)

In the first case you are replacing an element in the "outer" vector by another vector (while other three "inner" vectors still point all to the same element). In the second case you replace an element in the "inner" vector (and you have only one inner vector duplicated four times, as per your example. A simple way to initialize vector to different distinct vectors would be something like this:
(let ((i 0) (new-vector (make-vector 4 nil))
(while (< (progn (aset new-vector i (make-vector 5 0))
(incf i))
(length new-vector)))
Sorry if there are any typos, was writing it in-place. But the idea should be simple enough to figure it out.

Related

Creating a function to turn a vector of vectors into a list of lists

I understand how to turn a vector into a list with vector->list but I was wondering if there was a way to create a function in order to do so. For example:
(define test-board (vector
(vector 1 0 1 0 0 1)
(vector 0 0 0 1 0 1)
(vector 1 0 0 0 1 1)))
I know that I can go line by line and do this:
(define test-board (vector->list(vector
(vector->list(vector 1 0 1 0 0 1))
(vector->list(vector 0 0 0 1 0 1))
(vector->list(vector 1 0 0 0 1 1))
)
)
)
But is there a way to create a function to do this without having to go line by line?
This should work:
(vector->list
(vector-map vector->list test-board))

randomly select histogram data MATLAB

I have an input 2D histogram that I want to do 2-fold cross-validation with. The problem is I don't know how to extract two mutually exclusive random samples of the data from a histogram. If it was a couple of lists of the positional information of each data point, that would be easy - shuffle the data in the lists in the same way, and split the lists equally.
So for a list I would do this:
list1 = [1,2,3,3,5,6,1];
list2 = [1,3,6,6,5,2,1];
idx = randperm(length(list1)); % ie. idx = [4 3 1 5 6 2 7]
shlist1 = list1(idx); % shlist1 = [3,3,1,5,6,2,1]
shlist2 = list2(idx); % shlist2 = [6,6,1,5,2,3,1]
slist1 = shlist1(1:3); % slist1 = [3,3,1]
elist1 = shlist1(4:6); % elist1 = [5,6,2,1]
slist2 = shlist2(1:3); % slist2 = [6,6,1]
elist2 = shlist2(4:6); % elist2 = [5,2,3,1]
But if this same data was presented to me as a histogram
hist = [2 0 0 0 0 0]
[0 0 0 0 0 1]
[0 1 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 1 0]
[0 0 2 0 0 0]
I want the result to be something like this
hist1 = [0 0 0 0 0 0]
[0 0 0 0 0 1]
[0 1 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 1 0 0 0]
hist2 = [2 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 1 0]
[0 0 1 0 0 0]
so that different halves of the data are randomly, and equally assigned to two new histograms.
Would this be equivalent to taking a random integer height of each bin hist(i,j), and adding that to the equivalent bin in hist1(i,j), and the difference to hist2(i,j)?
% hist as shown above
hist1 = zeros(6);
hist2 = zeros(6);
for i = 1:length(hist(:,1))*length(hist(1,:))
randNum = rand;
hist1(i) = round(hist(i)*randNum);
hist2(i) = hist(i) - hist1(i);
end
And if that is equivalent, is there a better way/built-in way of doing it?
My actual histogram is 300x300 bins, and contains about 6,000,000 data points, and it needs to be fast.
Thanks for any help :)
EDIT:
The suggested bit of code I made is not equivalent to taking a random sample of positional points from a list, as it does not maintain the overall probability density function of the data.
Halving the histograms should be fine for my 6,000,000 points, but I was hoping for a method that would still work for few points.
You can use rand or randi to generate two histograms. The first method is more efficient however the second is more random.
h = [[2 0 0 0 0 0]
[0 0 0 0 0 1]
[0 1 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 1 0]
[0 0 2 0 0 0]];
%using rand
h1 = round(rand(size(h)).*h);
h2 = h - h1;
%using randi
h1 = zeros(size(h));
for k = 1:numel(h)
h1(k) = randi([0 h(k)]);
end
h2 = h - h1;
Suppose H is your 2D histogram. The following code extracts a single random index with a probability proportional to the count at that index - which I think is what you want.
cc = cumsum(H(:));
if cc(1) ~= 0
cc = [0; cc];
end
m = cc(end);
ix = find(cc > m*rand, 1);
To extract multiple samples, you need to write your own find function (preferably a binary search for efficiency) that extracts some n number of samples in one call. This will give you a vector of indices (call it ix_vec) chosen with probability proportional to the Histogram count at each index.
Then if we denote by X the numerical values corresponding to each location in the Histogram, your random sample is:
R1 = X(ix_vec);
Repeat for the second random sample set.

Matlab, generate new matrix

How do you translate matrix of A [(N) x (N)] to matrix B [(2N) x (2N)], such that:
if A(i,j)>=0, then:
B(i,j) = [ A(i,j) 0
0 A(i,j)]
if A(i,j)<0, then:
B(i,j) = [ 0 A(i,j)
A(i,j) 0 ]
?
For example1 by:
1 2
3 4
I'm want to get:
1 0 2 0
0 1 0 2
3 0 4 0
0 3 0 4
For example2 by:
1 -2
3 -4
I'm want to get:
1 0 0 2
0 1 2 0
3 0 0 4
0 3 4 0
Use the Kronecker tensor product:
B = kron(A.*(A>=0), [1 0; 0 1]) + kron(A.*(A<0), [0 1; 1 0]);
Or maybe
B = kron(A.*(A>=0), [1 0; 0 1]) - kron(A.*(A<0), [0 1; 1 0]);
if you want all positive values (your examples and your original formulation don't agree on this)
very simple using logical conditions:
B=[A.*(A>=0), A.*(A<0) ; A.*(A<0), A.*(A>=0)];
for example,
A=[1 2 ; -3 4];
B =
1 2 0 0
0 4 -3 0
0 0 1 2
-3 0 0 4
Postscipt:
This answer was written to answer the question above in its initial forms:
How do you translate matrix of A [(N) x (N)] to matrix B [(2N) x (2N)], such that:
if A(i,j)>=0, then:
B(i,j) = [ A(i,j) 0
0 A(i,j)]
if A(i,j)<0, then:
B(i,j) = [ 0 A(i,j)
A(i,j) 0 ]
?
later the OP wrote down some examples that made clear what he\she were after.

How do I 2D-plot my own function with two arguments?

I've started out with MATLAB a few hours ago and began with plotting some simple functions, e.g.:
k = -20:20;
a = 0.01;
x_k = exp(-a * k.^2)
f_1 = figure(1);
plot(k, x_k)
This works fine and plots each value of k on the x-axis, with its corresponding function response at the y-axis. Now I've defined my own function:
function [y] = triangle(t, a)
if (a <= t) & (t <= 0)
y = (1/a * t + 1) * a
elseif (0 <= t) & (t <= a)
y = (-1/a * t + 1) * a
else
error('Function not defined for these values')
end
end
I now want to plot triangle for a range of t with a specific parameter a. So I call:
a = 1;
int = (2 * a) / 20;
t = -a:int:a;
f_1 = figure(1);
plot(t, triangle(t, a))
… but my function errors out because the entire t array (vector, I suppose?) is passed to it instead of each element of t.
How do I plot my triangle function for a specific a, over a defined range?
I've also tried fplot(triangle(a), t) (since fplot accepts a function as an argument) but that again complains about triangle not receiving enough input arguments—rightly so, but I need to pass a to it as well.
The problem of this is the that you pass a vector to your function triangle but you want to check every single if-statement for each single value of the vetor t. So either you use a for-loop within the function triangle or you could also do it by using this:
function [y] = triangle(t, a)
y = ((a <= t) & (t <= 0)) .* ((1/a * t + 1) * a) + ((0 <= t) & (t <= a)) .* ((-1/a * t + 1) * a);
end
I know it looks somehow weird, but if you need me to explain it a bif more in detail, I can do this for you ;-)
EDIT: Let's shortly examine the problem: You pass a vector t to the function, which means that the first if statement if (a <= t) & (t <= 0) splitted looks like this:
(a <= t) % resulting in:
ans =
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
(t <= 0) % resulting in:
ans =
1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
so combining them via the AND operator (& for vectors), this obviously gives you
ans =
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
So this branch wont be executed. The elseif gives you:
(0 <= t)
ans =
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
(t <= a)
ans =
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
((0 <= t) & (t <= a))
ans =
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
so this won't be executed either even though you'd want it to be executed for the second half of your values because you'd like to check the two statements for each value-pair on it's own.
So by leaving away the statements completely you could do it like I posted above: simply multiply the result of the logical statements elementwise with the piecewise function which will yield the result you want to calculate :-)
The best approach is to define the triangle function so that it admits vector inputs. You and do it with logical indexing, which selects a range of values of t depending on a logical condition:
function [y] = triangle(t, a)
y = NaN(size(t)); %// pre-allocate and define NaN as default return value
ind = (a <= t) & (t <= 0); %// select first range
y(ind) = (1/a * t(ind) + 1) * a; %//compute output for first range
ind = (0 <= t) & (t <= a); %// select second range
y(ind) = (-1/a * t(ind) + 1) * a; %//compute output for second range
end
This returns NaN for out-of-range values. As an example, for your t,
>> triangle(t, a)
ans =
Columns 1 through 13
NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.0000 0.9000 0.8000
Columns 14 through 21
0.7000 0.6000 0.5000 0.4000 0.3000 0.2000 0.1000 0
Once you define the function like this, you can do plot(t, triangle(t, a)).
To pass your function to fplot, you need to use an anonymous function (like what is called a lambda in many other programming languages).
This is done with the # syntax in matlab (see help function_handle for how to use this).
So your fplot try should be:
fplot(#(x) triangle(x,a), t([1 end]))
Note that the t input for fplot is the bounds in which you want to evaluate your function, not the values to evaluate itself (you can use bounds in combination with fplot's third input argument for some control over that).
That said, as other posters also noted, the part of your example input where t<0 end up right in your else branch and yields an error.

Matlab: How to insert zeros in specific places of vector

Can someone help me with the following problem in Matlab? I have a first vector containing the elements values. For example,
[2 8 4 9 3].
And a second one with the desired places in a second vector. For example,
[0 0 1 0 0 0 0 1 1 0 0 1 0 0 1].
Now I want to put the values from the first vector on the positions of the second one to end up with
[0 0 2 0 0 0 0 8 4 0 0 9 0 0 3].
What is the most efficient way of doing this when the size of the vector can be very large. (then thousands of elements)?
You can consider the y values as logical indicators, then use logical indexing to set those values to the values in x.
x = [2 8 4 9 3];
y = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
y(logical(y)) = x;
Alternatively, you could use
y(y==1) = x;
Use self-indexing:
% Your values:
V = [2 8 4 9 3];
% The desired locations of these values:
inds = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
% index the indices and assign
inds(inds>0) = V