fuzzy-dl-owl2 1.0.6__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 +3 -1
- 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/config_reader.py +44 -2
- fuzzy_dl_owl2/fuzzydl/util/constants.py +5 -6
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2.py +3 -1
- {fuzzy_dl_owl2-1.0.6.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/METADATA +72 -4
- {fuzzy_dl_owl2-1.0.6.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/RECORD +14 -14
- {fuzzy_dl_owl2-1.0.6.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/LICENSE +0 -0
- {fuzzy_dl_owl2-1.0.6.dist-info → fuzzy_dl_owl2-1.0.7.dist-info}/WHEEL +0 -0
|
@@ -122,26 +122,32 @@ class FeatureFunction:
|
|
|
122
122
|
self, a: Individual, milp: MILPHelper
|
|
123
123
|
) -> typing.Optional[Expression]:
|
|
124
124
|
if self.type == FeatureFunctionType.ATOMIC:
|
|
125
|
+
# Get the filler "b" for feature(a)
|
|
125
126
|
rel_set: list[Relation] = a.role_relations.get(self.feature)
|
|
127
|
+
assert len(rel_set) > 0
|
|
126
128
|
b: CreatedIndividual = typing.cast(
|
|
127
129
|
CreatedIndividual, rel_set[0].get_object_individual()
|
|
128
130
|
)
|
|
131
|
+
# Get the variable xB
|
|
129
132
|
x_b: Variable = milp.get_variable(b)
|
|
130
133
|
return Expression(Term(1.0, x_b))
|
|
131
134
|
elif self.type == FeatureFunctionType.NUMBER:
|
|
132
135
|
return Expression(self.n)
|
|
133
136
|
elif self.type == FeatureFunctionType.PRODUCT:
|
|
137
|
+
assert len(self.f) == 1
|
|
134
138
|
ex: Expression = self.f[0].to_expression(a, milp)
|
|
135
|
-
return
|
|
139
|
+
return ex * self.n
|
|
136
140
|
elif self.type == FeatureFunctionType.SUBTRACTION:
|
|
141
|
+
assert len(self.f) == 2
|
|
137
142
|
ex1: Expression = self.f[0].to_expression(a, milp)
|
|
138
143
|
ex2: Expression = self.f[1].to_expression(a, milp)
|
|
139
|
-
return
|
|
144
|
+
return ex1 - ex2
|
|
140
145
|
elif self.type == FeatureFunctionType.SUM:
|
|
146
|
+
assert len(self.f) >= 1
|
|
141
147
|
ex1: Expression = self.f[0].to_expression(a, milp)
|
|
142
148
|
for i in range(1, len(self.f)):
|
|
143
149
|
ex2: Expression = self.f[i].to_expression(a, milp)
|
|
144
|
-
ex1
|
|
150
|
+
ex1 = ex1 + ex2
|
|
145
151
|
return ex1
|
|
146
152
|
return None
|
|
147
153
|
|
|
@@ -129,6 +129,8 @@ from pyowl2.individual.named_individual import OWLNamedIndividual
|
|
|
129
129
|
from pyowl2.literal.literal import OWLLiteral
|
|
130
130
|
from pyowl2.ontology import OWLOntology
|
|
131
131
|
|
|
132
|
+
from fuzzy_dl_owl2.fuzzydl.util.config_reader import ConfigReader
|
|
133
|
+
|
|
132
134
|
|
|
133
135
|
# @utils.timer_decorator
|
|
134
136
|
class FuzzydlToOwl2:
|
|
@@ -149,7 +151,7 @@ class FuzzydlToOwl2:
|
|
|
149
151
|
self.ontology_iri, OWL1_annotations=True
|
|
150
152
|
)
|
|
151
153
|
self.fuzzyLabel: OWLAnnotationProperty = OWLAnnotationProperty(
|
|
152
|
-
IRI(self.ontology_iri.namespace,
|
|
154
|
+
IRI(self.ontology_iri.namespace, ConfigReader.OWL_ANNOTATION_LABEL)
|
|
153
155
|
)
|
|
154
156
|
|
|
155
157
|
self.ontology.add_axiom(OWLDeclaration(self.fuzzyLabel))
|
|
@@ -6435,6 +6435,7 @@ class DatatypeReasoner:
|
|
|
6435
6435
|
k: list[float],
|
|
6436
6436
|
type: InequalityType,
|
|
6437
6437
|
) -> None:
|
|
6438
|
+
# Gets fillers bi from every feature fi
|
|
6438
6439
|
array: set[str] = fun.get_features()
|
|
6439
6440
|
new_variable: bool = False
|
|
6440
6441
|
for feature in array:
|
|
@@ -6454,21 +6455,28 @@ class DatatypeReasoner:
|
|
|
6454
6455
|
x_fi: Variable = kb.milp.get_variable(
|
|
6455
6456
|
ind, bi, feature, VariableType.BINARY
|
|
6456
6457
|
)
|
|
6458
|
+
# (a,bi):Fi >= x_{(a,bi):Fi}
|
|
6457
6459
|
IndividualHandler.add_relation(
|
|
6458
6460
|
ind, feature, bi, DegreeVariable.get_degree(x_fi), kb
|
|
6459
6461
|
)
|
|
6460
|
-
x_bi: Variable = (
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6462
|
+
x_bi: Variable = kb.milp.get_variable(
|
|
6463
|
+
bi,
|
|
6464
|
+
(
|
|
6465
|
+
VariableType.INTEGER
|
|
6466
|
+
if t.get_type() == ConcreteFeatureType.INTEGER
|
|
6467
|
+
else VariableType.CONTINUOUS
|
|
6468
|
+
),
|
|
6464
6469
|
)
|
|
6465
|
-
if new_variable
|
|
6470
|
+
if new_variable and ki is not None:
|
|
6466
6471
|
kb.restrict_range(x_bi, x_fi, ki[0], ki[1])
|
|
6472
|
+
# xIsC <= xFi
|
|
6467
6473
|
kb.milp.add_new_constraint(
|
|
6468
6474
|
Expression(Term(1.0, x_is_c), Term(-1.0, x_fi)),
|
|
6469
6475
|
InequalityType.LESS_THAN,
|
|
6470
6476
|
)
|
|
6477
|
+
# xF \in {0,1}
|
|
6471
6478
|
x_fi.set_binary_variable()
|
|
6479
|
+
# xB is a datatype filler
|
|
6472
6480
|
x_bi.set_datatype_filler_variable()
|
|
6473
6481
|
DatatypeReasoner.write_feature_equation(ind, fun, x_b, x_is_c, x_f, k, type, kb)
|
|
6474
6482
|
|
|
@@ -98,7 +98,7 @@ class Expression:
|
|
|
98
98
|
|
|
99
99
|
def add_term(self, term: Term) -> None:
|
|
100
100
|
for idx, t in enumerate(self.terms):
|
|
101
|
-
if t == term:
|
|
101
|
+
if t.get_var() == term.get_var():
|
|
102
102
|
self.terms[idx] = t + term
|
|
103
103
|
return
|
|
104
104
|
self.terms.append(term)
|
|
@@ -169,6 +169,17 @@ class Expression:
|
|
|
169
169
|
def __truediv__(self, scalar: typing.Union[int, float]) -> typing.Self:
|
|
170
170
|
return self * (1 / scalar)
|
|
171
171
|
|
|
172
|
+
def __hash__(self) -> int:
|
|
173
|
+
return hash(str(self))
|
|
174
|
+
|
|
175
|
+
def __eq__(self, value: typing.Self) -> bool:
|
|
176
|
+
if not isinstance(value, Expression):
|
|
177
|
+
return False
|
|
178
|
+
return len(self.terms) == len(value.terms) and all(term in value.terms for term in self.terms)
|
|
179
|
+
|
|
180
|
+
def __ne__(self, value: typing.Self) -> bool:
|
|
181
|
+
return not (self == value)
|
|
182
|
+
|
|
172
183
|
def __repr__(self) -> str:
|
|
173
184
|
return str(self)
|
|
174
185
|
|
|
@@ -184,5 +195,5 @@ class Expression:
|
|
|
184
195
|
elif n == -1.0:
|
|
185
196
|
parts.append(f"- {term.get_var()}")
|
|
186
197
|
else:
|
|
187
|
-
parts.append(f"{'+ ' if n >= 0 else '- '}{n} {term.get_var()}")
|
|
198
|
+
parts.append(f"{'+ ' if n >= 0 else '- '}{abs(n)} {term.get_var()}")
|
|
188
199
|
return " ".join(parts)
|
|
@@ -43,6 +43,18 @@ class Inequation:
|
|
|
43
43
|
assert self.type == InequalityType.GREATER_THAN
|
|
44
44
|
return ">="
|
|
45
45
|
|
|
46
|
+
def is_zero(self) -> bool:
|
|
47
|
+
return all(term.get_coeff() == 0 for term in self.expr.get_terms()) and self.expr.get_constant() == 0
|
|
48
|
+
|
|
49
|
+
def __hash__(self) -> int:
|
|
50
|
+
return hash(str(self))
|
|
51
|
+
|
|
52
|
+
def __eq__(self, value: typing.Self) -> bool:
|
|
53
|
+
return self.expr == value.expr and self.type == value.type
|
|
54
|
+
|
|
55
|
+
def __ne__(self, value: typing.Self) -> bool:
|
|
56
|
+
return not (self == value)
|
|
57
|
+
|
|
46
58
|
def __repr__(self) -> str:
|
|
47
59
|
return str(self)
|
|
48
60
|
|
|
@@ -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)
|
|
@@ -64,11 +64,14 @@ class Term:
|
|
|
64
64
|
def __eq__(self, term: typing.Self) -> bool:
|
|
65
65
|
if not isinstance(term, Term):
|
|
66
66
|
return False
|
|
67
|
-
return self.var == term.var
|
|
67
|
+
return self.var == term.var and self.coeff == term.coeff
|
|
68
68
|
|
|
69
69
|
def __ne__(self, term: typing.Self) -> bool:
|
|
70
70
|
return not (self == term)
|
|
71
71
|
|
|
72
|
+
def __hash__(self) -> int:
|
|
73
|
+
return hash(str(self))
|
|
74
|
+
|
|
72
75
|
def __repr__(self) -> str:
|
|
73
76
|
return str(self)
|
|
74
77
|
|
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import configparser
|
|
4
|
+
import enum
|
|
4
5
|
import math
|
|
5
6
|
|
|
7
|
+
from fuzzy_dl_owl2.fuzzydl.util import constants
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MILPProvider(enum.StrEnum):
|
|
11
|
+
GUROBI = enum.auto()
|
|
12
|
+
MIP = enum.auto()
|
|
13
|
+
# SCIPY = enum.auto()
|
|
14
|
+
PULP = enum.auto()
|
|
15
|
+
PULP_GLPK = enum.auto()
|
|
16
|
+
PULP_HIGHS = enum.auto()
|
|
17
|
+
PULP_CPLEX = enum.auto()
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def from_str(value: str) -> MILPProvider:
|
|
21
|
+
try:
|
|
22
|
+
return MILPProvider(value.lower())
|
|
23
|
+
except ValueError:
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Invalid MILP provider: {value}. Valid options are: {list(MILPProvider)}"
|
|
26
|
+
)
|
|
27
|
+
|
|
6
28
|
|
|
7
29
|
class ConfigReader:
|
|
8
30
|
ANYWHERE_DOUBLE_BLOCKING: bool = True
|
|
9
31
|
ANYWHERE_SIMPLE_BLOCKING: bool = True
|
|
10
|
-
RELAX_MILP: bool = False
|
|
11
32
|
DEBUG_PRINT: bool = True
|
|
12
33
|
EPSILON: float = 0.001
|
|
13
34
|
MAX_INDIVIDUALS: int = -1
|
|
14
35
|
NUMBER_DIGITS: int = 2
|
|
15
36
|
OPTIMIZATIONS: int = 1
|
|
16
37
|
RULE_ACYCLIC_TBOXES: bool = True
|
|
38
|
+
OWL_ANNOTATION_LABEL: str = "fuzzyLabel"
|
|
39
|
+
MILP_PROVIDER: MILPProvider = MILPProvider.GUROBI
|
|
17
40
|
|
|
18
41
|
@staticmethod
|
|
19
42
|
def load_parameters(config_file: str, args: list[str]) -> None:
|
|
@@ -33,13 +56,32 @@ class ConfigReader:
|
|
|
33
56
|
# "author": False,
|
|
34
57
|
# }
|
|
35
58
|
|
|
36
|
-
ConfigReader.RELAX_MILP = config.getboolean("DEFAULT", "relaxMilp")
|
|
37
59
|
ConfigReader.DEBUG_PRINT = config.getboolean("DEFAULT", "debugPrint")
|
|
38
60
|
ConfigReader.EPSILON = config.getfloat("DEFAULT", "epsilon")
|
|
39
61
|
ConfigReader.MAX_INDIVIDUALS = config.getint("DEFAULT", "maxIndividuals")
|
|
62
|
+
ConfigReader.OWL_ANNOTATION_LABEL = config.get(
|
|
63
|
+
"DEFAULT", "owlAnnotationLabel"
|
|
64
|
+
)
|
|
65
|
+
ConfigReader.MILP_PROVIDER = MILPProvider(
|
|
66
|
+
config.get("DEFAULT", "milpProvider").lower()
|
|
67
|
+
)
|
|
40
68
|
ConfigReader.NUMBER_DIGITS = int(
|
|
41
69
|
round(abs(math.log10(ConfigReader.EPSILON) - 1.0))
|
|
42
70
|
)
|
|
71
|
+
if ConfigReader.MILP_PROVIDER in [
|
|
72
|
+
MILPProvider.MIP,
|
|
73
|
+
MILPProvider.PULP,
|
|
74
|
+
]:
|
|
75
|
+
constants.MAXVAL = (1 << 31) - 1
|
|
76
|
+
constants.MAXVAL2 = constants.MAXVAL * 2
|
|
77
|
+
elif ConfigReader.MILP_PROVIDER in [
|
|
78
|
+
MILPProvider.PULP_GLPK,
|
|
79
|
+
MILPProvider.PULP_HIGHS,
|
|
80
|
+
MILPProvider.PULP_CPLEX,
|
|
81
|
+
# MILPProvider.SCIPY,
|
|
82
|
+
]:
|
|
83
|
+
constants.MAXVAL = (1 << 28) - 1
|
|
84
|
+
constants.MAXVAL2 = constants.MAXVAL * 2
|
|
43
85
|
|
|
44
86
|
if ConfigReader.DEBUG_PRINT:
|
|
45
87
|
print(f"Debugging mode = {ConfigReader.DEBUG_PRINT}")
|
|
@@ -4,7 +4,6 @@ import re
|
|
|
4
4
|
import typing
|
|
5
5
|
|
|
6
6
|
import pyparsing as pp
|
|
7
|
-
from gurobipy import GRB
|
|
8
7
|
|
|
9
8
|
SEPARATOR: str = "-" * 25
|
|
10
9
|
STAR_SEPARATOR: str = "*" * 25
|
|
@@ -239,10 +238,10 @@ class InequalityType(enum.StrEnum):
|
|
|
239
238
|
|
|
240
239
|
|
|
241
240
|
class VariableType(enum.StrEnum):
|
|
242
|
-
BINARY =
|
|
243
|
-
CONTINUOUS =
|
|
244
|
-
INTEGER =
|
|
245
|
-
SEMI_CONTINUOUS =
|
|
241
|
+
BINARY = enum.auto()
|
|
242
|
+
CONTINUOUS = enum.auto()
|
|
243
|
+
INTEGER = enum.auto()
|
|
244
|
+
SEMI_CONTINUOUS = enum.auto()
|
|
246
245
|
|
|
247
246
|
def __repr__(self) -> str:
|
|
248
247
|
return self.name
|
|
@@ -421,5 +420,5 @@ class FuzzyLogic(enum.StrEnum):
|
|
|
421
420
|
|
|
422
421
|
|
|
423
422
|
KNOWLEDGE_BASE_SEMANTICS: FuzzyLogic = FuzzyLogic.CLASSICAL
|
|
424
|
-
MAXVAL: float = 2.147483647e12
|
|
423
|
+
MAXVAL: float = ((1 << 31) - 1) * 1000 # 2.147483647e12
|
|
425
424
|
MAXVAL2: float = MAXVAL * 2
|
|
@@ -146,6 +146,8 @@ from pyowl2.individual.anonymous_individual import OWLAnonymousIndividual
|
|
|
146
146
|
from pyowl2.literal.literal import OWLLiteral
|
|
147
147
|
from pyowl2.ontology import OWLOntology
|
|
148
148
|
|
|
149
|
+
from fuzzy_dl_owl2.fuzzydl.util.config_reader import ConfigReader
|
|
150
|
+
|
|
149
151
|
|
|
150
152
|
class FuzzyOwl2(object):
|
|
151
153
|
POS_INFINITY: float = 10000.0
|
|
@@ -174,7 +176,7 @@ class FuzzyOwl2(object):
|
|
|
174
176
|
self.ontology_iri, self.ontology_path, OWL1_annotations=True
|
|
175
177
|
)
|
|
176
178
|
self.fuzzy_label: OWLAnnotationProperty = OWLAnnotationProperty(
|
|
177
|
-
IRI(self.ontology_iri.namespace,
|
|
179
|
+
IRI(self.ontology_iri.namespace, ConfigReader.OWL_ANNOTATION_LABEL)
|
|
178
180
|
)
|
|
179
181
|
self.ontologies.add(self.ontology)
|
|
180
182
|
# self.ontologies.update(self.manager.getImportsClosure(self.ontology))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: fuzzy-dl-owl2
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: A python porting of the Fuzzy Description Language (see https://www.umbertostraccia.it/cs/software/fuzzyDL/fuzzyDL.html) and the Fuzzy OWL 2 framework (see https://www.umbertostraccia.it/cs/software/FuzzyOWL/index.html).
|
|
5
5
|
License: CC-BY-SA-4.0
|
|
6
6
|
Author: Giuseppe Filippone
|
|
@@ -11,12 +11,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Requires-Dist: gurobipy (>=12.0.0,<13.0.0)
|
|
15
14
|
Requires-Dist: networkx (>=3.3,<4.0)
|
|
16
15
|
Requires-Dist: owlready2 (>=0.47,<0.48)
|
|
17
16
|
Requires-Dist: pyowl2 (>=1.0.2,<2.0.0)
|
|
18
17
|
Requires-Dist: pyparsing (>=3.2.3,<4.0.0)
|
|
19
18
|
Requires-Dist: rdflib (>=7.1.4,<8.0.0)
|
|
19
|
+
Requires-Dist: setuptools (>=80.8.0,<81.0.0)
|
|
20
20
|
Requires-Dist: sortedcontainers (>=2.4.0,<3.0.0)
|
|
21
21
|
Requires-Dist: trycast (>=1.2.0,<2.0.0)
|
|
22
22
|
Project-URL: Repository, https://github.com/giuseppefilippone/fuzzy_dl_owl2
|
|
@@ -78,17 +78,85 @@ The file `CONFIG.ini` is structured as follows:
|
|
|
78
78
|
```text
|
|
79
79
|
[DEFAULT]
|
|
80
80
|
debugPrint = False
|
|
81
|
-
relaxMilp = False
|
|
82
81
|
epsilon = 0.001
|
|
83
82
|
maxIndividuals = -1
|
|
83
|
+
owlAnnotationLabel = fuzzyLabel
|
|
84
|
+
milpProvider = mip
|
|
84
85
|
```
|
|
85
86
|
|
|
86
87
|
| Configuration Variable | Description |
|
|
87
88
|
|----------------------|-----------------------------------|
|
|
88
89
|
| debugPrint | Enable/disable debugging |
|
|
89
|
-
| relaxMilp | Enable/disable MILP constraint relaxation. Important: The solution may be wrong by enabling this flag |
|
|
90
90
|
| epsilon | Define the precision of the solution. For instance, epsilon = 0.001 means that the solution will be calculated with an accuracy to the third decimal place |
|
|
91
91
|
| maxIndividuals | Define the maximal number of individuals to handle. The value -1 indicate that there is no maximum |
|
|
92
|
+
| owlAnnotationLabel | Define the Annotation label used to build the Fuzzy OWL 2 RDF/XML ontology |
|
|
93
|
+
| milpProvider | Define the MILP provider used by the reasoner. The supported providers are listed below. |
|
|
94
|
+
|
|
95
|
+
Supported MILP Providers:
|
|
96
|
+
| Provider | milpProvider |
|
|
97
|
+
|--------------|----------------------|
|
|
98
|
+
| Gurobi | gurobi |
|
|
99
|
+
| CPLEX | pulp_cplex |
|
|
100
|
+
| CBC | pulp |
|
|
101
|
+
| GLPK | pulp_glpk |
|
|
102
|
+
| HiGHS | pulp_highs |
|
|
103
|
+
| MIP | mip |
|
|
104
|
+
|
|
105
|
+
⸻
|
|
106
|
+
|
|
107
|
+
# MILP Provider Usage and Configuration
|
|
108
|
+
|
|
109
|
+
## GUROBI
|
|
110
|
+
|
|
111
|
+
- Install [gurobipy](https://pypi.org/project/gurobipy/):
|
|
112
|
+
```python
|
|
113
|
+
pip install gurobipy==12.0.0
|
|
114
|
+
```
|
|
115
|
+
- Download the GUROBI license from their [website](https://www.gurobi.com/solutions/licensing/).
|
|
116
|
+
- Add Gurobi to the PATH
|
|
117
|
+
|
|
118
|
+
## MIP
|
|
119
|
+
|
|
120
|
+
- Install python [MIP](https://www.python-mip.com/):
|
|
121
|
+
```python
|
|
122
|
+
pip install mip==1.16rc0
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## GLPK
|
|
126
|
+
|
|
127
|
+
- Install [GLPK](https://www.gnu.org/software/glpk/) v5.0 and [GMP](https://gmplib.org/) v6.3.0
|
|
128
|
+
- Install python [pulp](https://github.com/coin-or/PuLP?tab=readme-ov-file):
|
|
129
|
+
```python
|
|
130
|
+
pip install pulp==3.2.1
|
|
131
|
+
```
|
|
132
|
+
- Add GLPK to the PATH
|
|
133
|
+
|
|
134
|
+
## CBC
|
|
135
|
+
|
|
136
|
+
- Install [CBC](https://github.com/coin-or/Cbc)
|
|
137
|
+
- Install python [pulp](https://github.com/coin-or/PuLP?tab=readme-ov-file):
|
|
138
|
+
```python
|
|
139
|
+
pip install pulp==3.2.1
|
|
140
|
+
```
|
|
141
|
+
- Add CBC to the PATH
|
|
142
|
+
|
|
143
|
+
## CPLEX
|
|
144
|
+
|
|
145
|
+
- Install [CPLEX](https://www.ibm.com/it-it/products/ilog-cplex-optimization-studio) v22.11
|
|
146
|
+
- Install python [pulp](https://github.com/coin-or/PuLP?tab=readme-ov-file):
|
|
147
|
+
```python
|
|
148
|
+
pip install pulp==3.2.1
|
|
149
|
+
```
|
|
150
|
+
- Add CPLEX to the PATH
|
|
151
|
+
|
|
152
|
+
## HiGHS
|
|
153
|
+
|
|
154
|
+
- Install [HiGHS](https://ergo-code.github.io/HiGHS/dev/interfaces/cpp/) v1.10.0
|
|
155
|
+
- Install python [pulp](https://github.com/coin-or/PuLP?tab=readme-ov-file):
|
|
156
|
+
```python
|
|
157
|
+
pip install pulp==3.2.1
|
|
158
|
+
```
|
|
159
|
+
- Add HiGHS to the PATH
|
|
92
160
|
|
|
93
161
|
⸻
|
|
94
162
|
|
|
@@ -61,22 +61,22 @@ fuzzy_dl_owl2/fuzzydl/domain_axiom.py,sha256=qPjeqmA7zQt6VT-bLtT82F74fiORPegQytd
|
|
|
61
61
|
fuzzy_dl_owl2/fuzzydl/exception/__init__.py,sha256=IoYY5IQoU4UYyoB-dFOVLZyDvJN20kgZVBqWkF6J30w,135
|
|
62
62
|
fuzzy_dl_owl2/fuzzydl/exception/fuzzy_ontology_exception.py,sha256=eH1ybBCx1QoZaf8PLCq1rC_3tiBRA-gKCwECTcUUuro,122
|
|
63
63
|
fuzzy_dl_owl2/fuzzydl/exception/inconsistent_ontology_exception.py,sha256=ez0RQN4KGlNRcfB7IXfPz3bM86CFLl6zo-RRTBRpa_o,129
|
|
64
|
-
fuzzy_dl_owl2/fuzzydl/feature_function.py,sha256=
|
|
65
|
-
fuzzy_dl_owl2/fuzzydl/fuzzydl_to_owl2.py,sha256=
|
|
64
|
+
fuzzy_dl_owl2/fuzzydl/feature_function.py,sha256=Ipfd_UuKWKqCp8jdyV3Hxia0l3yj8jjNu-kOGQ7qf3Y,6525
|
|
65
|
+
fuzzy_dl_owl2/fuzzydl/fuzzydl_to_owl2.py,sha256=VjmHtokMAE0jC9jI8WjGeiCTQ-A8YmmUH14FEVTyrDU,53111
|
|
66
66
|
fuzzy_dl_owl2/fuzzydl/general_concept_inclusion.py,sha256=Noom35WAeJosPrliGd9_gvEtcK4BthazsSuZH-cxfyU,2380
|
|
67
67
|
fuzzy_dl_owl2/fuzzydl/individual/__init__.py,sha256=zBCa24kE2nv08VgtphjLshpbGNEARUJgCdtyv9r6JGc,110
|
|
68
68
|
fuzzy_dl_owl2/fuzzydl/individual/created_individual.py,sha256=HOo_UXjPPPtm7B0a7k90kE1veuR9gOCK5hp2f_aaJnY,7653
|
|
69
69
|
fuzzy_dl_owl2/fuzzydl/individual/individual.py,sha256=FgtOmJwkPUKIOr-o8a1NqHepL-sN5fGe314e895DHYg,3846
|
|
70
70
|
fuzzy_dl_owl2/fuzzydl/individual/representative_individual.py,sha256=C5ZG43Xy0Iz71S5IYPzaBGeT-fWIqQGpg85DPgU1NjM,1070
|
|
71
|
-
fuzzy_dl_owl2/fuzzydl/knowledge_base.py,sha256=
|
|
71
|
+
fuzzy_dl_owl2/fuzzydl/knowledge_base.py,sha256=ve0NYDz1b2Up-ZoTzJO-JltyupMFhyy9meIzMvFIt-I,385863
|
|
72
72
|
fuzzy_dl_owl2/fuzzydl/label.py,sha256=KD39rTIlg0XhDJSVqNC6t0Pu60MVfO8xNGSjrcJFtD0,1023
|
|
73
73
|
fuzzy_dl_owl2/fuzzydl/milp/__init__.py,sha256=g2oFT2Ge8W5Li2kP2CJjpjJ1a0PRI2vDoDdzYDsEtDY,246
|
|
74
|
-
fuzzy_dl_owl2/fuzzydl/milp/expression.py,sha256=
|
|
75
|
-
fuzzy_dl_owl2/fuzzydl/milp/inequation.py,sha256=
|
|
76
|
-
fuzzy_dl_owl2/fuzzydl/milp/milp_helper.py,sha256=
|
|
74
|
+
fuzzy_dl_owl2/fuzzydl/milp/expression.py,sha256=HTCSk_EGTO7ATIQuV65mKa06eY433PVs_8jyw4kbELg,6596
|
|
75
|
+
fuzzy_dl_owl2/fuzzydl/milp/inequation.py,sha256=4agNmrrT8K1uEnm553nD8OPwVY4l4rF3Dxw-_PBj5lw,2040
|
|
76
|
+
fuzzy_dl_owl2/fuzzydl/milp/milp_helper.py,sha256=aghOzlFqkZUK53lIPXIeDbwgt2E6cCy805bN35DGq0E,58324
|
|
77
77
|
fuzzy_dl_owl2/fuzzydl/milp/show_variables_helper.py,sha256=7y-lfhoERoE8qNSMr0cq_-Ezo46BGsNszp44YSVWA2A,5754
|
|
78
78
|
fuzzy_dl_owl2/fuzzydl/milp/solution.py,sha256=suoE1F2XORwzP4pNm-6Ivf6eK5Z98KFxFUdarh1CjQk,1210
|
|
79
|
-
fuzzy_dl_owl2/fuzzydl/milp/term.py,sha256=
|
|
79
|
+
fuzzy_dl_owl2/fuzzydl/milp/term.py,sha256=JIRO3rrMz1e6I3g0tElFbwXyOxtiy8L7Wh6EisQfSuM,2294
|
|
80
80
|
fuzzy_dl_owl2/fuzzydl/milp/variable.py,sha256=_qqLZpOkXCaeyguQQWLIQvTPzyPaMNSpPIAL4T0A9C8,2725
|
|
81
81
|
fuzzy_dl_owl2/fuzzydl/modifier/__init__.py,sha256=mgJml-9PVs566EYpwBxfmmiw8oPXiSgJRUyIX9hiSNA,126
|
|
82
82
|
fuzzy_dl_owl2/fuzzydl/modifier/linear_modifier.py,sha256=Rn6q4ytIdTiCI-TRZIK5qjWSA4K3q78fYSrYxlQklVc,2022
|
|
@@ -118,12 +118,12 @@ fuzzy_dl_owl2/fuzzydl/restriction/has_value_restriction.py,sha256=DL-50TlD289OXV
|
|
|
118
118
|
fuzzy_dl_owl2/fuzzydl/restriction/restriction.py,sha256=SyeFvaJeKcTe750eAbLoAVYkWTK_UjdqWr2Lw8OF1S0,948
|
|
119
119
|
fuzzy_dl_owl2/fuzzydl/role_parent_with_degree.py,sha256=1J5dtlVbiascxHBwAJ7uc97IHnJke9RWqxq5rgrrkoA,282
|
|
120
120
|
fuzzy_dl_owl2/fuzzydl/util/__init__.py,sha256=3GufSMUuWGISGukXM5T5ZGA0BC1WX-5eLFSuttVYueU,109
|
|
121
|
-
fuzzy_dl_owl2/fuzzydl/util/config_reader.py,sha256=
|
|
122
|
-
fuzzy_dl_owl2/fuzzydl/util/constants.py,sha256=
|
|
121
|
+
fuzzy_dl_owl2/fuzzydl/util/config_reader.py,sha256=dh2Xa1sYVlKavbkKShHkxzA0ieLoQOV1JmzkOvIIVMI,3174
|
|
122
|
+
fuzzy_dl_owl2/fuzzydl/util/constants.py,sha256=tZKlMOZlZD9iKgaLv8NIId5WK04JuFg6FuXyA7zEe8E,12815
|
|
123
123
|
fuzzy_dl_owl2/fuzzydl/util/util.py,sha256=5COC79TAJz8fNrRzXLbNpAT9rLd_0KrRI1OU-hob3oU,1903
|
|
124
124
|
fuzzy_dl_owl2/fuzzydl/util/utils.py,sha256=TPVLEL9NJXgReuxEIOTEOVYqojSymg_-kyrLETXnYdo,2344
|
|
125
125
|
fuzzy_dl_owl2/fuzzyowl2/__init__.py,sha256=C44P0-Sn35FQdVMqYLzeDWa5qPmokbcs8GPiD_zQaSg,153
|
|
126
|
-
fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2.py,sha256=
|
|
126
|
+
fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2.py,sha256=TYnSLXK-oR7jsOEFR46WryA0gKVBLbBI0_3Cd-dHUuU,71691
|
|
127
127
|
fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2_to_fuzzydl.py,sha256=egspxTzY4kNvhsQLP0AAaqJgFUqyO6VJuXLLOej06PA,36994
|
|
128
128
|
fuzzy_dl_owl2/fuzzyowl2/owl_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
129
129
|
fuzzy_dl_owl2/fuzzyowl2/owl_types/choquet_concept.py,sha256=ymnyNfvkvWA3y2UMXyPviD0U98vJ6jrX6zddj09SUoI,671
|
|
@@ -158,7 +158,7 @@ fuzzy_dl_owl2/fuzzyowl2/parser/owl2_xml_parser.py,sha256=qbx6SsrYUdDOn1-qClq-0EC
|
|
|
158
158
|
fuzzy_dl_owl2/fuzzyowl2/util/__init__.py,sha256=4qG4CwkdYoT0vh3uX9N8DlmXh4QfKimVUqR4h2DR8Gg,50
|
|
159
159
|
fuzzy_dl_owl2/fuzzyowl2/util/constants.py,sha256=Oev5Q-H4mhmdvV3nrp0fZKZx8jpo9beXjJwm0dfDUSc,6970
|
|
160
160
|
fuzzy_dl_owl2/fuzzyowl2/util/fuzzy_xml.py,sha256=iYAodtBkZYt3cOvMBA0VEMOU87ljb-06_aUfH14gvwE,3416
|
|
161
|
-
fuzzy_dl_owl2-1.0.
|
|
162
|
-
fuzzy_dl_owl2-1.0.
|
|
163
|
-
fuzzy_dl_owl2-1.0.
|
|
164
|
-
fuzzy_dl_owl2-1.0.
|
|
161
|
+
fuzzy_dl_owl2-1.0.7.dist-info/LICENSE,sha256=er4Z7Ju3OzYUG5mbhh0krYVegIuv4PgehMzihVb2wpc,20131
|
|
162
|
+
fuzzy_dl_owl2-1.0.7.dist-info/METADATA,sha256=NM2tQrq1p7MNs5PbRMBl4ECC1qYG1EC-eqmWjTGHyNk,14681
|
|
163
|
+
fuzzy_dl_owl2-1.0.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
164
|
+
fuzzy_dl_owl2-1.0.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|