Octave: Set matrix values according to vector [duplicate] - octave

I'm trying to vectorize the following MATLAB operation:
Given a column vector with indexes, I want a matrix with the
same number of rows of the column and a fixed number of columns. The
matrix is initialized with zeroes and contains ones in the locations
specified by the indexes.
Here is an example of the script I've already written:
y = [1; 3; 2; 1; 3];
m = size(y, 1);
% For loop
yvec = zeros(m, 3);
for i=1:m
yvec(i, y(i)) = 1;
end
The desired result is:
yvec =
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
Is it possible to achieve the same result without the for loop? I tried something like this:
% Vectorization (?)
yvec2 = zeros(m, 3);
yvec2(:, y(:)) = 1;
but it doesn't work.

Two approaches you can use here.
Approach 1:
y = [1; 3; 2; 1; 3];
yvec = zeros(numel(y),3);
yvec(sub2ind(size(yvec),1:numel(y),y'))=1
Approach 2 (One-liner):
yvec = bsxfun(#eq, 1:3,y)

Yet another approach:
yvec = full(sparse(1:numel(y),y,1));

You could do this with accumarray:
yvec = accumarray([(1:numel(y)).' y], 1);

I did it this way:
classes_count = 10;
sample_count = 20;
y = randi([1 classes_count], 1, sample_count);
y_onehot = zeros(classes_count, size(y, 2));
idx = sub2ind(size(y_onehot), y, [1:size(y, 2)]);
y_onehot(idx) = 1

Related

Octave: Replacing element of matix/vector with a vector

I am trying to turn each element in a matrix from a value from 1 to 10 into a 10x1 zeros matrix where the element of the zeros matrix corresponding to the value of the original element is equal to 1.
Here is the code:
function q = convert
% Convert y matrix values to 10x1 vector
load('y.mat');
ZERO = zeros(10,1);
% Set 10x1 Matrix of zeros
for i = 1:length(y)
ZERO(y(i)) = 1; % Set yth element of ZERO to 1
y(i) = ZERO; % Set ith element of y equal to new zero
ZERO = zeros(10,1); % Re-establish zero
endfor
When I run it I get the error A(I) = X: X must have the same size as I. Where the matrix I am trying to input does not agree with the size of element of matrix y. Can I get around this?
Sample input:
y = [1; 2; 3; 4; 5]
Sample output:
y = [[1;0;0;0;0;0;0;0;0;0],
[0;1;0;0;0;0;0;0;0;0],
[0;0;1;0;0;0;0;0;0;0],
[0;0;0;0;1;0;0;0;0;0],
[0;0;0;0;0;1;0;0;0;0]]
I'm going to make a couple of assumptions:
You want the return value to be q as in the function signature, and
You want the output in your sample case to be a 10x5 matrix like so:
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
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
Fixing the loop
The problem that gives the error is that you're assigning a 10x1 vector ZERO to a single (scalar) element of the 5x1 vector y:
y(i) = ZERO;
A vector doesn't fit in a scalar. But even if you change this to assign ZERO to a column of y, it doesn't fit because the lengths of the columns are different. That's not what you want to do anyway, because if it had worked, you would have just wiped out the values in y. So let's set the values in the columns of the output array q. (Changes are marked with <== in the comments.)
function q = convert
% Convert y matrix values to 10xn matrix
%load('y.mat');
y = [1; 2; 3; 4; 5]; % <== replace load temporarily
% Set 10x1 Matrix of zeros
ZERO = zeros(10,1);
% Preallocate output array
q = zeros(10, length(y)); % <== preallocate for speed
for i = 1:length(y)
ZERO(y(i)) = 1; % Set yth element of ZERO to 1
q(:,i) = ZERO; % <== Set ith *column* of *q* equal to new zero
ZERO = zeros(10,1); % Re-establish zero
endfor
Improving the loop
This will work, but if you preallocate q, you've already got the correct number of ZERO vectors, so why not just set the values directly?
function q = convert
% Convert y matrix values to 10xn matrix
%load('y.mat');
y = [1; 2; 3; 4; 5]; % <== replace load temporarily
% Preallocate output array
q = zeros(10, length(y)); % <== preallocate for speed
for i = 1:length(y)
q(y(i),i) = 1; % <== Set element at y(ith) row and ith column of q to 1
endfor
Killing the loop
Either of these loops will give you the desired results, but you can do this whole operation without a loop. This answer summarizes different ways to do this, but I'll just show you the first one using sub2ind:
function q = convert
% Convert y matrix values to 10xn matrix
%load('y.mat');
y = [1; 2; 3; 4; 5]; % <== replace load temporarily
% Preallocate output array
q = zeros(10, length(y)); % <== preallocate for speed
idx = sub2ind(size(q), y, [1:length(y)].');
q(idx) = 1;
Final note
It's best not to use i as a variable name in Octave/MATLAB. It's natural in other languages, but in MATLAB i (or j) is the imaginary unit. If you use i as a variable, it shadows that constant. That doesn't make a difference if you use 1i (or 1j) when assigning complex values, but you're going to have to remember to do that and at some point you're going to forget.

Random generate three integer values and check if they are unique

First, I am generating random integer values to get some values to check.
var A1, B2, C3:int;
A1 = Math.random() * 100 + 1;
B2 = Math.random() * 100 + 1;
C3 = Math.random() * 100 + 1;
Then I want to check if all the variables are unique from each other.
if (!(A1 == B2 || A1 == C3 || B2 == C3)){
unique = true;
}else{ // Not unique
}
If the variables are not unique to each other, I want to keep only the value for A1, and then change the two other variables B2 and C3 and then again check if they are unique.
}else{ // Not unique
if (unique = false){
do{
B2 = Math.random() * A1 + 1;
C3 = Math.random() * A1 + 1;
if (!(A1 == B2 || A1 == C3 || B2 == C3)){
unique = true;
}while (unique = true)
}
trace("Not unique");
}
My problem is that I cannot get three unique values, and any help on how I can solve this is highly appreciated.
This is a case where instead of asking to resolve the problem at hand you should probably have started by explaining what you are trying to do and what's the best way to achieve it. Since you have been posting a few times already my guess is that you are trying to extract 3 unique int from a range of 0 to 100. If that's the case then you are trying to create a complex and inefficient way to do it which is interesting by itself but is far from the point. The solution is to simply generate an array of int from 0 to 100 and then extract 3 of them randomly. In that case they will always be unique and always from 0 to 100.
var intRange:Array = [];
for(var i:int = 0; i < 100; i++)
{
intRange.push(i);
}
var index:int = Math.flor(Math.random() * intRange.length);
var a:int = intRange[index];
intRange.splice(index, 1);
index = Math.flor(Math.random() * intRange.length);
var b:int = intRange[index];
intRange.splice(index, 1);
index = Math.flor(Math.random() * intRange.length);
var c:int = intRange[index];
intRange.splice(index, 1);
//3 unique int from 0 to 100 range
Your problem is the wrong code here:
if (unique = false) { // must be: if (unique == false)
do {
...
} while (unique = true) // must be: while(unique == false)
}
also it can be reduced to
while(!unique) {
...
}
Also, there you are taking random from A1, not 100. Just too many errors. The proper code should be:
var a:int, b:int, c:int; // also, why would you call variables A1, B2, C3???
a = Math.random() * 100 + 1;
do {
b = Math.random() * 100 + 1;
while(b == a);
do {
c = Math.random() * 100 + 1;
} while(c == a || c == b);
// here you have unique
Now, the answer given by BotMaster is correct and robust but it involves filling an array and splicing it which is not always ok, especially if random range is significantly more than 100 and we need only three values from it.

AS3 convert a positive number to 1 and a negative number to -1

There is a simple trick to convert a number to 1 or -1.
Just raise it to the power of 0.
So:
4^0 = 1
-4^0 = -1
However, in AS3:
Math.pow( 4, 0); // = 1
Math.pow(-4, 0); // = 1
Is there a way to get the right answer without an if else?
This could be done bitwise.
Given the number n (avg time: 0.0065ms):
1 + 2 * (n >> 31);
Or slightly slower (avg time: 0.0095ms):
(n < 0 && -1) || 1;
However, Marty's solution is the fastest (avg time: 0.0055ms)
n < 0 ? -1 : 1;
Not sure if without an if/else includes the ternary operator in your eyes, but if not:
// Where x is your input.
var r:int = x < 0 ? -1 : 1;
Will be more efficient than Math.pow() anyway.

How do I generate a visually distinct, non-random color from a single input number?

In Flash AS3, how would I write a function that will:
Take in an integer (a list index, for example)
return a visually distinct hex color based on that number (and will consistently return that same color given that same number)
The purpose is to provide a visually distinct color for each item in varying-length list of items. The most I expect to support is around 200, but I don't see the count going far above 20 or so for most.
Here's my quick and dirty:
public static function GetAColor(idx:int):uint {
var baseColors:Array = [0xff0000, 0x00ff00, 0xff0080, 0x0000ff, 0xff00ff, 0x00ffff, 0xff8000];
return Math.round(baseColors[idx % baseColors.length] / (idx + 1) * 2);
}
It does OK, but it would be nice to see a more distinct set of colors that are not so visually close to one another
You could go with generator of random values that supports seed, so you will be able return same color. As for color you could build it - by randomValue * 0xFFFFFF, where randomValue between 0 and 1. And exclude values (colors) that are close.
Second option: build palette of 200 colors with step - 0xFFFFFF / 200 and shuffle palette with predefined logic, so you will have same colors.
Third option: as for really distinct colors, you could go with big jumps in every channel. Example: 0xFF * 0.2 - 5 steps in every channel.
Fourth option: go with HSV. It's easy to understand(watch image, rotate hue from 0 to 360, change saturation and value from 0 to 100) how to manipulate parameters to get distinct color:
//Very simple demo, where I'm only rotating Hue
var step:uint = 15;
var position:uint = 0;
var colors:Array = [];
for (; position < 360; position += step) {
colors.push(HSVtoRGB(position, 100, 100));
}
//Visualisation for demo
var i:uint, len:uint = colors.length, size:uint = 40, shape:Shape, posX:uint, posY:uint;
for (i; i < len; ++i) {
shape = new Shape();
shape.graphics.beginFill(colors[i]);
shape.graphics.drawRect(0, 0, size, size);
addChild(shape);
shape.x = posX;
shape.y = posY;
posX += size;
if (posX + size >= stage.stageWidth) {
posX = 0;
posY += size;
}
}
public function HSVtoRGB(h:Number, s:Number, v:Number):uint {
var r:Number = 0;
var g:Number = 0;
var b:Number = 0;
var tempS:Number = s / 100;
var tempV:Number = v / 100;
var hi:int = Math.floor(h / 60) % 6;
var f:Number = h / 60 - Math.floor(h / 60);
var p:Number = (tempV * (1 - tempS));
var q:Number = (tempV * (1 - f * tempS));
var t:Number = (tempV * (1 - (1 - f) * tempS));
switch (hi) {
case 0:
r = tempV;
g = t;
b = p;
break;
case 1:
r = q;
g = tempV;
b = p;
break;
case 2:
r = p;
g = tempV;
b = t;
break;
case 3:
r = p;
g = q;
b = tempV;
break;
case 4:
r = t;
g = p;
b = tempV;
break;
case 5:
r = tempV;
g = p;
b = q;
break;
}
return (Math.round(r * 255) << 16 | Math.round(g * 255) << 8 | Math.round(b * 255));
}
And last one, if you want go with this task like a pro, this wiki article could be helpful for you.

How can I set only the outer booleans of a 2d array to false?

If I have a 2d array like:
boolean[][] map = new boolean[50][50];
How can I set the outer edge of booleans to true only in a loop?
So, for the following array:
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 0 0 0
You would have:
1 1 1 1 1 1
1 0 0 0 0 1
1 0 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
I'm new to programming and I've been struggling to get this to work?
I thought possibly using 2 loops like:
for(int i = 0; i < map.length; i++)
{
map[i][0] = true;
map[i][map[0].length] = true;
}
for(int i = 0; i < map[0].length; i++)
{
map[0][i] = true;
map[map.length][i] = true;
}
But honestly I'm not sure if this is the correct approach?
for( int i = 0; i<maxx; i++)
{
for( int j = 0; j<maxy; j++)
{
if( i==0 || i == maxx-1 || j == 0 || j == maxy-1 )
{
//Write 1
}
else
{
//Write 0
}
}
}
This is probably not the best possible code, but it demonstrates easily how to achieve it:
Write something in all fields.
If the field is:
At the top or bottom of the 2d array
to the left or right
write a 1, otherwise a 0.
The question is, when it is at the top or bottom?
At the time the line-index (i) is either 0 or highest possible.
The same counts for the column index (j).
for( int i = 0; i<50; i++)
{
map[i][0] = 1;
map[i][49] = 1;
map[0][i] = 1;
map[49][i] = 1;
}
I'm assuming the structure is already initialized with 0s.
integer max = 50;
boolean[][] map = new boolean[max][max];
for ( integer x=0;x<max;x++) {
map[0,x] =1;
map[max-1,x] =1;
map[x,0] =1;
map[max-1,x] =1;
}
Problem: this initializes the corners more than once ..
In Java:
int firstRow = 0;
int lastRow = map.length - 1;
int width = map[0].length;
for (int i=0; i<width; i++) {
map[firstRow][i] = true;
}
System.arrayCopy (map[firstRow], 0, map[lastRow], 0, width);
int lastColumn = width - 1;
for (int i=1; i<lastRow; i++) {
map[i][0] = map[i][lastColumn] = true;
}
This is of course limited by the number of writes you must do, which are O(n) where n is the side length of the matrix, assuming the matrix is square.
You can of course simplify the code to only touch the outer elements:
for i in xrange(0, n - 1):
matrix[0][i] = true
matrix[i][-1] = true
matrix[-1][-(i + 1)] = true
matrix[-(i + 1)][0] = true
This does four writes per iteration of the loop. I think I did the indexing correctly now, the idea is to do the writes in this order, for the case where n=4 (apologies for the stunning ASCII graphics):
0120
2 1
1 2
0210
So, you can see that each side only goes from 0 to n - 2, inclusive. This is expressed in Python as for i in xrange(0, n -1).
In Python it is very easy
X=10
Y=5
m=[[1]*X]+[[1]+[0]*(X-2)+[1]]*(Y-2)+[[1]*X]
for row in m:
print row
outputs:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Here is the breakdown
[1]*X # gives us a list of X 1's [1,1,1,1,1,1,1,1,1,1] in this case
[0]*(X-2) # gives us a list of (X-2) 0's [0,0,0,0,0,0,0,0] in this case
so
[[1]*x] # gives us an 1 by X array [[1,1,1,1,1,1,1,1,1,1]]
[[1]+[0]*(X-2)+[1]] # gives a 1 by X array [[1,0,0,0,0,0,0,0,0,1]]
we multiply the array above to give Y-2 identical lines
and then add another row of 1's to the bottom