getting result from doopl in python - python-3.x

Hi I'm using doOPL in python.
The following is part of my code.
with create_opl_model(model="phase0.mod",data="prob1.dat") as opl:
# tuple can be a list of tuples, a pandas dataframe...
# Generate the problem and solve it.
start_time = time.time()
opl.mute()
opl.run()
print("obj:",opl.objective_value,", time:",(time.time() - start_time))
After running it, I would like to check the result of decision variable x
opl.get_table('x')
But it doesn't work saying expecting tupleset x was passed.
I'm looking forward your help.

I think get_table() will only work for tables (aka tuple sets) that you created explicitly in post-processing. So you have to create this table in post processing.
Consider this example definition of x:
range I = 1..2;
range J = 1..4;
dvar float+ x[I][J];
In post-processing, you can do
tuple R {
int i;
int j;
float val;
}
{R} xResult = { <i,j,x[i][j]> | i in I, j in J };
With that you should be able to to opl.get_table('xResult') and in this table you should have all the triplets (i, j, x[i][j]).

Related

How to compute the average of a string of floats

temp = "75.1,77.7,83.2,82.5,81.0,79.5,85.7"
I am stuck in this assignment and unable to find a relevant answer to help.
I’ve used .split(",") and float()
and I am still stuck here.
temp = "75.1,77.7,83.2,82.5,81.0,79.5,85.7"
li = temp.split(",")
def avr(li):
av = 0
for i in li:
av += float(i)
return av/len(li)
print(avr(li))
You can use sum() to add the elements of a tuple of floats:
temp = "75.1,77.7,83.2,82.5,81.0,79.5,85.7"
def average (s_vals):
vals = tuple ( float(v) for v in s_vals.split(",") )
return sum(vals) / len(vals)
print (average(temp))
Admittedly similar to the answer by #emacsdrivesmenuts (GMTA).
However, opting to use the efficient map function which should scale nicely for larger strings. This approach removes the for loop and explicit float() conversion of each value, and passes these operations to the lower-level (highly optimised) C implementation.
For example:
def mean(s):
vals = tuple(map(float, s.split(',')))
return sum(vals) / len(vals)
Example use:
temp = '75.1,77.7,83.2,82.5,81.0,79.5,85.7'
mean(temp)
>>> 80.67142857142858

Extract list from all_simple_paths and their lengths in python

I have a long list of sources and targets that form a graph as follows:
id_a = [...] #source nodes
id_b = [...] #target nodes
distance = [..] #distance between source and target nodes
G = nx.Graph()
path, length = [], []
for a, b, c in zip(id_a, id_b, distance):
G.add_edge(a, b, weight=c)
cl is a subset of all the nodes in the graph and I want to extract the paths interconnecting all of cl together so I use all_simple_paths()
path = []
for i in range(len(cl)):
for j in range(len(cl)):
if i != j:
path.append(nx.all_simple_paths(G, source=cl[i], target=cl[j]))
I want to be able to list all the simple paths and their lengths so I try:
for i in range(len(path)):
total_length = 0
for j in range(len(path[i])-1):
source, target = path[i][j], path[i][j+1]
edge = G[source][target]
length = edge['weight']
total_length += length
length.append(total_length)
But I keep getting the error
object of type 'generator' has no len()
And I can't figure out how to convert the generator of all_simple_paths() to lists that I can iterate over and extract the full lengths of all the paths.
Any help is appreciated!
If you read the documentation of all_simple_paths, you will see that it returns a generator. So, just use extend instead of append method like this
path = []
for i in range(len(cl)):
for j in range(len(cl)):
if i != j:
path.extend(nx.all_simple_paths(G, source=cl[i], target=cl[j]))
For more info on why extend works in this case, see this answer.
Also I see in the last part of your code, you are setting length as length = edge['weight'], then appending using length.append(total_length). This will return as error, since the edge weight will be an int. Use different variable names something like this
path_weight = [] #<----- List to store all path's weights
for i in range(len(path)):
total_length = 0
for j in range(len(path[i])-1):
source, target = path[i][j], path[i][j+1]
edge = G[source][target]
length = edge['weight'] #<--- Get the weight
total_length += length
path_weight.append(total_length) #Append to the list

2-opt algorithm using generators instead for nested for loop

I am using an opt-2 approach on the TSP problem and have adapted some code I found on-line. I pass in a list road_map which is a list of tuples that contains a region (string), city (string), latitude (float) and longitude (float) like the following (lats and longs made up here)
[('South England' 'London', '32.361538', '-86.279118'),
('Yorkshire', 'Manchester', 35,6656, '-86.4543')]
I want to use this 2-opt algorithm to reorder the map and return a new map/route that contains a shorter distance than the previous one, this will be the best_map.
Below are my two functions I am using but it seems messy with the while nested fors and if statements. I think there must be a much cleaner way of doing this with generator functions, but I am unable to think how. Any ideas?
def opt2(best_map, i, j):
new_map = best_map[:]
new_map[i:j] = best_map[j:i:-1]
return new_map
def start_opt2(road_map):
best_map = road_map[:]
best_distance = compute_total_distance(best_map)
for i in range(len(best_map) + 1):
for j in range(i+1, len(best_map)):
new_map = opt2(best_map, i, j)
new_distance = compute_total_distance(new_map)
if new_distance < best_distance:
best_distance= new_distance
best_map = new_map
break
return best_map

How to apply multiprocessing in python3.x for the following nested loop

for i in range(1,row):
for j in range(1,col):
if i > j and i != j:
x = Aglo[0][i][0]
y = Aglo[j][0][0]
Aglo[j][i] = offset.myfun(x,y)
Aglo[i][j] = Aglo[j][i]
Aglo[][] is a 2D array, which consists of lists in the first row
offset.myfun() is a function defined elsewhere
This might be a trivial question but i couldn't understand how to use multiprocessing for these nested loops as x,y (used in myfun()) is different for each process(if multiprocessing is used)
Thank you
If I'm reading your code right, you are not overwriting any previously calculated values. If that's true, then you can use multiprocessing. If not, then you can't guarantee that the results from multiprocessing will be in the correct order.
To use something like multiprocessing.Pool, you would need to gather all valid (x, y) pairs to pass to offset.myfun(). Something like this might work (untested):
pairs = [(i, j, Aglo[0][i][0], Aglo[j][0][0]) for i in range(1, row) for j in range(1, col) if i > j and i != j]
# offset.myfun now needs to take a tuple instead of x, y
# it additionally needs to emit i and j in addition to the return value
# e.g. (i, j, result)
p = Pool(4)
results = p.map(offset.myfun, pairs)
# fill in Aglo with the results
for pair in pairs:
i, j, value = pair
Aglo[i][j] = value
Aglo[j][i] = value
You will need to pass in i and j to offset.myfun because otherwise there is no way to know which result goes where. offset.myfun should then return i and j along with the result so you can fill in Aglo appropriately. Hope this helps.

MATLAB: Write Dynamic matrix to Excel

I'm using MATLAB R2009a and following this example:
http://uk.mathworks.com/help/matlab/matlab_external/using-a-matlab-application-as-an-automation-client.html
I'd like to edit it so that I can write a matrix of unknown size into a column in an excel sheet, therefore not explicitly stating the range. I've attempted it this way:
%Put MATLAB data into the worksheet
Hop = [47; 53; 93; 10]; %Pretend I don't know what size this matrix is.
p = length(Hop);
p = strcat('A',num2str(p));
eActivesheetRange = e.Activesheet.get('Range','A1:p');
eActivesheetRange.Value = Hop;
However, this errors out. I've tried several variations of this to no avail. For example, using 'A:B' puts this array in columns A and B in excel and a NAN into every cell beyond my array. As I only want column A filled, using simple ('Range','A') errors out also.
Thanks in advance for any advice you can offer.
You're having issues because you're trying to use your variable p in a string directly
range = 'A1:p';
'A1:p'
This isn't going to work, you want to include the value of p. There are a number of ways you can do this.
In the code you have provided, you have already set p = 'A10' so if you wanted to append that to your range, you'd perform string concatenation
p = 'A10';
range = strcat('A1:', p);
I personally prefer to use sprintf to place the number directly into my strings rather than concatenating a bunch of strings.
p = 10;
range = sprintf('A1:A%d', p)
'A1:A10`
So if we adapt your code to use this we should get
range = sprintf('A1:A%d', numel(Hop));
eActivesheetRange = e.Activesheet.get('Range', range);
eActivesheetRange.Value = Hop;
Also just to be a little explicit, I would use numel rather than length as length is ambiguous. Also, I would flatten Hop into a column vector just to make sure that it's the proper dimension to be written to the spreadsheet.
eActivesheetRange.Value = Hop(:);
Essentially, the idea is to replace xx in 'B1:Bxx' with the number of elements in your matrix.
I tried this:
e = actxserver('Excel.Application');
eWorkbook = e.Workbooks.Add;
e.Visible = 1;
eSheets = e.ActiveWorkbook.Sheets;
eSheet1 = eSheets.get('Item',1);
eSheet1.Activate;
A = [1 2 3 4];
eActivesheetRange = e.Activesheet.get('Range','A1:A4');
eActivesheetRange.Value = A;
The above is directly from the link you shared. The reason why what you are trying to do is failing is that the p you pass into e.Activesheet.get() is a variable and not a string. To avoid this, try the following:
B = randi([0 10],10,1)
eActivesheetRange = e.Activesheet.get('Range',['B1:B' num2str(numel(B))]);
eActivesheetRange.Value = B;
Here, num2str(numel(B)) will pass in a string, which is the number of elements in B. This is variable in the sense that it depends on the number of elements in B.

Resources