fuzzy-dl-owl2 1.0.5__py3-none-any.whl → 1.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fuzzy_dl_owl2/fuzzydl/feature_function.py +9 -3
- fuzzy_dl_owl2/fuzzydl/fuzzydl_to_owl2.py +204 -66
- fuzzy_dl_owl2/fuzzydl/knowledge_base.py +13 -5
- fuzzy_dl_owl2/fuzzydl/milp/expression.py +13 -2
- fuzzy_dl_owl2/fuzzydl/milp/inequation.py +12 -0
- fuzzy_dl_owl2/fuzzydl/milp/milp_helper.py +694 -54
- fuzzy_dl_owl2/fuzzydl/milp/term.py +4 -1
- fuzzy_dl_owl2/fuzzydl/util/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzydl/util/config_reader.py +44 -2
- fuzzy_dl_owl2/fuzzydl/util/constants.py +5 -6
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2.py +25 -17
- fuzzy_dl_owl2/fuzzyowl2/owl_types/modified_property.py +7 -1
- fuzzy_dl_owl2/fuzzyowl2/parser/__init__.py +2 -1
- fuzzy_dl_owl2/fuzzyowl2/parser/owl2_parser.py +7 -7
- fuzzy_dl_owl2/fuzzyowl2/parser/owl2_xml_parser.py +226 -0
- fuzzy_dl_owl2/fuzzyowl2/util/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzyowl2/util/constants.py +138 -52
- fuzzy_dl_owl2/fuzzyowl2/util/fuzzy_xml.py +107 -0
- {fuzzy_dl_owl2-1.0.5.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/METADATA +72 -4
- {fuzzy_dl_owl2-1.0.5.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/RECORD +22 -20
- {fuzzy_dl_owl2-1.0.5.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/LICENSE +0 -0
- {fuzzy_dl_owl2-1.0.5.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/WHEEL +0 -0
|
@@ -2,11 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import os
|
|
5
|
+
import traceback
|
|
5
6
|
import typing
|
|
6
7
|
|
|
7
|
-
import gurobipy as gp
|
|
8
|
-
from gurobipy import GRB
|
|
9
|
-
|
|
10
8
|
from fuzzy_dl_owl2.fuzzydl.assertion.assertion import Assertion
|
|
11
9
|
from fuzzy_dl_owl2.fuzzydl.concept.concept import Concept
|
|
12
10
|
from fuzzy_dl_owl2.fuzzydl.concept.interface.has_value_interface import (
|
|
@@ -26,7 +24,7 @@ from fuzzy_dl_owl2.fuzzydl.milp.variable import Variable
|
|
|
26
24
|
from fuzzy_dl_owl2.fuzzydl.relation import Relation
|
|
27
25
|
from fuzzy_dl_owl2.fuzzydl.restriction.restriction import Restriction
|
|
28
26
|
from fuzzy_dl_owl2.fuzzydl.util import constants
|
|
29
|
-
from fuzzy_dl_owl2.fuzzydl.util.config_reader import ConfigReader
|
|
27
|
+
from fuzzy_dl_owl2.fuzzydl.util.config_reader import ConfigReader, MILPProvider
|
|
30
28
|
from fuzzy_dl_owl2.fuzzydl.util.constants import (
|
|
31
29
|
ConceptType,
|
|
32
30
|
InequalityType,
|
|
@@ -62,8 +60,25 @@ class MILPHelper:
|
|
|
62
60
|
milp.variables = [v.clone() for v in self.variables]
|
|
63
61
|
return milp
|
|
64
62
|
|
|
65
|
-
def optimize(self, objective: Expression) -> Solution:
|
|
66
|
-
|
|
63
|
+
def optimize(self, objective: Expression) -> typing.Optional[Solution]:
|
|
64
|
+
Util.debug(f"Running MILP solver: {ConfigReader.MILP_PROVIDER.name}")
|
|
65
|
+
if ConfigReader.MILP_PROVIDER == MILPProvider.GUROBI:
|
|
66
|
+
return self.solve_gurobi(objective)
|
|
67
|
+
elif ConfigReader.MILP_PROVIDER == MILPProvider.MIP:
|
|
68
|
+
return self.solve_mip(objective)
|
|
69
|
+
elif ConfigReader.MILP_PROVIDER in [
|
|
70
|
+
MILPProvider.PULP,
|
|
71
|
+
MILPProvider.PULP_GLPK,
|
|
72
|
+
MILPProvider.PULP_HIGHS,
|
|
73
|
+
MILPProvider.PULP_CPLEX,
|
|
74
|
+
]:
|
|
75
|
+
return self.solve_pulp(objective)
|
|
76
|
+
# elif ConfigReader.MILP_PROVIDER == MILPProvider.SCIPY:
|
|
77
|
+
# return self.solve_scipy(objective)
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
f"Unsupported MILP provider: {ConfigReader.MILP_PROVIDER.name}"
|
|
81
|
+
)
|
|
67
82
|
|
|
68
83
|
@typing.overload
|
|
69
84
|
def print_instance_of_labels(
|
|
@@ -592,8 +607,10 @@ class MILPHelper:
|
|
|
592
607
|
return y
|
|
593
608
|
|
|
594
609
|
def solve_gurobi(self, objective: Expression) -> typing.Optional[Solution]:
|
|
610
|
+
import gurobipy as gp
|
|
611
|
+
from gurobipy import GRB
|
|
612
|
+
|
|
595
613
|
try:
|
|
596
|
-
Util.debug("Running MILP solver: Gurobi")
|
|
597
614
|
Util.debug(f"Objective function -> {objective}")
|
|
598
615
|
|
|
599
616
|
num_binary_vars: int = 0
|
|
@@ -616,37 +633,45 @@ class MILPHelper:
|
|
|
616
633
|
env.start()
|
|
617
634
|
|
|
618
635
|
model = gp.Model("model", env=env)
|
|
619
|
-
vars_gurobi:
|
|
636
|
+
vars_gurobi: dict[str, gp.Var] = dict()
|
|
620
637
|
show_variable: list[bool] = [False] * size
|
|
621
638
|
|
|
622
639
|
my_vars: list[Variable] = self.show_vars.get_variables()
|
|
623
640
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
641
|
+
var_types: dict[VariableType, str] = {
|
|
642
|
+
VariableType.BINARY: GRB.BINARY,
|
|
643
|
+
VariableType.INTEGER: GRB.INTEGER,
|
|
644
|
+
VariableType.CONTINUOUS: GRB.CONTINUOUS,
|
|
645
|
+
VariableType.SEMI_CONTINUOUS: GRB.SEMICONT,
|
|
646
|
+
}
|
|
647
|
+
var_name_map: dict[str, str] = {
|
|
648
|
+
str(v): f"x{i}" for i, v in enumerate(self.variables)
|
|
649
|
+
}
|
|
650
|
+
inv_var_name_map: dict[str, str] = {v: k for k, v in var_name_map.items()}
|
|
651
|
+
|
|
652
|
+
for i, curr_variable in enumerate(self.variables):
|
|
653
|
+
v_type: VariableType = curr_variable.get_type()
|
|
627
654
|
ov: float = objective_value[i]
|
|
628
655
|
|
|
629
656
|
Util.debug(
|
|
630
657
|
(
|
|
631
658
|
f"Variable -- "
|
|
632
|
-
f"[{
|
|
659
|
+
f"[{curr_variable.get_lower_bound()}, {curr_variable.get_upper_bound()}] - "
|
|
633
660
|
f"Obj value = {ov} - "
|
|
634
661
|
f"Var type = {v_type.name} -- "
|
|
635
|
-
f"Var = {
|
|
662
|
+
f"Var = {curr_variable}"
|
|
636
663
|
)
|
|
637
664
|
)
|
|
638
665
|
|
|
639
|
-
vars_gurobi.
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
name=str(v),
|
|
646
|
-
)
|
|
666
|
+
vars_gurobi[var_name_map[str(curr_variable)]] = model.addVar(
|
|
667
|
+
lb=curr_variable.get_lower_bound(),
|
|
668
|
+
ub=curr_variable.get_upper_bound(),
|
|
669
|
+
obj=ov,
|
|
670
|
+
vtype=var_types[v_type],
|
|
671
|
+
name=var_name_map[str(curr_variable)],
|
|
647
672
|
)
|
|
648
673
|
|
|
649
|
-
if
|
|
674
|
+
if curr_variable in my_vars:
|
|
650
675
|
show_variable[i] = True
|
|
651
676
|
|
|
652
677
|
if v_type == VariableType.BINARY:
|
|
@@ -663,11 +688,15 @@ class MILPHelper:
|
|
|
663
688
|
Util.debug(f"# constraints -> {len(self.constraints)}")
|
|
664
689
|
constraint_name: str = "constraint"
|
|
665
690
|
for i, constraint in enumerate(self.constraints):
|
|
691
|
+
if constraint in self.constraints[:i]:
|
|
692
|
+
continue
|
|
693
|
+
if constraint.is_zero():
|
|
694
|
+
continue
|
|
695
|
+
|
|
666
696
|
curr_name: str = f"{constraint_name}_{i + 1}"
|
|
667
697
|
expr: gp.LinExpr = gp.LinExpr()
|
|
668
698
|
for term in constraint.get_terms():
|
|
669
|
-
|
|
670
|
-
v: gp.Var = vars_gurobi[index]
|
|
699
|
+
v: gp.Var = vars_gurobi[var_name_map[str(term.get_var())]]
|
|
671
700
|
c: float = term.get_coeff()
|
|
672
701
|
if c == 0:
|
|
673
702
|
continue
|
|
@@ -684,26 +713,26 @@ class MILPHelper:
|
|
|
684
713
|
gp_constraint: gp.Constr = expr >= constraint.get_constant()
|
|
685
714
|
|
|
686
715
|
model.addConstr(gp_constraint, curr_name)
|
|
687
|
-
Util.debug(f"{curr_name}: {
|
|
716
|
+
Util.debug(f"{curr_name}: {constraint}")
|
|
688
717
|
|
|
689
718
|
model.update()
|
|
690
719
|
model.optimize()
|
|
691
720
|
|
|
692
|
-
model.write(os.path.join(constants.RESULTS_PATH, "
|
|
693
|
-
model.write(os.path.join(constants.RESULTS_PATH, "
|
|
721
|
+
model.write(os.path.join(constants.RESULTS_PATH, "gurobi_model.lp"))
|
|
722
|
+
model.write(os.path.join(constants.RESULTS_PATH, "gurobi_solution.json"))
|
|
694
723
|
|
|
695
724
|
Util.debug(f"Model:")
|
|
696
725
|
sol: Solution = None
|
|
697
|
-
if model.Status == GRB.INFEASIBLE and ConfigReader.RELAX_MILP:
|
|
698
|
-
|
|
726
|
+
# if model.Status == GRB.INFEASIBLE and ConfigReader.RELAX_MILP:
|
|
727
|
+
# self.__gurobi_handle_model_infeasibility(model)
|
|
699
728
|
|
|
700
729
|
if model.Status == GRB.INFEASIBLE:
|
|
701
730
|
sol = Solution(False)
|
|
702
731
|
else:
|
|
703
732
|
for i in range(size):
|
|
704
733
|
if ConfigReader.DEBUG_PRINT or show_variable[i]:
|
|
705
|
-
name: str =
|
|
706
|
-
value: float = round(vars_gurobi[
|
|
734
|
+
name: str = self.variables[i].name
|
|
735
|
+
value: float = round(vars_gurobi[var_name_map[name]].X, 6)
|
|
707
736
|
if self.PRINT_VARIABLES:
|
|
708
737
|
Util.debug(f"{name} = {value}")
|
|
709
738
|
if self.PRINT_LABELS:
|
|
@@ -729,29 +758,640 @@ class MILPHelper:
|
|
|
729
758
|
Util.error(f"Error code: {e.errno}. {e.message}")
|
|
730
759
|
return None
|
|
731
760
|
|
|
732
|
-
def
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
761
|
+
# def __gurobi_handle_model_infeasibility(self, model: typing.Any) -> None:
|
|
762
|
+
# import gurobipy as gp
|
|
763
|
+
|
|
764
|
+
# model: gp.Model = typing.cast(gp.Model, model)
|
|
765
|
+
# model.computeIIS()
|
|
766
|
+
# # Print out the IIS constraints and variables
|
|
767
|
+
# Util.debug("The following constraints and variables are in the IIS:")
|
|
768
|
+
# Util.debug("Constraints:")
|
|
769
|
+
# for c in model.getConstrs():
|
|
770
|
+
# assert isinstance(c, gp.Constr)
|
|
771
|
+
# if c.IISConstr:
|
|
772
|
+
# Util.debug(f"\t\t{c.ConstrName}: {model.getRow(c)} {c.Sense} {c.RHS}")
|
|
773
|
+
|
|
774
|
+
# Util.debug("Variables:")
|
|
775
|
+
# for v in model.getVars():
|
|
776
|
+
# if v.IISLB:
|
|
777
|
+
# Util.debug(f"\t\t{v.VarName} ≥ {v.LB}")
|
|
778
|
+
# if v.IISUB:
|
|
779
|
+
# Util.debug(f"\t\t{v.VarName} ≤ {v.UB}")
|
|
780
|
+
|
|
781
|
+
# Util.debug("Relaxing the variable bounds:")
|
|
782
|
+
# # relaxing only variable bounds
|
|
783
|
+
# model.feasRelaxS(0, False, True, False)
|
|
784
|
+
# # for relaxing variable bounds and constraint bounds use
|
|
785
|
+
# # model.feasRelaxS(0, False, True, True)
|
|
786
|
+
# model.optimize()
|
|
787
|
+
|
|
788
|
+
def solve_mip(self, objective: Expression) -> typing.Optional[Solution]:
|
|
789
|
+
import mip
|
|
790
|
+
|
|
791
|
+
try:
|
|
792
|
+
Util.debug(f"Objective function -> {objective}")
|
|
793
|
+
|
|
794
|
+
num_binary_vars: int = 0
|
|
795
|
+
num_free_vars: int = 0
|
|
796
|
+
num_integer_vars: int = 0
|
|
797
|
+
num_up_vars: int = 0
|
|
798
|
+
size: int = len(self.variables)
|
|
799
|
+
objective_value: list[float] = [0.0] * size
|
|
800
|
+
|
|
801
|
+
if objective is not None:
|
|
802
|
+
for term in objective.get_terms():
|
|
803
|
+
index = self.variables.index(term.get_var())
|
|
804
|
+
objective_value[index] += term.get_coeff()
|
|
805
|
+
|
|
806
|
+
model: mip.Model = mip.Model(
|
|
807
|
+
name="FuzzyDL", sense=mip.MINIMIZE, solver_name=mip.CBC
|
|
808
|
+
)
|
|
809
|
+
model.verbose = 0
|
|
810
|
+
model.infeas_tol = 1e-9
|
|
811
|
+
model.integer_tol = 1e-9
|
|
812
|
+
model.max_mip_gap = ConfigReader.EPSILON
|
|
813
|
+
model.emphasis = mip.SearchEmphasis.OPTIMALITY
|
|
814
|
+
model.opt_tol = 0
|
|
815
|
+
model.preprocess = 1
|
|
816
|
+
|
|
817
|
+
if ConfigReader.DEBUG_PRINT:
|
|
818
|
+
model.verbose = 1
|
|
819
|
+
|
|
820
|
+
vars_mip: dict[str, mip.Var] = dict()
|
|
821
|
+
show_variable: list[bool] = [False] * size
|
|
822
|
+
|
|
823
|
+
my_vars: list[Variable] = self.show_vars.get_variables()
|
|
824
|
+
var_types: dict[VariableType, str] = {
|
|
825
|
+
VariableType.BINARY: mip.BINARY,
|
|
826
|
+
VariableType.INTEGER: mip.INTEGER,
|
|
827
|
+
VariableType.CONTINUOUS: mip.CONTINUOUS,
|
|
828
|
+
VariableType.SEMI_CONTINUOUS: mip.CONTINUOUS,
|
|
829
|
+
}
|
|
830
|
+
var_name_map: dict[str, str] = {
|
|
831
|
+
str(v): f"x{i}" for i, v in enumerate(self.variables)
|
|
832
|
+
}
|
|
833
|
+
inv_var_name_map: dict[str, str] = {v: k for k, v in var_name_map.items()}
|
|
834
|
+
|
|
835
|
+
for i, curr_variable in enumerate(self.variables):
|
|
836
|
+
v_type: VariableType = curr_variable.get_type()
|
|
837
|
+
ov: float = objective_value[i]
|
|
838
|
+
|
|
839
|
+
Util.debug(
|
|
840
|
+
(
|
|
841
|
+
f"Variable -- "
|
|
842
|
+
f"[{curr_variable.get_lower_bound()}, {curr_variable.get_upper_bound()}] - "
|
|
843
|
+
f"Obj value = {ov} - "
|
|
844
|
+
f"Var type = {v_type.name} -- "
|
|
845
|
+
f"Var = {curr_variable}"
|
|
846
|
+
)
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
vars_mip[var_name_map[str(curr_variable)]] = model.add_var(
|
|
850
|
+
name=var_name_map[str(curr_variable)],
|
|
851
|
+
var_type=var_types[v_type],
|
|
852
|
+
lb=curr_variable.get_lower_bound(),
|
|
853
|
+
ub=curr_variable.get_upper_bound(),
|
|
854
|
+
obj=ov,
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
if curr_variable in my_vars:
|
|
858
|
+
show_variable[i] = True
|
|
859
|
+
|
|
860
|
+
if v_type == VariableType.BINARY:
|
|
861
|
+
num_binary_vars += 1
|
|
862
|
+
elif v_type == VariableType.CONTINUOUS:
|
|
863
|
+
num_free_vars += 1
|
|
864
|
+
elif v_type == VariableType.INTEGER:
|
|
865
|
+
num_integer_vars += 1
|
|
866
|
+
elif v_type == VariableType.SEMI_CONTINUOUS:
|
|
867
|
+
num_up_vars += 1
|
|
868
|
+
|
|
869
|
+
Util.debug(f"# constraints -> {len(self.constraints)}")
|
|
870
|
+
constraint_name: str = "constraint"
|
|
871
|
+
for i, constraint in enumerate(self.constraints):
|
|
872
|
+
if constraint in self.constraints[:i]:
|
|
873
|
+
continue
|
|
874
|
+
if constraint.is_zero():
|
|
875
|
+
continue
|
|
876
|
+
curr_name: str = f"{constraint_name}_{i + 1}"
|
|
877
|
+
expr: mip.LinExpr = mip.xsum(
|
|
878
|
+
term.get_coeff() * vars_mip[var_name_map[str(term.get_var())]]
|
|
879
|
+
for term in constraint.get_terms()
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
if constraint.get_type() == InequalityType.EQUAL:
|
|
883
|
+
gp_constraint: mip.Constr = expr == constraint.get_constant()
|
|
884
|
+
elif constraint.get_type() == InequalityType.LESS_THAN:
|
|
885
|
+
gp_constraint: mip.Constr = expr <= constraint.get_constant()
|
|
886
|
+
elif constraint.get_type() == InequalityType.GREATER_THAN:
|
|
887
|
+
gp_constraint: mip.Constr = expr >= constraint.get_constant()
|
|
888
|
+
|
|
889
|
+
model.add_constr(gp_constraint, curr_name)
|
|
890
|
+
Util.debug(f"{curr_name}: {constraint}")
|
|
891
|
+
|
|
892
|
+
model.objective = mip.xsum(
|
|
893
|
+
ov * vars_mip[var_name_map[str(self.variables[i])]]
|
|
894
|
+
for i, ov in enumerate(objective_value)
|
|
895
|
+
if ov != 0
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
# model.optimize(relax=ConfigReader.RELAX_MILP)
|
|
899
|
+
model.optimize()
|
|
900
|
+
|
|
901
|
+
model.write(os.path.join(constants.RESULTS_PATH, "mip_model.lp"))
|
|
902
|
+
|
|
903
|
+
Util.debug(f"Model:")
|
|
904
|
+
sol: Solution = None
|
|
905
|
+
if model.status == mip.OptimizationStatus.INFEASIBLE:
|
|
906
|
+
sol = Solution(False)
|
|
907
|
+
else:
|
|
908
|
+
model.write(os.path.join(constants.RESULTS_PATH, "mip_solution.sol"))
|
|
909
|
+
for i in range(size):
|
|
910
|
+
if ConfigReader.DEBUG_PRINT or show_variable[i]:
|
|
911
|
+
name: str = self.variables[i].name
|
|
912
|
+
value: float = round(vars_mip[var_name_map[name]].x, 6)
|
|
913
|
+
if self.PRINT_VARIABLES:
|
|
914
|
+
Util.debug(f"{name} = {value}")
|
|
915
|
+
if self.PRINT_LABELS:
|
|
916
|
+
self.print_instance_of_labels(name, value)
|
|
917
|
+
result: float = Util.round(abs(model.objective_value))
|
|
918
|
+
sol = Solution(result)
|
|
919
|
+
|
|
920
|
+
Util.debug(
|
|
921
|
+
f"{constants.STAR_SEPARATOR}Statistics{constants.STAR_SEPARATOR}"
|
|
922
|
+
)
|
|
923
|
+
Util.debug("MILP problem:")
|
|
924
|
+
Util.debug(f"\t\tSemi continuous variables: {num_up_vars}")
|
|
925
|
+
Util.debug(f"\t\tBinary variables: {num_binary_vars}")
|
|
926
|
+
Util.debug(f"\t\tContinuous variables: {num_free_vars}")
|
|
927
|
+
Util.debug(f"\t\tInteger variables: {num_integer_vars}")
|
|
928
|
+
Util.debug(f"\t\tTotal variables: {len(self.variables)}")
|
|
929
|
+
Util.debug(f"\t\tConstraints: {len(self.constraints)}")
|
|
930
|
+
return sol
|
|
931
|
+
except Exception as e:
|
|
932
|
+
Util.error(f"Error: {e} {traceback.format_exc()}")
|
|
933
|
+
return None
|
|
934
|
+
|
|
935
|
+
def solve_pulp(self, objective: Expression) -> typing.Optional[Solution]:
|
|
936
|
+
import pulp
|
|
937
|
+
|
|
938
|
+
try:
|
|
939
|
+
Util.debug(f"Objective function -> {objective}")
|
|
940
|
+
|
|
941
|
+
num_binary_vars: int = 0
|
|
942
|
+
num_free_vars: int = 0
|
|
943
|
+
num_integer_vars: int = 0
|
|
944
|
+
num_up_vars: int = 0
|
|
945
|
+
size: int = len(self.variables)
|
|
946
|
+
objective_value: list[float] = [0.0] * size
|
|
947
|
+
show_variable: list[bool] = [False] * size
|
|
948
|
+
my_vars: list[Variable] = self.show_vars.get_variables()
|
|
949
|
+
|
|
950
|
+
if objective is not None:
|
|
951
|
+
for term in objective.get_terms():
|
|
952
|
+
objective_value[
|
|
953
|
+
self.variables.index(term.get_var())
|
|
954
|
+
] += term.get_coeff()
|
|
955
|
+
|
|
956
|
+
model = pulp.LpProblem(
|
|
957
|
+
f"FuzzyDL-{ConfigReader.MILP_PROVIDER.upper()}", pulp.LpMinimize
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
var_types: dict[VariableType, str] = {
|
|
961
|
+
VariableType.BINARY: pulp.LpBinary,
|
|
962
|
+
VariableType.INTEGER: pulp.LpInteger,
|
|
963
|
+
VariableType.CONTINUOUS: pulp.LpContinuous,
|
|
964
|
+
VariableType.SEMI_CONTINUOUS: pulp.LpContinuous,
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
vars_pulp: dict[str, pulp.LpVariable] = dict()
|
|
968
|
+
var_name_map: dict[str, str] = {
|
|
969
|
+
str(v): f"x{i}" for i, v in enumerate(self.variables)
|
|
970
|
+
}
|
|
971
|
+
semicontinuous_var_counter: int = 1
|
|
972
|
+
semicontinuous_var_name: str = "semic_z"
|
|
973
|
+
for i, curr_variable in enumerate(self.variables):
|
|
974
|
+
v_type: VariableType = curr_variable.get_type()
|
|
975
|
+
Util.debug(
|
|
976
|
+
(
|
|
977
|
+
f"Variable -- "
|
|
978
|
+
f"[{curr_variable.get_lower_bound()}, {curr_variable.get_upper_bound()}] - "
|
|
979
|
+
f"Obj value = {objective_value[i]} - "
|
|
980
|
+
f"Var type = {v_type.name} -- "
|
|
981
|
+
f"Var = {curr_variable}"
|
|
982
|
+
)
|
|
983
|
+
)
|
|
984
|
+
|
|
985
|
+
vars_pulp[var_name_map[str(curr_variable)]] = pulp.LpVariable(
|
|
986
|
+
name=var_name_map[str(curr_variable)],
|
|
987
|
+
lowBound=(
|
|
988
|
+
curr_variable.get_lower_bound()
|
|
989
|
+
if curr_variable.get_lower_bound() != float("-inf")
|
|
990
|
+
else None
|
|
991
|
+
),
|
|
992
|
+
upBound=(
|
|
993
|
+
curr_variable.get_upper_bound()
|
|
994
|
+
if curr_variable.get_upper_bound() != float("inf")
|
|
995
|
+
else None
|
|
996
|
+
),
|
|
997
|
+
cat=var_types[v_type],
|
|
998
|
+
)
|
|
999
|
+
|
|
1000
|
+
if curr_variable in my_vars:
|
|
1001
|
+
show_variable[i] = True
|
|
1002
|
+
|
|
1003
|
+
if (
|
|
1004
|
+
v_type == VariableType.SEMI_CONTINUOUS
|
|
1005
|
+
and ConfigReader.MILP_PROVIDER
|
|
1006
|
+
in [
|
|
1007
|
+
MILPProvider.PULP_GLPK,
|
|
1008
|
+
MILPProvider.PULP_CPLEX,
|
|
1009
|
+
]
|
|
1010
|
+
):
|
|
1011
|
+
# Semi Continuous variables are not handled by GLPK and HiGHS
|
|
1012
|
+
# if x in [L, U] u {0} is semi continuous, then add the following constraints
|
|
1013
|
+
# L * y <= x <= U * y, where y in {0, 1} is a binary variable
|
|
1014
|
+
bin_var = pulp.LpVariable(
|
|
1015
|
+
name=f"{semicontinuous_var_name}{semicontinuous_var_counter}",
|
|
1016
|
+
cat=pulp.LpBinary,
|
|
1017
|
+
)
|
|
1018
|
+
constraint_1 = (
|
|
1019
|
+
vars_pulp[var_name_map[str(curr_variable)]]
|
|
1020
|
+
>= bin_var * curr_variable.get_lower_bound()
|
|
1021
|
+
)
|
|
1022
|
+
constraint_2 = (
|
|
1023
|
+
vars_pulp[var_name_map[str(curr_variable)]]
|
|
1024
|
+
<= bin_var * curr_variable.get_upper_bound()
|
|
1025
|
+
)
|
|
1026
|
+
if constraint_1 not in model.constraints.values():
|
|
1027
|
+
model.addConstraint(
|
|
1028
|
+
constraint_1, name=f"constraint_{bin_var.name}_1"
|
|
1029
|
+
)
|
|
1030
|
+
if constraint_2 not in model.constraints.values():
|
|
1031
|
+
model.addConstraint(
|
|
1032
|
+
constraint_2, name=f"constraint_{bin_var.name}_2"
|
|
1033
|
+
)
|
|
1034
|
+
semicontinuous_var_counter += 1
|
|
1035
|
+
Util.debug(
|
|
1036
|
+
(
|
|
1037
|
+
f"New Variable -- "
|
|
1038
|
+
f"[{bin_var.lowBound}, {bin_var.upBound}] - "
|
|
1039
|
+
f"Var type = {bin_var.cat} -- "
|
|
1040
|
+
f"Var = {bin_var.name}"
|
|
1041
|
+
)
|
|
1042
|
+
)
|
|
1043
|
+
Util.debug(f"New Constraint 1 -- {constraint_1}")
|
|
1044
|
+
Util.debug(f"New Constraint 2 -- {constraint_2}")
|
|
1045
|
+
|
|
1046
|
+
if v_type == VariableType.BINARY:
|
|
1047
|
+
num_binary_vars += 1
|
|
1048
|
+
elif v_type == VariableType.CONTINUOUS:
|
|
1049
|
+
num_free_vars += 1
|
|
1050
|
+
elif v_type == VariableType.INTEGER:
|
|
1051
|
+
num_integer_vars += 1
|
|
1052
|
+
elif v_type == VariableType.SEMI_CONTINUOUS:
|
|
1053
|
+
num_up_vars += 1
|
|
1054
|
+
|
|
1055
|
+
Util.debug(f"# constraints -> {len(self.constraints)}")
|
|
1056
|
+
constraint_name: str = "constraint"
|
|
1057
|
+
pulp_sense: dict[InequalityType, int] = {
|
|
1058
|
+
InequalityType.EQUAL: pulp.LpConstraintEQ,
|
|
1059
|
+
InequalityType.LESS_THAN: pulp.LpConstraintLE,
|
|
1060
|
+
InequalityType.GREATER_THAN: pulp.LpConstraintGE,
|
|
1061
|
+
}
|
|
1062
|
+
for i, constraint in enumerate(self.constraints):
|
|
1063
|
+
if constraint in self.constraints[:i]:
|
|
1064
|
+
continue
|
|
1065
|
+
# ignore zero constraints
|
|
1066
|
+
if constraint.is_zero():
|
|
1067
|
+
continue
|
|
1068
|
+
|
|
1069
|
+
curr_name: str = f"{constraint_name}_{i + 1}"
|
|
1070
|
+
pulp_expr: pulp.LpAffineExpression = pulp.lpSum(
|
|
1071
|
+
term.get_coeff() * vars_pulp[var_name_map[str(term.get_var())]]
|
|
1072
|
+
for term in constraint.get_terms()
|
|
1073
|
+
)
|
|
1074
|
+
pulp_constraint: pulp.LpConstraint = pulp.LpConstraint(
|
|
1075
|
+
e=pulp_expr,
|
|
1076
|
+
sense=pulp_sense[constraint.get_type()],
|
|
1077
|
+
rhs=constraint.get_constant(),
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1080
|
+
# ignore zero constraints of type a * x - a * x
|
|
1081
|
+
if (
|
|
1082
|
+
len(pulp_constraint) == 1
|
|
1083
|
+
and list(pulp_constraint.values())[0] == 0
|
|
1084
|
+
and pulp_constraint.constant == 0
|
|
1085
|
+
):
|
|
1086
|
+
continue
|
|
1087
|
+
|
|
1088
|
+
model.addConstraint(pulp_constraint, name=curr_name)
|
|
1089
|
+
Util.debug(f"{curr_name}: {constraint}")
|
|
1090
|
+
|
|
1091
|
+
if ConfigReader.MILP_PROVIDER == MILPProvider.PULP:
|
|
1092
|
+
solver = pulp.PULP_CBC_CMD(
|
|
1093
|
+
mip=True,
|
|
1094
|
+
msg=ConfigReader.DEBUG_PRINT,
|
|
1095
|
+
gapRel=1e-9,
|
|
1096
|
+
presolve=True,
|
|
1097
|
+
keepFiles=False, # ConfigReader.DEBUG_PRINT,
|
|
1098
|
+
logPath=(
|
|
1099
|
+
os.path.join(".", "logs", f"pulp_{pulp.PULP_CBC_CMD.name}.log")
|
|
1100
|
+
if ConfigReader.DEBUG_PRINT
|
|
1101
|
+
else None
|
|
1102
|
+
),
|
|
1103
|
+
options=[
|
|
1104
|
+
"--primalTolerance", # feasibility tolerance
|
|
1105
|
+
"1e-9",
|
|
1106
|
+
"--integerTolerance", # integer feasibility tolerance
|
|
1107
|
+
"1e-9",
|
|
1108
|
+
"--ratioGap", # relative mip gap
|
|
1109
|
+
str(ConfigReader.EPSILON),
|
|
1110
|
+
"--allowableGap", # optimality gap tolerance
|
|
1111
|
+
"0",
|
|
1112
|
+
"--preprocess", # enable preprocessing
|
|
1113
|
+
"on",
|
|
1114
|
+
],
|
|
1115
|
+
)
|
|
1116
|
+
elif ConfigReader.MILP_PROVIDER == MILPProvider.PULP_GLPK:
|
|
1117
|
+
solver = pulp.GLPK_CMD(
|
|
1118
|
+
mip=True,
|
|
1119
|
+
msg=ConfigReader.DEBUG_PRINT,
|
|
1120
|
+
keepFiles=False, # ConfigReader.DEBUG_PRINT,
|
|
1121
|
+
options=[
|
|
1122
|
+
"--presol", # use presolver (default; assumes --scale and --adv)
|
|
1123
|
+
"--exact", # use simplex method based on exact arithmetic
|
|
1124
|
+
"--xcheck", # check final basis using exact arithmetic
|
|
1125
|
+
"--intopt", # enforce MIP (Mixed Integer Programming)
|
|
1126
|
+
"--mipgap",
|
|
1127
|
+
str(
|
|
1128
|
+
ConfigReader.EPSILON
|
|
1129
|
+
), # no relative gap between primal & best bound
|
|
1130
|
+
]
|
|
1131
|
+
+ (
|
|
1132
|
+
[
|
|
1133
|
+
"--log",
|
|
1134
|
+
os.path.join(".", "logs", f"pulp_{pulp.GLPK_CMD.name}.log"),
|
|
1135
|
+
]
|
|
1136
|
+
if ConfigReader.DEBUG_PRINT
|
|
1137
|
+
else []
|
|
1138
|
+
),
|
|
1139
|
+
)
|
|
1140
|
+
elif ConfigReader.MILP_PROVIDER == MILPProvider.PULP_HIGHS:
|
|
1141
|
+
solver = pulp.HiGHS(
|
|
1142
|
+
mip=True,
|
|
1143
|
+
msg=ConfigReader.DEBUG_PRINT,
|
|
1144
|
+
gapRel=1e-6,
|
|
1145
|
+
log_file=(
|
|
1146
|
+
os.path.join(".", "logs", f"pulp_{pulp.HiGHS.name}.log")
|
|
1147
|
+
if ConfigReader.DEBUG_PRINT
|
|
1148
|
+
else None
|
|
1149
|
+
),
|
|
1150
|
+
primal_feasibility_tolerance=1e-9,
|
|
1151
|
+
dual_feasibility_tolerance=1e-9,
|
|
1152
|
+
mip_feasibility_tolerance=1e-9,
|
|
1153
|
+
presolve="on",
|
|
1154
|
+
parallel="on",
|
|
1155
|
+
write_solution_to_file=True,
|
|
1156
|
+
write_solution_style=1,
|
|
1157
|
+
solution_file=os.path.join(
|
|
1158
|
+
constants.RESULTS_PATH, "highs_solution.sol"
|
|
1159
|
+
),
|
|
1160
|
+
write_model_file=os.path.join(
|
|
1161
|
+
constants.RESULTS_PATH, "highs_model.lp"
|
|
1162
|
+
),
|
|
1163
|
+
)
|
|
1164
|
+
elif ConfigReader.MILP_PROVIDER == MILPProvider.PULP_CPLEX:
|
|
1165
|
+
solver = pulp.CPLEX_CMD(
|
|
1166
|
+
# path="/Applications/CPLEX_Studio2211/cplex/bin/arm64_osx/cplex",
|
|
1167
|
+
mip=True,
|
|
1168
|
+
msg=ConfigReader.DEBUG_PRINT,
|
|
1169
|
+
gapRel=1e-9,
|
|
1170
|
+
keepFiles=False, # ConfigReader.DEBUG_PRINT,
|
|
1171
|
+
logPath=(
|
|
1172
|
+
os.path.join(".", "logs", f"pulp_{pulp.CPLEX_CMD.name}.log")
|
|
1173
|
+
if ConfigReader.DEBUG_PRINT
|
|
1174
|
+
else None
|
|
1175
|
+
),
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
model.objective = pulp.lpSum(
|
|
1179
|
+
ov * vars_pulp[var_name_map[str(self.variables[i])]]
|
|
1180
|
+
for i, ov in enumerate(objective_value)
|
|
1181
|
+
if ov != 0
|
|
1182
|
+
)
|
|
1183
|
+
result = model.solve(solver=solver)
|
|
1184
|
+
if ConfigReader.MILP_PROVIDER == MILPProvider.PULP_CPLEX:
|
|
1185
|
+
for file in os.listdir("./"):
|
|
1186
|
+
if "clone" in file:
|
|
1187
|
+
os.remove(file)
|
|
1188
|
+
|
|
1189
|
+
Util.debug(f"Model:")
|
|
1190
|
+
sol: Solution = None
|
|
1191
|
+
if result != pulp.LpStatusOptimal:
|
|
1192
|
+
sol = Solution(False)
|
|
1193
|
+
else:
|
|
1194
|
+
var_dict: dict[str, pulp.LpVariable] = model.variablesDict()
|
|
1195
|
+
for i in range(size):
|
|
1196
|
+
if ConfigReader.DEBUG_PRINT or show_variable[i]:
|
|
1197
|
+
name: str = self.variables[i].name
|
|
1198
|
+
value: float = (
|
|
1199
|
+
round(var_dict[var_name_map[name]].value(), 6)
|
|
1200
|
+
if var_name_map[name] in var_dict
|
|
1201
|
+
else 0.0
|
|
1202
|
+
)
|
|
1203
|
+
if self.PRINT_VARIABLES:
|
|
1204
|
+
Util.debug(f"{name} = {value}")
|
|
1205
|
+
if self.PRINT_LABELS:
|
|
1206
|
+
self.print_instance_of_labels(name, value)
|
|
1207
|
+
result: float = Util.round(abs(model.objective.value()))
|
|
1208
|
+
sol = Solution(result)
|
|
1209
|
+
|
|
1210
|
+
Util.debug(
|
|
1211
|
+
f"{constants.STAR_SEPARATOR}Statistics{constants.STAR_SEPARATOR}"
|
|
1212
|
+
)
|
|
1213
|
+
Util.debug("MILP problem:")
|
|
1214
|
+
Util.debug(f"\t\tSemi continuous variables: {num_up_vars}")
|
|
1215
|
+
Util.debug(f"\t\tBinary variables: {num_binary_vars}")
|
|
1216
|
+
Util.debug(f"\t\tContinuous variables: {num_free_vars}")
|
|
1217
|
+
Util.debug(f"\t\tInteger variables: {num_integer_vars}")
|
|
1218
|
+
Util.debug(f"\t\tTotal variables: {len(self.variables)}")
|
|
1219
|
+
Util.debug(f"\t\tConstraints: {len(self.constraints)}")
|
|
1220
|
+
return sol
|
|
1221
|
+
except Exception as e:
|
|
1222
|
+
Util.error(f"Error: {e} {traceback.format_exc()}")
|
|
1223
|
+
return None
|
|
1224
|
+
|
|
1225
|
+
# def solve_scipy(self, objective: Expression) -> typing.Optional[Solution]:
|
|
1226
|
+
# import numpy as np
|
|
1227
|
+
# from scipy.optimize import milp, OptimizeResult, LinearConstraint, Bounds, linprog, linprog_verbose_callback, show_options
|
|
1228
|
+
|
|
1229
|
+
# num_binary_vars: int = 0
|
|
1230
|
+
# num_free_vars: int = 0
|
|
1231
|
+
# num_integer_vars: int = 0
|
|
1232
|
+
# num_up_vars: int = 0
|
|
1233
|
+
# size: int = len(self.variables)
|
|
1234
|
+
# objective_value: list[float] = [0.0] * size
|
|
1235
|
+
# show_variable: list[bool] = [False] * size
|
|
1236
|
+
# my_vars: list[Variable] = self.show_vars.get_variables()
|
|
1237
|
+
|
|
1238
|
+
# if objective is not None:
|
|
1239
|
+
# for term in objective.get_terms():
|
|
1240
|
+
# index = self.variables.index(term.get_var())
|
|
1241
|
+
# objective_value[index] += term.get_coeff()
|
|
1242
|
+
|
|
1243
|
+
# var_types: dict[VariableType, str] = {
|
|
1244
|
+
# VariableType.BINARY: 1,
|
|
1245
|
+
# VariableType.CONTINUOUS: 0,
|
|
1246
|
+
# VariableType.INTEGER: 1,
|
|
1247
|
+
# VariableType.SEMI_CONTINUOUS: 2,
|
|
1248
|
+
# }
|
|
1249
|
+
|
|
1250
|
+
# for i, curr_variable in enumerate(self.variables):
|
|
1251
|
+
# v_type: VariableType = curr_variable.get_type()
|
|
1252
|
+
|
|
1253
|
+
# Util.debug(
|
|
1254
|
+
# (
|
|
1255
|
+
# f"Variable -- "
|
|
1256
|
+
# f"[{curr_variable.get_lower_bound()}, {curr_variable.get_upper_bound()}] - "
|
|
1257
|
+
# f"Obj value = {objective_value[i]} - "
|
|
1258
|
+
# f"Var type = {v_type.name} -- "
|
|
1259
|
+
# f"Var = {curr_variable}"
|
|
1260
|
+
# )
|
|
1261
|
+
# )
|
|
1262
|
+
|
|
1263
|
+
# if curr_variable in my_vars:
|
|
1264
|
+
# show_variable[i] = True
|
|
1265
|
+
|
|
1266
|
+
# if v_type == VariableType.BINARY:
|
|
1267
|
+
# num_binary_vars += 1
|
|
1268
|
+
# elif v_type == VariableType.CONTINUOUS:
|
|
1269
|
+
# num_free_vars += 1
|
|
1270
|
+
# elif v_type == VariableType.INTEGER:
|
|
1271
|
+
# num_integer_vars += 1
|
|
1272
|
+
# elif v_type == VariableType.SEMI_CONTINUOUS:
|
|
1273
|
+
# num_up_vars += 1
|
|
1274
|
+
|
|
1275
|
+
# Util.debug(f"# constraints -> {len(self.constraints)}")
|
|
1276
|
+
# constraint_name: str = "constraint"
|
|
1277
|
+
# matrix_A = np.zeros((len(self.constraints), len(self.variables)))
|
|
1278
|
+
# inequality_A = np.zeros((len(self.constraints), len(self.variables)))
|
|
1279
|
+
# equality_A = np.zeros((len(self.constraints), len(self.variables)))
|
|
1280
|
+
# lb = np.zeros(len(self.constraints))
|
|
1281
|
+
# ub = np.zeros(len(self.constraints))
|
|
1282
|
+
# in_ub = np.zeros(len(self.constraints))
|
|
1283
|
+
# eq_ub = np.zeros(len(self.constraints))
|
|
1284
|
+
# for i, constraint in enumerate(self.constraints):
|
|
1285
|
+
# curr_name: str = f"{constraint_name}_{i + 1}"
|
|
1286
|
+
# row = np.zeros(len(self.variables))
|
|
1287
|
+
# for term in constraint.get_terms():
|
|
1288
|
+
# row[self.variables.index(term.get_var())] = term.get_coeff()
|
|
1289
|
+
# if np.allclose(row, 0):
|
|
1290
|
+
# continue
|
|
1291
|
+
# Util.debug(f"{curr_name}: {constraint}")
|
|
1292
|
+
# matrix_A[i, :] = row
|
|
1293
|
+
# if constraint.type == InequalityType.EQUAL:
|
|
1294
|
+
# equality_A[i, :] = row
|
|
1295
|
+
# eq_ub[i] = constraint.get_constant()
|
|
1296
|
+
|
|
1297
|
+
# lb[i] = constraint.get_constant()
|
|
1298
|
+
# ub[i] = constraint.get_constant()
|
|
1299
|
+
# elif constraint.type == InequalityType.LESS_THAN:
|
|
1300
|
+
# inequality_A[i, :] = row
|
|
1301
|
+
# in_ub[i] = constraint.get_constant()
|
|
1302
|
+
|
|
1303
|
+
# lb[i] = -np.inf
|
|
1304
|
+
# ub[i] = constraint.get_constant()
|
|
1305
|
+
# elif constraint.type == InequalityType.GREATER_THAN:
|
|
1306
|
+
# inequality_A[i, :] = -row
|
|
1307
|
+
# in_ub[i] = -constraint.get_constant()
|
|
1308
|
+
|
|
1309
|
+
# lb[i] = constraint.get_constant()
|
|
1310
|
+
# ub[i] = np.inf
|
|
1311
|
+
|
|
1312
|
+
# indices = np.all(matrix_A == 0, axis=1)
|
|
1313
|
+
# matrix_A = np.delete(matrix_A, indices, axis=0)
|
|
1314
|
+
# lb = np.delete(lb, indices, axis=0)
|
|
1315
|
+
# ub = np.delete(ub, indices, axis=0)
|
|
1316
|
+
|
|
1317
|
+
# indices = np.all(inequality_A == 0, axis=1)
|
|
1318
|
+
# inequality_A = np.delete(inequality_A, indices, axis=0)
|
|
1319
|
+
# in_ub = np.delete(in_ub, indices, axis=0)
|
|
1320
|
+
|
|
1321
|
+
# indices = np.all(equality_A == 0, axis=1)
|
|
1322
|
+
# equality_A = np.delete(equality_A, indices, axis=0)
|
|
1323
|
+
# eq_ub = np.delete(eq_ub, indices, axis=0)
|
|
1324
|
+
|
|
1325
|
+
# bounds = Bounds(
|
|
1326
|
+
# [var.get_lower_bound() for var in self.variables],
|
|
1327
|
+
# [var.get_upper_bound() for var in self.variables],
|
|
1328
|
+
# keep_feasible=True,
|
|
1329
|
+
# )
|
|
1330
|
+
# integrality = np.array([var_types[var.get_type()] for var in self.variables])
|
|
1331
|
+
# constraint = LinearConstraint(
|
|
1332
|
+
# matrix_A, lb, ub, keep_feasible=True
|
|
1333
|
+
# )
|
|
1334
|
+
|
|
1335
|
+
# result: OptimizeResult = milp(
|
|
1336
|
+
# c=np.array(objective_value),
|
|
1337
|
+
# integrality=integrality,
|
|
1338
|
+
# constraints=constraint,
|
|
1339
|
+
# bounds=bounds,
|
|
1340
|
+
# options={
|
|
1341
|
+
# "disp": ConfigReader.DEBUG_PRINT,
|
|
1342
|
+
# "presolve": True,
|
|
1343
|
+
# "mip_rel_gap": 1e-6,
|
|
1344
|
+
# },
|
|
1345
|
+
# )
|
|
1346
|
+
|
|
1347
|
+
# result: OptimizeResult = linprog(
|
|
1348
|
+
# c=np.array(objective_value),
|
|
1349
|
+
# A_ub=inequality_A,
|
|
1350
|
+
# b_ub=in_ub,
|
|
1351
|
+
# A_eq=equality_A,
|
|
1352
|
+
# b_eq=eq_ub,
|
|
1353
|
+
# method="highs-ipm",
|
|
1354
|
+
# integrality=integrality,
|
|
1355
|
+
# bounds=[(var.get_lower_bound(), var.get_upper_bound()) for var in self.variables],
|
|
1356
|
+
# options={
|
|
1357
|
+
# "disp": ConfigReader.DEBUG_PRINT,
|
|
1358
|
+
# "presolve": False,
|
|
1359
|
+
# "mip_rel_gap": 1e-3,
|
|
1360
|
+
# "ipm_optimality_tolerance": 1e-5,
|
|
1361
|
+
# },
|
|
1362
|
+
# # callback=linprog_verbose_callback if ConfigReader.DEBUG_PRINT else None
|
|
1363
|
+
# )
|
|
1364
|
+
|
|
1365
|
+
# Util.debug(f"Model:\n{result}")
|
|
1366
|
+
|
|
1367
|
+
# sol: Solution = None
|
|
1368
|
+
# if not result.success:
|
|
1369
|
+
# sol = Solution(False)
|
|
1370
|
+
# else:
|
|
1371
|
+
# for i in range(size):
|
|
1372
|
+
# if ConfigReader.DEBUG_PRINT or show_variable[i]:
|
|
1373
|
+
# name: str = self.variables[i].name
|
|
1374
|
+
# value: float = (
|
|
1375
|
+
# round(result.x[i], 6)
|
|
1376
|
+
# )
|
|
1377
|
+
# if self.PRINT_VARIABLES:
|
|
1378
|
+
# Util.debug(f"{name} = {value}")
|
|
1379
|
+
# if self.PRINT_LABELS:
|
|
1380
|
+
# self.print_instance_of_labels(name, value)
|
|
1381
|
+
# result: float = Util.round(abs(result.fun))
|
|
1382
|
+
# sol = Solution(result)
|
|
1383
|
+
|
|
1384
|
+
# Util.debug(
|
|
1385
|
+
# f"{constants.STAR_SEPARATOR}Statistics{constants.STAR_SEPARATOR}"
|
|
1386
|
+
# )
|
|
1387
|
+
# Util.debug("MILP problem:")
|
|
1388
|
+
# Util.debug(f"\t\tSemi continuous variables: {num_up_vars}")
|
|
1389
|
+
# Util.debug(f"\t\tBinary variables: {num_binary_vars}")
|
|
1390
|
+
# Util.debug(f"\t\tContinuous variables: {num_free_vars}")
|
|
1391
|
+
# Util.debug(f"\t\tInteger variables: {num_integer_vars}")
|
|
1392
|
+
# Util.debug(f"\t\tTotal variables: {len(self.variables)}")
|
|
1393
|
+
# Util.debug(f"\t\tConstraints: {len(self.constraints)}")
|
|
1394
|
+
# return sol
|
|
755
1395
|
|
|
756
1396
|
def add_crisp_concept(self, concept_name: str) -> None:
|
|
757
1397
|
self.crisp_concepts.add(concept_name)
|