Algebraic pyramid python challenge- more efficient way? - python

I'm doing a python challenge where you have to create an upside-down algebraic pyramid based on a list. Each level (going down) needs to be the sum of the numbers above it.
I created the code to do this for 4 layers.
The challenge part 2 was to do it for any length of list, so I added the len(list) code to accommodate. You can see my code below.
I just wondered if there was a more efficient way to do this for long lists, or would I just need to type out more code for the remaining layers.
Also, I wondered how the return statement is meant to fit into it (you're given the hint written in the code below to update the return statement).
def drawPyramid(list):
layer = ""
layer2 = " "
layer3 = " "
layer4 = " "
for i in range(len(list)):
layer = layer + " " + str(list[i])
for i in range(len(list)-1):
layer2 = layer2 + " " + str(list[i]+list[i+1])
for i in range(len(list)-2):
layer3 = layer3 + " " + str(list[i]+(list[i+1]*2)+list[i+2])
for i in range(len(list)-3):
layer4 = layer4 + " " + str(list[i]+(list[i+1]*3)+(list[i+2]*3)+list[i+3])
print(layer)
print(layer2)
print(layer3)
print(layer4)
#Update this code to generate all 4 layers of the pyramid
#Update this return statement to return the value of the single brick on the last layer of the pyramid
return 0
#Main code starts here
list = [30,12,10,22]
drawPyramid(list)

Here this function will calculate your pyramid using list:
def calcul_pyramid(base):
pyramid = [base]
for i in range(len(base) - 1):
actual_layer = []
last_layer = pyramid[i]
for j in range(len(last_layer) - 1):
actual_layer.append(last_layer[j] + last_layer[j + 1])
pyramid.append(actual_layer)
return pyramid
This function will get your pyramid as string:
def print_pyramid(pyramid):
lines = []
for layer in pyramid:
line = ""
for brick in layer:
line += str(brick)
line += " "
lines.append(line)
pyramid_len = max([len(layer) for layer in lines])
txt = ""
for line in lines:
diff = (pyramid_len - len(line)) / 2
txt += " " * int(diff + 0.5)
txt += line
txt += " " * int(diff - 0.5)
txt += "\n"
print(txt)
Now you can enter every base you want, it will work
print_pyramid(calcul_pyramid([30,12,10,22])))

You can use zip to add up the values, then it's just a question of formatting:
def pyramid(A):
indent = ""
width = len(str(sum(A)))
while A:
print(indent,*(f"{a:{width}}" for a in A))
A = [a+b for a,b in zip(A,A[1:])]
indent += " "*max(1,width-1)
output:
L = [30,12,10,22]
pyramid(L)
30 12 10 22
42 22 32
64 54
118
L = [30,12,10,22,23,43]
pyramid(L)
30 12 10 22 23 43
42 22 32 45 66
64 54 77 111
118 131 188
249 319
568

Related

how can I align the output horizantally with python?

can anyone take a look to my code and tell me what I'm missing?
I am trying to solve a freecodingcamp project called arithmetic formatter
this is my code:
def arithmetic_arranger(lst):
for x in lst:
if '+' in x:
x = x.split('+')
a = int(x[0])
b = int(x[1])
upa = str(a)
downb = str(b)
total = str(a + b)
s_total = str(total)
plusAndB = '+ ' + downb
line = '---------'
print('{:>8}'.format(upa),'\n','{:>7}'.format(plusAndB),'\n', '{:>8}'.format(line[0:len(s_total)]),'\n','{:>7}'.format(s_total))
if '-' in x:
y = x.split('-')
c = int(y[0])
d = int(y[1])
substracion = c - d
s_sub = str(substracion)
subAndD = '- ' + str(d)
line = '---------'
print('{:>8}'.format( c),'\n','{:>7}'.format(subAndD),'\n', '{:>8}'.format(line[0:len(s_sub) + 2]),'\n','{:>7}'.format(s_sub))
print('')
print(arithmetic_arranger(["32 + 8", "1 - 3801", "9999 + 9999", "523 - 49"]))
I want the results to be aligned as follows:
32 1 9999 523
+ 8 - 3801 + 9999 - 49
---- ------ ------ -----
40 -3800 19998 474
no matter what I have tried I always get this output:
32
+ 8
--
40
1
- 3801
-------
-3800
9999
+ 9999
-----
19998
523
- 49
-----
474
I left inline comments to explain what the code does
def output(seq):
final = [] # final output list
for expression in seq:
op = "+" if "+" in expression else "-" # op will represent the operator
top,bottom = [i.strip() for i in expression.split(op)] # split equation
ibottom = int(bottom) if op == "+" else int(bottom) * -1 # make bottom
# negative if
# operater is a
# minus
solution = str(sum([i for i in [int(top), ibottom]])) # sum solution
bottom = op + " " + bottom # add operator to bottom
out = [] # formated output list
mx = max(int(i) for i in [top, bottom, solution]) # largest string
for val in [top, bottom, solution]:
out.append(str(val).rjust(mx, " ")) # pad with spaces
out.insert(2, ("-" * mx)) # insert line before answer
final.append(out)
return final # return all solutions
out = output(["32 + 8", "1 - 3801", "9999 + 9999", "523 - 49"])
# join lines from each solution into their own lines to print them one at a time
print('\n'.join([(' '.join([out[i][j] for i in range(len(out))])) for j in range(len(out))]))
output
32 1 9999 523
+ 8 - 3801 + 9999 - 49
--- ------ ------ ----
40 -3800 19998 474

How to print math operations vertically?

I want to print strings like children in solving math operations, which is like this
32 3801 45 123
+ 698 - 2 + 43 + 49
----- ------ ---- -----
I have tried it as follows
def arithmetic(problems):
# pisahkan setiap value
atas = [i.split()[0] for i in problems]
bawah = [i.split()[2] for i in problems]
operator = [i.split()[1] for i in problems]
output_atas = ""
output_bawah = ""
for j in range( len(problems) ):
output_atas += f"{atas[j]:>8}"
output_bawah += f"{operator[j]} {bawah[j]:>5}"
print(output_atas)
print(output_bawah)
arithmetic(["32 + 698", "3801 - 2", "45 + 43", "123 + 49"])
how to tidy up the string and adjust the line ---- according to the length of the number?
Add a new line /n in after first value and then operation and next value will be on anew line

How would I reverse this? Python 3.8

So I've created a very... odd little caesar cipher using python. Very simple. Except, I'm not really all that great at math and am wondering how I'd reverse this?
def encrypt(text,s):
result = ""
for i in range(len(text)):
char = text[i]
if (char.isupper()):
result += chr((ord(char) + s - 23+213**3) % 26 + 713)
else:
result += chr((ord(char) + s - 23+213**3) % 26 + 715)
return result
text = input("Message: ")
s = 964
print ("Text: " + text)
print ("Shift: " + str(s))
print ("Cipher: " + encrypt(text,s))
Any form of help would be appreciated.
Edit:
I'M SO CLOSE!
I did that math as to how the shift works:
if the letter is a capital:
1. 964 - 23+213^3, which ends up as -9662656
2. Get the remainder of that divided by 26 (modulo operator) -9662656 % 26 = 10
3. 10 + 714 = 724
4. 724-63 I got the 63 just through trial and error...
ONLY PROBLEM!
It all works up until the letter M, in which case the last 13 letters shift backward 26 characters. How would I solve this?
def decrypt(text,s):
result = ""
for i in range(len(text)):
char = text[i]
result += chr((ord(char) - s))
return result
text = input("Message: ")
s = 724-63
print ("Text: " + text)
print ("Shift: " + str(s))
print ("Cipher: " + decrypt(text,s))
Text: ˖˗˘˙˚˛˜˝˞˟ˠˡˢˉˊˋˌˍˎˏːˑ˒˓˔˕
Shift: 661
Cipher: ABCDEFGHIJKLM456789:;<=>?#
I rewrote your encrypt function to show the individual piece of the calculation. Then I wrote the decrypt function to show how to "undo" them.
Note that -23+2133 is equivalent to 24 when working mod 26.
def encrypt(text, s):
cipher = ""
for pt_char in text:
val = ord(pt_char) # 65 <= val < 91
t0 = val % 26 # 0 <= t0 < 26, with A=>13, B=>14, ... N=>0 etc.
t1 = (t0 + s + 24) % 26 # 0 <= t1 < 26
t2 = t1 + 715 # 715 <= t2 < 741
cipher += chr(t2)
return cipher
def decrypt(ct, s):
plain = ""
for ct_char in ct:
t2 = ord(ct_char) # 715 <= t2 < 741
t1 = t2 - 715 # 0 <= t1 < 26
t0 = (t1 - s - 24 + 13) % 26 # 0 <= t0 < 26
val = t0 + 65 # 65 <= val < 91
plain += chr(val)
return plain
Again, this only works for upper case ASCII letters. Pay attention to the comments, they are telling you something.
Here are shorter one-liner just to show you something about how generators can produce compact code.
def encrypt_one_liner(text, s):
return ''.join(chr((ord(x) + s + 24) % 26 + 715) for x in text)
def decrypt_one_liner(text, s):
return ''.join(chr((ord(x) + 2 - s) % 26 + 65) for x in text)

What is the next step when having completed first neural network? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I'm a big fan of the youtube channel 3Blue1Brown and his series on Neural networks really got me excited on the subject.
I decided to create my own neural network in python from scratch engaging deeply in the mathematics. So with the help from the MNIST database on hand-written numbers I got started and succeded with the task after 2 weeks.
I have since then been further developing my code so that I can adjust the number of neurons and hidden layers neatly within the code.
I also experimented with different activation functions.
The best accuracy I've gotten is about 95% with 2 hidden layers of 16 neurons and 5 minutes of training.
Now, my question is fairly vague but I am now looking for the next challenge within the area, do you guys have any suggestions?
I now have the framework set up so I'd love some new type of problem with a bigger dataset or something or maybe should I work more on my existing problem to increase the accuracy of the ouput further?
What do you guys think?
Yours,
Emil
(Here's the code if anyone is interested)
import pickle
import gzip
import numpy as np
import random
import time
import pickle
import gzip
import numpy as np
import random
import time
class mnistClass:
def __init__(self, inputAmount=784, layers=2, layerSize=16, outputSize=10, loops=1, sampleSize=100):
with gzip.open('mnist.pkl.gz', 'rb') as f:
train_set, valid_set, test_set = pickle.load(f, encoding='latin1')
self.A, self.y = train_set
self.V, self.v2 = valid_set
self.dataSize = len(self.A)
self.inputAmount = inputAmount
self.layers = layers
self.layerSize = layerSize
self.outputSize = outputSize
self.loops = loops
self.sampleSize = sampleSize
self.iterations = int(self.dataSize/self.sampleSize)
self.clock = time.time()
self.Weights = []
self.Biases = []
self.initializeArrays()
self.initializeTraining()
print("Accuracy: " + str(self.getAccuracy()) + "%")
def initializeArrays(self):
for i in range(self.layers):
if self.layers - i > 2: #Adding middle layers
self.Weights.append(np.random.rand(self.layerSize, self.layerSize)-0.5)
if self.layers - i > 1:
self.Biases.append(np.random.rand(self.layerSize)-0.5)
if self.layers > 1:
self.Weights.insert(0, np.random.rand(self.layerSize, self.inputAmount)-0.5)
self.Weights.insert(len(self.Weights), np.random.rand(self.outputSize, self.layerSize)-0.5)
else:
self.Weights.insert(len(self.Weights), np.random.rand(self.outputSize, self.inputAmount)-0.5)
self.Biases.insert(len(self.Biases), np.random.rand(self.outputSize)-0.5)
def sigmoid(self, x, shiftType):
if shiftType == 0:
result = 1/(1+np.exp(-x))
elif shiftType == 1:
result = 2 * (1/(1+np.exp(-x))) - 1
return result
def sigmoidPrime(self, x, shiftType):
if shiftType == 0:
result = self.sigmoid(x, 0) - self.sigmoid(x, 0)**2
elif shiftType == 1:
result = 2*np.exp(-x)/(1+np.exp(-x))**2
return result
def Rdependance(self, Z, layer1, layer2, multi=False): #How R depends on a preceeding R
multi = layer1-layer2 > 1
if not multi:
if layer1 == self.layers-1:
shiftType = 0
else:
shiftType = 1
R1_R2_differential = np.multiply(self.Weights[layer1], self.sigmoidPrime(Z[layer1]+self.Biases[layer1], shiftType)[:, np.newaxis])
result = R1_R2_differential
else:
chainRule = []
for i in reversed(range(layer2, layer1)):
chainRule.append(self.Rdependance(Z, i+1, i))
result = chainRule[0]
for i in range(len(chainRule)-1):
result = np.dot(result, chainRule[i+1])
return result
def RWdependance(self, R, Z, dataCaseNo, layer): #How R depends on connecting Weights
if layer == self.layers-1:
shiftType = 0
else:
shiftType = 1
R_W_differential = self.Weights[layer]/self.Weights[layer]
mergeW_Z = np.multiply(R_W_differential, self.sigmoidPrime(Z[layer]+self.Biases[layer], shiftType)[:, np.newaxis])
if layer == 0:
R_W_differential = np.multiply(mergeW_Z.T, self.A[dataCaseNo][:, np.newaxis]).T
else:
R_W_differential = np.multiply(mergeW_Z.T, R[layer-1][:, np.newaxis]).T
return R_W_differential
def RBdependance(self, Z, layer): #How R depends on internal Biases
if layer == self.layers-1:
shiftType = 0
else:
shiftType = 1
R_B_differential = np.multiply(self.Rdependance(Z, self.layers-1, layer).T, self.sigmoidPrime(Z[layer]+self.Biases[layer], shiftType)[:, np.newaxis]).T
return R_B_differential
def integralWeightCost(self, R, Z, dataCaseNo, quadDifferential, layer): # Cost of system for weights
if layer == self.layers-1:
nodes = np.identity(self.outputSize)
else:
nodes = self.Rdependance(Z, self.layers-1, layer)
cost_differential = np.multiply(nodes, quadDifferential[:, np.newaxis])
cost_differential = np.sum(cost_differential, 0)
result = np.multiply(self.RWdependance(R, Z, dataCaseNo, layer), cost_differential[:, np.newaxis])
return result
def integralBiasCost(self, Z, quadDifferential, layer): # Cost of system for biases
if layer == self.layers-1:
nodes = np.identity(self.outputSize)
else:
nodes = self.RBdependance(Z, layer)
cost_differential = np.multiply(nodes, quadDifferential[:, np.newaxis])
result = np.sum(cost_differential, 0)
return result
def initializeTraining(self):
for loop in range(self.loops):
for iteration in range(self.iterations):
avg_cost = 0
avg_deltaWeights = []
avg_deltaBiases = []
for i in range(len(self.Weights)): #Creating zeros of weight arrays
avg_deltaWeights.append(self.Weights[i]*0)
for i in range(len(self.Biases)):
avg_deltaBiases.append(self.Biases[i]*0)
for dataCaseNo in range(iteration*self.sampleSize, iteration*self.sampleSize + self.sampleSize):
if self.layers == 1:
shiftType = 0
else:
shiftType = 1
Y1 = np.zeros(self.outputSize)
Y1[self.y[dataCaseNo]] = 1
Z = []
Z.append(np.dot(self.Weights[0], self.A[dataCaseNo]))
R = []
R.append(self.sigmoid(Z[0]+self.Biases[0], shiftType))
for i in range(1, self.layers):
if i == self.layers-1:
shiftType = 0
else:
shiftType = 1
Z.append(np.dot(self.Weights[i], R[i-1]))
R.append(self.sigmoid(Z[i]+self.Biases[i], shiftType))
C = np.sum((R[-1] - Y1)**2)
avg_cost += C
quadDifferential = 2 * (R[-1]-Y1)
for i in range(self.layers):
avg_deltaWeights[i] += self.integralWeightCost(R, Z, dataCaseNo, quadDifferential, i)
avg_deltaBiases[i] += self.integralBiasCost(Z, quadDifferential, i)
avg_cost = avg_cost/self.sampleSize
for i in range(self.layers):
self.Weights[i] = self.Weights[i] - avg_deltaWeights[i]/self.sampleSize
self.Biases[i] = self.Biases[i] - avg_deltaBiases[i]/self.sampleSize
print("Average cost: " + str(round(avg_cost, 4)))
print("\n" + "*"*25 + " " + str(loop+1) +" " + "*"*25 + "\n")
executionEndTime = round((time.time() - self.clock), 2)
print("Completed " + str(self.loops) + " rounds of " + str(self.sampleSize*self.iterations) + " samples (sampleSize: " + str(self.sampleSize) + "), " + " in " + str(executionEndTime) + " seconds..")
print("Layers: " + str(self.layers))
print("Middle layer nodes: " + str(self.layerSize))
print("Input amount: " + str(self.inputAmount))
amountVariables = 0
for i in range(self.layers):
amountVariables += self.Weights[i].size
amountVariables += self.Biases[i].size
print("Variables: " + str(amountVariables))
print("Output size: " + str(self.outputSize))
time.sleep(2)
def getAccuracy(self):
runs = 10000
correct = 0
print("Testing validation set accuracy over " + str(runs) + " samples...\n")
for i in range(runs):
if self.layers == 1:
shiftType = 0
else:
shiftType = 1
ran = i
Y1 = np.zeros(self.outputSize)
Y1[self.v2[ran]] = 1
Z = []
Z.append(np.dot(self.Weights[0], self.V[ran]))
R = []
R.append(self.sigmoid(Z[0]+self.Biases[0], shiftType))
for i in range(1, self.layers):
if i == self.layers-1:
shiftType = 0
else:
shiftType = 1
Z.append(np.dot(self.Weights[i], R[i-1]))
R.append(self.sigmoid(Z[i]+self.Biases[i], shiftType))
result = np.where(R[-1] == np.amax(R[-1]))
maxNum = result[0][0]
if int(self.v2[ran]) == int(maxNum):
correct += 1
accuracy = correct*100/runs
return accuracy
instance = mnistClass(784, 3, 16, 10, 2, 100)
#(input, layers, layer size, output, loops, sample subsize)
#input - amount of nodes in input data
#layers - amount of layers including last output layer but not first input layer
#layer size - amount of nodes in hidden layers
#output - amount of nodes in output layer
#loops - how many times to train through the entire data set
#sample subsize - what quantity of data samples to average the gradient on
I'm so glad to hear about new faces joining the field of ML (specifically DL),
That's quite an accomplishment what you said you've achieved so first of all salute.
Now as for your question, I'd suggest you take a step back and understand the concept of data exploration, and features extraction, and why those are important and how I suggest you do it is by exploring some kaggle tutorials about machine learning, trying to do some basic classification of data sets from there like the titanic data set etc...
https://www.kaggle.com/learn/overview
go for the "into to machine learning".
Best of luck!

Find Numbers That Multiply To Make List Of Numbers

I have a voting system for something where people rate things from one to ten. I am able to get the number of total votes, but not their distribution. I can, however, access the totals for each score (but not what score they are for).
For example, say two people voted 2 and three 4 then I would get [4, 12]. Humanly, it is possibly to work out what the votes were, however as there is a lot of data, I need an algorithm that is able to do it programmatically. To solve this humanly, I would know that there were 5 votes and this I would know that it was either one four and four thees or two twos and three fours. Because this isn't the best example, we can't tell which one it would be and so it this situation, the algorithm should spit out all of the solutions. With the real data, it is very rare that something like this occurs.
The input is in the form of an int representing the total number of votes cast, and a list of all of the vote subtotals. The output should be an array containing pars (x, y) where there are x number of y votes cast. If more than one solution is present, the algorithm should return all of them in an array.
EDIT:
Here's some real data (17 people voted):
Dunkel - 60 + 18 + 8 + 18 + 10 + 4 + 3 + 1 = 122
Satomi - 20 + 14 + 24 + 12 + 3 + 4 + 3 = 80
Bottersnike - 16 + 28 + 5 + 8 + 6 + 4 + 4 = 71
Woon - 40 + 36 + 8 + 21 + 5 + 16 = 126
Limelier - 10 + 18 + 6 + 15 + 8 + 4 + 6 = 67
RandomGamer - 16 + 6 + 10 + 4 + 6 + 4 + 7 = 53
Pillar - 10 + 8 + 21 + 6 + 15 + 4 + 9 + 4 + 2 = 79
EdgedPixel - 8 + 28 + 12 + 4 + 18 + 2 + 2 = 74
Lock - 20 + 24 + 7 + 18 + 10 + 8 + 6 + 2 = 95
Huri - 10 + 8 + 7 + 6 + 15 + 20 + 3 + 2 + 3 = 74
Sean - 18 + 32 + 8 + 5 + 4 + 9 + 2 = 78
And the answers (sorry about the different order):
Woon - 4*10 + 4*9 + 1*8 + 3*7 + 0*6 + 1*5 + 4*4 + 0*3 + 0*2 + 0*1 = 126
Dunkel - 6*10 + 2*9 + 1*8 + 0*7 + 3*6 + 2*5 + 1*4 + 1*3 + 0*2 + 1*1 = 122
Lock - 2*10 + 0*9 + 3*8 + 1*7 + 3*6 + 2*5 + 2*4 + 2*3 + 0*2 + 2*1 = 95
Satomi - 2*10 + 0*9 + 3*8 + 4*7 + 2*6 + 0*5 + 0*4 + 1*3 + 2*2 + 3*1 = 80
Pillar - 1*10 + 0*9 + 1*8 + 3*7 + 1*6 + 3*5 + 1*4 + 3*3 + 2*2 + 2*1 = 79
Sean - 0*10 + 0*9 + 4*8 + 0*7 + 3*6 + 1*5 + 2*4 + 3*3 + 2*2 + 2*1 = 78
EdgedPixel - 0*10 + 0*9 + 1*8 + 4*7 + 2*6 + 0*5 + 1*4 + 6*3 + 1*2 + 2*1 = 74
Huri - 1*10 + 0*9 + 1*8 + 1*7 + 1*6 + 3*5 + 5*4 + 1*3 + 1*2 + 3*1 = 74
Bottersnike - 0*10 + 0*9 + 2*8 + 4*7 + 0*6 + 1*5 + 2*4 + 2*3 + 2*2 + 4*1 = 71
Limelier - 1*10 + 2*9 + 0*8 + 0*7 + 1*6 + 3*5 + 2*4 + 0*3 + 2*2 + 6*1 = 67
RandomGamer - 0*10 + 0*9 + 2*8 + 0*7 + 1*6 + 2*5 + 1*4 + 2*3 + 2*2 + 7*1 = 53
I need an algorithm that is able to do it programmatically
I'd begin by factoring your totals.
What is the most efficient way of finding all the factors of a number in Python?
def factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
This will return all of the factors, very quickly, of a number n.
that would get you well on your way; obviously a listed total that doesn't have 5 for a factor did not come from a group that rated 5's
step 1) factor each number in your list of totals
step 2) create dictionary with all possible ratings as the keys; ie keys 1-10; each with empty lists as values.
step 3) check if each list of factors has a factor which matches each rating key; if so append the total it represents to the values list of possibilities for that respective key
from random import randint
from random import shuffle
VOTES = 200
RATINGS = 10
# Generate Test Data
ratings = {}
for i in range(1,(RATINGS+1)):
ratings[i] = []
for i in range(VOTES):
rate = randint(1,RATINGS)
ratings[rate].append(rate)
subtotals = []
for key, values in ratings.iteritems():
subtotals.append(sum(values))
subtotals = [i for i in subtotals if i != 0]
subtotals.sort()
hidden_subtotals = {}
for key, values in ratings.iteritems():
hidden_subtotals[key] = sum(values)
print '==================================='
print 'Generate Hidden Test Data'
print 'unknown actual votes: %s' % ratings
print 'unknown actual subtotals: %s' % hidden_subtotals
print '==================================='
print 'Present Problem'
print 'known vote total: %s' % VOTES
print 'known subtotals: %s' % subtotals
print 'known total: %s' % sum(subtotals)
print 'number of ratings used: %s of %s' % (len(subtotals), RATINGS)
print '==================================='
def factors(n):
f = list(set(reduce(list.__add__, ([i, n//i] for i in range(
1, int(n**0.5) + 1) if n % i == 0))))
f.sort()
return f
# Factor Each
subtotal_factors = {}
for i in subtotals:
subtotal_factors[i]=(factors(i))
print 'process 1: %s' % subtotal_factors
# Remove Factors greater than highest rating
possible_ratings = {}
for i in subtotal_factors:
possible_ratings[i] = [
z for z in subtotal_factors[i] if z<=RATINGS]
print 'process 2: %s' % possible_ratings
# Remove Factors if not enough votes for that possibility; too small relative to subtotal
for i in possible_ratings:
possible_ratings[i] = [
z for z in possible_ratings[i] if i/z < VOTES]
print 'process 3: %s' % possible_ratings
step 4) then you'll have a problem where 2's will fit in 4's, 6's, 8's, 10's; 4's will fit in 8's, and 3's will fit in 6's and 9's. You'll have to apply some logic to clean up the results.
I have now solved my problem. I used litepresence's code as a base, and then implemented what they described as step four. For the future, this is the code I used:
from random import randint
from random import shuffle
import itertools
NUM_RATINGS = 10
RATING = [10, 10, 10, 10, 10, 10, 9, 9, 8, 6, 6, 6, 5, 5, 4, 3, 1]
VOTES = len(RATING)
ratings = {}
for i in range(1, (NUM_RATINGS + 1)):
ratings[i] = []
for i in RATING:
ratings[i].append(i)
subtotals = []
for key, values in ratings.iteritems():
subtotals.append(sum(values))
subtotals = [i for i in subtotals if i != 0]
subtotals.sort()
hidden_subtotals = {}
for key, values in ratings.iteritems():
hidden_subtotals[key] = sum(values)
print '==================================='
print 'Hidden Test Data:'
print 'unknown actual votes: %s' % ratings
print 'unknown actual subtotals: %s' % hidden_subtotals
print '==================================='
print 'Present Problem:'
print 'known vote total: %s' % VOTES
print 'known subtotals: %s' % subtotals
print 'known total: %s' % sum(subtotals)
print 'number of ratings used: %s of %s' % (len(subtotals), NUM_RATINGS)
print '==================================='
def factors(n):
f = list(set(reduce(list.__add__, ([i, n//i] for i in range(
1, int(n**0.5) + 1) if n % i == 0))))
f.sort()
return f
# Factor Each
subtotal_factors = {}
for i in subtotals:
subtotal_factors[i]=(factors(i))
print 'process 1: %s' % subtotal_factors
# Remove Factors greater than highest rating
possible_ratings = {}
for i in subtotal_factors:
possible_ratings[i] = [
z for z in subtotal_factors[i] if z<=NUM_RATINGS]
print 'process 2: %s' % possible_ratings
# Remove Factors if not enough votes for that possibility; too small relative to subtotal
for i in possible_ratings:
possible_ratings[i] = [
z for z in possible_ratings[i] if i/z < VOTES]
print 'process 3: %s' % possible_ratings
end_res = {}
other = {} # (count, [poss])
for i in possible_ratings.items():
if len(i[1]) == 1:
end_res[i[0]] = (i[1][0], i[1][0])
else:
other[i[0]] = (subtotals.count(i[0]), i[1])
combs = {}
for i in other.items():
combs[i[0]] = (i[1][0], []) # (count, [data])
for a in i[1][1]:
for b in i[1][1]:
if (a, b) not in combs[i[0]]:
if a * b == i[0]:
combs[i[0]][1].append((a, b))
lists = []
for i in combs.items():
for j in range(i[1][0]):
lists.append([])
for n in i[1][1]:
lists[-1].append((n[0], n[1], i[0]))
toprocess = itertools.product(*lists)
working = []
for test in toprocess:
works = True
seen = []
tot = 0
for i in test:
if i[1] in seen:
works = False
break
tot += i[0]
if tot > VOTES:
works = False
break
seen.append(i[1])
if not works:
continue
else:
working.append(test)
formattedWs = []
for w in working:
w = list(w)
notseen = [i + 1 for i in range(NUM_RATINGS)]
for i in w:
notseen.remove(i[1])
for i in notseen:
w.append((0, i))
t = ""
def f(x, y):
return y[1] - x[1]
w.sort(cmp=f)
for i in w:
t += "%d*%d + " % (i[0], i[1])
t = t[:-3]
formattedWs.append(t)
seen = []
for w in list(formattedWs):
if w in seen:
formattedWs.remove(w)
else:
seen.append(w)
print "==================================="
for n, w in enumerate(formattedWs):
print "Solution #%d: %s" % (n + 1, w)

Categories

Resources