When I try to compile the following program, the compiler complains that j and row are undeclared, which surprised me because a similar construction in Chapel - Ranges defined using bounds of type 'range(int(64),bounded,false)' are not currently supported was legal. When I declare row, j it prints 0 for both while the loop starts at 1. Declarations auto-initialise to zero, so is the row from forall row in 1..mat.m somehow different from the declaration above?
use BlockDist;
record CSRMatrix {
/* The matrix is m x n */
var m: int;
var n: int;
/* Number of non-zeroes */
var nz: int;
/* Stores the non-zeroes */
var val: [1..nz] real;
/* The first non-zero of row k is the row_ptr(k)th non-zero overall.
* row_ptr(m + 1) is the total number of non-zeroes. */
var row_ptr: [1..m + 1] int;
/* The kth non-zero has column-index col_ind(k) */
var col_ind: [1..nz] int;
}
/* We assume some global sparse matrix A has been distributed blockwise along the first
dimension and that mat is the local part of the global matrix A(s). Is not
distributed from Chapel's POV!
vec is distributed blockwise, is distributed from Chapel's POV!
Returns matmul(A(s), vec), the local part of matmul(A, vec). */
proc spmv(mat: CSRMatrix, vec: [1..mat.n] real)
{
var result: [1..mat.m] real = 0.0;
// var row: int;
// var j: int;
forall row in 1..mat.m do
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 do
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
return result;
}
#StrugglingProgrammer's response in the notes is correctly diagnosing the problem here, but to capture the explanation with more rationale and commentary:
In Chapel, the index variables in for-, foreach-, forall-, and coforall-loops are new variables defined for the scope of the loop's body, as you expected. Thus for i in myIterand declares a new variable i that takes on the values yielded by myIterand—e.g., an integer in the common case of iterating over a range like for i in 1..n and your loops.
The problem here is that Chapel is not a whitespace-sensitive language (as Python is, say), and its loops have two syntactic forms:
A keyword-based form in which the body must be a single statement following do
And a form in which the body is a compound statement using curly brackets
Thus, when your code says:
forall row in 1..mat.m do
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 do
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
to get the effect desired, you would need to write this as:
forall row in 1..mat.m do
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 {
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
}
Note that the first forall loop does not require curly brackets because its body is a single statement—the for-loop, which happens to have its own multi-statement body.
Because of the possibility of this class of errors, particularly as code is evolving, defensive Chapel programmers tend to prefer always using curly brackets to avoid the possibility of this mistake:
forall row in 1..mat.m {
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 {
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
}
}
And to be pedantic, your original code, indented to reflect the actual control flow would have been as follows (and a good Chapel-aware editor mode would ideally help you by indenting it in this way):
forall row in 1..mat.m do
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 do
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
Seeing the code written this way, you can see why the compiler complains about j and row in the final two statements, but not about row on the first one, since it is within the nested loop as expected.
It's also why, when you introduce explicit variables for j and row they evaluate to zero in those lines. Essentially, your loops are introducing new variables that temporarily shadow the explicitly-defined ones, and the two statements that were outside the loop nest refer to those original variables rather than the loops' index variables as expected. As you note, since Chapel variables are default initialized, they have the value 0.
As one final piece of trivia, since compound statements { ... } are themselves single statements in Chapel, it is legal to write loops with both do and { ... }:
forall row in 1..mat.m do {
for j in mat.row_ptr(row)..mat.row_ptr(row + 1) - 1 do {
writeln(row);
writeln(j);
result(row) += mat.val(j) * vec(mat.col_ind(j));
}
}
However, this is not at all necessary, so I personally tend to discourage its use, considering it overkill and likely to lead to further misunderstandings.
Related
Which is the best way to store a symmetric matrix in memory?
It would be good to save half of the space without compromising speed and complexity of the structure too much. This is a language-agnostic question but if you need to make some assumptions just assume it's a good old plain programming language like C or C++..
It seems a thing that has a sense just if there is a way to keep things simple or just when the matrix itself is really big, am I right?
Just for the sake of formality I mean that this assertion is always true for the data I want to store
matrix[x][y] == matrix[y][x]
Here is a good method to store a symmetric matrix, it requires only N(N+1)/2 memory:
int fromMatrixToVector(int i, int j, int N)
{
if (i <= j)
return i * N - (i - 1) * i / 2 + j - i;
else
return j * N - (j - 1) * j / 2 + i - j;
}
For some triangular matrix
0 1 2 3
4 5 6
7 8
9
1D representation (stored in std::vector, for example) looks like as follows:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
And call fromMatrixToVector(1, 2, 4) returns 5, so the matrix data is vector[5] -> 5.
For more information see http://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c11211/TIP-Half-Size-Triangular-Matrix.htm
I find that many high performance packages just store the whole matrix, but then only read the upper triangle or lower triangle. They might then use the additional space for storing temporary data during the computation.
However if storage is really an issue then just store the n(n+1)/2 elements making the upper triangle in a one-dimensional array. If that makes access complicated for you, just define a set of helper functions.
In C to access a matrix matA you could define a macro:
#define A(i,j, dim) ((i <= j)?matA[i*dim + j]:matA[j*dim + i])
then you can access your array nearly normally.
Well I would try a triangular matrix, like this:
int[][] sym = new int[rows][];
for( int i = 0; i < cols; ++i ) {
sym=new int[i+1];
}
But then you wil have to face the problem when someone wants to access the "other side". Eg he wants to access [0][10] but in your case this val is stored in[10][0] (assuming 10x10).
The probably "best" way is the lazy one - dont do anything until the user requests. So you could load the specific row if the user types somethin like print(matrix[4]).
If you want to use a one dimensional array the code would look something like this:
int[] new matrix[(rows * (rows + 1 )) >> 1];
int z;
matrix[ ( ( z = ( x < y ? y : x ) ) * ( z + 1 ) >> 1 ) + ( y < x ? y : x ) ] = yourValue;
You can get rid of the multiplications if you create an additional look-up table:
int[] new matrix[(rows * (rows + 1 )) >> 1];
int[] lookup[rows];
for ( int i= 0; i < rows; i++)
{
lookup[i] = (i * (i+1)) >> 1;
}
matrix[ lookup[ x < y ? y : x ] + ( x < y ? x : y ) ] = yourValue;
If you're using something that supports operator overloading (e.g. C++), it's pretty easy to handle this transparently. Just create a matrix class that checks the two subscripts, and if the second is greater than the first, swap them:
template <class T>
class sym_matrix {
std::vector<std::vector<T> > data;
public:
T operator()(int x, int y) {
if (y>x)
return data[y][x];
else
return data[x][y];
}
};
For the moment I've skipped over everything else, and just covered the subscripting. In reality, to handle use as both an lvalue and an rvalue correctly, you'll typically want to return a proxy instead of a T directly. You'll want a ctor that creates data as a triangle (i.e., for an NxN matrix, the first row will have N elements, the second N-1, and so on -- or, equivalantly 1, 2, ...N). You might also consider creating data as a single vector -- you have to compute the correct offset into it, but that's not terribly difficult, and it will use a bit less memory, run a bit faster, etc. I'd use the simple code for the first version, and optimize later if necessary.
You could use a staggered array (or whatever they're called) if your language supports it, and when x < y, switch the position of x and y. So...
Pseudocode (somewhat Python style, but not really) for an n x n matrix:
matrix[n][]
for i from 0 to n-1:
matrix[i] = some_value_type[i + 1]
[next, assign values to the elements of the half-matrix]
And then when referring to values....
if x < y:
return matrix[y][x]
else:
return matrix[x][y]
It says the index in position 1 of the diff function must be a positive integer or a logical value which is it so why am I getting this error? I'm trying to implement the basic Euler method in MATLAB
y=zeros(1,6);
h=0;
x(1)= 0;
y(1)= 0;
i=1;
diff(y,x)= x+y
while h<=1
y(i+1)=y(i) + h*f(x(i))
h=h+0.2;
i=i+1;
end
Edit: Changed it to the code below but it still raises the same error in the line y(i+1)=...
y=zeros(1,6);
x=zeros(1,6);
h=0;
i=1;
g=x+y;
while h<=1
y(i+1)=y(i) + h*g(x(i),y(i));
h=h+0.2;
i=i+1;
end
Approach: I would recommend defining an anonymous function
diffh =#(x,y) x + y; % define this prior to use
to use later inside the loop.
Then changing one line
y(ii+1)=y(ii) + h*diffh(x(ii),y(ii));
should work. I've added the "h" to the end as a convention to remind me this is an anonymous function (see note at end).
% MATLAB R2019a
y = zeros(1,6);
x = zeros(1,6);
h=0;
ii=1;
diffh =#(x,y) x + y;
while h <= 1
y(ii+1)=y(ii) + h*diffh(x(ii),y(ii));
x(ii+1) = x(ii)+h;
h=h+0.2;
ii=ii+1;
end
Side note: I've also changed the index i to ii by convention (though MATLAB doesn't require this). Unless you overwrite their values, both i and j default as the sqrt(-1). You can absolutely use them as indices without issue (provided you don't later need complex or imaginary numbers). To ensure this never becomes an issue, many people just use ii and jj as a convention to preserve the default values.
Note that diff is a MATLAB function itself.
Using i as an index is mostly not a good idea in Matlab, because i is also imaginary number. Perhaps another name could solve the problem.
I'm working in a Matlab project and I have a function that is working, but I want to optimize it, reducing the number of for loops that I have in my code.
I read about vectorization, I could use it but how would I include the if conditional statement if I have to test every single value at a time?
function [y, zf] = MyFunction(x, b, zi)
y = zeros([length(x) 1]);
for n = 1:length(x)
for k=1:length(zi)
if n<k
y(n) = y(n) + b(k)*zi(length(zi)+(n-k)+1);
else
y(n) = y(n) + b(k)*x(n-k+1);
end
end
end
zf = x(length(x)-length(zi)+1:length(x));
I manage to do the vectorization, but I can't figure how to do the conditional, I get the warning:
Variable 'n' might be set by a nonscalar operator
function [y, zf] = MyFunction(x, b, zi)
y = zeros([length(x) 1]);
n=1:1:length(x); % use of vectorization
for k=1:length(zi)
if n<k % problem with if
y = y + b(k)*zi(length(zi)+(n-k)+1);
else
y = y + b(k)*x(n-k+1);
end
end
zf = x(length(x)-length(zi)+1:length(x));
Currently n is a vector and k is a scalar, and n<k returns a logical vector. If you directly use if, it would be the same as if all(n), which will only return true when everything in that vector is true! That's unexpected behavior.
I don't know if there's a general way to vectorize codes with if. But in your case, I can do it this way.
% use indice to deal with if
for k=1:length(zi)
y(1:k-1)=y(1:k-1)+b(k)*zi(length(zi)+2-k:end);
y(k:end)=y(k:end)+b(k)*x(1:length(x)-k+1);
end
I also notice that actually if you cat zi and x, it's no need to use 2 individual statement.
% assume both zi & x to be column vector
ziandx=[zi;x];
for k=1:length(zi)
y=y+b(k)*ziandx(length(zi)+2-k:length(zi)+length(x)-k+1);
end
Finally, even this for-loop is no need if you use conv. (check the doc for more detail)
ziandx=[zi;x];
s=conv(b(1:length(zi)),ziandx);
y=s(length(zi)+1:length(zi)+length(x))
I recommend you to read all three methods and understand the idea, thus you can do it yourself next time.
I have a small code snippet where I have defined a local macro i to be used in a forvalues loop:
matrix I=I(4)
scalar x1=b[1,1]
scalar sum1=0
local i = 2
forvalues i = 2/4 {
scalar chk=i-1
forvalues j = 1/`=chk' {
scalar sum1=I[`i',`j']*x`j'+sum1
}
scalar x`i'=(b[`i',1]-sum1)/I[`i',`i']
}
However, Stata complains:
error 111
i not found
Note that this error is appearing only if I use the macro in a loop, not otherwise.
The Stata problem you raise is with the line
scalar chk = i - 1
Stata sees a reference there to i, which evidently cannot be interpreted as a variable or scalar name, hence the error message you got. That's Stata's point of view.
From your point of view, the error is not using single quotation marks to extract the value or contents of the local macro i, or at least that appears to be your intention, as you nowhere else explain your aim. So, nothing is disappearing; you just referred to a non-existent entity. That's only a detail, however, and there is a larger story here.
Here is a first rewriting of your code.
matrix I = I(4)
scalar x1 = b[1,1]
scalar sum1 = 0
forvalues i = 2/4 {
local chk = `i' - 1
forvalues j = 1/`chk' {
scalar sum1 = I[`i',`j'] * x`j' + sum1
}
scalar x`i' = (b[`i',1] - sum1) / I[`i',`i']
}
Notes.
The line local i = 2 appears redundant. The forvalues loop initialises the macro.
As a matter of style, experienced Stata programmers would typically use a local macro, not a permanent scalar, for a transient loop limit.
But wait: I(4) is just an identity matrix with 4 rows and columns, 1s on the principal diagonal and 0s elsewhere. So
I[`i',`i']
is necessarily 1 and
I[`i',`j']
for earlier entries on the same row of the matrix is 0. So sum1 is never anything but 0. So you don't need the identity matrix for any obvious purpose and your code seems reducible to extracting four scalars from a vector:
forvalues i = 1/4 {
scalar x`i' = b[`i',1]
}
EDIT. Double loops like
forvalues i = 2/4 {
local chk = `i' - 1
forvalues j = 1/`chk' {
...
}
...
}
can also be written more concisely
forvalues i = 2/4 {
forvalues j = 1/`= `i' - 1' {
...
}
...
}
The sum of f(i) for all integers i =
k, k + 1, .., continuing only as long
as the condition p(i) holds.
I'm going for:
for (i = 0; i <= V_COUNT; i++) {
sum += sine_coeff[i] * pow(E, e_factor[i]) * sin(
(solar_coeff[i] * solar_anomaly)
+ (lunar_coeff[i] * lunar_anomaly)
+ (moon_coeff[i] * moon_argument)
);
}
based on the following Common LISP code:
(sigma ((v sine-coeff)
(w E-factor)
(x solar-coeff)
(y lunar-coeff)
(z moon-coeff))
(* v (expt cap-E w)
(sin-degrees
(+ (* x solar-anomaly)
(* y lunar-anomaly)
(* z moon-argument)))))))
where sigma is:
(defmacro sigma (list body)
;; TYPE (list-of-pairs (list-of-reals->real))
;; TYPE -> real
;; $list$ is of the form ((i1 l1)..(in ln)).
;; Sum of $body$ for indices i1..in
;; running simultaneously thru lists l1..ln.
`(apply '+ (mapcar (function (lambda
,(mapcar 'car list)
,body))
,#(mapcar 'cadr list))))
(for full source code, see Calendrical calculations source code
Edit
Thanks for all your answers. Investigating the code examples, I have come to the conclusion that, in programming terms, the author indeed ment that one has to loop over a certain set of values. From that, it was easy to conclude that p had to return False when it has run out of values, i.e. control has reached the end of the list.
Define a function p(), e.g.:
bool_t p(int i)
{
// some conditional code here, that returns TRUE or FALSE
}
It seems like you need to loop for an arbitrarily long time (i.e. there's no hard upper limit), and you need to stop looping when p(i) returns FALSE. Therefore, you probably want a loop something like this:
int sum = 0;
for (int i = k; p(i); i++)
{
sum += f(i);
}
Depending on how large i and sum can get, you may want to declare them as long rather than int.
Something like:
sum = 0;
i = k;
while (p(i))
sum += f(i++);