Restarting a loop after a specific number of iterations? - loops

I'm new to coding but is being asked to create a simulation of a 10-year experiment 1000 times. I have it at a number lower than 1000 to speed up the testing process. This is a partial copy of my code, I can get the other parameters of the task to work but instead of stopping at and restarting for every 10-years, it seems to accumulate the results of the previous years'.
For example, the code is supposed to compound money earned the year following a 'Success,' while I can get it to compound, my code seems to compound into year 11 and 12 instead of stopping at 10 and essentially restarting at year 1.
I tried .count() to keep track of how many elements I'm iterating through and also tried the while xyz function but I can't seem to get either to work.
for sim in range(5):
for yr in range(10):
experiment = "Success" if np.random.random() <= 0.1 else "Failure"
expense = 25000
margin = 0
results1.append(experiment)
expenses1.append(expense)
margins1.append(margin)
iter = 0
if iter < 10:
for i in range(len(results1)):
if i + 1 < len(results1) and i - 1 >= 0:
if results1[i] == 'Success':
expenses1[i + 1] = 0
margins1[i + 1] = 10000
if results1[i - 1] == 'Success':
expenses1[i] = 0
if margins1[i] != 10000:
margins1[i] = 10000
if expenses1[i - 1] == 0:
expenses1[i] = 0
expenses1[i + 1] = 0
if margins1[i] >= 10000:
margins1[i + 1] = margins1[i] * 1.2
iter += 1
else:
continue
iter = 0
all_data1 = zip(results1, expenses1, margins1)
df1 = pd.DataFrame(all_data1, columns=["Results", "R&D", "Margins"])

Let's look at the following simplified code snippet of your implementation.
import numpy as np
results1 = []
for sim in range(10):
for yr in range(10):
experiment = "Success" if np.random.random() <= 0.1 else "Failure"
results1.append(experiment)
What is the problem here? Well, what I assume you want is that for every year we add a result to a list for that simulation. However, what is the difference between what you currently have, and this following code?
import numpy as np
results1 = []
for yr in range(10 * 10):
experiment = "Success" if np.random.random() <= 0.1 else "Failure"
results1.append(experiment)
Well, unless you left something out of your included code, it looks like not much! You want the simulation to reset after n years (in this example 10), but you don't change anything in your code! Here is an example of how this reset could be represented:
import numpy as np
results1 = []
for sim in range(10):
sim_results1 = []
for yr in range(10):
experiment = "Success" if np.random.random() <= 0.1 else "Failure"
sim_results1.append(experiment)
results1.append(sim_results1)
Now, your results1 list will contain m lists (where m is the number of simulations) with each sublist showing whether the experiment was a success or failure over n years. In short: if you just add each experimental result to a big list that is the same across all simulation runs, it's not a surprise that it looks like you are simulating into year 11, 12, etc. What is actually happening is year 11 is really year 1 of simulation number 2, but you do not separate the simulations currently.

Related

Find Minimum Score Possible

Problem statement:
We are given three arrays A1,A2,A3 of lengths n1,n2,n3. Each array contains some (or no) natural numbers (i.e > 0). These numbers denote the program execution times.
The task is to choose the first element from any array and then you can execute that program and remove it from that array.
For example:
if A1=[3,2] (n1=2),
A2=[7] (n2=1),
A3=[1] (n3=1)
then we can execute programs in various orders like [1,7,3,2] or [7,1,3,2] or [3,7,1,2] or [3,1,7,2] or [3,2,1,7] etc.
Now if we take S=[1,3,2,7] as the order of execution the waiting time of various programs would be
for S[0] waiting time = 0, since executed immediately,
for S[1] waiting time = 0+1 = 1, taking previous time into account, similarly,
for S[2] waiting time = 0+1+3 = 4
for S[3] waiting time = 0+1+3+2 = 6
Now the score of array is defined as sum of all wait times = 0 + 1 + 4 + 6 = 11, This is the minimum score we can get from any order of execution.
Our task is to find this minimum score.
How can we solve this problem? I tried with approach trying to pick minimum of three elements each time, but it is not correct because it gets stuck when two or three same elements are encountered.
One more example:
if A1=[23,10,18,43], A2=[7], A3=[13,42] minimum score would be 307.
The simplest way to solve this is with dynamic programming (which runs in cubic time).
For each array A: Suppose you take the first element from array A, i.e. A[0], as the next process. Your total cost is the wait-time contribution of A[0] (i.e., A[0] * (total_remaining_elements - 1)), plus the minimal wait time sum from A[1:] and the rest of the arrays.
Take the minimum cost over each possible first array A, and you'll get the minimum score.
Here's a Python implementation of that idea. It works with any number of arrays, not just three.
def dp_solve(arrays: List[List[int]]) -> int:
"""Given list of arrays representing dependent processing times,
return the smallest sum of wait_time_before_start for all job orders"""
arrays = [x for x in arrays if len(x) > 0] # Remove empty
#functools.lru_cache(100000)
def dp(remaining_elements: Tuple[int],
total_remaining: int) -> int:
"""Returns minimum wait time sum when suffixes of each array
have lengths in 'remaining_elements' """
if total_remaining == 0:
return 0
rem_elements_copy = list(remaining_elements)
best = 10 ** 20
for i, x in enumerate(remaining_elements):
if x == 0:
continue
cost_here = arrays[i][-x] * (total_remaining - 1)
if cost_here >= best:
continue
rem_elements_copy[i] -= 1
best = min(best,
dp(tuple(rem_elements_copy), total_remaining - 1)
+ cost_here)
rem_elements_copy[i] += 1
return best
return dp(tuple(map(len, arrays)), sum(map(len, arrays)))
Better solutions
The naive greedy strategy of 'smallest first element' doesn't work, because it can be worth it to do a longer job to get a much shorter job in the same list done, as the example of
A1 = [100, 1, 2, 3], A2 = [38], A3 = [34],
best solution = [100, 1, 2, 3, 34, 38]
by user3386109 in the comments demonstrates.
A more refined greedy strategy does work. Instead of the smallest first element, consider each possible prefix of the array. We want to pick the array with the smallest prefix, where prefixes are compared by average process time, and perform all the processes in that prefix in order.
A1 = [ 100, 1, 2, 3]
Prefix averages = [(100)/1, (100+1)/2, (100+1+2)/3, (100+1+2+3)/4]
= [ 100.0, 50.5, 34.333, 26.5]
A2=[38]
A3=[34]
Smallest prefix average in any array is 26.5, so pick
the prefix [100, 1, 2, 3] to complete first.
Then [34] is the next prefix, and [38] is the final prefix.
And here's a rough Python implementation of the greedy algorithm. This code computes subarray averages in a completely naive/brute-force way, so the algorithm is still quadratic (but an improvement over the dynamic programming method). Also, it computes 'maximum suffixes' instead of 'minimum prefixes' for ease of coding, but the two strategies are equivalent.
def greedy_solve(arrays: List[List[int]]) -> int:
"""Given list of arrays representing dependent processing times,
return the smallest sum of wait_time_before_start for all job orders"""
def max_suffix_avg(arr: List[int]):
"""Given arr, return value and length of max-average suffix"""
if len(arr) == 0:
return (-math.inf, 0)
best_len = 1
best = -math.inf
curr_sum = 0.0
for i, x in enumerate(reversed(arr), 1):
curr_sum += x
new_avg = curr_sum / i
if new_avg >= best:
best = new_avg
best_len = i
return (best, best_len)
arrays = [x for x in arrays if len(x) > 0] # Remove empty
total_time_sum = sum(sum(x) for x in arrays)
my_averages = [max_suffix_avg(arr) for arr in arrays]
total_cost = 0
while True:
largest_avg_idx = max(range(len(arrays)),
key=lambda y: my_averages[y][0])
_, n_to_remove = my_averages[largest_avg_idx]
if n_to_remove == 0:
break
for _ in range(n_to_remove):
total_time_sum -= arrays[largest_avg_idx].pop()
total_cost += total_time_sum
# Recompute the changed array's avg
my_averages[largest_avg_idx] = max_suffix_avg(arrays[largest_avg_idx])
return total_cost

How many random requests do I need to make to a set of records to get 80% of the records?

Suppose I have an array of 100_000 records ( this is Ruby code, but any language will do)
ary = ['apple','orange','dog','tomato', 12, 17,'cat','tiger' .... ]
results = []
I can only make random calls to the array ( I cannot traverse it in any way)
results << ary.sample
# in ruby this will pull a random record from the array, and
# push into results array
How many random calls like that, do I need to make, to get least 80% of records from ary. Or expressed another way - what should be the size of results so that results.uniq will contain around 80_000 records from ary.
From my rusty memory of Stats class in college, I think it's needs to be 2*result set size = or around 160_000 requests ( assuming random function is random, and there is no some other underlying issue) . My testing seems to confirm this.
ary = [*1..100_000];
result = [];
160_000.times{result << ary.sample};
result.uniq.size # ~ 80k
This is stats, so we are talking about probabilities, not guaranteed results. I just need a reasonable guess.
So the question really, what's the formula to confirm this?
I would just perform a quick simulation study. In R,
N = 1e5
# Simulate 300 times
s = replicate(300, sample(x = 1:N, size = 1.7e5, replace = TRUE))
Now work out when you hit your target
f = function(i) which(i == unique(i)[80000])[1]
stats = apply(s, 2, f)
To get
summary(stats)
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 159711 160726 161032 161037 161399 162242
So in 300 trials, the maximum number of simulations needed was 162242 with an average number of 161032.
With Fisher-Yates shuffle you could get 80K items from exactly 80K random calls
Have no knowledge of Ruby, but looking at https://gist.github.com/mindplace/3f3a08299651ebf4ab91de3d83254fbc and modifying it
def shuffle(array, counter)
#counter = array.length - 1
while counter > 0
# item selected from the unshuffled part of array
random_index = rand(counter)
# swap the items at those locations
array[counter], array[random_index] = array[random_index], array[counter]
# de-increment counter
counter -= 1
end
array
end
indices = [0, 1, 2, 3, ...] # up to 99999
counter = 80000
shuffle(indices, 80000)
i = 0
while counter > 0
res[i] = ary[indices[i]]
counter -= 1
i += 1
UPDATE
Packing sampled indices into custom RNG (bear with me, know nothing about Ruby)
class FYRandom
_indices = indices
_max = 80000
_idx = 0
def rand()
if _idx > _max
return -1.0
r = _indices[idx]
_idx += 1
return r.to_f / max.to_f
end
end
And code for sample would be
rng = FYRandom.new
results << ary.sample(random: rng)

Repeating utility values in Value Iteration (Markov Decision Process)

I am trying to implement the value iteration algorithm of the Markov Decision Process using python. I have one implementation. But, this is giving me many repeated values for the utilities. My transition matrix is quite sparse. Probably, this is causing the problem. But, I am not very sure if this assumption is correct. How should I correct this?
The code might be pretty shoddy. I am very new to value iteration. So please help me identify problems with my code. The reference code is this :http://carlo-hamalainen.net/stuff/mdpnotes/. I have used the ipod_mdp.py code file. Here is the snippet of my implementation:
num_of_states = 470 #total number of states
#initialization
V1 = [0.25] * num_of_states
get_target_index = state_index[(u'48.137654', u'11.579949')] #each state is a location
#print "The target index is ", get_target_index
V1[get_target_index] = -100 #assigning least cost to the target state
V2 = [0.0] * num_of_states
policy = [0.0] * num_of_states
count = 0.0
while max([abs(V1[i] - V2[i]) for i in range(num_of_states)]) > 0.001:
print max([abs(V1[i] - V2[i]) for i in range(num_of_states)])
print count
for s in range(num_of_states): #for each state
#initialize minimum action to the first action in the list
min_action = actions_index[actions[0]] #initialize - get the action index for the first iteration
min_action_cost = cost[s, actions_index[actions[0]]] #initialize the cost
for w in range(num_of_states):
if (s, state_index[actions[0]], w) in transitions: #if this transition exists in the matrix - non-zero value
min_action_cost += 0.9 * transitions[s, state_index[actions[0]], w] * V1[w]
else:
min_action_cost += 0.9 * 0.001 * V1[w] #if not - give it a small value of 0.001 instead of 0.0
#get the minimum action cost for the state
for a in actions:
this_cost = cost[s, actions_index[a]]
for w in range(num_of_states):
# if index_state[w] != 'm':
if (s, state_index[a], w) in transitions:
this_cost += 0.9 * transitions[s, state_index[a], w] * V1[w]
else:
this_cost += 0.9 * 0.001 * V1[w]
if this_cost < min_action_cost:
min_action = actions_index[a]
min_action_cost = this_cost
V2[s] = min_action_cost
policy[s] = min_action
V1, V2 = V2, V1 #swap
count += 1
Thank you very much.
I am not sure I understand your code fully. I will just leave my implementation here in case someone needs it.
import numpy as np
def valueIteration(R, P, discount, threshold):
V = np.copy(R)
old_V = np.copy(V)
error = float("inf")
while error > threshold:
old_V, V = (V, old_V)
max_values = np.dot(P, old_V).max(axis=1)
np.copyto(V, R + discount * max_values)
error = np.linalg.norm(V - old_V)
return V
S = 30
A = 4
R = np.zeros(S)
# Goal state S-1
R[S-2] = 1
P = np.random.rand(S,A,S)
# Goal state goes to dwell state
P[S-2,:,:] = 0
P[S-2,:,S-1] = 1
P[S-1,:,:] = 0
P[S-1,:,S-1] = 1
for s in range(S-2): #goal and dwell states do not need normalization
for a in range(A):
P[s,a,:] /= P[s,a,:].sum()
V = valueIteration(R,P,0.97,0.001)

Monty Hall simulation issue regarding arrays

I am running into an issue with a simulation I did of the "Montey Hall" statistics riddle. I should get consistent results for my answer (33%/66%), but every third time I run the simulation the results end up being 0/100 and then they flip to to 66%/33%. I believe the issue might be with how I am creating my arrays (i.e the results of one simulation are bleeding over into the next simulation), but I can't pinpoint the issue. Also, if you have any tips on a better way to write my simulation, I would appreciate that as well.
Below is my code
#simulates guessing a door
def sim_guess(nsim):
answer = []
guess = [0,1,2]
stratagy = [0.2,0.6,0.2]
for element in range(nsim):
answer.append(np.random.choice(guess, p=stratagy))
return answer
#simulates placing the prize
def simulate_prizedoor(nsim):
doors = [0,1,2]
answer = []
for element in range(nsim):
answer.append(np.random.choice(doors))
return answer
#simulates opening a door to reveal a goat
def goat_door(prize, guess):
answer = []
for i in range(len(prize)):
door = [0,1,2]
if prize[i] == guess[i]:
door.remove(prize[i])
answer.append(np.random.choice(door))
else:
door.remove(prize[i])
door.remove(guess[i])
answer.append(door[0])
return answer
#simulates changing guess after goat has been revealed
def switch_guess(goat, guess):
answer = []
for i in range(len(goat)):
door = [0,1,2]
door.remove(goat[i])
door.remove(guess[i])
answer.append(door[0])
return answer
#shows percentages after 10,000 trials
def win_percentage(prize, guess):
wins = []
for element in prize:
wins.append(prize[element] == guess[element])
answer = (float(np.sum(wins))/len(guess))*100
return answer
prize = simulate_prizedoor(10000)
guess = sim_guess(10000)
#wins without changing guess
print win_percentage(prize, guess)
#wins with changing guess
goat = goat_door(prize, guess)
switch = switch_guess(goat, guess)
print win_percentage(prize, switch)
I feel like this would be a lot easier to do with objects, as each game is separate from the others. I would probably do it something like
import random
class Game:
winningDoor = 0
chosenDoor = 0
goat = 0
def __init__(self):
self.winningDoor = random.randint(1,3)
def play(self, move, willSwap):
self.chosenDoor = move
self.goat = 0
i=1
while(self.goat <= 0):
if(i != self.winningDoor and i != self.chosenDoor):
self.goat = i
i += 1
if(willSwap):
self.chosenDoor = 6-(self.chosenDoor + self.goat)
return (self.winningDoor == self.chosenDoor)
def main():
swapwins = 0
staywins = 0
for i in range(0,10000):
testswap = Game()
if(testswap.play(random.randint(1,3), 1)):
swapwins += 1
teststay = Game()
if(teststay.play(random.randint(1,3), 0)):
staywins += 1
print swapwins, staywins
main()
Here, each game is made separately, with each game being played once. It's not the most efficient use of objects, and could probably be just a subroutine for this, but if you want more statistics, this will end up being much better. The only potentially confusing thing here would be
self.chosenDoor = 6-(self.chosenDoor + self.goat)
which is a simplification of the statement that if goat is 1 and 2 was chosen, change it to 3; if goat was 2 and 3 was chosen, change it to 1; if goat was 3 and chosen was 1, change it to 2; etc...
As far as why your original code didn't work, returning all of your things in groups of 10000 looks very odd and difficult to debug. your random numbers could also be accomplished with randint, which would also make your code more human-readable.

Vector search Algorithm

I have the following problem. Say I have a vector:
v = [1,2,3,4,5,1,2,3,4,...]
I want to sequentially sample points from the vector, that have an absolute maginute difference higher than a threshold from a previously sampled point. So say my threshold is 2.
I start at the index 1, and sample the first point 1. Then my condition is met at v[3], and I sample 3 (since 3-1 >= 2). Then 3, the new sampled point becomes the reference, that I check against. The next sampled point is 5 which is v[5] (5-3 >= 2). Then the next point is 1 which is v[6] (abs(1-5) >= 2).
Unfortunately my code in R, is taking too long. Basically I am scanning the array repeatedly and looking for matches. I think that this approach is naive though. I have a feeling that I can accomplish this task in a single pass through the array. I dont know how though. Any help appreciated. I guess the problem I am running into is that the location of the next sample point can be anywhere in the array, and I need to scan the array from the current point to the end to find it.
Thanks.
I don't see a way this can be done without a loop, so here is one:
my.sample <- function(x, thresh) {
out <- x
i <- 1
for (j in seq_along(x)[-1]) {
if (abs(x[i]-x[j]) >= thresh) {
i <- j
} else {
out[j] <- NA
}
}
out[!is.na(out)]
}
my.sample(x = c(1:5,1:4), thresh = 2)
# [1] 1 3 5 1 3
You can do this without a loop using a bit of recursion:
vsearch = function(v, x, fun=NULL) {
# v: input vector
# x: threshold level
if (!length(v) > 0) return(NULL)
y = v-rep(v[1], times=length(v))
if (!is.null(fun)) y = fun(y)
i = which(y >= x)
if (!length(i) > 0) return(NULL)
i = i[1]
return(c(v[i], vsearch(v[-(1:(i-1))], x, fun=fun)))
}
With your vector above:
> vsearch(c(1,2,3,4,5,1,2,3,4), 2, abs)
[1] 3 5 1 3

Resources