I need to generate a file filled with three "random" values per line (10 lines), but those values sum must equal 15.
The structure is: "INDEX A B C".
Example:
1 15 0 0
2 0 15 0
3 0 0 15
4 1 14 0
5 2 13 0
6 3 12 0
7 4 11 0
8 5 10 0
9 6 9 0
10 7 8 0
If you want to avoid needing to create (or iterate through) the full space of satisfying permutations (which, for large N is important), then you can solve this problem with sequential sample.
My first approach was to just draw a value uniformly from [0, N], call it x. Then draw a value uniformly from [0, N-x] and call it y, then set z = N - x - y. If you then shuffle these three, you'll get back a reasonable draw from the space of solutions, but it won't be exactly uniform.
As an example, consider where N=3. Then the probability of some permutation of (3, 0, 0) is 1/4, even though it is only one out of 10 possible triplets. So this privileges values that contain a high max.
You can perfectly counterbalance this effect by sampling the first value x proportionally to how many values will be possible for y conditioned on x. So for example, if x happened to be N, then there is only 1 compatible value for y, but if x is 0, then there are 4 compatible values, namely 0 through 3.
In other words, let Pr(X=x) be (N-x+1)/sum_i(N-i+1) for i from 0 to N. Then let Pr(Y=y | X=x) be uniform on [0, N-x].
This works out to P(X,Y) = P(Y|X=x) * P(X) = 1/(N-x+1) * [N - x + 1]/sum_i(N-i+1), which is seen to be uniform, 1/sum_i(N-i+1), for each candidate triplet.
Note that sum(N-i+1 for i in range(0, N+1)) gives the number of different ways to sum 3 non-negative integers to get N. I don't know a good proof of this, and would happy if someone adds one to the comments!
Here's a solution that will sample this way:
import random
from collections import Counter
def discrete_sample(weights):
u = random.uniform(0, 1)
w_t = 0
for i, w in enumerate(weights):
w_t += w
if u <= w_t:
return i
return len(weights)-1
def get_weights(N):
vals = [(N-i+1.0) for i in range(0, N+1)]
totl = sum(vals)
return [v/totl for v in vals]
def draw_summing_triplet(N):
weights = get_weights(N)
x = discrete_sample(weights)
y = random.randint(0, N-x)
triplet = [x, y, N - x - y]
random.shuffle(triplet)
return tuple(triplet)
Much credit goes to #DSM in the comments for questioning my original answer and providing good feedback.
In this case, we can test out the sampler like this:
foo = Counter(draw_summing_triplet(3) for i in range(10**6))
print foo
Counter({(1, 2, 0): 100381,
(0, 2, 1): 100250,
(1, 1, 1): 100027,
(2, 1, 0): 100011,
(0, 3, 0): 100002,
(3, 0, 0): 99977,
(2, 0, 1): 99972,
(1, 0, 2): 99854,
(0, 0, 3): 99782,
(0, 1, 2): 99744})
If the numbers can by any just use combinations:
from itertools import combinations
with open("rand.txt","w") as f:
combs = [x for x in combinations(range(16),3) if sum(x ) == 15 ][:10]
for a,b,c in combs:
f.write("{} {} {}\n".format(a,b,c))
This seems straight forward to me and it utilizes the random module.
import random
def foo(x):
a = random.randint(0,x)
b = random.randint(0,x-a)
c = x - (a +b)
return (a,b,c)
for i in range(100):
print foo(15)
Related
Given an input n, I want to print n lines with each n numbers such that the numbers 1 through n² are displayed in a zig-zag way, starting with 1 appearing at the bottom-right corner of the output matrix, and 2 at the end of the one-but-last row, ...etc.
Examples:
Given Input 3.
Print:
9 4 3
8 5 2
7 6 1
Given Input 1.
Print:
1
Given Input 4.
Print:
13 12 5 4
14 11 6 3
15 10 7 2
16 9 8 1
Attempt
n = int(input("Enter dimensions of matrix :"))
m = n
x = 1
columns = []
for row in range(n):
inner_column = []
for col in range(m):
inner_column.append(x)
x = x + 1
columns.append(inner_column)
for inner_column in columns:
print(' '.join(map(str, inner_column)))
I've tried something like this, but it prints out the array incorrectly. Any ideas?
Your code explicitly performs x = 1 and then x = x + 1 in a loop. As you need the first column in reverse order, and there are n*n numbers to output, instead the first top-left value should be x = n * n and in the first column it should decrease like with x = x - 1. The next column should be filled from end to start, and the next should be filled from start to end, ...etc.
I would suggest making an iterator that visits rows in that zig-zag manner: 0, 1, 2, ... n - 1, and then n - 1, n - 2, ... 0, and back from the start. With that iterator you know exactly to which row you should append the next x value:
# Helper function to generate row numbers in zig-zag order, for as
# long as needed.
def zigzag(n):
if n % 2:
yield from range(n)
while True:
yield from range(n - 1, -1, -1)
yield from range(n)
n = int(input("Enter dimensions of matrix :"))
matrix = [[] for _ in range(n)]
visit = zigzag(n)
for x in range(n*n, 0, -1):
matrix[next(visit)].append(x)
Then print it:
for row in matrix:
print(' '.join(map(str, row)))
I'm writing this code for the problem #18 in Codeabbey. I need to calculate the square root of an array of numbers [150, 0, 5, 1 10, 3] I have to divide this array in three arrays (x,n) [[150, 0], [5, 1], [10 3]] where x: is the number I want to calculate the square root of and n: is the number of times I have to try the formula r = (r + x / r) / 2 to get the result which is r, r is starting with 1. There's no problem with that, the problem is when I have to append the result because if r is 3.0 I have to append it as an integer: 3 but if r is 3.964 I have to append it as a floating.
def squareRoot():
rawArr = [int(n) for n in input().split()]
arr = [rawArr[i:i+2] for i in range(0,len(rawArr)-1,2)]
results = []
for a in arr:
x,n = a
r = 1.0
for i in range(0,n):
r = (r + x / r) / 2
if r.is_integer:
results.append(str(int(r)))
else:
results.append(str(round(r,3)))
return " ".join(results)
The input is:
150 0 5 1 10 3
and the output is:
'1 3 3'
This is what I get if I don't use is_integer():
'1 3.0 3.196xxxxx'
What the output should be:
1 3 3.196
I can't see where the problem is.
is_integer is a method you run on float type. You forgot to invoke it, so it evaluates to True as it returns a builtin which is something (not nothing).
Just replace
if r.is_integer:
with
if r.is_integer():
Sorry if the title was a little confusing, I didn't know what to call it. However, I'm still new to programming and I'm stuck on this coding problem that I just have no idea where to start.
Here is the summarized version of the problem:
I have a randomized plot of land, lets just call the variables x and y. This plot of land is a 2D array of all numbers that can be negative or positive. Now, there will be another, smaller plot of randomized numbers, lets call them width, height. With these new variables I need to find the greatest number from the x,y array that is width, height in size.
All numbers will be valid integers.
x ≥ width > 0
y ≥ height > 0
I will need to output the largest sum of land in the x y plot that is width, height in size.
Here is an example
3 - randomly picked y value
4 - randomly picked x value
2 - randomly picked height
1 - randomly picked width
1 2 3 4
-1 0 -1 9
-4 1 -2 7
Now, you can see from the example that the output will be 16, because the biggest 1x2 plot in the 4x3 plot is 16. I was wondering if anyone could point me in the right direction and give me tips on where to start. I have tried researching this, but it has led nowhere because I have no idea what to look up.
A summed-area table seems to be an interesting way to tackle this problem. If I'm not mistaken such an algorithm would be linear in the number of cells (x*y).
The basic idea of a summed-area table is that the sum of a subparcel can be calculated by adding the values for two corners and subtracting the values of the opposite corners, as explained in the Wikipedia article.
Numpy's cumsum helps to quickly create the summed-area table. Maybe there is also a numpy way to calculate the areas?
Here's my sample code (note that numpy first indexes the vertical direction, and then the horizontal). The tests inside the loop could be skipped if we added an extra row and extra column of zeros (but would make the code slightly more difficult to understand).
import numpy as np
def find_highest_area_sum(parcel, x, y, width, height):
sums = np.cumsum(np.cumsum(parcel, axis=0), axis=1)
areas = np.zeros((y - height + 1, x - width + 1), dtype=sums.dtype)
print("Given parcel:")
print(parcel)
print("Cumulative area sums:")
print(sums)
for i in range(x - width + 1):
for j in range(y - height + 1):
areas[j, i] = sums[j + height - 1, i + width - 1]
if i > 0:
areas[j, i] -= sums[j + height - 1, i - 1]
if j > 0:
areas[j, i] -= sums[j - 1, i + width - 1]
if i > 0 and j > 0:
areas[j, i] += sums[j - 1, i - 1]
print("Areas of each subparcel:")
print(areas)
ind_highest = np.unravel_index(np.argmax(areas), areas.shape)
print(f'The highest area sum is {areas[ind_highest]} at pos ({ind_highest[1]}, {ind_highest[0]}) to pos ({ind_highest[1] + width - 1}, {ind_highest[0] + height - 1}) ')
x, y = 4, 3
width, height = 1, 2
parcel = np.array([[1, 2, 3, 4],
[-1, 0, -1, 9],
[-4, 1, -2, 7]])
find_highest_area_sum(parcel, x, y, width=1, height=2)
x = 12
y = 20
parcel = np.random.randint(-10, 20, (y, x))
find_highest_area_sum(parcel, x, y, width=10, height=12)
Output of the first part:
Given parcel:
[[ 1 2 3 4]
[-1 0 -1 9]
[-4 1 -2 7]]
Cumulative area sums:
[[ 1 3 6 10]
[ 0 2 4 17]
[-4 -1 -1 19]]
Areas of each subparcel:
[[ 0 2 2 13]
[-5 1 -3 16]]
The highest area sum is 16 at pos (3, 1) to pos (3, 2)
Suppose we have a matrix of dimension N x M and we want to reduce its dimension preserving the values in each by summing the firs neighbors.
Suppose the matrix A is a 4x4 matrix:
A =
3 4 5 6
2 3 4 5
2 2 0 1
5 2 2 3
we want to reduce it to a 2x2 matrix as following:
A1 =
12 20
11 6
In particular my matrix represent the number of incident cases in an x-y plane. My matrix is A=103x159, if I plot it I get:
what I want to do is to aggregate those data to a bigger area, such as
Assuming you're using a numpy.matrix:
import numpy as np
A = np.matrix([
[3,4,5,6],
[2,3,4,5],
[2,2,0,1],
[5,2,2,3]
])
N, M = A.shape
assert N % 2 == 0
assert M % 2 == 0
A1 = np.empty((N//2, M//2))
for i in range(N//2):
for j in range(M//2):
A1[i,j] = A[2*i:2*i+2, 2*j:2*j+2].sum()
Though these loops can probably be optimized away by proper numpy functions.
I see that there is a solution using numpy.maxtrix, maybe you can test my solution too and return your feedbacks.
It works with a*b matrix if a and b are even. Otherwise, it may fail if a or b are odd.
Here is my solution:
v = [
[3,4,5,6],
[2,3,4,5],
[2,2,0,1],
[5,2,2,3]
]
def shape(v):
return len(v), len(v[0])
def chunks(v, step):
"""
Chunk list step per step and sum
Example: step = 2
[3,4,5,6] => [7,11]
[2,3,4,5] => [5,9]
[2,2,0,1] => [4,1]
[5,2,2,3] => [7,5]
"""
for i in v:
for k in range(0, len(i),step):
yield sum(j for j in i[k:k+step])
def sum_chunks(k, step):
"""
Sum near values with step
Example: step = 2
[
[7,11], [
[5,9], => [12, 11],
[4,1], [20, 6]
[7,5] ]
]
"""
a, c = [k[i::step] for i in range(step)], []
print(a)
for m in a:
# sum near values
c.append([sum(m[j:j+2]) for j in range(0, len(m), 2)])
return c
rows, columns = shape(v)
chunk_list = list(chunks(v, columns // 2))
final_sum = sum_chunks(chunk_list, rows // 2)
print(final_sum)
Output:
[[12, 11], [20, 6]]
This question already has answers here:
Generate random numbers summing to a predefined value
(7 answers)
Closed 5 years ago.
Let's say bob = 6
I want to create 3 random integers that have a sum of 106 (100 + whatever bob's original integer is. It could be 10, but in this case, it's 6).
I've got:
from random import *
bob = 6
bob1 = (randint(0,100))
bob2 = (randint(0,100))
bob3 = (randint(0,100))
print bob1
print bob2
print bob3
I can generate integers, but how can I make sure the sum of them = 100 + original integer? (106 total). If the sum doesn't = 106, then I want the script to keep going until it makes 106.
The general approach to generate numbers that add up to a certain number is like this:
import random
bob = 6
numbers = sorted(random.sample(range(100+bob), 2))
bob1 = numbers[0]
bob2 = numbers[1] - numbers[0]
bob3 = 100 + bob - numbers[1]
It selects two cut points between 0 and 100 + bob and assigns the numbers as illustrated:
This will also ensure all three numbers have the same distribution (simulated with 1m trials):
mean 34.700746 35.639730 35.659524
std 24.886456 24.862377 24.861724
As opposed to the numbers generated dependently:
mean 50.050665 27.863753 28.085582
std 29.141171 23.336316 23.552992
And their histograms:
Just calculate the third value:
from random import randint
bob = 6
bob1 = randint(0, 100)
bob2 = randint(0, min(100, 100 + bob - bob1))
bob3 = 100 + bob - bob1 - bob2
print bob1
print bob2
print bob3
bob1 = (randint(0,100))
bob2 = (randint(0,(100-bob1)))
bob3 = 100 - (bob1 + bob2)
Here is a general function that will always randomly generate 3 numbers in [0, n] that add to n; as the intermediate values are determined by "bob"'s initial value, we pass it this value and a target total number. The function returns a tuple of 3 numbers that together with bob-initial-value add up to the target:
import random
def three_numbers_to_n(bob, target):
n = target - bob
a = random.randrange(0, n+1)
b = random.randrange(a, n+1) - a
c = n - a - b
return a, b, c
for _ in range(5):
bob = 6
result = three_numbers_to_n(bob, 106)
print(bob, result, sum(result) + bob)
sample output:
6 (13, 3, 84) 106
6 (45, 49, 6) 106
6 (27, 2, 71) 106
6 (44, 18, 38) 106
6 (100, 0, 0) 106
If you wish, you could random.shuffle(a, b, c) before returning to remove the predictability that the first number is likely larger than the second likely larger than the 3rd.