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

addVar in highs.py doesn't add columns to the model #1681

Open
jajhall opened this issue Mar 18, 2024 · 5 comments
Open

addVar in highs.py doesn't add columns to the model #1681

jajhall opened this issue Mar 18, 2024 · 5 comments
Assignees

Comments

@jajhall
Copy link
Sponsor Member

jajhall commented Mar 18, 2024

Hence, if highspy calls are made to change model data for columns, they fail
needs self.update() call?

See mats.py

@jajhall jajhall self-assigned this Mar 18, 2024
@mathgeekcoder
Copy link

mathgeekcoder commented Mar 18, 2024

Correct, this was by design so that we can efficiently add a batch of variables. It's not ideal for people to add many variables one-by-one - but obviously it's still possible for them to do so.

For the mats.py example, instead of:

for i in range(nvars):
   h.addVar(0, inf)
   h.changeColCost(i, 1)

we can simply use:

for i in range(nvars):
   h.addVar(0, inf, 1)

h.update()  # needed since calling low-level addRow afterwards (instead of addConstr)

or (horribly):

for i in range(nvars):
   h.addVar(0, inf)
   h.update()
   h.changeColCost(i, 1)

That said, this also connects to #1679, and so it depends if we want the default API to use the new highspy interface, or directly access the base HiGHS class.

@mathgeekcoder
Copy link

BTW: I believe with the new highspy, mats.py can be rewritten from:

for i in range(nvars):
   h.addVar(0, inf)
   h.changeColCost(i, 1)
row_nnz = 2
index = np.array([0, 1])
value = np.array([1, 1], dtype=np.double)
for i in range(nvars - 1):
    index[0] = i
    index[1] = i+1
    h.addRow(1, inf, row_nnz, index, value)
h.run()

to:

X = [h.addVar(0, inf, 1)             for _ in range(nvars)]
C = [h.addConstr(X[i] + X[i+1] >= 1) for i in range(nvars - 1)]    
h.run()

@jajhall
Copy link
Sponsor Member Author

jajhall commented Mar 18, 2024

mats.py was actually my attempt to re-write

https://github.com/ERGO-Code/HiGHS/blob/highspy-modelling/examples/scip.py

when we lost the ability to build highspy with your modelling language.

Your version is even more succinct, although (keeping within the modelling language) it would work with

X = [h.addVar(obj=1) for _ in range(nvars)]
C = [h.addConstr(X[i] + X[i+1] >= 1) for i in range(nvars - 1)]
h.run()

@mathgeekcoder
Copy link

mathgeekcoder commented Mar 18, 2024

Good point. Referring to comment in #1679, if we also support addVars/addConstrs in highspy, we could simplify even further:

X = h.addVars(nvars, obj=1)
C = h.addConstrs(X[i] + X[i+1] >= 1 for i in range(nvars - 1))
h.run()

@mathgeekcoder
Copy link

mathgeekcoder commented Mar 18, 2024

That highspy code would look something like the following:

    def addVars(self, nvars, lb = 0, ub = kHighsInf, obj = 0, type=HighsVarType.kContinuous, name_prefix = None):
        return [self.addVar(lb, ub, obj, type, None if name_prefix == None else name_prefix + str(_)) for _ in range(nvars)]

    def addConstrs(self, generator, name_prefix=None):
        self.update()

        lower = []
        upper = []
        starts = [0]
        indices = []
        values = []
        nnz = 0;

        for cons in generator:
            # if we have duplicate variables, add the vals together
            vars,vals = zip(*[(var, sum(v[1] for v in Vals)) for var, Vals in groupby(sorted(zip(cons.vars, cons.vals)), key=itemgetter(0))])
            
            lower.append(cons.LHS - cons.constant)
            upper.append(cons.RHS - cons.constant)
            indices.extend(vars)
            values.extend(vals)
            
            nnz += len(vars)
            starts.append(nnz)

        new_rows = len(lower)
        super().addRows(new_rows, lower, upper, nnz, starts, indices, values);

        cons = [highs_cons(self.numConstrs - new_rows + n, self, None if name_prefix == None else name_prefix + str(n)) for n in range(new_rows)]
        self._cons.extend(cons)
        return cons

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants