@@ -389,7 +389,7 @@ function _indices_and_coefficients(
389389)
390390 i = 1
391391 for term in f. terms
392- indices[i] = Cint (_info (model, term. variable_index). column )
392+ indices[i] = Cint (column (model, term. variable_index))
393393 coefficients[i] = term. coefficient
394394 i += 1
395395 end
@@ -422,6 +422,8 @@ function _info(model::Optimizer, key::MOI.VariableIndex)
422422 throw (MOI. InvalidIndex (key))
423423end
424424
425+ column (model, x:: MOI.VariableIndex ) = _info (model, x). column
426+
425427function MOI. add_variable (model:: Optimizer )
426428 # Initialize `VariableInfo` with a dummy `VariableIndex` and a column,
427429 # because we need `add_item` to tell us what the `VariableIndex` is.
@@ -569,8 +571,8 @@ function MOI.set(
569571 num_vars = length (model. variable_info)
570572 obj = zeros (Float64, num_vars)
571573 for term in f. terms
572- column = _info (model, term. variable_index). column
573- obj[column ] += term. coefficient
574+ col = column (model, term. variable_index)
575+ obj[col ] += term. coefficient
574576 end
575577 for (col, coef) in enumerate (obj)
576578 glp_set_obj_coef (model, col, coef)
@@ -619,6 +621,10 @@ function _info(
619621 return throw (MOI. InvalidIndex (c))
620622end
621623
624+ function column (model, c:: MOI.ConstraintIndex{MOI.SingleVariable, <:Any} )
625+ return _info (model, c). column
626+ end
627+
622628function MOI. is_valid (
623629 model:: Optimizer ,
624630 c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}
@@ -862,7 +868,7 @@ function MOI.get(
862868 c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}} ,
863869)
864870 MOI. throw_if_not_valid (model, c)
865- lower = glp_get_col_lb (model, _info (model, c). column )
871+ lower = glp_get_col_lb (model, column (model, c))
866872 return MOI. GreaterThan (lower)
867873end
868874
@@ -872,7 +878,7 @@ function MOI.get(
872878 c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}} ,
873879)
874880 MOI. throw_if_not_valid (model, c)
875- upper = glp_get_col_ub (model, _info (model, c). column )
881+ upper = glp_get_col_ub (model, column (model, c))
876882 return MOI. LessThan (upper)
877883end
878884
@@ -882,7 +888,7 @@ function MOI.get(
882888 c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}} ,
883889)
884890 MOI. throw_if_not_valid (model, c)
885- lower = glp_get_col_lb (model, _info (model, c). column )
891+ lower = glp_get_col_lb (model, column (model, c))
886892 return MOI. EqualTo (lower)
887893end
888894
@@ -892,9 +898,9 @@ function MOI.get(
892898 c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.Interval{Float64}} ,
893899)
894900 MOI. throw_if_not_valid (model, c)
895- info = _info (model, c)
896- lower = glp_get_col_lb (model, info . column )
897- upper = glp_get_col_ub (model, info . column )
901+ col = column (model, c)
902+ lower = glp_get_col_lb (model, col )
903+ upper = glp_get_col_ub (model, col )
898904 return MOI. Interval (lower, upper)
899905end
900906
@@ -906,8 +912,7 @@ function MOI.set(
906912) where {S<: _SCALAR_SETS }
907913 MOI. throw_if_not_valid (model, c)
908914 lower, upper = _bounds (s)
909- info = _info (model, c)
910- _set_variable_bound (model, info. column, lower, upper)
915+ _set_variable_bound (model, column (model, c), lower, upper)
911916 return
912917end
913918
@@ -1411,14 +1416,18 @@ function MOI.optimize!(model::Optimizer)
14111416 else
14121417 _solve_linear_problem (model)
14131418 end
1414- if MOI. get (model, MOI. ResultCount ()) > 0
1415- if MOI. get (model, MOI. PrimalStatus ()) == MOI. INFEASIBILITY_CERTIFICATE
1416- model. unbounded_ray = fill (NaN , glp_get_num_cols (model))
1417- _get_unbounded_ray (model, model. unbounded_ray)
1418- end
1419- if MOI. get (model, MOI. DualStatus ()) == MOI. INFEASIBILITY_CERTIFICATE
1420- model. infeasibility_cert = fill (NaN , glp_get_num_rows (model))
1421- _get_infeasibility_ray (model, model. infeasibility_cert)
1419+ if _certificates_potentially_available (model)
1420+ (status, _) = _get_status (model)
1421+ if status == MOI. DUAL_INFEASIBLE
1422+ ray = zeros (glp_get_num_cols (model))
1423+ if _get_unbounded_ray (model, ray)
1424+ model. unbounded_ray = ray
1425+ end
1426+ elseif status == MOI. INFEASIBLE
1427+ ray = zeros (glp_get_num_rows (model))
1428+ if _get_infeasibility_ray (model, ray)
1429+ model. infeasibility_cert = ray
1430+ end
14221431 end
14231432 end
14241433 model. solve_time = time () - start_time
@@ -1561,7 +1570,7 @@ function MOI.get(model::Optimizer, attr::MOI.PrimalStatus)
15611570 elseif status == MOI. LOCALLY_INFEASIBLE
15621571 return MOI. INFEASIBLE_POINT
15631572 elseif status == MOI. DUAL_INFEASIBLE
1564- if _certificates_potentially_available ( model)
1573+ if model. unbounded_ray != = nothing
15651574 return MOI. INFEASIBILITY_CERTIFICATE
15661575 end
15671576 else
@@ -1579,7 +1588,7 @@ function MOI.get(model::Optimizer, attr::MOI.DualStatus)
15791588 if status == MOI. OPTIMAL
15801589 return MOI. FEASIBLE_POINT
15811590 elseif status == MOI. INFEASIBLE
1582- if _certificates_potentially_available ( model)
1591+ if model. infeasibility_cert != = nothing
15831592 return MOI. INFEASIBILITY_CERTIFICATE
15841593 end
15851594 end
@@ -1622,9 +1631,9 @@ function MOI.get(model::Optimizer, attr::MOI.VariablePrimal, x::MOI.VariableInde
16221631 _throw_if_optimize_in_progress (model, attr)
16231632 MOI. check_result_index_bounds (model, attr)
16241633 if model. unbounded_ray != = nothing
1625- return model. unbounded_ray[_info (model, x). column ]
1634+ return model. unbounded_ray[column (model, x)]
16261635 else
1627- return _get_col_primal (model, _info (model, x). column )
1636+ return _get_col_primal (model, column (model, x))
16281637 end
16291638end
16301639
@@ -1650,18 +1659,33 @@ function _dual_multiplier(model::Optimizer)
16501659 return MOI. get (model, MOI. ObjectiveSense ()) == MOI. MIN_SENSE ? 1.0 : - 1.0
16511660end
16521661
1662+ function _farkas_variable_dual (model:: Optimizer , col:: Int )
1663+ nnz = glp_get_mat_col (model, col, C_NULL , C_NULL )
1664+ vind = Vector {Cint} (undef, nnz)
1665+ vval = Vector {Cdouble} (undef, nnz)
1666+ nnz = glp_get_mat_col (model, Cint (col), offset (vind), offset (vval))
1667+ return sum (
1668+ model. infeasibility_cert[row] * val for (row, val) in zip (vind, vval)
1669+ )
1670+ end
1671+
16531672function MOI. get (
1654- model:: Optimizer , attr:: MOI.ConstraintDual ,
1655- c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}
1673+ model:: Optimizer ,
1674+ attr:: MOI.ConstraintDual ,
1675+ c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}} ,
16561676)
16571677 _throw_if_optimize_in_progress (model, attr)
16581678 MOI. check_result_index_bounds (model, attr)
1659- column = _info (model, c). column
1679+ col = column (model, c)
1680+ if model. infeasibility_cert != = nothing
1681+ dual = _farkas_variable_dual (model, col)
1682+ return min (dual, 0.0 )
1683+ end
16601684 reduced_cost = if model. method == SIMPLEX || model. method == EXACT
1661- glp_get_col_dual (model, column )
1685+ glp_get_col_dual (model, col )
16621686 else
16631687 @assert model. method == INTERIOR
1664- glp_ipt_col_dual (model, column )
1688+ glp_ipt_col_dual (model, col )
16651689 end
16661690 sense = MOI. get (model, MOI. ObjectiveSense ())
16671691 # The following is a heuristic for determining whether the reduced cost
@@ -1683,17 +1707,22 @@ function MOI.get(
16831707end
16841708
16851709function MOI. get (
1686- model:: Optimizer , attr:: MOI.ConstraintDual ,
1687- c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}
1710+ model:: Optimizer ,
1711+ attr:: MOI.ConstraintDual ,
1712+ c:: MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}} ,
16881713)
16891714 _throw_if_optimize_in_progress (model, attr)
16901715 MOI. check_result_index_bounds (model, attr)
1691- column = _info (model, c). column
1716+ col = column (model, c)
1717+ if model. infeasibility_cert != = nothing
1718+ dual = _farkas_variable_dual (model, col)
1719+ return max (dual, 0.0 )
1720+ end
16921721 reduced_cost = if model. method == SIMPLEX || model. method == EXACT
1693- glp_get_col_dual (model, column )
1722+ glp_get_col_dual (model, col )
16941723 else
16951724 @assert model. method == INTERIOR
1696- glp_ipt_col_dual (model, column )
1725+ glp_ipt_col_dual (model, col )
16971726 end
16981727 sense = MOI. get (model, MOI. ObjectiveSense ())
16991728 # The following is a heuristic for determining whether the reduced cost
@@ -1715,23 +1744,29 @@ function MOI.get(
17151744end
17161745
17171746function MOI. get (
1718- model:: Optimizer , attr:: MOI.ConstraintDual ,
1719- c:: MOI.ConstraintIndex{MOI.SingleVariable, S}
1747+ model:: Optimizer ,
1748+ attr:: MOI.ConstraintDual ,
1749+ c:: MOI.ConstraintIndex{MOI.SingleVariable, S} ,
17201750) where {S <: Union{MOI.EqualTo, MOI.Interval} }
17211751 _throw_if_optimize_in_progress (model, attr)
17221752 MOI. check_result_index_bounds (model, attr)
1723- return _get_col_dual (model, _info (model, c). column)
1753+ col = column (model, c)
1754+ if model. infeasibility_cert != = nothing
1755+ return _farkas_variable_dual (model, col)
1756+ end
1757+ return _get_col_dual (model, col)
17241758end
17251759
17261760function MOI. get (
1727- model:: Optimizer , attr:: MOI.ConstraintDual ,
1728- c:: MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, <:Any}
1761+ model:: Optimizer ,
1762+ attr:: MOI.ConstraintDual ,
1763+ c:: MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, <:Any} ,
17291764)
17301765 _throw_if_optimize_in_progress (model, attr)
17311766 MOI. check_result_index_bounds (model, attr)
17321767 row = _info (model, c). row
17331768 if model. infeasibility_cert != = nothing
1734- return model. infeasibility_cert[row]
1769+ return - model. infeasibility_cert[row]
17351770 else
17361771 @assert ! model. last_solved_by_mip
17371772 if model. method == SIMPLEX || model. method == EXACT
@@ -1911,7 +1946,7 @@ function MOI.modify(
19111946 chg:: MOI.ScalarCoefficientChange{Float64}
19121947)
19131948 row = Cint (_info (model, c). row)
1914- col = _info (model, chg. variable). column
1949+ col = column (model, chg. variable)
19151950 nnz = glp_get_mat_row (model, row, C_NULL , C_NULL )
19161951 indices, coefficients = zeros (Cint, nnz), zeros (Cdouble, nnz)
19171952 glp_get_mat_row (model, row, offset (indices), offset (coefficients))
@@ -1933,9 +1968,7 @@ function MOI.modify(
19331968 c:: MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}} ,
19341969 chg:: MOI.ScalarCoefficientChange{Float64}
19351970)
1936- glp_set_obj_coef (
1937- model, _info (model, chg. variable). column, chg. new_coefficient
1938- )
1971+ glp_set_obj_coef (model, column (model, chg. variable), chg. new_coefficient)
19391972 return
19401973end
19411974
@@ -1979,8 +2012,8 @@ function MOI.get(
19792012 c:: MOI.ConstraintIndex{MOI.SingleVariable, S} ,
19802013) where {S <: _SCALAR_SETS }
19812014 _throw_if_optimize_in_progress (model, attr)
1982- column = _info (model, c). column
1983- vbasis = glp_get_col_stat (model, column )
2015+ col = column (model, c)
2016+ vbasis = glp_get_col_stat (model, col )
19842017 if vbasis == GLP_BS
19852018 return MOI. BASIC
19862019 elseif vbasis == GLP_NL
0 commit comments