How to use a LifoQueue for function calls? - python

I am making a Sudoku solver and want to make the instructions go one at a time, in a LIFO structure to resemble how most (or at least I) play Sudoku.
The relevant parts of my solver class -
class SudokuSolver():
possible_answers = None
def __init__(self, board):
self.board = board
self.instruction_stack = LifoQueue()
...
def work_on_group(self, group_num):
print(f"working on group {group_num}")
def work_on_row(self, row):
print(f"working on row {row}")
def work_on_column(self, column):
print(f"working on column {column}")
def do_next_step(self):
if self.instruction_stack.empty():
self.instruction_stack.put(self.work_on_group(9))
self.instruction_stack.put(self.work_on_group(8))
...
self.instruction_stack.put(self.work_on_group(2))
self.instruction_stack.put(self.work_on_group(1))
self.instruction_stack.pop()
Where eventually my work_on_group, work_on_row and work_on_column functions will have criteria that will add instructions to the stack as results unfold. However, right now, what I am getting when I try do_next_step() is
working on group 9
working on group 8
...
working on group 2
working on group 1
So it seems like my functions are evaluating as I put them into the stack instead of waiting for me to pop them.
Ideally, what I would see when this runs correctly, is only
working on group 1
since that's the last instruction given, and I only have one pop command.
One other thing of note - those these three functions only need one paramter, I can see more complex functions based on the board that would require more parameters, and would like my stack/pop to be able to handle that - store the function reference and then run with with an arbitrary number of *args **kwargs. How can I accomplish this?
Edit:
I've come up with this which works and I think would work fro an arbitrary number of positional parameters, but don't know how I would incorporate keyword argument with this.
def do_next_step(self):
if self.instruction_stack.empty():
self.instruction_stack.put((self.work_on_group,(9)))
self.instruction_stack.put((self.work_on_group,(8)))
self.instruction_stack.put((self.work_on_group,(7)))
self.instruction_stack.put((self.work_on_group,(6)))
self.instruction_stack.put((self.work_on_group,(5)))
self.instruction_stack.put((self.work_on_group,(4)))
self.instruction_stack.put((self.work_on_group,(3)))
self.instruction_stack.put((self.work_on_group,(2)))
self.instruction_stack.put((self.work_on_group,(1)))
func, params = self.instruction_stack.get()
func(params)

I got this working by changing my do_next_step function to the following
def do_next_step(self):
"""
Creates, and then does, next step into stack.
"""
if self.instruction_stack.empty():
self.instruction_stack.put((self.work_on_group,(9,),{}))
self.instruction_stack.put((self.work_on_group,(8,),{}))
self.instruction_stack.put((self.work_on_group,(7,),{}))
self.instruction_stack.put((self.work_on_group,(6,),{}))
self.instruction_stack.put((self.work_on_group,(5,),{}))
self.instruction_stack.put((self.work_on_group,(4,),{}))
self.instruction_stack.put((self.work_on_group,(3,),{}))
self.instruction_stack.put((self.work_on_group,(2,),{}))
self.instruction_stack.put((self.work_on_group,(1,),{}))
func, params, keyword_params = self.instruction_stack.get()
func(*params, **keyword_params)

Related

Function vs if-statement: Function is not working, but the code in the function will work when outside a function?

I was working on building a randomized character generator for Pathfinder 3.5 and got stuck.
I am using the Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill): function to populate a randiomized list of skills with their class based points total, class bonus, and point buy. So modelling the action of a player picking skills for their character.
As an example below, Wizards.
I pick Knowledge_Arcana as a skill and spend one of my skill point pool (Calculated by taking my intelligence modifier +2) on it. So that skill now equals my intelligence modifier(+1 in this case), class skill bonus as a wizard (+3), plus the point I spent(+1) for a total of 5.
The problem is while the function prints the correct result of 5, the outstanding variables do not populate with the final total. To continue our example I'd run the function on Knowledge_Arcana, get a +5, and then check the Knowledge_Arcana after the function call and get just +1. Conversely, if I write out the function as just an if statement it works. Example is next to the function for comparison.
Does anyone know why Im getting the different result?
## Creating the lists and breaking into two separate sections
Int_Mod = 1
Skill_Ranks = 3
Rand_Class = 'Wizard'
Knowledge_Arcana = Int_Mod
Knowledge_Dungeoneering = Int_Mod
Wizard_Class_Top_Skills = ["Knowledge_Arcana"]
Wizard_Class_Less_Skills = ["Knowledge_Dungeoneering"]
Class_Skill = 3
Important_Skills_Weighted = .6
Less_Important_Skills_Weighted = .4
Important_Skills_Total_Weighted = round(Skill_Ranks*Important_Skills_Weighted)
Less_Skill_Total_Weighted = round(Skill_Ranks*Less_Important_Skills_Weighted)
Wiz_Draw =['Knowledge_Arcana', 'Knowledge_Dungeoneering']
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
## Function Calls
Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
Populate_Skills('Knowledge_Dungeoneering', Wiz_Draw, Knowledge_Dungeoneering, Class_Skill)
print(Knowledge_Arcana,Knowledge_Dungeoneering)
Edited to be a MRE, I believe. Sorry folks, Im new.
You are passing in a reference to a list and expect the function to modify it; but you are reassigning the variable inside the function which creates a local variable, which is then lost when the function is exited. You want to manipulate the same variable which the caller passed in, instead.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List.extend(Class_Skill + Draw.count(Skill_String))
print(Skill_String, Skill_List)
else:
print('Nuts!')
Alternatively, have the function return the new value, and mandate for the caller to pick it up and assign it to the variable.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
return Skill_List
Skill_List = Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
# etc
You should probably also rename your variables (capital letters should be used for classes and globals; regular Python functions and variables should use snake_case) and avoid using global variables at all. The entire program looks like you should probably look into refactoring it into objects, but that's far beyond the scope of what you are asking.

Nothing is output in python recursive function

List item
I'm working on a code that calculates the 'distance' between two configurations of a Flip Cube, The distance between two configurations x and y is the minimum number of steps required to go from x to y, or conversely.
To make that I've created a simpler version that makes something different, this code takes two integer numbers ci and cf. with ci returns an iterable called main_level through the generator called multi, then, it iterates through it searching for the parameter cf, whenever cf is not in main_level the variable steps is increased by 1 and for each element in main_level we repeat the same process done for ci. Finally, when cii==cf the program ends and returns the steps variable, which counts the number of "levels" that we have to go down to find the given parameter cf. This code doesn't have any practical purpose is just a base for the problem I mentioned above.
If I call the distance(ci, cf) function with ci=5, the first two levels are:
{0,3,6,9,12} <-- first level (steps is initialized with 1)
if cf is any of the numbers in the set, the program should end and return steps=1,
if cf is not in that set, the programs form the second level:
{15,18,21,24,27,30,33} and search cf, if cf is there, the program ends and should return steps=2, if not, it forms the third level, and so on. But there is a problem, actually, when I call the distance function with ci=5 and cf= any natural number, and print its value, anything is output, only for cf=0, it outputs step=1. I don't really know what's going on. I would appreciate your help.
Here is the code:
#Base solution to FlipCube problem
def multi(par):
for i in range(par):
yield i*3
steps=1
def distance(ci,cf):
main_level =set(multi(ci))
global steps
def check_main_level(cf):
global steps
nonlocal main_level
def lower_level(config_list):
sett=set()
for i in config_list:
sett.update(q for q in multi(i) if q not in config_list)
nonlocal main_level
main_level=sett
check_main_level(cf)
for i in main_level:
if i==cf:
break
else:
steps+=1
lower_level(main_level)
check_main_level(cf)
return steps
#testing
e= distance(5,0)
print(e)# prints 1, very good
e2= distance(5,9)
print(e2)# should print 1, but doesn't print anything :(
e3= distance(5,27)
print(e3)# should print 2, but doesn't print anything :(
The program does not terminate recursion under all circumstances. The culprit seems to be the for loop in check_main_level. Change the code after your definition of lower_level to:
# code portion of check_main_level
if cf > max(main_level):
steps+=1
lower_level(main_level)
# end of code portion check_main_level (replacing for-loop)
you have an infinity loop, that's why nothing is printed.
You can see it easyly by adding a print :
for i in config_list:
print(i)
sett=set()
sett.update(q for q in list(multi(i)) if q not in config_list)

Curious about effect of recursion of a method

I have written an instance method which uses recursion to find a certain solution. It works perfectly fine except the time when I'm exiting the if-elif block. I call the function itself inside IF block. Also, I have only one return statement. The output from the method is weird for me to understand. Here is the code and the output:
def create_schedule(self):
"""
Creates the day scedule for the crew based on the crew_dict passed.
"""
sched_output = ScheduleOutput()
assigned_assignements = []
for i in self.crew_list:
assigned_assignements.extend(i.list_of_patients)
rest_of_items = []
for item in self.job.list_of_patients:
if item not in assigned_assignements:
rest_of_items.append(item)
print("Rest of the items are:", len(rest_of_items))
if len(rest_of_items) != 0:
assignment = sorted(rest_of_items, key=lambda x: x.window_open)[0]
# print("\nNext assignment to be taken ", assignment)
output = self.next_task_eligibility(assignment, self.crew_list)
if len(output) != 0:
output_sorted = sorted(output, key=itemgetter(2))
crew_to_assign = output_sorted[0][1]
assignment.eta = output_sorted[0][4]
assignment.etd = int(assignment.eta) + int(assignment.care_duration)
crew = next((x for x in self.crew_list if x.crew_number == crew_to_assign), None)
self.crew_list.remove(crew)
crew.list_of_patients.append(assignment)
crew.time_spent = assignment.etd
self.crew_list.append(crew)
self.create_schedule()
else:
print("*" * 80, "\n", "*" * 80, "\nWe were not able to assign a task so stopped.\n", "*" * 80, "\n", "*" * 80)
sched_output.crew_output = self.crew_list
sched_output.patients_left = len(rest_of_items)
elif not rest_of_items:
print("Fully solved.")
sched_output.crew_output = self.crew_list
sched_output.patients_left = 0
print("After completely solving coming here.")
return sched_output
This was the output:
Rest of the items are: 10
Rest of the items are: 9
Rest of the items are: 8
Rest of the items are: 7
Rest of the items are: 6
Rest of the items are: 5
Rest of the items are: 4
Rest of the items are: 3
Rest of the items are: 2
Rest of the items are: 1
Rest of the items are: 0
Fully solved.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
What I don't understand is that as soon as my list rest_of_items is empty, I assign data to sched_output and return it. However, print statement is being executed for the same number of time as recursion was done. How can I avoid this?
My output is perfectly fine. All I want to do is understand the cause of this behaviour and how to avoid it.
The reason it's printing out 11 times is that you always call print at the end of the function, and you're calling the function 11 times. (It's really the same reason you get Rest of the items are: … 11 times, which should be a lot more obvious.)
Often, the best solution is to redesign things so instead of doing "side effects" like print inside the function, you just return a value, and the caller can then do whatever side effects it wants with the result. In that case, it doesn't matter that you're calling print 11 times; the print will only happen once, in the caller.
If that isn't possible, you can change this so that you only print something when you're at the top of the stack. But in many recursive functions, there's no obvious way to figure that out without passing down more information:
def create_schedule(self, depth=0):
# etc.
self.create_schedule(depth+1)
# etc.
if not depth:
print('After completely solving come here.')
returns sched_output
The last resort is to just wrap the recursive function, like this:
def _create_schedule(self):
# etc.
self._create_schedule()
# etc.
# don't call print
return sched_output
def create_schedule(self):
result = self._create_schedule()
print('After completely solving come here.')
return result
That's usually only necessary when you need to do some one-time setup for the recursive process, but here you want to do some one-time post-processing instead, which is basically the same problem, so it can be solved the same way.
(Of course this is really just the first solution in disguise, but it's hidden inside the implementation of create_schedule, so you don't need to change the interface that the callers see.)
As you call your create_schedule function within itself before the function finishes, once it has gotten to the end and doesn't need to call itself again, each function ends, and hits the "After completely solving coming here.", at the end of the function.
This means that each function, after calling itself, is still running - just stuck at the line where it calls itself - until they have all completed, which is when the paused functions can finish their task, printing out your statement.
You have print("After completely solving coming here.") at the end of your recursive function. That line will be executed once for each recursion.
Consider this simple example, which recreates your issue:
def foo(x):
print("x = {x}".format(x=x))
if x > 1:
foo(x-1)
print("Done.")
Now call the function:
>>> foo(5)
x = 5
x = 4
x = 3
x = 2
x = 1
Done.
Done.
Done.
Done.
Done.
As you can see, on the final call to foo(x=0), it will print "Done.". At that point, the function will return to the previous call, which will also print "Done." and so on.

At certain levels of functions, where does the final function returns the value?

This question may sound silly, but this is what I'm going through, I wrote a project with some modules, and certan levels of functions, as one function calls the another one and so on, the final function to return the result, a dictionary.
when I call the function on the first level, everything works well to the last funciton,
while at the last function,
printing the return dictionary works well while returning the dictionary with return result return None
I have a finite number of functions, spread over different modules.
# on module 1
def funciton_one(the_user_input):
# code to process param at
# stage 1 if conditions are met
function_two(parameter,the_user_input)
# on module 2
def function_two(parameter,the_user_input):
# code to process param at
# stage 2 if conditions are met
function_three(parameter,the_user_input)
# on module 3
def function_three(parameter,the_user_input):
# code to process param at
# stage 3 if conditions are met
function_four(parameter,the_user_input)
# on module 4
def function_four(parameter,the_user_input):
# code to process param at
# stage 4 if conditions are met
function_five(parameter,the_user_input)
# on module 5
def function_five(parameter,the_user_input):
# code to process param at
# stage 5 if conditions are met
function_six(parameter,the_user_input)
# on module 1
def function_six(parameter,the_user_input):
# code to the process parameter and original parameter
# stage 6 if conditions are met
return result
user_input = 'blahblah'
processed = function_one(user_input)
what I'm doing wrong here?
Edit:
Its like input is passed through all the functions, (the input to the first function is the original_parameter) and the parameter is processed values at different levels.
Update:
Much mess up, renaming the variables.
Thanks.
I take it you want to get your final output into processed? You need to return the final result to each of the functions, so function_six returns to function_five, returns to function_four, etc., until function_one returns into the processed variable.
I changed your code slightly to make it work (there was no original_param in function_one. Next time, please make sure your example code is valid before posting it.
# on module 1
def function_one(parameter):
return function_two(parameter,parameter)
# on module 2
def function_two(parameter,original_param):
return function_three(parameter,original_param)
# on module 3
def function_three(parameter,original_param):
return function_four(parameter,original_param)
# on module 4
def function_four(parameter,original_param):
return function_five(parameter,original_param)
# on module 5
def function_five(parameter,original_param):
return function_six(parameter,original_param)
# on module 1
def function_six(parameter,original_param):
result = "foobar"
return result # returns foobar
user_input = 'blahblah'
processed = function_one(user_input)
print processed # prints foobar
You want each function to return the result of the call to the next one.
There should be a variable to hold the value/dict/list in every function that you are passing to. Means there should be like var=function1(...) and so on

Python Algorithm Challenge?

I have a python function (call it myFunction) that gets as input a list of numbers, and, following a complex calculation, returns back the result of the calculation (which is a number).
The function looks like this:
def myFunction( listNumbers ):
# initialize the result of the calculation
calcResult = 0
# looping through all indices, from 0 to the last one
for i in xrange(0, len(listNumbers), 1):
# some complex calculation goes here, changing the value of 'calcResult'
# let us now return the result of the calculation
return calcResult
I tested the function, and it works as expected.
Normally, myFunction is provided a listNumbers argument that contains 5,000,000 elements in it. As you may expect, the calculation takes time. I need this function to run as fast as possible
Here comes the challenge: assume that the time now is 5am, and that listNumbers contains just 4,999,999 values in it. Meaning, its LAST VALUE is not yet available. This value will only be available at 6am.
Obviously, we can do the following (1st mode): wait until 6am. Then, append the last value into listNumbers, and then, run myFunction. This solution works, BUT it will take a while before myFunction returns our calculated result (as we need to process the entire list of numbers, from the first element on). Remember, our goal is to get the results as soon as possible past 6am.
I was thinking about a more efficient way to solve this (2nd mode): since (at 5am) we have listNumbers with 4,999,999 values in it, let us immediately start running myFunction. Let us process whatever we can (remember, we don't have the last piece of data yet), and then -- exactly at 6am -- 'plug in' the new data piece -- and generate the computed result. This should be significantly faster, as most of the processing will be done BEFORE 6am, hence, we will only have to deal with the new data -- which means the computed result should be available immediately after 6am.
Let's suppose that there's no way for us to inspect the code of myFunction or modify it. Is there ANY programming technique / design idea that will allow us to take myFunction AS IS, and do something with it (without changing its code) so that we can have it operate in the 2nd mode, rather than the 1st one?
Please do not suggest using c++ / numpy + cython / parallel computing etc to solve this problem. The goal here is to see if there's any programming technique or design pattern that can be easily used to solve such problems.
You could use a generator as an input. The generator will only return when there is data available to process.
Update: thanks for the brilliant comment, I wanted to remove this entry :)
class lazylist(object):
def __init__(self):
self.cnt = 0
self.length = 5000000
def __iter__(self):
return self
def __len__(self):
return self.length
def next(self):
if self.cnt < self.length:
self.cnt += 1
#return data here or wait for it
return self.cnt #just return a counter for this example
else:
raise StopIteration()
def __getitem__(self, i):
#again, block till you have data.
return i+1 #simple counter
myFunction(lazylist())
Update: As you can see from the comments and other solutions your loop construct and len call causes a lot of headaches, if you can eliminate it you can use a lot more elegant solution. for e in li or enumerate is the pythonic way to go.
By "list of numbers", do you mean an actual built-in list type?
If not, it's simple. Python uses duck-typing, so passing any sequence that supports iteration will do. Use the yield keyword to pass a generator.
def delayed_list():
for val in numpy_array[:4999999]:
yield val
wait_until_6am()
yield numpy_array[4999999]
and then,
myFunction(delayed_list())
If yes, then it's trickier :)
Also, check out PEP8 for recommended Python code style:
no spaces around brackets
my_function instead of myFunction
for i, val in enumerate(numbers): instead of for i in xrange(0, len(listNumbers), 1): etc.
subclass list so that when the function tries to read the last value it blocks until another thread provides the value.
import threading
import time
class lastblocks(list):
def __init__(self,*args,**kwargs):
list.__init__(self,*args,**kwargs)
self.e = threading.Event()
def __getitem__(self, index):
v1 = list.__getitem__(self,index)
if index == len(self)-1:
self.e.wait()
v2 = list.__getitem__(self,index)
return v2
else:
return v1
l = lastblocks(range(5000000-1)+[None])
def reader(l):
s = 0
for i in xrange(len(l)):
s += l[i]
print s
def writer(l):
time.sleep(10)
l[5000000-1]=5000000-1
l.e.set()
print "written"
reader = threading.Thread(target=reader, args=(l,))
writer = threading.Thread(target=writer, args=(l,))
reader.start()
writer.start()
prints:
written
12499997500000
for numpy:
import threading
import time
import numpy as np
class lastblocks(np.ndarray):
def __new__(cls, arry):
obj = np.asarray(arry).view(cls)
obj.e = threading.Event()
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.e = getattr(obj, 'e', None)
def __getitem__(self, index):
v1 = np.ndarray.__getitem__(self,index)
if index == len(self)-1:
self.e.wait()
v2 = np.ndarray.__getitem__(self,index)
return v2
else:
return v1
l = lastblocks(np.asarray(range(5000000-1)+[None]))
def reader(l):
s = 0
for i in xrange(len(l)):
s += l[i]
print s
def writer(l):
time.sleep(10)
l[5000000-1]=5000000-1
l.e.set()
print "written"
reader = threading.Thread(target=reader, args=(l,))
writer = threading.Thread(target=writer, args=(l,))
reader.start()
writer.start()
Memory protection barriers are a general way to solve this type of problem when the techniques suggested in the other answers (generators and mock objects) are unavailable.
A memory barrier is a hardware feature that causes an interrupt when a program tries to access a forbidden area of memory (usually controllable at the page level). The interrupt handler can then take appropriate action, for example suspending the program until the data is ready.
So in this case you'd set up a barrier on the last page of the list, and the interrupt handler would wait until 06:00 before allowing the program to continue.
You could just create your own iterator to iterate over the 5,000,000 elements. This would do whatever you need to do to wait around for the final element (can't be specific since the example in the question is rather abstract). I'm assuming you don't care about the code hanging until 6:00, or know how to do it in a background thread.
More information about writing your own iterator is at http://docs.python.org/library/stdtypes.html#iterator-types
There is a simpler generator solution:
def fnc(lst):
result = 0
index = 0
while index < len(lst):
while index < len(lst):
... do some manipulations here ...
index += 1
yield result
lst = [1, 2, 3]
gen = fnc(lst)
print gen.next()
lst.append(4)
print gen.next()
I'm a little bit confused about not being able to investigate myFunction. At least you have to know if your list is being iterated or accessed by index. Your example might suggest an index is used. If you want to take advantage of iterators/generators, you have to iterate. I know you said myFunction is unchangeable, but just want to point out, that most pythonic version would be:
def myFunction( listNumbers ):
calcResult = 0
# enumerate if you really need an index of element in array
for n,v in enumerate(listNumbers):
# some complex calculation goes here, changing the value of 'calcResult'
return calcResult
And now you can start introducing nice ideas. One is probably wrapping list with your own type and provide __iter__ method (as a generator); you could return value if accessible, wait for more data if you expect any or return after yielding last element.
If you have to access list by index, you can use __getitem__ as in Dan D's example. It'll have a limitation though, and you'll have to know the size of array in advance.
Couldn't you simply do something like this:
processedBefore6 = myFunction([1,2,3]) # the first 4,999,999 vals.
while lastVal.notavailable:
sleep(1)
processedAfter6 = myFunction([processedBefore6, lastVal])
If the effects are linear (step 1 -> step 2 -> step 3, etc) this should allow you to do as much work as possible up front, then catch the final value when it's available and finish up.

Categories

Resources