I'm currently trying to program a backtrack resolver for an university project. It should resolve the job scheduling problem. I created 2 classes to do this: JobSchedulingProblem and Constraint.
class JobSchedulingProblem:
def __init__(self):
self.constraints = constrs.constraint()
self.variables={}
def checkAllconstraints(self,assignment) ->bool:
for var1,var2 in self.constraints.constraints:
result=self.check_constraint(var1,var2, assignment)
if not result:
return False
return True
def check_constraint(arg1,arg2,self,assignment) ->bool:
if (self.variables[arg1] not in assignment) or (self.variables[arg2] not in assignment):
return True
if self.constraints.constraints[arg1][arg2][1]==0:
return assignment[arg2]>=assignment[arg1]+self.constraints.constraints[arg1][arg2][0]
if self.constraints.constraints[arg1][arg2][1]==1:
return assignment[arg1]+self.constraints.constraints[arg1][arg2][0]<=assignment[arg2]
if self.constraints.constraints[arg1][arg2][1]==2:
return (assignment[arg1]+self.constraints.constraints[arg1][arg2][0]<=assignment[arg2])or(assignment[arg2]+self.constraints.constraints[arg1][arg2][0]<=assignment[arg1])
def add_variable(self, var, domain):
self.variables[var] = domain
print (self.variables.keys())
def add_constraint(self, arg1,arg2, value, type, assignment):
self.constraints.constraints[arg1][arg2]=(value,type)
if type==1:
self.constraints.constraints[arg2][arg1]=(value,0)
if type==0:
self.constraints.constraints[arg2][arg1]=(value,1)
else:
self.constraints.constraints[arg2][arg1]=(value,2)
def removeDomains(new_assignment, var,self):
removeddomains={}
for var1 in self.constraints.constraints[var]:
if self.constraints.constraints[var][var1][1]==0:
intervallo_da_rimuovere = range(1, new_assignment+1-self.constraints.constraints[var][var1][0])
# crea un nuovo range escludendo l'intervallo specificato
nuovo_dominio = list(self.variables[var1])
nuovo_dominio = list(filter(lambda x: x not in intervallo_da_rimuovere, nuovo_dominio))
self.variables[var1] = range(nuovo_dominio[0], nuovo_dominio[-1] + 1)
removeddomains[var1]=intervallo_da_rimuovere
if (self.constraints.constraints[var][var1][1]==1) or (self.constraints.constraints[var][var1][1]==2):
intervallo_da_rimuovere = range(1, new_assignment+1+self.constraints.constraints[var][var1][0])
# crea un nuovo range escludendo l'intervallo specificato
nuovo_dominio = list(self.variables[var1])
nuovo_dominio = list(filter(lambda x: x not in intervallo_da_rimuovere, nuovo_dominio))
self.variables[var1] = range(nuovo_dominio[0], nuovo_dominio[-1] + 1)
removeddomains[var1]=intervallo_da_rimuovere
return removeddomains
def putRemovedDomains(tmp, var,self):
for var1 in self.constraints.constraints[var]:
lista1 = list(tmp[var1])
lista2 = list(self.variables[var1])
lista_unione = lista1 + lista2
# Crea un nuovo range basato sulla lista unione
self.variables[var1] = range(lista_unione[0], lista_unione[-1] + 1)
def backtracking_search(self, assignment={}):
if len(assignment) == len(self.variables):
return assignment
var_not_assigned = [var for var in self.variables if var not in assignment]
var = var_not_assigned[0]
for value in self.variables[var]:
new_assignment = assignment.copy()
new_assignment[var] = value
if self.checkAllconstraints( new_assignment):
tmp = self.removeDomains(new_assignment, var, self)
result = self.backtracking_search(self, new_assignment)
if result is None:
self.putRemovedDomains(tmp,var,self)
if result is not None:
return result
return None
class constraint:
constraints={}
def __init__(self):
self.constraints = {
'Aa': {},
'Ap': {},
'Rda': {},
'Rsa': {},
'Rdp': {},
'Rsp': {},
'Dda': {},
'Dsa': {},
'Ddp': {},
'Dsp': {},
'Cda': {},
'Csa': {},
'Cdp': {},
'Csp': {},
'I': {},
}
self.constraints['Aa']['Rda']=(10,1)
self.constraints['Aa']['Rsa']=(10,1)
self.constraints['Ap']['Rdp']=(10,1)
self.constraints['Ap']['Rdp']=(10,1)
self.constraints['Rda']['Dda']=(1,1)
self.constraints['Dda']['Cda']=(2,1)
self.constraints['Rsa']['Dsa']=(1,1)
self.constraints['Ddp']['Cdp']=(2,1)
self.constraints['Rsp']['Dsp']=(1,1)
self.constraints['Dsp']['Csp']=(2,1)
self.constraints['Aa']['Ap']=(10,2)
self.constraints['Ap']['Aa']=(10,2)
self.constraints['Aa']['I']=(3,1)
self.constraints['Ap']['I']=(3,1)
self.constraints['Rda']['I']=(3,1)
self.constraints['Dda']['I']=(3,1)
self.constraints['Cda']['I']=(3,1)
self.constraints['Rsa']['I']=(3,1)
self.constraints['Dsa']['I']=(3,1)
self.constraints['Csa']['I']=(3,1)
self.constraints['Rdp']['I']=(3,1)
self.constraints['Ddp']['I']=(3,1)
self.constraints['Cdp']['I']=(3,1)
self.constraints['Rsp']['I']=(3,1)
self.constraints['Dsp']['I']=(3,1)
self.constraints['Csp']['I']=(3,1)
self.constraints['I']['Aa']=(3,0)
self.constraints['I']['Ap']=(3,0)
self.constraints['I']['Rda']=(3,0)
self.constraints['I']['Dda']=(3,0)
self.constraints['I']['Cda']=(3,0)
self.constraints['I']['Rsa']=(3,0)
self.constraints['I']['Dsa']=(3,0)
self.constraints['I']['Csa']=(3,0)
self.constraints['I']['Rdp']=(3,0)
self.constraints['I']['Ddp']=(3,0)
self.constraints['I']['Cdp']=(3,0)
self.constraints['I']['Rsp']=(3,0)
self.constraints['I']['Dsp']=(3,0)
self.constraints['I']['Csp']=(3,0)
self.constraints['Rda']['Aa']=(10,0)
self.constraints['Rsa']['Aa']=(10,0)
self.constraints['Rdp']['Ap']=(10,0)
self.constraints['Rsp']['Ap']=(10,0)
self.constraints['Dda']['Rda']=(1,0)
self.constraints['Cda']['Dda']=(2,0)
self.constraints['Dsa']['Rsa']=(1,0)
self.constraints['Csa']['Dsa']=(2,0)
self.constraints['Ddp']['Rdp']=(1,0)
self.constraints['Cdp']['Ddp']=(2,0)
self.constraints['Dsp']['Rsp']=(1,0)
self.constraints['Csp']['Dsp']=(2,0)
While trying to run it, I got 2 errors:
Exception has occurred: AttributeError 'str' object has no attribute 'variables' File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 15, in check_constraint if (self.variables[arg1] not in assignment) or (self.variables[arg2] not in assignment): File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 9, in checkAllconstraints result=self.check_constraint(var1,var2, assignment) File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 79, in backtracking_search if self.checkAllconstraints( new_assignment): File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 114, in main soluzione = csp.backtracking_search() File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 149, in main() AttributeError: 'str' object has no attribute 'variables'
or
Exception has occurred: TypeError JobSchedulingProblem.check_constraint() takes 4 positional arguments but 5 were given File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 9, in checkAllconstraints result=self.check_constraint(var1,var2, self, assignment) File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 79, in backtracking_search if self.checkAllconstraints( new_assignment): File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 114, in main soluzione = csp.backtracking_search() File "/home/alebonch/Python/Progetto IA/Backtrackjobscheduling.py", line 149, in main() TypeError: JobSchedulingProblem.check_constraint() takes 4 positional arguments but 5 were given
When I tried to change:
result=self.check_constraint(var1,var2, assignment)
into:
result=self.check_constraint(var1,var2, self, assignment)
I tried asking chatGPT for help, but Im really confused by how the variables become strings and by the fact that the editor thinks Im passing more arguments than Im supposed to do. Its my first time programming in python and I probably made lots of mistakes, any help would be really appreciated.
Class functions in Python have an automatic first argument of
self, which is the instance of the class that you called the function. All of your class functions (e.g.check_constraint()) should haveselfas the first argument then so there's no confusion, but when you call that function on an instance of the class (e.g.my_instance_of_JobSchedulingProblem.check_constraint()) you skip theselfargument. I think both of your errors will be resolved by makingselfthe first argument of all of your functions.