PDA

View Full Version : matrix subscripts

hcrisp
08-10-2009, 08:21 AM
I have a surprisingly tricky PV-WAVE question regaring matrix subscripts. Assigning a row of values in a matrix is quite easy:

a = INTARR(5,5)
a(*,3) = 7
print, a
; 0 0 0 0 0
; 0 0 0 0 0
; 0 0 0 0 0
; 7 7 7 7 7
; 0 0 0 0 0

Is there an easy way to assign a subset of a matrix to a scalar value without resorting to a FOR loop?

; I want to get:
; 0 0 0 0 0
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 0 0 0

a = INTARR(5,5)
mids = [2,3,4]
nids = [1,2,3]

; This approach works in MATLAB, but not in PV-WAVE:
; a(mids, nids) = 7

; I found this way, but it is messy;
a(replv(mids, [3,3], 0), replv(nids, [3,3], 1)) = 7

hcrisp
08-10-2009, 08:28 AM
; Another interesting way to do it:
a(mids(0), nids(0)) = replv([7], [3,3], 0)

ed
08-10-2009, 09:02 AM
What about something like this? Just assign the submatrix to the upper left corner in the larger matrix.

a = intarr(5,5)
b = intarr(3,3) + 7
a(2,1) = b
print, a
; 0 0 0 0 0
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 0 0 0

hcrisp
08-12-2009, 01:16 PM
Found a simple way, but only works when subscript values are contiguous:

a = INTARR(5,5)
a(2:4,1:3) = 7
print, a
; 0 0 0 0 0
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 7 7 7
; 0 0 0 0 0

What is the simplest way to assign non-contiguous elements (and have it work on a larger scale)? I'm guessing it involves a FOR loop.

; I want to get:
; 0 0 0 0 0
; 0 7 0 7 7
; 0 7 0 7 7
; 0 7 0 7 7
; 0 0 0 0 0
a = INTARR(5,5)
mids = [1,3,4]
nids = [1,2,3]

acg
08-14-2009, 03:20 PM
The same "messy" way you mentioned before, using REPLV, will work for non-contiguous subscripts.

For example:

a = INTARR(10000,10000)
mids = INDGEN(500)*2
nids = INDGEN(500)*3
m = N_ELEMENTS(mids)
n = N_ELEMENTS(nids)
a(REPLV(mids, [m,n], 0), REPLV(nids, [m,n], 1)) = 7
INFO, WHERE(a EQ 7)

It will also work if the subscript arrays don't have the same length.

a = INTARR(10000,10000)
mids = INDGEN(1000)*3
nids = INDGEN(600)*2
m = N_ELEMENTS(mids)
n = N_ELEMENTS(nids)
a(REPLV(mids, [m,n], 0), REPLV(nids, [m,n], 1)) = 7
INFO, WHERE(a EQ 7)

hcrisp
08-02-2010, 09:31 AM
Interestingly, this same problem has arisen when trying to extract values from a matrix. Only now I don't know of a elegant way to code it without resorting to FOR loops.

x = FINDGEN(20,20)

; Works in MATLAB, but errors in PV-WAVE:
mids = [1, 3, 5]
nids = [3, 5, 7, 9]
y = x(mids, nids)
; %%%All array subscripts must be same size. Var = X
; %%%Execution halted at \$MAIN\$ .

; You must do it this way:
y = FLTARR(N_ELEMENTS(mids), N_ELEMENTS(nids))
FOR i=0L, N_ELEMENTS(nids)-1 DO BEGIN
y(*, i) = x(mids, nids(i))
ENDFOR

; This works, but is verbose:
mids_ = REPLV(mids, [N_ELEMENTS(mids),N_ELEMENTS(nids)], 0)
nids_ = REPLV(nids, [N_ELEMENTS(mids),N_ELEMENTS(nids)], 1)
y = x(mids_, nids_)

brian
08-02-2010, 03:56 PM
Hello hcrisp,

You may want to use the WHERE function. You should be aware that the WHERE function counts up the columns not the rows. For example, I'm going to create the array as seen before Post Count 3 (http://forums.vni.com/showpost.php?p=5118&postcount=3) and then access the elements with the WHERE function.

Create the matrix:

WAVE> a=intarr(5,5)
WAVE> b=indgen(3,3)
WAVE> pm,b
0 3 6
1 4 7
2 5 8
WAVE> a(1,2)=b
WAVE> pm,a
0 0 0 0 0
0 0 0 3 6
0 0 1 4 7
0 0 2 5 8
0 0 0 0 0

Find the element I want (In this case odd values):

WAVE> i=where((a mod 2) ne 0)
WAVE> print, i
12 16 18 22

:) Note: zero based count down the columns gives the position of "1" at element 12. It might be instructive to look at another orientation of the matrix:

WAVE> print,a
0 0 0 0 0
0 0 0 0 0
0 0 1 2 0
0 3 4 5 0
0 6 7 8 0

Finally, print the values identified:

WAVE> j=a(i)
WAVE> print,j
1 3 5 7

Regards,

brian

DGP
03-03-2011, 12:23 PM
You want to index with a set of rows and columns, while PV-Wave wants a 1-D index. So what about using the INDEX_CONV function to accomplish this.

rows = [1,2,3]
cols = [1,3,5]
aa = intarr(5,5)
pm, aa
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
idx = index_conv(aa,[[rows],[cols]])
pm , idx
6
17
28
aa(idx) = 7
pm, aa
0 0 0 0 0
0 7 0 0 0
0 0 0 7 0
0 0 0 0 0
0 0 0 0 7

or simply

aa(index_conv(aa,[[rows],[cols]])) = 8
pm, aa
0 0 0 0 0
0 8 0 0 0
0 0 0 8 0
0 0 0 0 0
0 0 0 0 8

hcrisp
03-03-2011, 01:16 PM
That doesn't appear any different than directly using the indices (although some of the indices get moved around):

rows = [1,2,3]
cols = [1,3,5]
aa = intarr(5,5)
aa(rows, cols) = 8

Note that what I am after is not pairs of indices (x1y1, x2y2, etc.) but all permutations (x1y1, x1y2, x2y1, x2y2, etc.). I think what we have concluded is that MATLAB allows shorthand assignment by index permutations, but WAVE does not. In WAVE you must resort to REPLV or a FOR loop.

allan
03-18-2011, 09:42 PM
WAVE does index permutations if subscripts are of mixed type,
i.e. not all arrays:

rows = [1,2,3]
cols = [1,3,5]
aa = intarr(5,5)
aa(rows, cols, 0) = 8
pm, aa

the '0' subscript in the 3rd (degenerate) dimension does the trick;
the more general case is associated with a(i,j) and the less
flexible (but quite common) case is associated with a(i,j,0);
both cases are documented in the programmer guide;

WAVE array subscripting is quite flexible and obeys the same rules
regardless of dimensionality (up to 8d) and regardless of whether
the subscripting is for element extraction or replacement;
below is a 2d example for each type of replacement subscripting:

;(0)
a = intarr(5,5)
a(6) = 1
pm, a

;(1)
a = intarr(5,5)
a(6) = indgen(7)+1
pm, a

;(2)
a = intarr(5,5)
a(6:12) = 1
pm, a

;(3)
a = intarr(5,5)
a(6:12) = indgen(7)+1
pm, a

;(4)
a = intarr(5,5)
a(6:*) = 1
pm, a

;(5)
a = intarr(5,5)
a(6:*) = indgen(19)+1
pm, a

;(6)
a = intarr(5,5)
a(*) = 1
pm, a

;(7)
a = intarr(5,5)
a(*) = indgen(25)+1
pm, a

;(8)
a = intarr(5,5)
a([6,19]) = 1
pm, a

;(9)
a = intarr(5,5)
a([6,19]) = [1,2]
pm, a

;(10)
a = intarr(5,5)
a(1,2) = 1
pm, a

;(11)
a = intarr(5,5)
a(1,2) = indgen(2,3)+1
pm, a

;(12)
a = intarr(5,5)
a(1:2,2:4) = 1
pm, a

;(13)
a = intarr(5,5)
a(1:2,2:4) = indgen(2,3)+1
pm, a

;(14)
a = intarr(5,5)
a(1:*,2:*) = 1
pm, a

;(15)
a = intarr(5,5)
a(1:*,2:*) = indgen(4,3)+1
pm, a

;(16)
a = intarr(5,5)
a(*,*) = 1
pm, a

;(17)
a = intarr(5,5)
a([3,0,1],[2,1,3]) = 1
pm, a

;(18)
a = intarr(5,5)
a([3,0,1],[2,1,3]) = [1,2,3]
pm, a

;(19)
a = intarr(5,5)
a([3,0,1],[2,1,3],0) = 1
pm, a

;(20)
a = intarr(5,5)
a([3,0,1],[2,1,3],0) = indgen(3,3)+1
pm, a

;(21)
a = intarr(5,5)
a([1,3],[0,2,4],0) = 1
pm, a

;(22)
a = intarr(5,5)
a([1,3],[0,2,4],0) = indgen(2,3)+1
pm, a

subscripts can be mixed in any way, and as mentioned before,
the rules are the same for arrays of arbitrary dimension and
for element extraction as well as replacement;

the last few examples show that the syntax a(i,j) is more
general than (i,j,0) since the it is not restricted to a grid
and since i and j can have different lengths;

allan

allan
03-18-2011, 11:36 PM
sorry, the last paragraph should read:

the last few examples show that the syntax a(i,j) is more
general than a(k,m,0) since it is not restricted to a grid;

hcrisp
03-21-2011, 09:32 AM
Outstanding. That is the answer I have been looking for. I was not aware of the method of using zero in the undeclared dimension to force permutation assignment. That will be very useful. Thank you so much for sharing this.

allan
03-21-2011, 11:14 AM
you are welcome, hcrisp