Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create redundant_facet_removal_backup.py #81

Merged
merged 23 commits into from
Oct 11, 2023
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6fd6807
Create redundant_facet_removal_backup.py
nitishmalang Oct 4, 2023
3234956
Update redundant_facet_removal_backup.py
nitishmalang Oct 4, 2023
f5a5061
Create update_gurobi_model_backup.py
nitishmalang Oct 4, 2023
3e85df2
Update redundant_facet_removal_backup.py
nitishmalang Oct 5, 2023
256ef15
Update redundant_facet_removal_backup.py
nitishmalang Oct 5, 2023
d2b8b1a
Update redundant_facet_removal_backup.py
nitishmalang Oct 5, 2023
b79313c
Rename redundant_facet_removal_backup.py to redundant_facet_removal_e…
nitishmalang Oct 6, 2023
05fa24a
Rename update_gurobi_model_backup.py to update_gurobi_model_experimen…
nitishmalang Oct 6, 2023
53d7d44
Create redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
0c200a2
Delete dingo/backup directory
nitishmalang Oct 6, 2023
19efaef
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
ed7a4c2
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
d8c0f3d
Delete dingo/experimental_gurobi_functions/update_gurobi_model_experi…
nitishmalang Oct 6, 2023
7254045
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
018003f
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
6a76a91
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
4711ef4
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
f6a741f
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
8f9936d
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
a1ac13e
Update redundant_facet_removal_experiment.py
nitishmalang Oct 6, 2023
23c0652
Update redundant_facet_removal_experiment.py
nitishmalang Oct 9, 2023
144608d
Update redundant_facet_removal_experiment.py
nitishmalang Oct 9, 2023
7fa7b21
Update redundant_facet_removal_experiment.py
nitishmalang Oct 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
# dingo : a python library for metabolic networks sampling and analysis
# dingo is part of GeomScale project

# Copyright (c) 2021 Apostolos Chalkis

# Licensed under GNU LGPL.3, see LICENCE file

import sys
import numpy as np
import scipy.sparse as sp
import gurobipy as gp
from gurobipy import GRB
import math

def update_model_constraints_and_bounds(model, Aeq_sparse=None, beq=None, A_sparse=None, b=None,
new_lower_bounds=None, new_upper_bounds=None):
if Aeq_sparse is not None and beq is not None:
# Remove the old equality constraints
model.remove("c")

# Add new equality constraints
model.addMConstr(sp.csr_matrix(Aeq_sparse), model.getVars(), "=", np.array(beq), name="c")

if A_sparse is not None and b is not None:
# Remove the old inequality constraints
model.remove("d")

# Add new inequality constraints
model.addMConstr(sp.csr_matrix(A_sparse), model.getVars(), "<", np.array(b), name="d")

if new_lower_bounds is not None or new_upper_bounds is not None:
# Retrieve the variable objects
x_vars = model.getVars()

# Update variable bounds if specified
if new_lower_bounds is not None:
for i, x_var in enumerate(x_vars):
x_var.lb = new_lower_bounds[i]

if new_upper_bounds is not None:
for i, x_var in enumerate(x_vars):
x_var.ub = new_upper_bounds[i]

# Update the model to apply the changes
model.update()

# Usage example:
# Assuming you have a Gurobi model 'model' and new constraint matrices/vectors and bounds
# Call the function to update the model
# update_model_constraints_and_bounds(model, Aeq_sparse_new, beq_new, A_sparse_new, b_new, new_lower_bounds, new_upper_bounds)


def solve_lp_with_different_objectives(model, new_objective_coeffs):
"""
Solve a linear program with a different objective function.

Parameters:
model (gurobipy.Model): The Gurobi model with the original constraints.
new_objective_coeffs (list or numpy.ndarray): List or array of new objective coefficients for the variables.

Returns:
gurobipy.Model: The updated Gurobi model with the new objective function.
"""
# Clear the existing objective function
model.setObjective(0, clear=True)
TolisChal marked this conversation as resolved.
Show resolved Hide resolved

# TODO: Optimization opportunity - You could pass a numpy array here (instead of a list of coefficients)
# and update the objective in one call without a for loop.
# For example, you can use:
# model.setObjective(new_objective_coeffs, GRB.MINIMIZE)

# Update the objective function with the new coefficients
for i, var in enumerate(model.getVars()):
TolisChal marked this conversation as resolved.
Show resolved Hide resolved
var.setAttr(GRB.Attr.Obj, new_objective_coeffs[i])

# Optimize the updated model
model.optimize()

return model


def fast_remove_redundant_facets(lb, ub, S, c, opt_percentage=100):
if lb.size != S.shape[1] or ub.size != S.shape[1]:
raise Exception(
"The number of reactions must be equal to the number of given flux bounds."
)

redundant_facet_tol = 1e-07
tol = 1e-06

m = S.shape[0]
n = S.shape[1]
beq = np.zeros(m)
Aeq_res = S

A = np.zeros((2 * n, n), dtype="float")
A[0:n] = np.eye(n)
A[n:] -= np.eye(n, n, dtype="float")

b = np.concatenate((ub, -lb), axis=0)
b = np.asarray(b, dtype="float")
b = np.ascontiguousarray(b, dtype="float")

max_biomass_flux_vector, max_biomass_objective = fast_fba(lb, ub, S, c)
val = -np.floor(max_biomass_objective / tol) * tol * opt_percentage / 100

b_res = []
A_res = np.empty((0, n), float)
beq_res = np.array(beq)

try:
with gp.Env(empty=True) as env:
env.setParam("OutputFlag", 0)
env.start()

with gp.Model(env=env) as model:
x = model.addMVar(
shape=n,
vtype=GRB.CONTINUOUS,
name="x",
lb=lb,
ub=ub,
)

Aeq_sparse = sp.csr_matrix(S)
A_sparse = sp.csr_matrix(np.array(-c))
b_sparse = np.array(val)

b = np.array(b)
beq = np.array(beq)

model.addMConstr(Aeq_sparse, x, "=", beq, name="c")
model.update()
model.addMConstr(A_sparse, x, "<", [val], name="d")
model.update()

model_iter = model.copy()

indices_iter = range(n)
removed = 1
offset = 1
facet_left_removed = np.zeros((1, n), dtype=bool)
facet_right_removed = np.zeros((1, n), dtype=bool)

while removed > 0 or offset > 0:
removed = 0
offset = 0
indices = indices_iter
indices_iter = []

Aeq_sparse = sp.csr_matrix(Aeq_res)
beq = np.array(beq_res)

b_res = []
A_res = np.empty((0, n), float)

update_model_constraints_and_bounds(model_iter, Aeq_sparse, beq, A_sparse, [val], lb, ub)


for i in indices:
objective_function = A[i]

redundant_facet_right = True
redundant_facet_left = True

objective_function_max = np.asarray(
[-x for x in objective_function]
)

model_iter = solve_lp_with_different_objectives(
model_iter.copy(), objective_function_max
)


status = model_iter.status
if status == GRB.OPTIMAL:
max_objective = -model_iter.objVal
else:
max_objective = ub[i]

if not facet_right_removed[0, i]:
ub_iter = ub.copy()
ub_iter[i] = ub_iter[i] + 1

# Call solve_lp_with_different_objectives to solve LP
model_iter = solve_lp_with_different_objectives(
model_iter.copy(), objective_function
)

status = model_iter.status
if status == GRB.OPTIMAL:
max_objective2 = -model_iter.objVal
if (
np.abs(max_objective2 - max_objective)
> redundant_facet_tol
):
redundant_facet_right = False
else:
removed += 1
facet_right_removed[0, i] = True

model_iter.reset()
x = model_iter.getVars()
for j in range(n):
x[j].LB = lb[j]
x[j].UB = ub[j]
x[j].obj = objective_function[j]

model_iter.optimize()

status = model_iter.status
if status == GRB.OPTIMAL:
min_objective = model_iter.objVal
else:
min_objective = lb[i]

if not facet_left_removed[0, i]:
lb_iter = lb.copy()
lb_iter[i] = lb_iter[i] - 1

# Call solve_lp_with_different_objectives to solve LP
model_iter = solve_lp_with_different_objectives(
model_iter.copy(), objective_function
)


status = model_iter.status
if status == GRB.OPTIMAL:
min_objective2 = model_iter.objVal
if (
np.abs(min_objective2 - min_objective)
> redundant_facet_tol
):
redundant_facet_left = False
else:
removed += 1
facet_left_removed[0, i] = True

if (not redundant_facet_left) or (not redundant_facet_right):
width = abs(max_objective - min_objective)

if width < redundant_facet_tol:
offset += 1
Aeq_res = np.vstack(
(
Aeq_res,
A[
i,
],
)
)
beq_res = np.append(
beq_res, min(max_objective, min_objective)
)
ub[i] = sys.float_info.max
lb[i] = -sys.float_info.max
else:
indices_iter.append(i)

if not redundant_facet_left:
A_res = np.append(
A_res,
np.array(
[
A[
n + i,
]
]
),
axis=0,
)
b_res.append(b[n + i])
else:
lb[i] = -sys.float_info.max

if not redundant_facet_right:
A_res = np.append(
A_res,
np.array(
[
A[
i,
]
]
),
axis=0,
)
b_res.append(b[i])
else:
ub[i] = sys.float_info.max
else:
ub[i] = sys.float_info.max
lb[i] = -sys.float_info.max

b_res = np.asarray(b_res)
A_res = np.asarray(A_res, dtype="float")
A_res = np.ascontiguousarray(A_res, dtype="float")

return A_res, b_res, Aeq_res, beq_res

except gp.GurobiError as e:
print("Error code " + str(e.errno) + ": " + str(e))
except AttributeError:
print("Gurobi solver failed.")


Loading