I am coding a heuristic for an optimization problem from the field of production. In this heuristic I have various conditions, stop criteria etc. In order to account for these different criteria, I worked with multiple nested loops, as you can see in the code below:
for tao in PERIODS:
print ("Iteration:", tao)
print ("-----------------------------------------")
print (SETUP_ITEMS)
for z in range(1,periods_count+1-tao):
print("z =",z)
for k in SETUP_ITEMS[tao+z]:
print("k =",k)
#### EXCEPTION 1
if production.loc[k][tao] == 0:
print("There is no setup in this period for product {}.".format(k))
counter =+ 1
continue
#### EXCEPTION 2
if demand.loc[k][tao+z] > spare_capacity[tao]['Spare Capacity']:
print("Capacity in period {} is insufficient to pre-produce demands for product {} from period {}.\n".format(tao, k, tao+z))
counter =+ 1
continue
if counter == k:
print("Stop Criterion is met!")
break
##########################################################################
if SM == 1:
if SilverMeal(k,z) == True:
print("Silver Meal Criterion is", SilverMeal(k,z))
production.loc[k][tao] += demand.loc[k][tao+z]
production.loc[k][tao+z] = 0
else:
print("Else: Silver Meal Criterion is", SilverMeal(k,z))
for t in range(tao,periods_count+1):
for k in PRODUCTS:
spare_capacity[t] = capacity[t][1]-sum(production.loc[k][t] for k in PRODUCTS)
SETUP_ITEMS = [[] for t in range(0,periods_count+1)]
for t in PERIODS:
for k in PRODUCTS:
if production.loc[k][t]==(max(0,demand.loc[k][t]-stock.loc[k][t-1])) > 0:
SETUP_ITEMS[t].append(k)
print(productionplan(production,spare_capacity,CF), '\n\n')
print(productionplan(production,spare_capacity,CF), '\n\n')
The idea is, that if for one tao, there is an exception true for all k, all the loops terminate early, apart from the most outer one, so that we would go to the next tao in PERIODS and it all starts again.
I tried to use it with the counter variable, but this did not turn out to be functioning really well.
I currently have for example this output (extract):
z = 1
k = 1
Capacity in period 1 is insufficient to pre-produce demands for product 1 from period 2.
k = 2
Capacity in period 1 is insufficient to pre-produce demands for product 2 from period 2.
z = 2
k = 2
Capacity in period 1 is insufficient to pre-produce demands for product 2 from period 3.
After the k=2 in z=1the iteration should terminate, but it keeps on checking further z values.
Could anyone give me a tip how to solve this issue? I read about putting loops into functions, so that one can break out of multiple loops, but I am not sure how to formulate this here, as I would have multiple points of exit..
Thanks!
Python does not have control for breaking out of multiple loops at once.
You can set a flag and break out of multiple loops, for more info Link
Related
I would like to do the calculation loop using my function.
b=list(data.iloc[1])
def balance(rate, payment, os):
interest_amount=os*rate/100/12
principal_amount=payment-interest_amount
next_balance=os+interest_amount-principal_amount
return next_balance
c=balance(b[9], b[11], b[8])
d=balance(b[9], b[11], c)
e=balance(b[9], b[11], d)
I would have to start with b[8] as the amount for calculation. After I got the next amount from the function balance, the next amount will be the beginning of the third calculation and so on until the next amount eqaul of less than 0. It should stop the loop.
I need to append calculated values since b[8] until the last (before getting 0 or less).
Any suggestion on this, thank you!
Edit: based on Zaraki Kenpachi
b[8] is amount of money given 17183
b[9] is rate of interest given 3.39
b[11] is payment per month given 5759
The output, which I am trying to do is:
[17183, 11,521, 5,826, 99]
Perhaps something like this
x = b[8]
output = []
output.append(x)
while x > 0:
x = balance(b[9], b[11], X)
output.append(x)
Here you go:
def balance(rate, payment, os):
interest_amount=os*rate/100/12
principal_amount=payment-interest_amount
next_balance=os+interest_amount-principal_amount
return next_balance
next_balance = 17183 # = b[8]
results = []
results.append(next_balance)
while next_balance > 0:
next_balance = balance(3.39, 5759, next_balance) # b[9], b[11]
if next_balance > 0:
results.append(next_balance)
Output:
[17183, 11521.08395, 5827.1780743175, 101.10163043739522]
Python doesn't have a builtin way to unfold / iterate but the normal way you'd implenent a specific unfold is through a generator, which can keep computational state and yield values:
def balances(balance, rate, payment):
while True:
interest_amount = balance*rate/100/12
principal_amount = payment-interest_amount
balance = os+interest_amount-principal_amount
# TO DO: end the computation when balance <= 0, maybe find a way to
# note extra in the last payment, or reject the last payment entirely
# and handle that case separately outside the generator
yield balance
then you can either call next() on your balances iterator to get successive values
bs = balances(b[8], b[9], b[11])
c = next(bs)
d = next(bs)
e = next(bs)
or iterate the entire thing
for balance in balances(b[8], b[9], b[11]):
if balance < 0:
"do something when the last payment was excessive and stop the loop"
...
I'm trying to write Python code to see how many coin tosses, on average, are required to get a sequences of N heads in a row.
The thing that I'm puzzled by is that the answers produced by my code don't match ones that are given online, e.g. here (and many other places) https://math.stackexchange.com/questions/364038/expected-number-of-coin-tosses-to-get-five-consecutive-heads
According to that, the expected number of tosses that I should need to get various numbers of heads in a row are: E(1) = 2, E(2) = 6, E(3) = 14, E(4) = 30, E(5) = 62. But I don't get those answers! For example, I get E(3) = 8, instead of 14. The code below runs to give that answer, but you can change n to test for other target numbers of heads in a row.
What is going wrong? Presumably there is some error in the logic of my code, but I confess that I can't figure out what it is.
You can see, run and make modified copies of my code here: https://trinket.io/python/17154b2cbd
Below is the code itself, outside of that runnable trinket.io page. Any help figuring out what's wrong with it would be greatly appreciated!
Many thanks,
Raj
P.S. The closest related question that I could find was this one: Monte-Carlo Simulation of expected tosses for two consecutive heads in python
However, as far as I can see, the code in that question does not actually test for two consecutive heads, but instead tests for a sequence that starts with a head and then at some later, possibly non-consecutive, time gets another head.
# Click here to run and/or modify this code:
# https://trinket.io/python/17154b2cbd
import random
# n is the target number of heads in a row
# Change the value of n, for different target heads-sequences
n = 3
possible_tosses = [ 'h', 't' ]
num_trials = 1000
target_seq = ['h' for i in range(0,n)]
toss_sequence = []
seq_lengths_rec = []
for trial_num in range(0,num_trials):
if (trial_num % 100) == 0:
print 'Trial num', trial_num, 'out of', num_trials
# (The free version of trinket.io uses Python2)
target_reached = 0
toss_num = 0
while target_reached == 0:
toss_num += 1
random.shuffle(possible_tosses)
this_toss = possible_tosses[0]
#print([toss_num, this_toss])
toss_sequence.append(this_toss)
last_n_tosses = toss_sequence[-n:]
#print(last_n_tosses)
if last_n_tosses == target_seq:
#print('Reached target at toss', toss_num)
target_reached = 1
seq_lengths_rec.append(toss_num)
print 'Average', sum(seq_lengths_rec) / len(seq_lengths_rec)
You don't re-initialize toss_sequence for each experiment, so you start every experiment with a pre-existing sequence of heads, having a 1 in 2 chance of hitting the target sequence on the first try of each new experiment.
Initializing toss_sequence inside the outer loop will solve your problem:
import random
# n is the target number of heads in a row
# Change the value of n, for different target heads-sequences
n = 4
possible_tosses = [ 'h', 't' ]
num_trials = 1000
target_seq = ['h' for i in range(0,n)]
seq_lengths_rec = []
for trial_num in range(0,num_trials):
if (trial_num % 100) == 0:
print('Trial num {} out of {}'.format(trial_num, num_trials))
# (The free version of trinket.io uses Python2)
target_reached = 0
toss_num = 0
toss_sequence = []
while target_reached == 0:
toss_num += 1
random.shuffle(possible_tosses)
this_toss = possible_tosses[0]
#print([toss_num, this_toss])
toss_sequence.append(this_toss)
last_n_tosses = toss_sequence[-n:]
#print(last_n_tosses)
if last_n_tosses == target_seq:
#print('Reached target at toss', toss_num)
target_reached = 1
seq_lengths_rec.append(toss_num)
print(sum(seq_lengths_rec) / len(seq_lengths_rec))
You can simplify your code a bit, and make it less error-prone:
import random
# n is the target number of heads in a row
# Change the value of n, for different target heads-sequences
n = 3
possible_tosses = [ 'h', 't' ]
num_trials = 1000
seq_lengths_rec = []
for trial_num in range(0, num_trials):
if (trial_num % 100) == 0:
print('Trial num {} out of {}'.format(trial_num, num_trials))
# (The free version of trinket.io uses Python2)
heads_counter = 0
toss_counter = 0
while heads_counter < n:
toss_counter += 1
this_toss = random.choice(possible_tosses)
if this_toss == 'h':
heads_counter += 1
else:
heads_counter = 0
seq_lengths_rec.append(toss_counter)
print(sum(seq_lengths_rec) / len(seq_lengths_rec))
We cam eliminate one additional loop by running each experiment long enough (ideally infinite) number of times, e.g., each time toss a coin n=1000 times. Now, it is likely that the sequence of 5 heads will appear in each such trial. If it does appear, we can call the trial as an effective trial, otherwise we can reject the trial.
In the end, we can take an average of number of tosses needed w.r.t. the number of effective trials (by LLN it will approximate the expected number of tosses). Consider the following code:
N = 100000 # total number of trials
n = 1000 # long enough sequence of tosses
k = 5 # k heads in a row
ntosses = []
pat = ''.join(['1']*k)
effective_trials = 0
for i in range(N): # num of trials
seq = ''.join(map(str,random.choices(range(2),k=n))) # toss a coin n times (long enough times)
if pat in seq:
ntosses.append(seq.index(pat) + k)
effective_trials += 1
print(effective_trials, sum(ntosses) / effective_trials)
# 100000 62.19919
Notice that the result may not be correct if n is small, since it tries to approximate infinite number of coin tosses (to find expected number of tosses to obtain 5 heads in a row, n=1000 is okay since actual expected value is 62).
import random
import sys
bestcounter1 = 0
bestcounter2=0
get_sample = int(sys.argv[1])
for i in range(get_sample):
for i in range(12):
if (random.randint(1,6)==1):
bestcounter1+=1
bestcounter2+=1
oneatleasttwice = (bestcounter2*1.0)/(2*(get_sample))
#Divide by 2 to make both comparable. Otherwise 2 will always be greater than 1 !
print("One atleast twice in 12 rolls: ", oneatleasttwice)
Can anybody explain whether the logic used here is correct or not? The output I get is always around 1.
Thanks
You have to place your counters on the right places. Suppose bestcounter1 is used to count values of 1 during every run (12 rolls) while bestcounter2 is used to count runs when you got 2 or more values of 1. Then your main for loop should look like this:
for i in range(get_sample):
# reset before every run
bestcounter1 = 0
for i in range(12):
if random.randint(1, 6) == 1:
# count values of 1
bestcounter1 += 1
# check if we got 2 or more values of 1
if bestcounter1 >= 2:
# count proper cases
bestcounter2 += 1
break
oneatleasttwice = bestcounter2 / get_sample
I got result 61.9% with one million runs.
I was trying to calculate the expected value for the longest consecutive heads streak in 200 coin flips, using python. I came up with a code which I think does the job right but it's just not efficient because of the amount of calculations and data storage it requires, and I was wondering if someone could help me out with this, making it faster and more efficient (I took only one course of python programming in last semester without any previous knowledge of the subject).
My code was
import numpy as np
from itertools import permutations
counter = 0
sett = 0
rle = []
matrix = np.zeros(200)
for i in range (0,200):
matrix[i] = 1
for j in permutations(matrix):
for k in j:
if k == 1:
counter += 1
else:
if counter > sett:
sett == counter
counter == 0
rle.append(sett)
After finding rle, I'd iterate over it to get how many streaks of which length there are, and their sum divided by 2^200 would give me the expected value I'm looking for.
Thanks in advance for help, much appreciated!
You don't have to try all the permutations (in fact you cannot), but you can do a simple Monte Carlo style simulation. Repeat the 200 coin flips many times. Average the lengths of longest streaks you get and this will be a good approximation of the expected value.
def oneTrial (noOfCoinFlips):
s = numpy.random.binomial(1, 0.5, noOfCoinFlips)
maxCount = 0
count = 0
for x in s:
if x == 1:
count += 1
if x == 0:
count = 0
maxCount = max(maxCount, count)
return maxCount
numpy.mean([oneTrial(200) for x in range(10000)])
Output: 6.9843
Also see this thread for exact computation without using Python simulation.
This is an answer to a slightly different question. But, as I had invested an hour and half of my time into it, I didn't wanna scrape it off.
Let E(k) denote a k head streak, i.e., you get k consecutive heads from the first toss onwards.
E(0): T { another 199 tosses that we do not care about }
E(1): H T { another 198 tosses... }
.
.
E(198): { 198 heads } T H
E(199): { 199 heads } T
E(200): { 200 heads }
Note that P(0) = 0.5, which is P(tails in first toss)
whereas P(1) = 0.25 , i.e., P(heads in first toss and tails in the second)
P(0) = 2**-1
P(1) = 2**-2
.
.
.
P(198) = 2**-199
P(199) = 2**-200
P(200) = 2**-200 #same as P(199)
Which means if you toss a coin 2**200 times, you'd get
E(0) 2**199 times
E(1) 2**198 times
.
.
E(198) 2**1 times
E(199) 2**0 times and
E(200) 2**0 times.
Thus, the expected value reduces to
(0*(2**199) + 1*(2**198) + 2*(2**197) + ... + 198*(2**1) + 199*(2**0) + 200*(2**0))/2**200
This number is virtually equal to 1.
Expected_value = 1 - 2**-200
How I got the difference.
>>> diff = 2**200 - sum([ k*(2**(199-k)) for k in range(200)], 200*(2**0))
>>> diff
1
This can be generalized to n tosses as
f(n) = 1 - 2**(-n)
I'm currently working on a piece of code for a school project, wherein we have to lead customers to an available register within a supermarket. Format is that we get first a string with two numbers "x y", where x is the amount of registers and y is the amount of people coming to/leaving a register. Next there is y lines of either "C X" or "L X" format, where "C X" means a customer arrives at register X, and "L X" would be a customer leaving register X. Now if a customer arrives at an empty register it should just print this register number, but if a customer arrives at an already taken register, it should print out the nearest free register, favoring lower numbers (say nr 4 is taken but a customer arrives and both 3 and 5 is free, it should print 3). I'm currently using an array wherein I'm keeping the amount of registers as 0's and then changing these to ones if the register is taken and if it is I then loop through +- 1, +- 2 and so on till I find a free register. However, for a full grade we need to be able to take inputs of up to a million M, and our code needs to execute within a minute and use up a max of 256 mb of memory. Current code is below, I keep hitting the time limit, probably because of the way I iterate over the array, any ideas on how I could optimize this?
N, M = map(int, raw_input().split())
entries = []
for x in range(0, M):
entries.append(raw_input())
registers = []
for x in range(0,M):
registers.append(0)
for line in entries:
if line[0] == "L":
registers[int(line[2])-1] = 0
elif registers[int(line[2])-1] == 1:
i = 0
n = int(line[2])-1
while True:
if registers[n-i] == 1:
pass
elif n-i >= 0:
registers[n-i] = 1
print n-i+1
break
if registers[n+i] == 1:
pass
else:
registers[n+i] = 1
print n+i+1
break
i += 1
else:
registers[int(line[2])-1] = 1
print int(line[2])