@@ -364,137 +364,157 @@ function ModelAnalyzer.analyze(
364364 println(" iis resolver cannot continue because no optimizer is provided" )
365365 return out
366366 end
367- # iis = iis_elastic_filter(model, optimizer)
368- # # for now, only one iis is computed
369- # if iis !== nothing
370- # push!(out.iis, IrreducibleInfeasibleSubset(iis))
371- # end
367+ iis = iis_elastic_filter(model, optimizer)
368+ # for now, only one iis is computed
369+ if iis != = nothing
370+ push!(out. iis, IrreducibleInfeasibleSubset(iis))
371+ end
372372
373373 return out
374374end
375375
376- #=
376+ function _fix_to_zero(model, variable:: MOI.VariableIndex , :: Type{T} ) where {T}
377+ ub_idx =
378+ MOI. ConstraintIndex{MOI. VariableIndex,MOI. LessThan{T}}(variable. value)
379+ lb_idx = MOI. ConstraintIndex{MOI. VariableIndex,MOI. GreaterThan{T}}(
380+ variable. value,
381+ )
382+ has_lower = false
383+ if MOI. is_valid(model, lb_idx)
384+ MOI. delete(model, lb_idx)
385+ has_lower = true
386+ elseif MOI. is_valid(model, ub_idx)
387+ MOI. delete(model, ub_idx)
388+ else
389+ error(" Variable is not bounded" )
390+ end
391+ MOI. add_constraint(model, variable, MOI. EqualTo{T}(zero(T)))
392+ return has_lower
393+ end
377394
378- function iis_elastic_filter(original_model::JuMP.GenericModel, optimizer)
395+ function _set_bound_zero(
396+ model,
397+ variable:: MOI.VariableIndex ,
398+ has_lower:: Bool ,
399+ :: Type{T} ,
400+ ) where {T}
401+ eq_idx =
402+ MOI. ConstraintIndex{MOI. VariableIndex,MOI. EqualTo{T}}(variable. value)
403+ @assert MOI. is_valid(model, eq_idx)
404+ MOI. delete(model, eq_idx)
405+ if has_lower
406+ MOI. add_constraint(model, variable, MOI. GreaterThan{T}(zero(T)))
407+ else
408+ MOI. add_constraint(model, variable, MOI. LessThan{T}(zero(T)))
409+ end
410+ return
411+ end
379412
380- # if JuMP.termination_status(original_model) == MOI.OPTIMIZE_NOT_CALLED
381- # println("iis resolver cannot continue because model is not optimized")
382- # # JuMP.optimize!(original_model)
383- # end
413+ function iis_elastic_filter(original_model:: MOI.ModelLike , optimizer)
414+ T = Float64
384415
385- status = JuMP.termination_status(original_model)
416+ # handle optimize not called
417+ status = MOI. get(original_model, MOI. TerminationStatus())
386418 if status != MOI. INFEASIBLE
387419 println(
388420 " iis resolver cannot continue because model is found to be $(status) by the solver" ,
389421 )
390422 return nothing
391423 end
392424
393- model, reference_map = JuMP.copy_model(original_model)
394- JuMP.set_optimizer(model, optimizer)
395- JuMP.set_silent(model)
396- # TODO handle ".ext" to avoid warning
425+ model = MOI. instantiate(optimizer)
426+ reference_map = MOI. copy_to(model, original_model)
427+ MOI. set(model, MOI. Silent(), true )
397428
398- constraint_to_affine = JuMP.relax_with_penalty!(model, default = 1.0)
429+ constraint_to_affine =
430+ MOI. modify(model, MOI. Utilities. PenaltyRelaxation(default = 1.0 ))
399431 # might need to do something related to integers / binary
400432
401- JuMP.optimize!(model)
402-
403433 max_iterations = length(constraint_to_affine)
404434
405435 tolerance = 1e-5
406436
407437 de_elastisized = []
408438
409439 for i in 1 : max_iterations
410- if JuMP.termination_status(model) == MOI.INFEASIBLE
440+ MOI. optimize!(model)
441+ status = MOI. get(model, MOI. TerminationStatus())
442+ if status == MOI. INFEASIBLE
411443 break
412444 end
413445 for (con, func) in constraint_to_affine
414446 if length(func. terms) == 1
415- var = collect(keys(func.terms))[1]
416- if JuMP.value(var) > tolerance
417- has_lower = JuMP.has_lower_bound(var)
418- JuMP.fix(var, 0.0; force = true)
419- # or delete(model, var)
447+ var = func. terms[1 ]. variable
448+ value = MOI. get(model, MOI. VariablePrimal(), var)
449+ if value > tolerance
450+ has_lower = _fix_to_zero(model, var, T)
420451 delete!(constraint_to_affine, con)
421452 push!(de_elastisized, (con, var, has_lower))
422453 end
423454 elseif length(func. terms) == 2
424- var = collect(keys(func.terms))
425- coef1 = func.terms[var[1]]
426- coef2 = func.terms[var[2]]
427- if JuMP.value(var[1]) > tolerance &&
428- JuMP.value(var[2]) > tolerance
455+ var1 = func. terms[1 ]. variable
456+ coef1 = func. terms[1 ]. coefficient
457+ var2 = func. terms[2 ]. variable
458+ coef2 = func. terms[2 ]. coefficient
459+ value1 = MOI. get(model, MOI. VariablePrimal(), var1)
460+ value2 = MOI. get(model, MOI. VariablePrimal(), var2)
461+ if value1 > tolerance && value2 > tolerance
429462 error(" IIS failed due numerical instability" )
430- elseif JuMP.value(var[1]) > tolerance
431- has_lower = JuMP.has_lower_bound(var[1])
432- JuMP.fix(var[1], 0.0; force = true)
433- # or delete(model, var[1])
463+ elseif value1 > tolerance
464+ has_lower = _fix_to_zero(model, var1, T)
434465 delete!(constraint_to_affine, con)
435- constraint_to_affine[con] = coef2 * var[2]
436- push!(de_elastisized, (con, var[1], has_lower))
437- elseif JuMP.value(var[2]) > tolerance
438- has_lower = JuMP.has_lower_bound(var[2])
439- JuMP.fix(var[2], 0.0; force = true)
440- # or delete(model, var[2])
466+ constraint_to_affine[con] = coef2 * var2
467+ push!(de_elastisized, (con, var1, has_lower))
468+ elseif value2 > tolerance
469+ has_lower = _fix_to_zero(model, var2, T)
441470 delete!(constraint_to_affine, con)
442- constraint_to_affine[con] = coef1 * var[1]
443- push!(de_elastisized, (con, var[2] , has_lower))
471+ constraint_to_affine[con] = coef1 * var1
472+ push!(de_elastisized, (con, var2 , has_lower))
444473 end
445474 else
446475 println(
447476 " $con and relaxing function with more than two terms: $func " ,
448477 )
449478 end
450- JuMP.optimize!(model)
451479 end
452480 end
453481
454482 # consider deleting all no iis constraints
455483 # be careful with intervals
456484
457485 # deletion filter
458- cadidates = JuMP.ConstraintRef []
486+ cadidates = MOI . ConstraintIndex []
459487 for (con, var, has_lower) in de_elastisized
460- JuMP.unfix(var)
461- if has_lower
462- JuMP.set_lower_bound(var, 0.0)
463- else
464- JuMP.set_upper_bound(var, 0.0)
465- end
466- JuMP.optimize!(model)
467- if JuMP.termination_status(model) in
468- (MOI.INFEASIBLE, MOI.ALMOST_INFEASIBLE)
488+ _set_bound_zero(model, var, has_lower, T)
489+ MOI. optimize!(model)
490+ status = MOI. get(model, MOI. TerminationStatus())
491+ if status in (MOI. INFEASIBLE, MOI. ALMOST_INFEASIBLE)
469492 # this constraint is not in IIS
470- elseif JuMP.termination_status(model) in
471- (MOI.OPTIMAL, MOI.ALMOST_OPTIMAL)
493+ elseif status in (MOI. OPTIMAL, MOI. ALMOST_OPTIMAL)
472494 push!(cadidates, con)
473- JuMP.fix(var, 0.0, force = true )
495+ _fix_to_zero(model, var, T )
474496 else
475- error(
476- "IIS failed due numerical instability, got status $(JuMP.termination_status(model))",
477- )
497+ error(" IIS failed due numerical instability, got status $status " )
478498 end
479499 end
480500
481501 pre_iis = Set(cadidates)
482- iis = JuMP.ConstraintRef[]
483- for con in JuMP.all_constraints(
484- original_model,
485- include_variable_in_set_constraints = false,
486- )
487- new_con = reference_map[con]
488- if new_con in pre_iis
489- push!(iis, con)
502+ iis = MOI. ConstraintIndex[]
503+ for (F, S) in MOI. get(original_model, MOI. ListOfConstraintTypesPresent())
504+ if F == MOI. VariableIndex
505+ continue
506+ end
507+ for con in MOI. get(original_model, MOI. ListOfConstraintIndices{F,S}())
508+ new_con = reference_map[con]
509+ if new_con in pre_iis
510+ push!(iis, con)
511+ end
490512 end
491513 end
492514
493515 return iis
494516end
495517
496- =#
497-
498518# API
499519
500520function ModelAnalyzer. _summarize(io:: IO , :: Type{InfeasibleBounds{T}} ) where {T}
0 commit comments