Trying to get a loop to restart when using a shuffled array - python

Dear Stackoverflow fam,
I wish to run some experiments whereby I import some parameters for a stimulus (random dot kinematogram) and I chose to do this by creating a CSV with said parameters (total of 8 parameters I wish to cycle through). I need to pseudo-randomise the trials so I used the numpy.random.shuffle function to create this array. With this new array "shuffledRDK" i made the following loop
for b in range(2):
for fps in range(120):
blank_trial.draw()
mywin.flip()
time.sleep(6)
print("Trial: " +str(trial_counter) + " , Orientation " +str(shuffledRDK[x,0]) + " Coherence " +str(shuffledRDK[x,1]))
trial_counter += 1
if x in range (9):
x += 1
for fps in range(120):
SignalDots = visual.DotStim(win=mywin, color=(1, 1, 1), dir=(shuffledRDK[x-1,0]), coherence=(shuffledRDK[x-1,1]), fieldSize=(20,20), speed=1, dotSize=5, dotLife=3, nDots=50, fieldShape='circle')
SignalDots.draw()
mywin.flip()
My issue is that at the end of the 8th parameter I wish for the cycle to start again. I get IndexError: index 8 is out of bounds for axis 0 with size 8 which I understand is out of the boundaries of the array but I don't know how to restart it. I've tried putting in if x > 8 statements or similar lines but I still get the index error. Would someone be able to help me out please?
Many thanks in advance

You shouldn't have to increment x up each time; it will do it on it's own as it iterates through the loop. I suppose you are doing this because you want your x to start at 1 and end at 9? you can specify that range explicitly.
for b in range(2):
for fps in range(120):
blank_trial.draw()
mywin.flip()
time.sleep(6)
print("Trial: " +str(trial_counter) + " , Orientation " +str(shuffledRDK[x,0]) + " Coherence " +str(shuffledRDK[x,1]))
trial_counter += 1
if x in range (1, 9):
for fps in range(120):
SignalDots = visual.DotStim(win=mywin, color=(1, 1, 1), dir=(shuffledRDK[x-1,0]), coherence=(shuffledRDK[x-1,1]), fieldSize=(20,20), speed=1, dotSize=5, dotLife=3, nDots=50, fieldShape='circle')
SignalDots.draw()
mywin.flip()

here is a variant using the data.createFactorialTrialList() permutation method and a .yaml configuration file
i edited the for loops to my understanding, as i cannot deduct what you are trying to do completely
from psychopy import core, visual, event, data
from psychopy.iohub.client import launchHubServer
import yaml
io = launchHubServer()
display = io.devices.display
mywin = visual.Window([640, 480], units='pix')
factors_info = yaml.load(open('stim_factors.yaml'))
stim_permutation = data.createFactorialTrialList(factors_info)
trial_handler = data.TrialHandler(trialList = stim_permutation, method ='random', nReps = 1)
for b in range(1):
for fps in range(1):
for stim in trial_handler:
print(f'stim {trial_handler.thisN + 1:d}/{trial_handler.nTotal:d}')
signal_dots = visual.DotStim(win=mywin, color=(1, 1, 1),
dir = trial_handler.thisTrial['dir'],
coherence = trial_handler.thisTrial['coher'],
fieldSize = trial_handler.thisTrial['field_size'],
speed = trial_handler.thisTrial['speed'],
dotSize = trial_handler.thisTrial['dot_size'],
dotLife = trial_handler.thisTrial['dot_life'],
nDots = trial_handler.thisTrial['n_dots'],
fieldShape = 'circle')
signal_dots.draw()
mywin.flip(); event.waitKeys()
io.quit(); mywin.close()
core.quit()
you can see the contents of the .yaml file on the picture's left

Related

Making a random int just be itself once in loop [duplicate]

This question already has answers here:
Generate 'n' unique random numbers within a range [duplicate]
(4 answers)
Closed 12 days ago.
So.. im working on this loop:
stuff_so_far = [intl_pt]
for i in range(0, num_pts - 1):
rdm = random.randint(0, len(points_in_code) - 1)
a = (stuff_so_far[i][0] + points_in_code[rdm][0]) // 2
b = (stuff_so_far[i][1] + points_in_code[rdm][1]) // 2
stuff_so_far.append((a, b))
Basically what i want to achive is to get a random index for "points_in_code" every time the code loops. It is doing that now, but what i want to know is, how do i make it not randomly repeat a number? As in, if in the first iteration of the loop rdm gets set to 1, and then in the second iteration of the loop rdm gets set to 3, and in some cases, rdm can be set to 1 again in the third itertion. How do i make it not be 1 again (as long as the loop is still going)?
Ive tried everything i know and searched online but i found nothing, how do i make that happen without altering my code too much? (im new to programming)
I know each time i call random.randint(), i am creating a single random number, it does not magically change to a new random not used before number everytime the loop iterates.
You can use random.sample:
import random
points_in_code = [11, 4, 13, 18, 7, 12] # Just a example
num_pts = 4
indexes = random.sample(range(len(points_in_code)), num_pts - 1)
for rdm, i in zip(indexes, range(0, num_pts - 1)):
pass # rdm will be a random unique index
# i will increase 1 each iteration
You could also use enumerate(indexes) instead of zip(indexes, range(0, num_pts - 1)) but then you would need to reverse i and rdm.
See the documentation for random.sample for more info. See also info on zip and enumerate
You can use an Array for keep track of which random number you already used. You only need to regenerate the random number if you get one which you already had.
stuff_so_far = [intl_pt]
tracking_num = [] # keeps track of the random number that was alreadey used.
for i in range(num_pts - 1): # small tip you can create a for-loop without the zero in the beginning.
# while loop in which a number will be regenerated if the current random number
# is contained in the 'tracking_num' array.
rdm = random.randint(0, len(points_in_code) - 1)
while tracking_num.__contains__(rdm):
rdm = random.randint(0, len(points_in_code) - 1)
a = (stuff_so_far[i][0] + points_in_code[rdm][0]) // 2
b = (stuff_so_far[i][1] + points_in_code[rdm][1]) // 2
stuff_so_far.append((a, b))
Try below approach
import random as rnd
## Lets say you want at max 100
MAX=100
arr = [i for i in range(101)]
while True:
curr = rnd.choice(arr)
arr.remove(curr)
print(curr)
if len(arr)==0: break
Your code :
stuff_so_far = [intl_pt]
choice_arr = [i for i in range(len(points_in_code))]
for i in range(0, num_pts - 1):
rdm = random.choice(choice_arr)
choice_arr.remove(rdm)
if len(choice_arr)==0:
print("No more choices available")
break
a = (stuff_so_far[i][0] + points_in_code[rdm][0]) // 2
b = (stuff_so_far[i][1] + points_in_code[rdm][1]) // 2
stuff_so_far.append((a, b))

I used return, however the recursion does not end. help me please

I am doing a question that gives me a start coordinate, a end coordinate and the number of times of moving.Every time you can add 1 or minus 1 to x or y coordinate based on previous coordinate and the number of moving limit the time the coordinate can move. At last, I need to identify whether there is a possibility to get to the end coordinate
I decide to use recursion to solve this problem however, it does not end even if I wrote return inside a if else statement. Do you mind to take a look at it.
This is the code
# https://cemc.uwaterloo.ca/contests/computing/2017/stage%201/juniorEF.pdf
# input
start = input()
end = input()
count = int(input())
coo_end = end.split(' ')
x_end = coo_end[0]
y_end = coo_end[1]
end_set = {int(x_end), int(y_end)}
#processing
coo = start.split(' ')
x = int(coo[0])
y = int(coo[1])
change_x = x
change_y = y
sum = x + y+count
set1 = set()
tim = 0
timer = 0
ways = 4** (count-1)
def elit(x, y, tim,timer, ways = ways):
print(tim,timer)
tim = tim +1
co1 = (x, y+1)
co2 = (x+1, y)
co3 = (x, y-1)
co4 = (x-1, y)
if tim == count:
tim =0
set1.add(co1)
set1.add(co2)
set1.add(co3)
set1.add(co4)
print(timer)
timer = timer +1
if timer == ways:
print('hiii')
return co1, co2, co3, co4 #### this is the place there is a problem
elit(co1[0],co1[1],tim,timer)
elit(co2[0],co2[1],tim,timer)
elit(co3[0],co3[1],tim, timer)
elit(co4[0],co4[1],tim, timer)
#print(elit(change_x,change_y,tim)) - none why
elit(change_x,change_y,tim, timer)
#print(list1)
for a in set1:
if end_set != a:
answer = 'N'
continue
else:
answer = "Y"
break
print(answer)
In addition, if you have any suggestions about writing this question, do you mind to tell me since I am not sure I am using the best solution.
one of example is
Sample Input
3 4 (start value)
3 3 (end value)
3 (count)
Output for Sample Input
Y
Explanation
One possibility is to travel from (3, 4) to (4, 4) to (4, 3) to (3, 3).
the detailed question can be seen in this file https://cemc.uwaterloo.ca/contests/computing/2017/stage%201/juniorEF.pdf
It is question 3. Thank you
thank you guys
the function is returning properly however by the time you reach the recursive depth to return anything you have called so many instances of the function that it seems like its in an infinite loop
when you call elite the first time the function calls itself four more times, in the example you have given timer is only incremented every 3 cycles and the function only return once timer hits 16 thus the function will need to run 48 times before returning anything and each time the function will be called 4 more times, this exponential growth means for this example the function will be called 19807040628566084398385987584 times, which depending on your machine may well take until the heat death of the universe
i thought i should add that i think you have somewhat over complicated the question, on a grid to get from one point to another the only options are the minimum distance or that same minimum with a diversion that must always be a multiple of 2 in length, so if t the movement is at least the minimum distance or any multiple of 2 over the result should be 'Y', the minimum distance will just be the difference between the coordinates on each axis this can be found by add in the difference between the x and y coordinates
abs(int(start[0]) - int(end[0])) + abs(int(start[1]) -int(end[1]))
the whole function therefore can just be:
def elit():
start = input('start: ').split(' ')
end = input('end: ').split(' ')
count = int(input('count: '))
distance = abs(int(start[0]) - int(end[0])) + abs(int(start[1]) -int(end[1]))
if (count - distance) % 2 == 0:
print('Y')
else:
print('N')
input:
3 4
3 3
3
output:
Y
input:
10 4
10 2
5
output:
N

Python multiprocessing: how to create x number of processes and get return value back

I have a program that I created using threads, but then I learned that threads don't run concurrently in python and processes do. As a result, I am trying to rewrite the program using multiprocessing, but I am having a hard time doing so. I have tried following several examples that show how to create the processes and pools, but I don't think it's exactly what I want.
Below is my code with the attempts I have tried. The program tries to estimate the value of pi by randomly placing points on a graph that contains a circle. The program takes two command-line arguments: one is the number of threads/processes I want to create, and the other is the total number of points to try placing on the graph (N).
import math
import sys
from time import time
import concurrent.futures
import random
import multiprocessing as mp
def myThread(arg):
# Take care of imput argument
n = int(arg)
print("Thread received. n = ", n)
# main calculation loop
count = 0
for i in range (0, n):
x = random.uniform(0,1)
y = random.uniform(0,1)
d = math.sqrt(x * x + y * y)
if (d < 1):
count = count + 1
print("Thread found ", count, " points inside circle.")
return count;
# end myThread
# receive command line arguments
if (len(sys.argv) == 3):
N = sys.argv[1] # original ex: 0.01
N = int(N)
totalThreads = sys.argv[2]
totalThreads = int(totalThreads)
print("N = ", N)
print("totalThreads = ", totalThreads)
else:
print("Incorrect number of arguments!")
sys.exit(1)
if ((totalThreads == 1) or (totalThreads == 2) or (totalThreads == 4) or (totalThreads == 8)):
print()
else:
print("Invalid number of threads. Please use 1, 2, 4, or 8 threads.")
sys.exit(1)
# start experiment
t = int(time() * 1000) # begin run time
total = 0
# ATTEMPT 1
# processes = []
# for i in range(totalThreads):
# process = mp.Process(target=myThread, args=(N/totalThreads))
# processes.append(process)
# process.start()
# for process in processes:
# process.join()
# ATTEMPT 2
#pool = mp.Pool(mp.cpu_count())
#total = pool.map(myThread, [N/totalThreads])
# ATTEMPT 3
#for i in range(totalThreads):
#total = total + pool.map(myThread, [N/totalThreads])
# p = mp.Process(target=myThread, args=(N/totalThreads))
# p.start()
# ATTEMPT 4
# with concurrent.futures.ThreadPoolExecutor() as executor:
# for i in range(totalThreads):
# future = executor.submit(myThread, N/totalThreads) # start thread
# total = total + future.result() # get result
# analyze results
pi = 4 * total / N
print("pi estimate =", pi)
delta_time = int(time() * 1000) - t # calculate time required
print("Time =", delta_time, " milliseconds")
I thought that creating a loop from 0 to totalThreads that creates a process for each iteration would work. I also wanted to pass in N/totalThreads (to divide the work), but it seems that processes take in an iterable list rather than an argument to pass to the method.
What is it I am missing with multiprocessing? Is it at all possible to even do what I want to do with processes?
Thank you in advance for any help, it is greatly appreciated :)
I have simplified your code and used some hard-coded values which may or may not be reasonable.
import math
import concurrent.futures
import random
from datetime import datetime
def myThread(arg):
count = 0
for i in range(0, arg[0]):
x = random.uniform(0, 1)
y = random.uniform(0, 1)
d = math.sqrt(x * x + y * y)
if (d < 1):
count += 1
return count
N = 10_000
T = 8
_start = datetime.now()
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = {executor.submit(myThread, (int(N / T),)): _ for _ in range(T)}
total = 0
for future in concurrent.futures.as_completed(futures):
total += future.result()
_end = datetime.now()
print(f'Estimate for PI = {4 * total / N}')
print(f'Run duration = {_end-_start}')
A typical output on my machine looks like this:-
Estimate for PI = 3.1472
Run duration = 0:00:00.008895
Bear in mind that the number of threads you start is effectively managed by the ThreadPoolExecutor (TPE) [ when constructed with no parameters ]. It makes decisions about the number of threads that can run based on your machine's processing capacity (number of cores etc). Therefore you could, if you really wanted to, set T to a very high number and the TPE will block execution of any new threads until it determines that there is capacity.

Restore corrupt 128-bit key from SHA-1

Disclaimer: This is a section from a uni assignment
I have been given the following AES-128-CBC key and told that up to 3 bits in the key have been changed/corrupt.
d9124e6bbc124029572d42937573bab4
The original key's SHA-1 hash is provided;
439090331bd3fad8dc398a417264efe28dba1b60
and I have to find the original key by trying all combinations of up to 3 bit flips.
Supposedly this is possible in 349633 guesses however I don't have a clue where that number came from; I would have assumed it would be closer to 128*127*126 which would be over 2M combinations, that's where my first problem lies.
Secondly, I created the python script below containing a triple nested loop (I know, far from the best code...) to iterate over all 2M possibilities however, after completion an hour later, it hadn't found any matches which I really don't understand.
Hoping someone can atleast point me in the right direction, cheers
#!/usr/bin/python2
import sys
import commands
global binary
def inverseBit(index):
global binary
if binary[index] == "0":
return "1"
return "0"
if __name__ == '__main__':
if len(sys.argv) != 3:
print "Usage: bitflip.py <hex> <sha-1>"
sys.exit()
global binary
binary = ""
sha = str(sys.argv[2])
binary = str(bin(int(sys.argv[1], 16)))
binary = binary[2:]
print binary
b2 = binary
tries = 0
file = open("shas", "w")
for x in range(-2, 128):
for y in range(-1,128):
for z in range(0,128):
if x >= 0:
b2 = b2[:x] + inverseBit(x) + b2[x+1:]
if y >= 0:
b2 = b2[:y] + inverseBit(y) + b2[y+1:]
b2 = b2[:z] + inverseBit(z) + b2[z+1:]
#print b2
hexOut = hex(int(b2,2))
command = "echo -n \"" + hexOut + "\" | openssl sha1"
cmdOut = str(commands.getstatusoutput(command))
cmdOut = cmdOut[cmdOut.index('=')+2:]
cmdOut = cmdOut[:cmdOut.index('\'')]
file.write(str(hexOut) + " | " + str(cmdOut) + "\n")
if len(cmdOut) != 40:
print cmdOut
if cmdOut == sha:
print "Found bit reversals in " + str(tries) + " tries. Corrected key:"
print hexOut
sys.exit()
b2 = binary
tries = tries + 1
if tries % 10000 == 0:
print tries
EDIT:
Changing for loop to
for x in range(-2, 128):
for y in range(x+1,128):
for z in range(y+1,128):
drastically cuts down on the number of guesses while (I think?) still covering the whole space. Still getting some duplicates and still no luck finding the match though..
Your code, if not very efficient, looks fine except for one thing:
hexOut = hex(int(b2,2))
as the output of hex
>>> hex(int('01110110000101',2))
'0x1d85'
starts with 'Ox', which shouldn't be part of the key. So, you should be fine by removing these two characters.
For the number of possible keys to try, you have:
1 with no bit flipped
128 with 1 bit flipped
128*127/2 = 8128 with 2 bits flipped (128 ways to choose the first one, 127 ways to choose the second, and each pair will appear twice)
128*127*126/6 = 341376 with 3 bits flipped (each triplet appears 6 times). This is the number of combinations of 128 bits taken 3 at a time.
So, the total is 1 + 128 + 8128 + 341376 = 349633 possibilities.
Your code tests each of them many times. You could avoid a the useless repetitions by looping like this (for 3 bits):
for x in range (0, 128):
for y in range(x+1, 128):
for z in range(y+1, 128):
.....
You could adapt your trick of starting at -2 with:
for x in range (-2, 128):
for y in range(x+1, 128):
for z in range(y+1, 128):
.... same code you used ...
You could also generate the combinations with itertools.combinations:
from itertools import combinations
for x, y, z in combinations(range(128), 3): # for 3 bits
......
but you'd need a bit more work to manage the cases with 0, 1, 2 and 3 flipped bits in this case.

Python interval interesction

My problem is as follows:
having file with list of intervals:
1 5
2 8
9 12
20 30
And a range of
0 200
I would like to do such an intersection that will report the positions [start end] between my intervals inside the given range.
For example:
8 9
12 20
30 200
Beside any ideas how to bite this, would be also nice to read some thoughts on optimization, since as always the input files are going to be huge.
this solution works as long the intervals are ordered by the start point and does not require to create a list as big as the total range.
code
with open("0.txt") as f:
t=[x.rstrip("\n").split("\t") for x in f.readlines()]
intervals=[(int(x[0]),int(x[1])) for x in t]
def find_ints(intervals, mn, mx):
next_start = mn
for x in intervals:
if next_start < x[0]:
yield next_start,x[0]
next_start = x[1]
elif next_start < x[1]:
next_start = x[1]
if next_start < mx:
yield next_start, mx
print list(find_ints(intervals, 0, 200))
output:
(in the case of the example you gave)
[(0, 1), (8, 9), (12, 20), (30, 200)]
Rough algorithm:
create an array of booleans, all set to false seen = [False]*200
Iterate over the input file, for each line start end set seen[start] .. seen[end] to be True
Once done, then you can trivially walk the array to find the unused intervals.
In terms of optimisations, if the list of input ranges is sorted on start number, then you can track the highest seen number and use that to filter ranges as they are processed -
e.g. something like
for (start,end) in input:
if end<=lowest_unseen:
next
if start<lowest_unseen:
start=lowest_unseen
...
which (ignoring the cost of the original sort) should make the whole thing O(n) - you go through the array once to tag seen/unseen and once to output unseens.
Seems I'm feeling nice. Here is the (unoptimised) code, assuming your input file is called input
seen = [False]*200
file = open('input','r')
rows = file.readlines()
for row in rows:
(start,end) = row.split(' ')
print "%s %s" % (start,end)
for x in range( int(start)-1, int(end)-1 ):
seen[x] = True
print seen[0:10]
in_unseen_block=False
start=1
for x in range(1,200):
val=seen[x-1]
if val and not in_unseen_block:
continue
if not val and in_unseen_block:
continue
# Must be at a change point.
if val:
# we have reached the end of the block
print "%s %s" % (start,x)
in_unseen_block = False
else:
# start of new block
start = x
in_unseen_block = True
# Handle end block
if in_unseen_block:
print "%s %s" % (start, 200)
I'm leaving the optimizations as an exercise for the reader.
If you make a note every time that one of your input intervals either opens or closes, you can do what you want by putting together the keys of opens and closes, sort into an ordered set, and you'll be able to essentially think, "okay, let's say that each adjacent pair of numbers forms an interval. Then I can focus all of my logic on these intervals as discrete chunks."
myRange = range(201)
intervals = [(1,5), (2,8), (9,12), (20,30)]
opens = {}
closes = {}
def open(index):
if index not in opens:
opens[index] = 0
opens[index] += 1
def close(index):
if index not in closes:
closes[index] = 0
closes[index] += 1
for start, end in intervals:
if end > start: # Making sure to exclude empty intervals, which can be problematic later
open(start)
close(end)
# Sort all the interval-endpoints that we really need to look at
oset = {0:None, 200:None}
for k in opens.keys():
oset[k] = None
for k in closes.keys():
oset[k] = None
relevant_indices = sorted(oset.keys())
# Find the clear ranges
state = 0
results = []
for i in range(len(relevant_indices) - 1):
start = relevant_indices[i]
end = relevant_indices[i+1]
start_state = state
if start in opens:
start_state += opens[start]
if start in closes:
start_state -= closes[start]
end_state = start_state
if end in opens:
end_state += opens[end]
if end in closes:
end_state -= closes[end]
state = end_state
if start_state == 0:
result_start = start
result_end = end
results.append((result_start, result_end))
for start, end in results:
print(str(start) + " " + str(end))
This outputs:
0 1
8 9
12 20
30 200
The intervals don't need to be sorted.
This question seems to be a duplicate of Merging intervals in Python.
If I understood well the problem, you have a list of intervals (1 5; 2 8; 9 12; 20 30) and a range (0 200), and you want to get the positions outside your intervals, but inside given range. Right?
There's a Python library that can help you on that: python-intervals (also available from PyPI using pip). Disclaimer: I'm the maintainer of that library.
Assuming you import this library as follows:
import intervals as I
It's quite easy to get your answer. Basically, you first want to create a disjunction of intervals based on the ones you provide:
inters = I.closed(1, 5) | I.closed(2, 8) | I.closed(9, 12) | I.closed(20, 30)
Then you compute the complement of these intervals, to get everything that is "outside":
compl = ~inters
Then you create the union with [0, 200], as you want to restrict the points to that interval:
print(compl & I.closed(0, 200))
This results in:
[0,1) | (8,9) | (12,20) | (30,200]

Categories