Jasmin
Jasmin

Reputation: 41

How to adjust values of numpy array until conditions satisfied

For example, I have 4 matrices like this

import random
import numpy as np

base = range(2, 46, 2)

table1 = np.array(random.sample(base, 9)).reshape(3,3)
table2 = np.array(random.sample(base, 9)).reshape(3,3)
table3 = np.array(random.sample(base, 9)).reshape(3,3)
table4 = np.array(random.sample(base, 9)).reshape(3,3)

The tables needs to satisfy the following conditions:

  1. table4 needs to have a row where each element is larger than elements in other rows by column. For example, [[1,2,3],[2,3,4],[5,6,7]], the third row satisfies this condition.

  2. in table1, table2 and table3 there should be one row whose sum of elements in this row is the highest compared to other two rows, and the other two rows need to have the same sum. For example, [[1,2,5],[2,3,3],[3,4,3]], the first two rows have the same sum of 8, and the third row has the highest sum of 13.

I am thinking to randomly generate 4 tables first, then adjust some values of the tables until the two conditions are satisfied.

Upvotes: 0

Views: 182

Answers (1)

al-dev
al-dev

Reputation: 256

In both cases, you can construct your tables to satisfy the conditions instead of generating a ton of random ones and hoping that one satisfies them. I'm assuming all values need to be in a specific set like base = range(2, 46, 2). Additionally, I'm enforcing all values to be unique in each table, which is a harder constraint than what you last mentioned but is easier to understand.

  1. For table4:
import random
import numpy as np

base = range(2, 46, 2)

# Generate a table at random
table = np.array(random.sample(base, 9)).reshape(3, 3)
# sort along first axis
table.sort(axis=0)
print table

e.g

[[16  8 20]
 [24 26 36]
 [30 40 42]]

You can then reorder the rows at random if you don't want the highest values (systematically) in the last one.

  1. For table1, table2, table3:
import random
from itertools import combinations
from collections import Counter
import numpy as np

base = range(2, 46, 2)

# generate all combinations of 3 elements in 'base'
# as a list of 3-tuple
comb = [x for x in combinations(base, 3)]
# append to each tuple the sum of its elements
sums = [x + (sum(x),) for x in comb]
# list all the sums
possible_sums = [x[3] for x in sums]
# count the occurrences of each sum value
c = Counter(possible_sums)
# keep only the sums which occur at least twice
# and which are not the highest
max_sum = max(possible_sums)
c2 = Counter(x for x in c.elements() if c[x] >= 2 and c[x] < max_sum)
valid_sums = list(c2)
# pick one of those at random
r_sum = random.choice(valid_sums)
# list all the combinations for this sum
combs_for_r_sum = [x[:3] for x in sums if x[3] == r_sum]
# pick 2 among those at random
row1, row2 = random.sample(combs_for_r_sum, 2)
# for row 3, pick a combination with a sum higher than r_sum
sum2 = random.choice([x for x in possible_sums if x > r_sum])
combs_for_sum2 = [x[:3] for x in sums if x[3] == sum2]
row3 = random.choice(combs_for_sum2)

table = np.array(row1 + row2 + row3).reshape(3, 3)
print table

e.g

[[ 2 28 32]
 [10 24 28]
 [20 42 44]]

Again, you can reorder the rows at random if you don't want the 'highest' row to be (systematically) the last one.

Upvotes: 1

Related Questions