I want to access the value of gurobi variable self.a and self.b here but its returning 0.0. How can I access the value of these variables. The code is below
from gurobipy import GRB, Model
class abc(object):
def __init__(self):
self.model = Model()
def creatingvarriables(self):
self.a = self.model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="y_")
self.b = self.model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="q_")
self.model.update()
def constraint1(self):
lhs1 = self.model.getVarByName("y_")
lhs1 = 2
rhs1 = self.model.getVarByName("q_")
rhs1 = 3
self.model.update()
self.model.addConstr(lhs1, GRB.LESS_EQUAL, rhs1)
def printvalues(self):
self.model.optimize()
#self.model.printAttr('')
print self.a.X
print self.b.X
if __name__ == "__main__":
newobject = abc()
newobject.creatingvarriables()
newobject.constraint1()
newobject.printvalues()
You can access it's value by calling the variable's *.X attribute, as explained in GUROBI's documentation. For reference, the direct link to the attribute: X Attribute
You are correctly accessing the variable values through the X attribute. The reason why you get confused by the zero solution is an error in the method constraint1:
lhs1 = self.model.getVarByName("y_")
lhs1 = 2
rhs1 = self.model.getVarByName("q_")
rhs1 = 3
self.model.update()
self.model.addConstr(lhs1, GRB.LESS_EQUAL, rhs1)
First you assign to lhs1 and rhs1 references to the created variables, but then you overwrite them with numbers. Effectively you are adding the constraint 2 <= 3, which is satisfied independently of y_ and q_. Hence, setting y_ and q_ to zero is an optimal solution.
Related
I have implemented a Depth-first search algorithm, and using an instance variable called "call-count", I am trying to track how many recursions/comparisons are executed inside the code, i.e. how many times "searchDFS" is ran. Inside "searchDFS", the call_count variable defaults to the instance variable the first time searchDFS is ran, then it is passed down through every recursion. All of the other instance variables work fine, I am able to append to the top-level instance array "final_path" just fine, but it refuses to increment call_count.
What am I doing wrong, and is there a better way to do this?
The code:
class Node:
def __init__(self, id, connections):
self.id = id
self.connections = connections
class DFS:
def __init__(self):
self.visited = {}
self.nodes = []
self.final_path = []
self.call_count = 0
def searchDFS(self, nodes, target, current, call_count=None, final_path=None, visited=None):
if(visited == None): visited = self.visited
if(final_path == None): final_path = self.final_path
if(call_count == None): call_count = self.call_count
call_count +=1 # <<< to increment every time searchDFS is ran
if current in visited.keys():
print(f'already visited node {current}')
return 0
else:
print(f'current -> {current}')
visited[current] = 1
if(current == target):
print('found!')
final_path.append(current)
return True
if(nodes[current].connections):
for node in nodes[current].connections:
if(self.searchDFS(nodes, target, node.id, call_count, final_path, visited)):
final_path.append(current)
if(current == 0):
print(final_path[::-1])
print(f'call count: {call_count}') # not incrementing !!! :(
return True
return False
def setup_graph(self):
for x in range(0, 5):
self.nodes.append(Node(x, []))
self.nodes[0].connections = [self.nodes[1], self.nodes[2]]
self.nodes[1].connections = [self.nodes[0], self.nodes[3]]
self.nodes[2].connections = [self.nodes[0], self.nodes[4]]
self.nodes[3].connections = [self.nodes[1]]
self.nodes[4].connections = [self.nodes[2]]
def print_graph(self):
for node in self.nodes:
print(f"node id: {node.id}")
print("children: ")
for childs in node.connections:
print(childs.id)
def main(self):
print('main() init')
self.setup_graph()
self.print_graph()
self.searchDFS(self.nodes, 4, 0)
if __name__ == "__main__":
DFS().main()
Solved thanks to #slothrop (in-depth explanation)
The difference comes down to "rebinding the name" versus "mutating the value"
Primitives are immutable in Python - They cannot be changed, only new ones created (and the variable name is re-bound to the new value):
x = 5
x = x + 1
The above creates a new block of memory with the new value, 6. Then, x rebinds to that new value. It is similar to how pointers work in C.
Unassigned values are automatically discarded by Python's garbage collector. The memory cell that was holding the '5' will be cleared, since it is no longer assigned to any variable.
Assignment never copies data, so assigning one variable to another won't make a second copy of the first, it just gives it 'directions' on where to look to find the value.
x = 5 # creates a value 5, with 'x' pointing to it
y = x # y is now pointing/bound to that same value, 5, as well
x = x + 1 # a new value, 6, is created, and x is "bound" to it
print(x) # outputs 6
print(y) # outputs 5
'y' is still "bound/looking" at the original '5'. There are also mutable values, like Lists. Lists contain a built-in function to append to themselves.
x = [1, 2]
y = x
x.append(3)
print(y) # outputs [1, 2, 3]
Since List is a class, it can have methods to change in-place, without having to create a completely new value like primitives.
In my code, when I assigned "call_count = self.call_count", I only pointed the value of "call_count" to the same value of instance variable "self.call_count". Incrementing "call_count" only assigns a new value for the local variable "call_count" without re-assigning the original instance variable "self.call_count". To fix this, I just made a function to update the instance's value, and bound a variable to that method inside my search function:
class DFS:
def __init__(self):
self.call_count = 0
def increment_call_count(self):
self.call_count += 1
def searchDFS(self, counter=0, inc=None):
if(inc == None): inc = self.increment_call_count # set once
inc() # execute the function which "inc" is pointing at
if(counter<5):
self.searchDFS(counter + 1, inc)
if(counter == 0): print(self.call_count) # prints 6 correctly
def main(self):
self.searchDFS()
if __name__ == "__main__":
DFS().main()
Since inc is only bound once to a single function, the 'value' of inc never changes, using it will just run that same function, which re-binds the original instance's variable to the new value.
I have a piece of code below:
// The only difference is grad
class TestOne(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = False)
class TestTwo(...):
def init(self):
self.input_one = tr.allocate( ..., grad = True)
self.input_two = tr.allocate( ..., grad = False)
class TestThree(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = True)
Test1 = TestOne()
Test2 = TestTwo()
Test3 = TestThree()
# definition of allocate. It is a wrapper of the PyTorch randn function
# https://pytorch.org/docs/stable/torch.html#torch.randn
def allocate(..., grad):
...
return torch.randn(..., require_grad=grad)
I want to reduce the duplicate code by implementing just one class but able to generate same objects as the code above.
class Test(...):
// how to make it return different values?
def auto_set(self):
return False
def init(self):
self.input_one = tr.allocate( ..., grad = self.auto_set())
self.input_two = tr.allocate( ..., grad = self.auto_set())
Test1 = Test()
# grad of input_one and input_two will be `False, False`
Test2 = Test()
# grad of input_one and input_two will be `True, False`
Test3 = Test()
# grad of input_one and input_two will be `False, True`
This is part of a big project, so I can't change the interface of the init function. There could be N number of inputs which would require N + 1 different classes. That is not a scalable implementation so want to find a solution to solve that.
PS: My previous question was causing too many confusions to others so I changed it hoping to clarify on what I really want to have.
Just posting my solution here:
class Test(object):
init_counter = 0
num_variable = 0
def increase_init_counter(self):
Test.init_counter += 1
Test.auto_set_counter = 0
def auto_set(self):
if Test.init_counter == 0:
Test.num_variable += 1
return False
else:
print ("init_counter: {}, auto_set_counter: {}".format(Test.init_counter, Test.auto_set_counter))
Test.auto_set_counter += 1
if Test.init_counter == Test.auto_set_counter:
return True
else:
return False
def init(self):
self.A = self.auto_set();
self.B = False;
self.C = self.auto_set();
print ("A: {}, B: {}, C: {}".format(self.A, self.B, self.C))
=== Test
TestA = Test()
TestA.init()
for _ in range(TestA.num_variable):
TestB = copy.deepcopy(TestA)
TestB.increase_init_counter()
TestB.init()
If you find yourself using numbered variable names (e.g. v1, v2, v3) you need to stop immediately and think "Should I use a list instead?" - and the answer is "yes" in almost all cases.
Other notes:
To pick random values, make a list of possible values (in this case, [True, False]) and use random.choice()
range() can make a list of N values, which we can use to make another list of random choices (see "list comprehension" when you don't understand the [x for x in iterable] syntax).
Classes have __init__ as the constructor, you don't need a manual init function.
Classes should use a capital letter at the start of their name.
Code:
from random import choice
class Test(object):
def __init__(self, num_values):
self.values = [choice([True, False]) for _ in range(num_values)]
def see(self):
print(self.values)
for _ in range(3):
test1 = Test(3)
test1.see()
prints something like:
[False, False, False]
[True, False, True]
[True, True, False]
Let's see IIUYC...:
What you can do is to add a global, or let's say better common variable to the class definition, which is incremented when instanciating new objects of that class (and perhaps also better decremented when they are deleted).
This would give you the opportunity to implement different behaviuors of __init__() depending on the number of objects already created before.
Imagine a test class like
class Test():
i = 0
def __init__(self):
Test.i += 1
def __del__(self):
Test.i -= 1
After creating a first object, the common counter is 1:
t1 = Test()
t1.i
1
After creating a second object, the common counter is 2:
t2 = Test()
t2.i
Out: 2
... in all existing objects, because it's a common counter:
t1.i
Out: 2
Some sample implementation of what I think you want to achieve:
class Test():
i = 0
def __init__(self):
self.A = bin(Test.i)[-1] == '1'
self.B = bin(Test.i)[-2] == '1'
Test.i += 1
def __del__(self):
Test.i -= 1
t1 = Test()
print(t1.i, t1.A, t1.B)
# 1 False False
t2 = Test()
print(t2.i, t2.A, t2.B)
# 2 True False
t3 = Test()
print(t3.i, t3.A, t3.B)
# 3 False True
First of all, I suspect that what you need is a list of instance attributes (the variables in each object of the type).
class test(object):
def __init__(self):
self.v = []
# how to make it return different values?
def auto_set(self):
return False
def init(self):
self.v.append(self.auto_set())
def see(self):
print (self.v)
for _ in range(3):
test1 = test()
test1.init()
test1.see()
This will allow you to add to the attribute list. Is that enough to get you moving? We can't suggest a more thorough solution until you explain your system better.
I have two self-defined classes, one is a child of the gurobipy-class and is supposed to make a lp-model. The other one I made to store variables. Now I want to store some variables of the model class in the variables class.
Here are my classes:
class Model(gb.Model):
def __init__(self):
super().__init__()
def create_model(self, var):
dim = var.dimensions()
# variables
x = self.addVars(dim[0], dim[1], vtype=gb.GRB.BINARY, name="x")
D_l = self.addVars(dim[1], lb=0, name='D_l')
D_max = self.addVar(lb=0, name='D_max')
# objective
self.setObjective(D_max, gb.GRB.MINIMIZE)
# constraints
self.addConstrs((x.sum(i, '*') == 1 for i in range(dim[0])), name="b")
self.addConstrs((D_max >= D_l[l] for l in range(dim[1])), name="c")
self.addConstrs((D_l[l] >= var.dist_mat()[i, j] * (x[i, l] + x[j, l] - 1) for i in range(dim[0])
for j in range(dim[0]) for l in range(dim[1])), name='a')
self.update()
class Variables:
def __init__(self, data, number_of_clusters, neighbourhood_size):
self.data = data
self.number_of_clusters = number_of_clusters
self.neighbourhood_size = neighbourhood_size
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
def dist_mat(self):
from scipy.spatial import distance_matrix
return distance_matrix(self.data, self.data)
def dimensions(self):
from numpy import shape
data_objects = shape(self.data)[0]
number_of_clusters = self.number_of_clusters
return data_objects, number_of_clusters
def print_dist_mat(self):
print(self.dist_mat())
It's the x-variable I want to store. First, I tried to store it in the instance of the Model-class. I added to the init-function this line self.x = None. But it raise an AttributeError: 'x' is not a model attribute. I guess, this is because the gurobipy-class doesn't have a x attribute.
Next, I wanted to store it in an instance of the variable-class. I wanted to write a function in the model class, which should do the trick. This is the function:
def store_x(self, var):
var.x = self.x
Then, I got this error: gurobipy.GurobiError: Unable to retrieve attribute 'x', I can't understand why.
I can't even access the x-variable from outside the function. I can print it from inside the function, but nothing more. The problem is, I need this x-variable in a later stage.
How can I achieve this? How can I store the x-variable to access it at a later point? It doesn't have to be in the variable-class, any other solution is appreciated as well.
Ok first off I see an issue with Your code:
def store_x(self, var):
var.x = self.x
It Needs to be changed to :
def store_x(self, var):
self.x = var.x
This is because whatever you send in the 'var' parameter will only be a copy of whatever you actually passed. And then its scope will only last to the end of that store_x method. So instead you pass that copy and tell your variable class instance to store it inside it's x value.
As for the error you got with:
self.x = None # inside your Model class
I'm not sure why, as I tried the following and it runs fine:
class Variables:
def __init__(self):
self.data = data
self.number_of_clusters = number_of_clusters
self.neighbourhood_size = neighbourhood_size
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
So I'm updating my answer with a deeper example after getting clarification on what is needed. Here are two skeleton classes named 'Variables', 'Model', respectivly:
class Variables:
def __init__(self):
self.data = None
self.number_of_clusters = None
self.neighbourhood_size = None
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
def get_x(self,modelx):
self.x = modelx
class Model:
def __init__(self):
self.x = ({}, {})
# create your class instances here
newVar = Variables()
newModel = Model()
# one way to assign your Variable class's x attribute the tuple dict in question.
newVar.x = newModel.x
# alternate way is to create a function inside your Variable class that updates the x variable based on the argument you send it.
newVar.get_x(newModel.x)
A few days ago, I asked about passing values between instances of classes here is my post here
That problem was easy to fix especially the movement.
But now I can't pass objects between methods.
Example code:
class MyClassA(object):
def function1(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
d = MyClassB()
d.function2()
c = MyClassC(b.k) #Initializied MyClassC to be ready for receive the value p
self.x = d.f #To get back the value k from MyClassB function2()
print(self.x)
self.x1 = c.p #To get back the value k from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self,M):
self.f = M
self.k = 0
def function2(self):
self.k = self.f * 10 # k will contain (the value entry from MyClassA *10)
c = MyClassC(self.k) #To pass variable k to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
h.function1()
Otherwise whenever i try to work with instanace it gonna work right but between methods not that such fixed.
as last time this my code should give this way of result :
Insert a value ::: 9 (assume the user typed 9 here)
so the output should be:
90
90.1
here my code complation say
d = MyClassB()
TypeError: __init__() takes exactly 2 arguments (1 given)
Any way I can fix my code > It doesn't need to work only with instances; I need some function inside some class
You need to pass something to the constructor for MyClassb()...
Ok My problem is
d = MyClassB()
d.function2()
Statu is Fixed now, i got the way !!!
Correct code is this way :
class MyClassA(object):
def function1(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
b.function2()
c = MyClassC(b.k) #Initializied MyClassC to be ready for receive the value p
self.x = b.f #To get back the value k from MyClassB function2()
print(self.x)
self.x1 = c.p #To get back the value k from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self,M):
self.f = M
def function2(self):
self.k = self.f * 10 # k will contain (the value entry from MyClassA *10)
c = MyClassC(self.k) #To pass variable k to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
h.function1()
class MyClassA(object):
def __init__(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
c = MyClassC() #Initializied MyClassC to be ready for receive the value p
self.x = b.f #To get back the value f from MyClassB
print(self.x)
self.x1 = c.p #To get back the value f from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self, M):
self.f = M * 10 # f will contain (the value entry from MyClassA *10)
c = MyClassC(self.f) #To pass variable f to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
Above is my sample code, first of all it will ask for a value and store it into variable named entry.
Then the second class named MyClassB will recover the value inside entry, after processing the entry value, a new one will be stored into new variable named f which will be passed to third class named MyClassC then also back to first class.
Finally the third class does some processing of the f value and stores it into yet another variable p.
That's how my code should work when the user runs the program, and this is what it would look like:
Insert a value ::: 9 (assume the user typed 9 here)
so the output should be:
90
90.1
Unfortunately my problem is that passing the value from MyClassC to myClassA doesn't work.
It says I must pass it two argument from the first class but it'a going to get the value after executing the 2st class.
I think that I have problem with initializing instances, could someone correct my code to work the way I described?
The problem you're having is because there are two independent instances of MyClassC being created, one in MyClassA.__init__() and a separate one in MyClassB.__init__().
The easy way to fix it — not necessarily the best — would be to make MyClassB.__init__() store the MyClassC instance it creates in yet another instance attribute, and then refer to the attribute of that object when you want to retrieve the value of p.
Here's what I mean:
class MyClassA(object):
def __init__(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) # To pass the variable entry to class MyClassB
####### c = MyClassC() # Initializied MyClassC to be ready for receive the value p
self.x = b.f # To get back the value f from MyClassB
print(self.x)
self.x1 = b.c.p # To get back the value p from MyClassC instance created in MyClassB
print(self.x1)
class MyClassB(object):
def __init__(self, M):
self.f = M * 10 # f will contain (the value entry from MyClassA *10)
self.c = MyClassC(self.f) # Pass variable f to class MyClassC and save instance
class MyClassC(object):
def __init__(self, passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
In line
c = MyClassC()
it should be
c = MyClassC(b.f)
Or you could set the value p to the class MyClassC
class MyClassC(object):
def __init__(self, passedVar):
MyClassC.p = passedVar + 0.1
but keep in mind that this situation can happen
class T(object):
def __init__(self, x):
T.x = x
if __name__ == '__main__':
t1 = T(3)
print t1.x, T.x
t1.x = 1
print t1.x, T.x
t2 = T(2)
print t1.x, t2.x, T.x
# output:
3 3
1 3
1 2 2