Related
I'm building a heatmap-like rectangular array interface and I want the 'hot' location to be at the top left of the array, and the 'cold' location to be at the bottom right. Therefore, I need an array to be filled diagonally like this:
0 1 2 3
|----|----|----|----|
0 | 0 | 2 | 5 | 8 |
|----|----|----|----|
1 | 1 | 4 | 7 | 10 |
|----|----|----|----|
2 | 3 | 6 | 9 | 11 |
|----|----|----|----|
So actually, I need a function f(x,y) such that
f(0,0) = 0
f(2,1) = 7
f(1,2) = 6
f(3,2) = 11
(or, of course, a similar function f(n) where f(7) = 10, f(9) = 6, etc.).
Finally, yes, I know this question is similar to the ones asked here, here and here, but the solutions described there only traverse and don't fill a matrix.
Interesting problem if you are limited to go through the array row by row.
I divided the rectangle in three regions. The top left triangle, the bottom right triangle and the rhomboid in the middle.
For the top left triangle the values in the first column (x=0) can be calculated using the common arithmetic series 1 + 2 + 3 + .. + n = n*(n+1)/2. Fields in the that triangle with the same x+y value are in the same diagonal and there value is that sum from the first colum + x.
The same approach works for the bottom right triangle. But instead of x and y, w-x and h-y is used, where w is the width and h the height of rectangle. That value have to be subtracted from the highest value w*h-1 in the array.
There are two cases for the rhomboid in the middle. If the width of rectangle is greater than (or equal to) the height, then the bottom left field of the rectangle is the field with the lowest value in the rhomboid and can be calculated that sum from before for h-1. From there on you can imagine that the rhomboid is a rectangle with a x-value of x+y and a y-value of y from the original rectangle. So calculations of the remaining values in that new rectangle are easy.
In the other case when the height is greater than the width, then the field at x=w-1 and y=0 can be calculated using that arithmetic sum and the rhomboid can be imagined as a rectangle with x-value x and y-value y-(w-x-1).
The code can be optimised by precalculating values for example. I think there also is one formula for all that cases. Maybe i think about it later.
inline static int diagonalvalue(int x, int y, int w, int h) {
if (h > x+y+1 && w > x+y+1) {
// top/left triangle
return ((x+y)*(x+y+1)/2) + x;
} else if (y+x >= h && y+x >= w) {
// bottom/right triangle
return w*h - (((w-x-1)+(h-y-1))*((w-x-1)+(h-y-1)+1)/2) - (w-x-1) - 1;
}
// rhomboid in the middle
if (w >= h) {
return (h*(h+1)/2) + ((x+y+1)-h)*h - y - 1;
}
return (w*(w+1)/2) + ((x+y)-w)*w + x;
}
for (y=0; y<h; y++) {
for (x=0; x<w; x++) {
array[x][y] = diagonalvalue(x,y,w,h);
}
}
Of course if there is not such a limitation, something like that should be way faster:
n = w*h;
x = 0;
y = 0;
for (i=0; i<n; i++) {
array[x][y] = i;
if (y <= 0 || x+1 >= w) {
y = x+y+1;
if (y >= h) {
x = (y-h)+1;
y -= x;
} else {
x = 0;
}
} else {
x++;
y--;
}
}
What about this (having an NxN matrix):
count = 1;
for( int k = 0; k < 2*N-1; ++k ) {
int max_i = std::min(k,N-1);
int min_i = std::max(0,k-N+1);
for( int i = max_i, j = min_i; i >= min_i; --i, ++j ) {
M.at(i).at(j) = count++;
}
}
Follow the steps in the 3rd example -- this gives the indexes (in order to print out the slices) -- and just set the value with an incrementing counter:
int x[3][3];
int n = 3;
int pos = 1;
for (int slice = 0; slice < 2 * n - 1; ++slice) {
int z = slice < n ? 0 : slice - n + 1;
for (int j = z; j <= slice - z; ++j)
x[j][slice - j] = pos++;
}
At a M*N matrix, the values, when traversing like in your stated example, seem to increase by n, except for border cases, so
f(0,0)=0
f(1,0)=f(0,0)+2
f(2,0)=f(1,0)+3
...and so on up to f(N,0). Then
f(0,1)=1
f(0,2)=3
and then
f(m,n)=f(m-1,n)+N, where m,n are index variables
and
f(M,N)=f(M-1,N)+2, where M,N are the last indexes of the matrix
This is not conclusive, but it should give you something to work with. Note, that you only need the value of the preceding element in each row and a few starting values to begin.
If you want a simple function, you could use a recursive definition.
H = height
def get_point(x,y)
if x == 0
if y == 0
return 0
else
return get_point(y-1,0)+1
end
else
return get_point(x-1,y) + H
end
end
This takes advantage of the fact that any value is H+the value of the item to its left. If the item is already at the leftmost column, then you find the cell that is to its far upper right diagonal, and move left from there, and add 1.
This is a good chance to use dynamic programming, and "cache" or memoize the functions you've already accomplished.
If you want something "strictly" done by f(n), you could use the relationship:
n = ( n % W , n / H ) [integer division, with no remainder/decimal]
And work your function from there.
Alternatively, if you want a purely array-populating-by-rows method, with no recursion, you could follow these rules:
If you are on the first cell of the row, "remember" the item in the cell (R-1) (where R is your current row) of the first row, and add 1 to it.
Otherwise, simply add H to the cell you last computed (ie, the cell to your left).
Psuedo-Code: (Assuming array is indexed by arr[row,column])
arr[0,0] = 0
for R from 0 to H
if R > 0
arr[R,0] = arr[0,R-1] + 1
end
for C from 1 to W
arr[R,C] = arr[R,C-1]
end
end
I have tried a cpp codeblock:
bool comp(const pair<int,int>&A, const pair<int,int>&B)
{
if(A.second<=B.second)
{
if(A.first>=B.first)
return 1;
else
return 0;
}
return 0;
}
int main()
{
int a, b, c, x[10], y[10];
cin>>a;
cin>>b;
cin>>c;
for(int i=0;i<4;++i)
{
cin>>x[i];
y[i]=a*x[i]*x[i]+b*x[i]+c;
}
vector<pair<int,int> >V;
for(int i=0;i<4;++i)
{
V.pb(mp(x[i],y[i]));
}
for(int i=0;i<4;++i)
{
sort(V.begin(),V.end(),&comp);
}
for(int i=0;i<V.size();i++)
{
cout<<V[i].first;
cout<<" "<<V[i].second<<" ";
}
return 0;
}
STDIN: a b c x1 x2 x3... and x is in sorted order i.e. x1 < x2 < x3. The Code should generate a new list (y = y1 y2 y3) using the parabola equation for every x and sort the above list with a run-time complexity of <= O(log n).
STDOUT: x3,y3 x1,y1 x2,y2 ... (assuming computed y3 < y1 < y2.. ).
Code should NOT compute the Y's. Multiplication on this compute node is "too" costly. The solution should identify a way of still sorting the list without computing the "y" values.
My code computes the y values. Can anyone find a method of sorting without computing the y values. A python code implementation would also work for me.
The farther an x value is from the parabola's apex x0, the higher is its y value when a is positive and the lower its y value when a is negative.
|x1 - x0| > |x2 - x0| && a > 0 --> y1 > y2
|x1 - x0| > |x2 - x0| && a < 0 --> y1 < y2
When a is zero, your parabola is really a line and the x values are already sorted in the correct order when b is positive or in the reverse order when b is negative.
So when a isn't zero, find the apex:
x0 = - b / (2*a)
Now find the value in your sorted list of x values that is closest to x:
i = index(x: min(|x - x0|))
Add point i to the list. Create two indices:
l = i - 1
r = i + 1
Now take the point at either index l or r that is closer to the apex, and add it to the list. Update the index until you have exhausted the list.
Revert the list when a is negative. (Or add the items from the end of the list.)
Edit: Here's an implementation in Python. It pops elements off sub-lists rather than using array indices, but the logic is the same:
import bisect
def parasort(a, b, c, x):
"""Return list sorted by y = a*x*x + b*x + c for sorted input x."""
if not x:
return x
if a == 0: # degenerate case: line
if b < 0: return x[::-1]
return x[:]
x0 = -0.5 * b / a # apex of parabola
i = bisect.bisect_left(x, x0) + 1 # closest point via bin. search
l = x[:i][::-1] # left array, reverted
r = x[i:] # right array
res = []
while l and r: # merge l and r
if x0 - l[0] > r[0] - x0: # right item is smaller
res += [r.pop(0)]
else: # left item is smaller
res += [l.pop(0)]
res += l + r # append rest of arrays
if a < 0: return res[::-1]
return res
a = 4
b = 0
c = 0
xx = parasort(a, b, c, [-3, 0, 1, 2])
for x in xx:
print x, a*x*x + b*x + c
def list_2d_locations(rows, columns, low_range, high_range):
matrix = list_2d_generate(rows, columns, low_range, high_range)
print(matrix)
low_val = high_val = matrix[0][0]
for i in range(rows):
for j in range(columns):
if matrix[i][j] < low_val:
low_val = matrix[i][j]
low_loc = [i][j]
if matrix[i][j] > high_val:
high_val = matrix[i][j]
high_loc = [i][j]
return low_val, high_val, low_loc, high_loc
I have here a function which is supposed to find the smallest and largest number within a list of lists (i.e. a matrix) and return the actual value, and the position of that value within the matrix. Now my problem is that both high_loc = [i][j] and low_loc = [i][j] give me the error of "list index out of range" and I don't understand why. Wouldn't the if statements also be out of range then by the same logic?
The problem is in the line low_loc = [i][j]. In the expression on the right-hand side of the = sign, [i] is a list with a single element, and [i][j] represents an attempt to extract the element at position j from that list. That will fail unless j == 0. Perhaps you wanted low_loc = [i, j] or low_loc = (i, j) instead? (The same comments apply to the line high_loc = [i][j], of course.)
Here is a solution. It is clean. However, for big matrices it should be optimized to iterate only once over them and collect all info during that iteration.
m = [[3,5,1], [56,43,12], [4,52,673]]
def f(matrix):
cols = len(matrix[0])
flatten = [val for row in matrix for val in row]
min_val, max_val = min(flatten), max(flatten)
min_i, max_i = flatten.index(min_val), flatten.index(max_val)
return min_val, max_val, divmod(min_i, cols), divmod(max_i, cols)
>>> f(m)
(1, 673, (0, 2), (2, 2))
EDIT: You know what, here is the optimized version:
def f(matrix):
try:
min_val, max_val = matrix[0][0], matrix[0][0]
except IndexError:
raise ValueError("Expected a real matrix.") from None
genexp = (val for row in matrix for val in row)
cols = len(matrix[0])
min_i, max_i = (0, 0), (0, 0)
for i, val in enumerate(genexp):
if val < min_val:
min_val, min_i = val, divmod(i, cols)
elif val > max_val:
max_val, max_i = val, divmod(i, cols)
return min_val, max_val, min_i, max_i
EDIT2:
Here are an experience for better understanding which could be done either by you. I suggest you do the same if you want to understand a code.
>>> matrix = [[3,5,1], [56,43,12], [4,52,673]]
>>> flatten = [val for row in matrix for val in row]
>>> flatten
[3, 5, 1, 56, 43, 12, 4, 52, 673]
>>> flatten.index(56)
3
>>> divmod(3,3)
(1, 0)
>>> for elem in enumerate(["one", "two", "three"]):
... elem
...
(0, 'one')
(1, 'two')
(2, 'three')
I'm attempting to enumerate all possible matrices of size r by r with a few constraints.
Row and column sums must be in non-ascending order.
Starting from the top left element down the main diagonal, each row and column subset from that entry must be made up of combinations with replacements from 0 to the value in that upper left entry (inclusive).
The row and column sums must all be less than or equal to a predetermined n value.
The main diagonal must be in non-ascending order.
Important note is that I need every combination to be store somewhere, or if written in c++, to be ran through another few functions after finding them
r and n are values that range from 2 to say 100.
I've tried a recursive way to do this, along with an iterative, but keep getting hung up on keeping track column and row sums, along with all the data in a manageable sense.
I have attached my most recent attempt (which is far from completed), but may give you an idea of what is going on.
The function first_section(): builds row zero and column zero correctly, but other than that I don't have anything successful.
I need more than a push to get this going, the logic is a pain in the butt, and is swallowing me whole. I need to have this written in either python or C++.
import numpy as np
from itertools import combinations_with_replacement
global r
global n
r = 4
n = 8
global myarray
myarray = np.zeros((r,r))
global arraysums
arraysums = np.zeros((r,2))
def first_section():
bigData = []
myarray = np.zeros((r,r))
arraysums = np.zeros((r,2))
for i in reversed(range(1,n+1)):
myarray[0,0] = i
stuff = []
stuff = list(combinations_with_replacement(range(i),r-1))
for j in range(len(stuff)):
myarray[0,1:] = list(reversed(stuff[j]))
arraysums[0,0] = sum(myarray[0,:])
for k in range(len(stuff)):
myarray[1:,0] = list(reversed(stuff[k]))
arraysums[0,1] = sum(myarray[:,0])
if arraysums.max() > n:
break
bigData.append(np.hstack((myarray[0,:],myarray[1:,0])))
if printing: print 'myarray \n%s' %(myarray)
return bigData
def one_more_section(bigData,index):
newData = []
for item in bigData:
if printing: print 'item = %s' %(item)
upperbound = int(item[index-1]) # will need to have logic worked out
if printing: print 'upperbound = %s' % (upperbound)
for i in reversed(range(1,upperbound+1)):
myarray[index,index] = i
stuff = []
stuff = list(combinations_with_replacement(range(i),r-1))
for j in range(len(stuff)):
myarray[index,index+1:] = list(reversed(stuff[j]))
arraysums[index,0] = sum(myarray[index,:])
for k in range(len(stuff)):
myarray[index+1:,index] = list(reversed(stuff[k]))
arraysums[index,1] = sum(myarray[:,index])
if arraysums.max() > n:
break
if printing: print 'index = %s' %(index)
newData.append(np.hstack((myarray[index,index:],myarray[index+1:,index])))
if printing: print 'myarray \n%s' %(myarray)
return newData
bigData = first_section()
bigData = one_more_section(bigData,1)
A possible matrix could look like this:
r = 4, n >= 6
|3 2 0 0| = 5
|3 2 0 0| = 5
|0 0 2 1| = 3
|0 0 0 1| = 1
6 4 2 2
Here's a solution in numpy and python 2.7. Note that all the rows and columns are in non-increasing order, because you only specified that they should be combinations with replacement, and not their sortedness (and generating combinations is the simplest with sorted lists).
The code could be optimized somewhat by keeping row and column sums around as arguments instead of recomputing them.
import numpy as np
r = 2 #matrix dimension
maxs = 5 #maximum sum of row/column
def generate(r, maxs):
# We create an extra row and column for the starting "dummy" values.
# Filling in the matrix becomes much simpler when we do not have to treat cells with
# one or two zero indices in special way. Thus, we start iteration from the
# (1, 1) index.
m = np.zeros((r + 1, r + 1), dtype = np.int32)
m[0] = m[:,0] = maxs + 1
def go(n, i, j):
# If we completely filled the matrix, yield a copy of the non-dummy parts.
if (i, j) == (r, r):
yield m[1:, 1:].copy()
return
# We compute the next indices in row major order (the choice is arbitrary).
(i2, j2) = (i + 1, 1) if j == r else (i, j + 1)
# Computing the maximum possible value for the current cell.
max_val = min(
maxs - m[i, 1:].sum(),
maxs - m[1:, j].sum(),
m[i, j-1],
m[i-1, j])
for n2 in xrange(max_val, -1, -1):
m[i, j] = n2
for matrix in go(n2, i2, j2):
yield matrix
return go(maxs, 1, 1) #note that this is a generator object
# testing
for matrix in generate(r, maxs):
print
print matrix
If you'd like to have all the valid permutations in the rows and columns, this code below should work.
def generate(r, maxs):
m = np.zeros((r + 1, r + 1), dtype = np.int32)
rows = [0]*(r+1) # We avoid recomputing row/col sums on each cell.
cols = [0]*(r+1)
rows[0] = cols[0] = m[0, 0] = maxs
def go(i, j):
if (i, j) == (r, r):
yield m[1:, 1:].copy()
return
(i2, j2) = (i + 1, 1) if j == r else (i, j + 1)
max_val = min(rows[i-1] - rows[i], cols[j-1] - cols[j])
if i == j:
max_val = min(max_val, m[i-1, j-1])
if (i, j) != (1, 1):
max_val = min(max_val, m[1, 1])
for n in xrange(max_val, -1, -1):
m[i, j] = n
rows[i] += n
cols[j] += n
for matrix in go(i2, j2):
yield matrix
rows[i] -= n
cols[j] -= n
return go(1, 1)
I have an array X(9,2) and I want to generate another array B(512,9) with all the possible combinations.
I thought about doing 9 do loops, but I was hoping for a more efficient way.
This is what I have
do i1=1, 2
do i2=1, 2
do i3=1,2
do i4=1,2
do i5=1,2
do i6=1,2
do i7=1,2
do i8=i,2
do i9=1,2
B(row, col) = X(1,i1)
col = col + 1
B(row, col) = X(2,i2)
col = col + 1
B(row, col) = X(3,i3)
col = col + 1
B(row, col) = X(4,i4)
col = col + 1
B(row, col) = X(5,i5)
col = col + 1
B(row, col) = X(6,i6)
col = col + 1
B(row, col) = X(7,i7)
col = col + 1
B(row, col) = X(8,i8)
col = col + 1
B(row, col) = X(9,i9)
col = 1
row = row + 1
end do
end do
end do
end do
end do
end do
end do
end do
end do
Is there something wrong with this way? Is there a better way of doing this?
Thanks!
You should make the loops the other way around by looping over the elements of B like the following (I have a print statement instead of the assignment...):
program test
implicit none
integer, parameter :: nn = 9, imax = 2
integer :: row, col, ii
integer :: indices(nn)
indices(:) = 1
do row = 1, imax**nn
do col = 1, nn
print "(A,I0,A,I0,A,I0,A,I0,A)", "B(", row, ",", col, ") = X(",&
& col, ",", indices(col), ")"
!B(row, col) = X(col, indices(col))
end do
indices(nn) = indices(nn) + 1
ii = nn
do while (ii > 1 .and. indices(ii) > imax)
indices(ii) = 1
indices(ii-1) = indices(ii-1) + 1
ii = ii - 1
end do
end do
end program test
As far as I can see, this gives the same result as your original code, but is by far more compact and works for any tuple sizes and index ranges.
I think this does the trick too
ncol = 9
B = 0
tot = 2**ncol
do n = 1, ncol
div = 2**n
step = tot/div
do m = 0, div-1
fr = 1 + m*step
to = fr + step
B(fr:to,n) = X(n, 1+mod(m,2))
end do
end do
do n = 1, tot
write(*,*) (B(n,i), i=1,ncol)
end do
There is indeed a better way. See, for instance, Martin Broadhurst's combinatorial algorithms -- in particular the cartesian product example and the file n-tuple.c. Despite being in C, the code uses arrays and reference parameters throughout and so could be translated to Fortran without any difficulty other than changing the indices to start at 1 rather than 0. The approach he uses is to count upwards with an index array.
character *70 ofil
ofil='allcomb.txt'
write(*,*)'feed n and m (Note: n or m larger than 20 takes time)'
read(*,*) n,m
write(*,*)'feed file name to store results'
read(*,*) ofil
call combin(n,m,ofil)
write(*,*)'Over'
end
!---------------------------------------------------------------
subroutine combin(n,m,ofil)
! Generates all ncm combinatins
parameter (mx=20)! mx is maximum dimension
Integer a(mx),b(mx),c
double precision ncm,ic
character *70 ofil
open(15,file=ofil)
ncm=1
do i=1,m
a(i)=i ! a is least indexed combination
b(i)=n-m+i ! b is maximum indexed combination
ncm=ncm*b(i)/i ! total possible combinations
enddo
write (15,*) (a(i),i=1,m)! Initial (least indexed) combination
incmpl=1
ic=1
! --------------------------------------------------------------
do while (incmpl.ne.0 .and.int(ic).lt.ncm)
incm=0
do i=1,m
incm=incm+(b(i)-a(i))
enddo
incmpl=incm
a(m)=a(m)+1
do i=1,m
ii=m-i+1
if(a(ii).gt.b(ii)) then
a(ii-1)=a(ii-1)+1
do j=ii,m
a(j)=a(j-1)+1
enddo
endif
enddo
ic=ic+1
write(15,*)(a(k),k=1,m)
enddo ! end do while loop
! --------------------------------------------------------------
close(15)
return
end