From fcdf134cf28e45293dfbbfaf7c59ff86915a67a8 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Wed, 4 Dec 2024 07:48:04 +0100 Subject: [PATCH] Minify the library to a stub, to start building it for arm64 using Qemu --- .github/workflows/build-test-gha-branches.yml | 199 +- doc-sources/get-started/get-started.ipynb | 12 +- .../alglib-learning/alglib-learning.ipynb | 2 +- .../gpu-learning/gpu-learning.ipynb | 2 +- .../synthetic-data/synthetic-data.ipynb | 8 +- lincs/__init__.py | 26 +- lincs/classification.py | 50 +- lincs/description.py | 324 --- lincs/liblincs/classification.cpp | 423 --- lincs/liblincs/classification.hpp | 22 - lincs/liblincs/generation.cpp | 912 ------- lincs/liblincs/generation.hpp | 50 - lincs/liblincs/io.cpp | 3 - lincs/liblincs/io.hpp | 11 - lincs/liblincs/io/alternatives.cpp | 331 --- lincs/liblincs/io/alternatives.hpp | 158 -- lincs/liblincs/io/exception.cpp | 3 - lincs/liblincs/io/exception.hpp | 23 - lincs/liblincs/io/model.cpp | 1098 -------- lincs/liblincs/io/model.hpp | 332 --- lincs/liblincs/io/problem.cpp | 476 ---- lincs/liblincs/io/problem.hpp | 201 -- lincs/liblincs/io/validation.cpp | 43 - lincs/liblincs/io/validation.hpp | 25 - lincs/liblincs/learning.cpp | 1810 ------------- lincs/liblincs/learning.hpp | 37 - lincs/liblincs/learning/exception.cpp | 3 - lincs/liblincs/learning/exception.hpp | 17 - .../mrsort-by-weights-profiles-breed.cpp | 270 -- .../mrsort-by-weights-profiles-breed.hpp | 175 -- .../breed/reinitialize-least-accurate.cpp | 17 - .../breed/reinitialize-least-accurate.hpp | 38 - .../accuracy-heuristic-on-cpu.cpp | 492 ---- .../accuracy-heuristic-on-cpu.hpp | 101 - .../accuracy-heuristic-on-gpu.cu | 736 ------ .../accuracy-heuristic-on-gpu.hpp | 91 - .../accuracy-heuristic/desirability.hpp | 62 - ...mal-discrimination-power-per-criterion.cpp | 254 -- ...mal-discrimination-power-per-criterion.hpp | 40 - .../optimize-weights/linear-program.cpp | 100 - .../optimize-weights/linear-program.hpp | 33 - .../after-iterations-without-progress.hpp | 46 - .../terminate/after-iterations.hpp | 27 - .../after-seconds-without-progress.hpp | 48 - .../terminate/after-seconds.hpp | 29 - .../terminate/at-accuracy.cpp | 12 - .../terminate/at-accuracy.hpp | 25 - .../terminate/composite.cpp | 18 - .../terminate/composite.hpp | 24 - lincs/liblincs/learning/pre-processing.cpp | 205 -- lincs/liblincs/learning/pre-processing.hpp | 59 - .../ucncs-by-max-sat-by-coalitions.cpp | 289 --- .../ucncs-by-max-sat-by-coalitions.hpp | 66 - .../ucncs-by-max-sat-by-separation.cpp | 356 --- .../ucncs-by-max-sat-by-separation.hpp | 62 - .../learning/ucncs-by-sat-by-coalitions.cpp | 305 --- .../learning/ucncs-by-sat-by-coalitions.hpp | 66 - .../learning/ucncs-by-sat-by-separation.cpp | 306 --- .../learning/ucncs-by-sat-by-separation.hpp | 59 - lincs/liblincs/liblincs-module/converters.cpp | 140 - .../liblincs-module/generation-functions.cpp | 55 - lincs/liblincs/liblincs-module/io-classes.cpp | 786 ------ .../liblincs-module/learning-classes.cpp | 591 ----- lincs/liblincs/liblincs-module/main.cpp | 4 - lincs/liblincs/lincs.hpp | 4 +- lincs/liblincs/linear-programming/alglib.cpp | 28 - lincs/liblincs/linear-programming/alglib.hpp | 95 - lincs/liblincs/linear-programming/glop.cpp | 27 - lincs/liblincs/linear-programming/glop.hpp | 69 - ...timization-goes-too-far-during-phase-1.cpp | 26 - ...tion-still-goes-too-far-during-phase-1.cpp | 1426 ----------- ...tion-still-goes-too-far-during-phase-1.cpp | 1426 ----------- ...all-error-gets-inverted-to-large-error.cpp | 29 - ...-0005-gpu-behaves-differently-from-cpu.cpp | 31 - lincs/liblincs/linear-programming/test.cpp | 660 ----- lincs/liblincs/linear-programming/testing.hpp | 84 - lincs/liblincs/randomness-utils.cpp | 71 - lincs/liblincs/randomness-utils.hpp | 67 - lincs/liblincs/sat/eval-max-sat.cpp | 25 - lincs/liblincs/sat/eval-max-sat.hpp | 66 - lincs/liblincs/sat/minisat.cpp | 28 - lincs/liblincs/sat/minisat.hpp | 52 - lincs/liblincs/sat/test.cpp | 110 - lincs/liblincs/test-cuda-floating-points.cu | 121 - .../vendored/alglib/alglibinternal.cpp | 1 - .../liblincs/vendored/alglib/alglibinternal.h | 1 - lincs/liblincs/vendored/alglib/alglibmisc.cpp | 1 - lincs/liblincs/vendored/alglib/alglibmisc.h | 1 - lincs/liblincs/vendored/alglib/ap.cpp | 1 - lincs/liblincs/vendored/alglib/ap.h | 1 - .../liblincs/vendored/alglib/dataanalysis.cpp | 1 - lincs/liblincs/vendored/alglib/dataanalysis.h | 1 - .../vendored/alglib/diffequations.cpp | 1 - .../liblincs/vendored/alglib/diffequations.h | 1 - .../vendored/alglib/fasttransforms.cpp | 1 - .../liblincs/vendored/alglib/fasttransforms.h | 1 - .../liblincs/vendored/alglib/integration.cpp | 1 - lincs/liblincs/vendored/alglib/integration.h | 1 - .../vendored/alglib/interpolation.cpp | 1 - .../liblincs/vendored/alglib/interpolation.h | 1 - .../liblincs/vendored/alglib/kernels_avx2.cpp | 1 - lincs/liblincs/vendored/alglib/kernels_avx2.h | 1 - .../liblincs/vendored/alglib/kernels_fma.cpp | 1 - lincs/liblincs/vendored/alglib/kernels_fma.h | 1 - .../liblincs/vendored/alglib/kernels_sse2.cpp | 1 - lincs/liblincs/vendored/alglib/kernels_sse2.h | 1 - lincs/liblincs/vendored/alglib/linalg.cpp | 1 - lincs/liblincs/vendored/alglib/linalg.h | 1 - .../liblincs/vendored/alglib/optimization.cpp | 1 - lincs/liblincs/vendored/alglib/optimization.h | 1 - lincs/liblincs/vendored/alglib/solvers.cpp | 1 - lincs/liblincs/vendored/alglib/solvers.h | 1 - .../vendored/alglib/specialfunctions.cpp | 1 - .../vendored/alglib/specialfunctions.h | 1 - lincs/liblincs/vendored/alglib/statistics.cpp | 1 - lincs/liblincs/vendored/alglib/statistics.h | 1 - lincs/liblincs/vendored/alglib/stdafx.h | 1 - .../vendored/eval-max-sat/EvalMaxSAT.h | 1 - .../vendored/eval-max-sat/MaLib/Chrono.h | 1 - .../vendored/eval-max-sat/MaLib/View.h | 1 - .../eval-max-sat/MaLib/communicationlist.h | 1 - .../vendored/eval-max-sat/cadical/analyze.cpp | 1 - .../vendored/eval-max-sat/cadical/arena.cpp | 1 - .../vendored/eval-max-sat/cadical/arena.hpp | 1 - .../vendored/eval-max-sat/cadical/assume.cpp | 1 - .../eval-max-sat/cadical/averages.cpp | 1 - .../eval-max-sat/cadical/averages.hpp | 1 - .../eval-max-sat/cadical/backtrack.cpp | 1 - .../eval-max-sat/cadical/backward.cpp | 1 - .../vendored/eval-max-sat/cadical/bins.cpp | 1 - .../vendored/eval-max-sat/cadical/bins.hpp | 1 - .../vendored/eval-max-sat/cadical/block.cpp | 1 - .../vendored/eval-max-sat/cadical/block.hpp | 1 - .../vendored/eval-max-sat/cadical/cadical.hpp | 1 - .../vendored/eval-max-sat/cadical/checker.cpp | 1 - .../vendored/eval-max-sat/cadical/checker.hpp | 1 - .../vendored/eval-max-sat/cadical/clause.cpp | 1 - .../vendored/eval-max-sat/cadical/clause.hpp | 1 - .../vendored/eval-max-sat/cadical/collect.cpp | 1 - .../vendored/eval-max-sat/cadical/compact.cpp | 1 - .../eval-max-sat/cadical/condition.cpp | 1 - .../vendored/eval-max-sat/cadical/config.cpp | 1 - .../vendored/eval-max-sat/cadical/config.hpp | 1 - .../eval-max-sat/cadical/constrain.cpp | 1 - .../eval-max-sat/cadical/contract.cpp | 1 - .../eval-max-sat/cadical/contract.hpp | 1 - .../vendored/eval-max-sat/cadical/cover.cpp | 1 - .../vendored/eval-max-sat/cadical/cover.hpp | 1 - .../vendored/eval-max-sat/cadical/decide.cpp | 1 - .../eval-max-sat/cadical/decompose.cpp | 1 - .../eval-max-sat/cadical/deduplicate.cpp | 1 - .../vendored/eval-max-sat/cadical/elim.cpp | 1 - .../vendored/eval-max-sat/cadical/elim.hpp | 1 - .../vendored/eval-max-sat/cadical/ema.cpp | 1 - .../vendored/eval-max-sat/cadical/ema.hpp | 1 - .../vendored/eval-max-sat/cadical/extend.cpp | 1 - .../eval-max-sat/cadical/external.cpp | 1 - .../eval-max-sat/cadical/external.hpp | 1 - .../vendored/eval-max-sat/cadical/flags.cpp | 1 - .../vendored/eval-max-sat/cadical/flags.hpp | 1 - .../vendored/eval-max-sat/cadical/format.cpp | 1 - .../vendored/eval-max-sat/cadical/format.hpp | 1 - .../vendored/eval-max-sat/cadical/gates.cpp | 1 - .../vendored/eval-max-sat/cadical/heap.hpp | 1 - .../eval-max-sat/cadical/instantiate.cpp | 1 - .../eval-max-sat/cadical/instantiate.hpp | 1 - .../eval-max-sat/cadical/internal.cpp | 1 - .../eval-max-sat/cadical/internal.hpp | 1 - .../eval-max-sat/cadical/inttypes.hpp | 1 - .../vendored/eval-max-sat/cadical/ipasir.h | 1 - .../vendored/eval-max-sat/cadical/level.hpp | 1 - .../vendored/eval-max-sat/cadical/limit.cpp | 1 - .../vendored/eval-max-sat/cadical/limit.hpp | 1 - .../vendored/eval-max-sat/cadical/logging.cpp | 1 - .../vendored/eval-max-sat/cadical/logging.hpp | 1 - .../eval-max-sat/cadical/lookahead.cpp | 1 - .../vendored/eval-max-sat/cadical/lucky.cpp | 1 - .../vendored/eval-max-sat/cadical/message.cpp | 1 - .../vendored/eval-max-sat/cadical/message.hpp | 1 - .../eval-max-sat/cadical/minimize.cpp | 1 - .../eval-max-sat/cadical/observer.hpp | 1 - .../vendored/eval-max-sat/cadical/occs.cpp | 1 - .../vendored/eval-max-sat/cadical/occs.hpp | 1 - .../vendored/eval-max-sat/cadical/options.cpp | 1 - .../vendored/eval-max-sat/cadical/options.hpp | 1 - .../vendored/eval-max-sat/cadical/parse.hpp | 1 - .../vendored/eval-max-sat/cadical/phases.cpp | 1 - .../vendored/eval-max-sat/cadical/phases.hpp | 1 - .../vendored/eval-max-sat/cadical/probe.cpp | 1 - .../vendored/eval-max-sat/cadical/profile.cpp | 1 - .../vendored/eval-max-sat/cadical/profile.hpp | 1 - .../eval-max-sat/cadical/propagate.cpp | 1 - .../vendored/eval-max-sat/cadical/queue.cpp | 1 - .../vendored/eval-max-sat/cadical/queue.hpp | 1 - .../vendored/eval-max-sat/cadical/radix.hpp | 1 - .../vendored/eval-max-sat/cadical/random.cpp | 1 - .../vendored/eval-max-sat/cadical/random.hpp | 1 - .../vendored/eval-max-sat/cadical/range.hpp | 1 - .../vendored/eval-max-sat/cadical/reduce.cpp | 1 - .../eval-max-sat/cadical/reluctant.hpp | 1 - .../vendored/eval-max-sat/cadical/rephase.cpp | 1 - .../vendored/eval-max-sat/cadical/report.cpp | 1 - .../eval-max-sat/cadical/resources.cpp | 1 - .../eval-max-sat/cadical/resources.hpp | 1 - .../vendored/eval-max-sat/cadical/restart.cpp | 1 - .../vendored/eval-max-sat/cadical/restore.cpp | 1 - .../vendored/eval-max-sat/cadical/score.cpp | 1 - .../vendored/eval-max-sat/cadical/score.hpp | 1 - .../vendored/eval-max-sat/cadical/shrink.cpp | 1 - .../vendored/eval-max-sat/cadical/signal.hpp | 1 - .../eval-max-sat/cadical/solution.cpp | 1 - .../vendored/eval-max-sat/cadical/solver.cpp | 1 - .../vendored/eval-max-sat/cadical/stats.cpp | 1 - .../vendored/eval-max-sat/cadical/stats.hpp | 1 - .../vendored/eval-max-sat/cadical/subsume.cpp | 1 - .../vendored/eval-max-sat/cadical/ternary.cpp | 1 - .../vendored/eval-max-sat/cadical/tracer.hpp | 1 - .../eval-max-sat/cadical/transred.cpp | 1 - .../vendored/eval-max-sat/cadical/util.cpp | 1 - .../vendored/eval-max-sat/cadical/util.hpp | 1 - .../vendored/eval-max-sat/cadical/var.cpp | 1 - .../vendored/eval-max-sat/cadical/var.hpp | 1 - .../vendored/eval-max-sat/cadical/version.cpp | 1 - .../vendored/eval-max-sat/cadical/version.hpp | 1 - .../vendored/eval-max-sat/cadical/vivify.cpp | 1 - .../vendored/eval-max-sat/cadical/vivify.hpp | 1 - .../vendored/eval-max-sat/cadical/walk.cpp | 1 - .../vendored/eval-max-sat/cadical/watch.cpp | 1 - .../vendored/eval-max-sat/cadical/watch.hpp | 1 - .../vendored/eval-max-sat/cadicalinterface.h | 1 - .../liblincs/vendored/eval-max-sat/card_oe.h | 1 - .../vendored/eval-max-sat/cardincremental.cpp | 1 - .../vendored/eval-max-sat/cardincremental.h | 1 - .../vendored/eval-max-sat/lazyvariable.cpp | 1 - .../vendored/eval-max-sat/lazyvariable.h | 1 - lincs/liblincs/vendored/eval-max-sat/mcqd.h | 1 - .../vendored/eval-max-sat/virtualcard.cpp | 1 - .../vendored/eval-max-sat/virtualcard.h | 1 - .../vendored/eval-max-sat/virtualmaxsat.h | 1 - .../vendored/eval-max-sat/virtualsat.cpp | 1 - .../vendored/eval-max-sat/virtualsat.h | 1 - lincs/liblincs/vendored/lov-e.hpp | 1 - lincs/liblincs/vendored/magic_enum.hpp | 1 - .../liblincs/vendored/minisat/core/Solver.cc | 1 - lincs/liblincs/vendored/minisat/core/Solver.h | 1 - .../vendored/minisat/core/SolverTypes.h | 1 - lincs/liblincs/vendored/minisat/mtl/Alg.h | 1 - lincs/liblincs/vendored/minisat/mtl/Alloc.h | 1 - lincs/liblincs/vendored/minisat/mtl/Heap.h | 1 - lincs/liblincs/vendored/minisat/mtl/IntMap.h | 1 - .../liblincs/vendored/minisat/mtl/IntTypes.h | 1 - lincs/liblincs/vendored/minisat/mtl/Map.h | 1 - lincs/liblincs/vendored/minisat/mtl/Queue.h | 1 - lincs/liblincs/vendored/minisat/mtl/Sort.h | 1 - lincs/liblincs/vendored/minisat/mtl/Vec.h | 1 - lincs/liblincs/vendored/minisat/mtl/XAlloc.h | 1 - .../vendored/minisat/simp/SimpSolver.cc | 1 - .../vendored/minisat/simp/SimpSolver.h | 1 - lincs/liblincs/vendored/rapidcsv.h | 1 - .../valijson/adapters/std_string_adapter.hpp | 1 - .../valijson/adapters/yaml_cpp_adapter.hpp | 1 - .../vendored/valijson/compat/optional.hpp | 1 - .../vendored/valijson/constraint_builder.hpp | 1 - .../valijson/constraints/basic_constraint.hpp | 1 - .../constraints/concrete_constraints.hpp | 1 - .../valijson/constraints/constraint.hpp | 1 - .../constraints/constraint_visitor.hpp | 1 - .../liblincs/vendored/valijson/exceptions.hpp | 1 - .../vendored/valijson/internal/adapter.hpp | 1 - .../valijson/internal/basic_adapter.hpp | 1 - .../valijson/internal/custom_allocator.hpp | 1 - .../vendored/valijson/internal/debug.hpp | 1 - .../valijson/internal/frozen_value.hpp | 1 - .../valijson/internal/json_pointer.hpp | 1 - .../valijson/internal/json_reference.hpp | 1 - .../vendored/valijson/internal/optional.hpp | 1 - .../valijson/internal/optional_bundled.hpp | 1 - .../vendored/valijson/internal/uri.hpp | 1 - lincs/liblincs/vendored/valijson/schema.hpp | 1 - .../vendored/valijson/schema_parser.hpp | 1 - .../liblincs/vendored/valijson/subschema.hpp | 1 - .../vendored/valijson/utils/file_utils.hpp | 1 - .../vendored/valijson/utils/utf8_utils.hpp | 1 - .../vendored/valijson/validation_results.hpp | 1 - .../vendored/valijson/validation_visitor.hpp | 1 - .../liblincs/vendored/valijson/validator.hpp | 1 - lincs/liblincs/vendored/yaml-cpp/anchor.h | 1 - lincs/liblincs/vendored/yaml-cpp/binary.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/binary.h | 1 - .../vendored/yaml-cpp/collectionstack.h | 1 - lincs/liblincs/vendored/yaml-cpp/convert.cpp | 1 - .../liblincs/vendored/yaml-cpp/depthguard.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/depthguard.h | 1 - .../liblincs/vendored/yaml-cpp/directives.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/directives.h | 1 - lincs/liblincs/vendored/yaml-cpp/dll.h | 1 - lincs/liblincs/vendored/yaml-cpp/emit.cpp | 1 - .../vendored/yaml-cpp/emitfromevents.cpp | 1 - .../vendored/yaml-cpp/emitfromevents.h | 1 - lincs/liblincs/vendored/yaml-cpp/emitter.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/emitter.h | 1 - lincs/liblincs/vendored/yaml-cpp/emitterdef.h | 1 - .../liblincs/vendored/yaml-cpp/emittermanip.h | 1 - .../vendored/yaml-cpp/emitterstate.cpp | 1 - .../liblincs/vendored/yaml-cpp/emitterstate.h | 1 - .../liblincs/vendored/yaml-cpp/emitterstyle.h | 1 - .../vendored/yaml-cpp/emitterutils.cpp | 1 - .../liblincs/vendored/yaml-cpp/emitterutils.h | 1 - .../liblincs/vendored/yaml-cpp/eventhandler.h | 1 - .../liblincs/vendored/yaml-cpp/exceptions.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/exceptions.h | 1 - lincs/liblincs/vendored/yaml-cpp/exp.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/exp.h | 1 - .../liblincs/vendored/yaml-cpp/indentation.h | 1 - lincs/liblincs/vendored/yaml-cpp/mark.h | 1 - lincs/liblincs/vendored/yaml-cpp/memory.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/node.cpp | 1 - .../liblincs/vendored/yaml-cpp/node/convert.h | 1 - .../vendored/yaml-cpp/node/detail/impl.h | 1 - .../vendored/yaml-cpp/node/detail/iterator.h | 1 - .../yaml-cpp/node/detail/iterator_fwd.h | 1 - .../vendored/yaml-cpp/node/detail/memory.h | 1 - .../vendored/yaml-cpp/node/detail/node.h | 1 - .../vendored/yaml-cpp/node/detail/node_data.h | 1 - .../yaml-cpp/node/detail/node_iterator.h | 1 - .../vendored/yaml-cpp/node/detail/node_ref.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/emit.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/impl.h | 1 - .../vendored/yaml-cpp/node/iterator.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/node.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/parse.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/ptr.h | 1 - lincs/liblincs/vendored/yaml-cpp/node/type.h | 1 - .../liblincs/vendored/yaml-cpp/node_data.cpp | 1 - .../vendored/yaml-cpp/nodebuilder.cpp | 1 - .../liblincs/vendored/yaml-cpp/nodebuilder.h | 1 - .../liblincs/vendored/yaml-cpp/nodeevents.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/nodeevents.h | 1 - lincs/liblincs/vendored/yaml-cpp/noexcept.h | 1 - lincs/liblincs/vendored/yaml-cpp/null.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/null.h | 1 - .../vendored/yaml-cpp/ostream_wrapper.cpp | 1 - .../vendored/yaml-cpp/ostream_wrapper.h | 1 - lincs/liblincs/vendored/yaml-cpp/parse.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/parser.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/parser.h | 1 - lincs/liblincs/vendored/yaml-cpp/ptr_vector.h | 1 - .../liblincs/vendored/yaml-cpp/regex_yaml.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/regex_yaml.h | 1 - lincs/liblincs/vendored/yaml-cpp/regeximpl.h | 1 - lincs/liblincs/vendored/yaml-cpp/scanner.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/scanner.h | 1 - .../liblincs/vendored/yaml-cpp/scanscalar.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/scanscalar.h | 1 - lincs/liblincs/vendored/yaml-cpp/scantag.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/scantag.h | 1 - .../liblincs/vendored/yaml-cpp/scantoken.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/setting.h | 1 - .../liblincs/vendored/yaml-cpp/simplekey.cpp | 1 - .../vendored/yaml-cpp/singledocparser.cpp | 1 - .../vendored/yaml-cpp/singledocparser.h | 1 - lincs/liblincs/vendored/yaml-cpp/stlemitter.h | 1 - lincs/liblincs/vendored/yaml-cpp/stream.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/stream.h | 1 - .../vendored/yaml-cpp/streamcharsource.h | 1 - .../liblincs/vendored/yaml-cpp/stringsource.h | 1 - lincs/liblincs/vendored/yaml-cpp/tag.cpp | 1 - lincs/liblincs/vendored/yaml-cpp/tag.h | 1 - lincs/liblincs/vendored/yaml-cpp/token.h | 1 - lincs/liblincs/vendored/yaml-cpp/traits.h | 1 - lincs/liblincs/vendored/yaml-cpp/yaml.h | 1 - lincs/liblincs_module_tests.py | 2258 ----------------- lincs/visualization.py | 285 --- setup.py | 1 - 374 files changed, 18 insertions(+), 19846 deletions(-) delete mode 100644 lincs/description.py delete mode 100644 lincs/liblincs/classification.cpp delete mode 100644 lincs/liblincs/classification.hpp delete mode 100644 lincs/liblincs/generation.cpp delete mode 100644 lincs/liblincs/generation.hpp delete mode 100644 lincs/liblincs/io.cpp delete mode 100644 lincs/liblincs/io.hpp delete mode 100644 lincs/liblincs/io/alternatives.cpp delete mode 100644 lincs/liblincs/io/alternatives.hpp delete mode 100644 lincs/liblincs/io/exception.cpp delete mode 100644 lincs/liblincs/io/exception.hpp delete mode 100644 lincs/liblincs/io/model.cpp delete mode 100644 lincs/liblincs/io/model.hpp delete mode 100644 lincs/liblincs/io/problem.cpp delete mode 100644 lincs/liblincs/io/problem.hpp delete mode 100644 lincs/liblincs/io/validation.cpp delete mode 100644 lincs/liblincs/io/validation.hpp delete mode 100644 lincs/liblincs/learning.cpp delete mode 100644 lincs/liblincs/learning.hpp delete mode 100644 lincs/liblincs/learning/exception.cpp delete mode 100644 lincs/liblincs/learning/exception.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.cu delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic/desirability.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations-without-progress.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds-without-progress.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.hpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.cpp delete mode 100644 lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.hpp delete mode 100644 lincs/liblincs/learning/pre-processing.cpp delete mode 100644 lincs/liblincs/learning/pre-processing.hpp delete mode 100644 lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.cpp delete mode 100644 lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.hpp delete mode 100644 lincs/liblincs/learning/ucncs-by-max-sat-by-separation.cpp delete mode 100644 lincs/liblincs/learning/ucncs-by-max-sat-by-separation.hpp delete mode 100644 lincs/liblincs/learning/ucncs-by-sat-by-coalitions.cpp delete mode 100644 lincs/liblincs/learning/ucncs-by-sat-by-coalitions.hpp delete mode 100644 lincs/liblincs/learning/ucncs-by-sat-by-separation.cpp delete mode 100644 lincs/liblincs/learning/ucncs-by-sat-by-separation.hpp delete mode 100644 lincs/liblincs/liblincs-module/converters.cpp delete mode 100644 lincs/liblincs/liblincs-module/generation-functions.cpp delete mode 100644 lincs/liblincs/liblincs-module/io-classes.cpp delete mode 100644 lincs/liblincs/liblincs-module/learning-classes.cpp delete mode 100644 lincs/liblincs/linear-programming/alglib.cpp delete mode 100644 lincs/liblincs/linear-programming/alglib.hpp delete mode 100644 lincs/liblincs/linear-programming/glop.cpp delete mode 100644 lincs/liblincs/linear-programming/glop.hpp delete mode 100644 lincs/liblincs/linear-programming/test-bug-0001-optimization-goes-too-far-during-phase-1.cpp delete mode 100644 lincs/liblincs/linear-programming/test-bug-0002-optimization-still-goes-too-far-during-phase-1.cpp delete mode 100644 lincs/liblincs/linear-programming/test-bug-0003-optimization-still-goes-too-far-during-phase-1.cpp delete mode 100644 lincs/liblincs/linear-programming/test-bug-0004-small-error-gets-inverted-to-large-error.cpp delete mode 100644 lincs/liblincs/linear-programming/test-bug-0005-gpu-behaves-differently-from-cpu.cpp delete mode 100644 lincs/liblincs/linear-programming/test.cpp delete mode 100644 lincs/liblincs/linear-programming/testing.hpp delete mode 100644 lincs/liblincs/randomness-utils.cpp delete mode 100644 lincs/liblincs/randomness-utils.hpp delete mode 100644 lincs/liblincs/sat/eval-max-sat.cpp delete mode 100644 lincs/liblincs/sat/eval-max-sat.hpp delete mode 100644 lincs/liblincs/sat/minisat.cpp delete mode 100644 lincs/liblincs/sat/minisat.hpp delete mode 100644 lincs/liblincs/sat/test.cpp delete mode 100644 lincs/liblincs/test-cuda-floating-points.cu delete mode 120000 lincs/liblincs/vendored/alglib/alglibinternal.cpp delete mode 120000 lincs/liblincs/vendored/alglib/alglibinternal.h delete mode 120000 lincs/liblincs/vendored/alglib/alglibmisc.cpp delete mode 120000 lincs/liblincs/vendored/alglib/alglibmisc.h delete mode 120000 lincs/liblincs/vendored/alglib/ap.cpp delete mode 120000 lincs/liblincs/vendored/alglib/ap.h delete mode 120000 lincs/liblincs/vendored/alglib/dataanalysis.cpp delete mode 120000 lincs/liblincs/vendored/alglib/dataanalysis.h delete mode 120000 lincs/liblincs/vendored/alglib/diffequations.cpp delete mode 120000 lincs/liblincs/vendored/alglib/diffequations.h delete mode 120000 lincs/liblincs/vendored/alglib/fasttransforms.cpp delete mode 120000 lincs/liblincs/vendored/alglib/fasttransforms.h delete mode 120000 lincs/liblincs/vendored/alglib/integration.cpp delete mode 120000 lincs/liblincs/vendored/alglib/integration.h delete mode 120000 lincs/liblincs/vendored/alglib/interpolation.cpp delete mode 120000 lincs/liblincs/vendored/alglib/interpolation.h delete mode 120000 lincs/liblincs/vendored/alglib/kernels_avx2.cpp delete mode 120000 lincs/liblincs/vendored/alglib/kernels_avx2.h delete mode 120000 lincs/liblincs/vendored/alglib/kernels_fma.cpp delete mode 120000 lincs/liblincs/vendored/alglib/kernels_fma.h delete mode 120000 lincs/liblincs/vendored/alglib/kernels_sse2.cpp delete mode 120000 lincs/liblincs/vendored/alglib/kernels_sse2.h delete mode 120000 lincs/liblincs/vendored/alglib/linalg.cpp delete mode 120000 lincs/liblincs/vendored/alglib/linalg.h delete mode 120000 lincs/liblincs/vendored/alglib/optimization.cpp delete mode 120000 lincs/liblincs/vendored/alglib/optimization.h delete mode 120000 lincs/liblincs/vendored/alglib/solvers.cpp delete mode 120000 lincs/liblincs/vendored/alglib/solvers.h delete mode 120000 lincs/liblincs/vendored/alglib/specialfunctions.cpp delete mode 120000 lincs/liblincs/vendored/alglib/specialfunctions.h delete mode 120000 lincs/liblincs/vendored/alglib/statistics.cpp delete mode 120000 lincs/liblincs/vendored/alglib/statistics.h delete mode 120000 lincs/liblincs/vendored/alglib/stdafx.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/EvalMaxSAT.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/MaLib/Chrono.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/MaLib/View.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/MaLib/communicationlist.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/analyze.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/arena.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/arena.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/assume.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/averages.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/averages.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/backtrack.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/backward.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/bins.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/bins.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/block.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/block.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/cadical.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/checker.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/checker.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/clause.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/clause.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/collect.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/compact.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/condition.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/config.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/config.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/constrain.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/contract.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/contract.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/cover.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/cover.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/decide.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/decompose.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/deduplicate.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/elim.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/elim.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/ema.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/ema.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/extend.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/external.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/external.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/flags.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/flags.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/format.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/format.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/gates.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/heap.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/internal.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/internal.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/inttypes.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/ipasir.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/level.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/limit.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/limit.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/logging.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/logging.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/lookahead.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/lucky.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/message.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/message.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/minimize.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/observer.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/occs.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/occs.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/options.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/options.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/parse.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/phases.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/phases.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/probe.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/profile.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/profile.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/propagate.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/queue.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/queue.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/radix.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/random.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/random.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/range.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/reduce.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/reluctant.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/rephase.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/report.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/resources.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/resources.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/restart.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/restore.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/score.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/score.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/shrink.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/signal.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/solution.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/solver.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/stats.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/stats.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/subsume.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/ternary.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/tracer.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/transred.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/util.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/util.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/var.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/var.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/version.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/version.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/vivify.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/vivify.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/walk.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/watch.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadical/watch.hpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cadicalinterface.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/card_oe.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cardincremental.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/cardincremental.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/lazyvariable.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/lazyvariable.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/mcqd.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/virtualcard.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/virtualcard.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/virtualmaxsat.h delete mode 120000 lincs/liblincs/vendored/eval-max-sat/virtualsat.cpp delete mode 120000 lincs/liblincs/vendored/eval-max-sat/virtualsat.h delete mode 120000 lincs/liblincs/vendored/lov-e.hpp delete mode 120000 lincs/liblincs/vendored/magic_enum.hpp delete mode 120000 lincs/liblincs/vendored/minisat/core/Solver.cc delete mode 120000 lincs/liblincs/vendored/minisat/core/Solver.h delete mode 120000 lincs/liblincs/vendored/minisat/core/SolverTypes.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Alg.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Alloc.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Heap.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/IntMap.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/IntTypes.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Map.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Queue.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Sort.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/Vec.h delete mode 120000 lincs/liblincs/vendored/minisat/mtl/XAlloc.h delete mode 120000 lincs/liblincs/vendored/minisat/simp/SimpSolver.cc delete mode 120000 lincs/liblincs/vendored/minisat/simp/SimpSolver.h delete mode 120000 lincs/liblincs/vendored/rapidcsv.h delete mode 120000 lincs/liblincs/vendored/valijson/adapters/std_string_adapter.hpp delete mode 120000 lincs/liblincs/vendored/valijson/adapters/yaml_cpp_adapter.hpp delete mode 120000 lincs/liblincs/vendored/valijson/compat/optional.hpp delete mode 120000 lincs/liblincs/vendored/valijson/constraint_builder.hpp delete mode 120000 lincs/liblincs/vendored/valijson/constraints/basic_constraint.hpp delete mode 120000 lincs/liblincs/vendored/valijson/constraints/concrete_constraints.hpp delete mode 120000 lincs/liblincs/vendored/valijson/constraints/constraint.hpp delete mode 120000 lincs/liblincs/vendored/valijson/constraints/constraint_visitor.hpp delete mode 120000 lincs/liblincs/vendored/valijson/exceptions.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/adapter.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/basic_adapter.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/custom_allocator.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/debug.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/frozen_value.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/json_pointer.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/json_reference.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/optional.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/optional_bundled.hpp delete mode 120000 lincs/liblincs/vendored/valijson/internal/uri.hpp delete mode 120000 lincs/liblincs/vendored/valijson/schema.hpp delete mode 120000 lincs/liblincs/vendored/valijson/schema_parser.hpp delete mode 120000 lincs/liblincs/vendored/valijson/subschema.hpp delete mode 120000 lincs/liblincs/vendored/valijson/utils/file_utils.hpp delete mode 120000 lincs/liblincs/vendored/valijson/utils/utf8_utils.hpp delete mode 120000 lincs/liblincs/vendored/valijson/validation_results.hpp delete mode 120000 lincs/liblincs/vendored/valijson/validation_visitor.hpp delete mode 120000 lincs/liblincs/vendored/valijson/validator.hpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/anchor.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/binary.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/binary.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/collectionstack.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/convert.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/depthguard.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/depthguard.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/directives.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/directives.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/dll.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emit.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitfromevents.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitfromevents.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitter.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitter.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterdef.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emittermanip.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterstate.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterstate.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterstyle.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterutils.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/emitterutils.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/eventhandler.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/exceptions.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/exceptions.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/exp.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/exp.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/indentation.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/mark.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/memory.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/convert.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/impl.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/iterator.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/iterator_fwd.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/memory.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/node.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/node_data.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/node_iterator.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/detail/node_ref.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/emit.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/impl.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/iterator.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/node.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/parse.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/ptr.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node/type.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/node_data.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/nodebuilder.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/nodebuilder.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/nodeevents.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/nodeevents.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/noexcept.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/null.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/null.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/parse.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/parser.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/parser.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/ptr_vector.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/regex_yaml.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/regex_yaml.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/regeximpl.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scanner.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scanner.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scanscalar.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scanscalar.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scantag.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scantag.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/scantoken.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/setting.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/simplekey.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/singledocparser.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/singledocparser.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/stlemitter.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/stream.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/stream.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/streamcharsource.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/stringsource.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/tag.cpp delete mode 120000 lincs/liblincs/vendored/yaml-cpp/tag.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/token.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/traits.h delete mode 120000 lincs/liblincs/vendored/yaml-cpp/yaml.h delete mode 100644 lincs/liblincs_module_tests.py delete mode 100644 lincs/visualization.py diff --git a/.github/workflows/build-test-gha-branches.yml b/.github/workflows/build-test-gha-branches.yml index f2d5056a..b480e86a 100644 --- a/.github/workflows/build-test-gha-branches.yml +++ b/.github/workflows/build-test-gha-branches.yml @@ -33,7 +33,7 @@ jobs: - make-source-dist strategy: matrix: - python_version: ['3.8', '3.13'] + python_version: ['3.8'] steps: - name: Install Python uses: actions/setup-python@v5 @@ -41,31 +41,6 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install Python packages run: pip${{ matrix.python_version }} install build auditwheel twine Chrones - - name: Install CUDA - run: | - sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/3bf863cc.pub - sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" - sudo apt-get update - sudo apt-get install --yes --no-install-recommends cuda-cudart-dev-12-4 cuda-nvcc-12-4 - echo "/usr/local/cuda-12.4/bin" >>$GITHUB_PATH - - name: Install Boost - run: | - cd /home/runner/work - wget https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.gz - tar xf boost_*.tar.gz - rm boost_*.tar.gz - cd boost_* - sudo cp -r boost /usr/local/include - - name: Install OR-Tools - run: | - cd /home/runner/work - wget https://github.com/google/or-tools/releases/download/v9.11/or-tools_amd64_ubuntu-20.04_cpp_v9.11.4210.tar.gz - tar xf or-tools_*.tar.gz - rm or-tools_*.tar.gz - cd or-tools_* - sudo cp -r include/* /usr/local/include - sudo cp -r lib/* /usr/local/lib - sudo ldconfig - name: Install patchelf run: | cd /home/runner/work @@ -86,9 +61,6 @@ jobs: - name: Build the wheel run: python${{ matrix.python_version }} -m build --wheel --outdir local-dist lincs-* - env: - LINCS_DEV_FORCE_NVCC: "true" - LINCS_DEV_FORCE_CHRONES: "true" - name: Make the wheel machine-independent run: auditwheel repair --plat manylinux_2_31_x86_64 --strip local-dist/*.whl --wheel-dir dist - name: Check the wheel @@ -100,178 +72,16 @@ jobs: name: wheel-dist-${{ matrix.python_version }}-linux path: dist - build-for-windows: - runs-on: windows-2022 - needs: - - make-source-dist - strategy: - matrix: - python_version: ['3.8', '3.13'] - steps: - - name: Install Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python_version }} - - name: Install Python packages - run: pip install build delvewheel twine - - name: Install CUDA - uses: Jimver/cuda-toolkit@v0.2.19 - id: cuda-toolkit - with: - cuda: '12.4.1' - use-github-cache: false - use-local-cache: false - method: network - # Package names from https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html#id2 - sub-packages: '["nvcc", "cudart"]' - - name: Install MSys2 - uses: msys2/setup-msys2@v2 - with: - update: true - msystem: UCRT64 - install: >- - gzip - tar - unzip - wget - - name: Install boost - shell: msys2 {0} - run: | - cd /d/a - wget https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.gz - tar xf boost_*.tar.gz - rm boost_*.tar.gz - mv boost_* boost - cd boost - mkdir -p /d/lincs-deps/include /d/lincs-deps/lib - cp -r boost /d/lincs-deps/include - - name: Install OR-Tools - shell: msys2 {0} - run: | - cd /d/a - wget https://github.com/google/or-tools/releases/download/v9.11/or-tools_x64_VisualStudio2022_cpp_v9.11.4210.zip - unzip or-tools_*.zip - rm or-tools_*.zip - cd or-tools_* - cp -r include/* /d/lincs-deps/include - cp -r lib/* /d/lincs-deps/lib - - - name: Download the source distribution from GitHub Actions artifacts - uses: actions/download-artifact@v4 - with: - name: source-dist - - name: Unzip the source distribution - shell: msys2 {0} - run: | - tar xf *.tar.gz - rm *.tar.gz - - - name: Build the wheel - run: python -m build --wheel --outdir local-dist (get-item lincs-*) - env: - LINCS_DEV_FORCE_NVCC: "true" - LINCS_DEV_DEPENDENCIES: d:\lincs-deps - - name: Make the wheel machine-independent - run: delvewheel repair --strip (get-item local-dist\*.whl) --wheel-dir dist --add-path d:\lincs-deps\lib - - name: Check the wheel - run: twine check (get-item dist\*.whl) - - - name: Upload the wheel to GitHub Actions artifacts - uses: actions/upload-artifact@v4 - with: - name: wheel-dist-${{ matrix.python_version }}-windows - path: dist - - build-for-macos: - runs-on: macos-13 - needs: - - make-source-dist - strategy: - matrix: - python_version: ['3.8', '3.13'] - env: - MACOSX_DEPLOYMENT_TARGET: 12.0 - steps: - - name: Install Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python_version }} - - name: Install Python packages - run: pip3 install build delocate twine - - name: Install OpenMP - run: | - cd /Users/runner/work - mkdir openmp - cd openmp - wget https://mac.r-project.org/openmp/openmp-16.0.4-darwin20-Release.tar.gz - tar xf *.tar.gz - sudo cp usr/local/lib/* /usr/local/lib - sudo cp usr/local/include/* /usr/local/include - - name: Install Boost - run: | - cd /Users/runner/work - wget https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.gz - tar xf boost_*.tar.gz - rm boost_*.tar.gz - cd boost_* - sudo cp -r boost /usr/local/include - - name: Install OR-Tools - run: | - cd /Users/runner/work - wget https://github.com/google/or-tools/releases/download/v9.11/or-tools_x86_64_macOS-14.6.1_cpp_v9.11.4210.tar.gz - tar xf or-tools_x86_64_*.tar.gz - rm or-tools_x86_64_*.tar.gz - wget https://github.com/google/or-tools/releases/download/v9.11/or-tools_arm64_macOS-14.6.1_cpp_v9.11.4210.tar.gz - tar xf or-tools_arm64_*.tar.gz - rm or-tools_arm64_*.tar.gz - sudo cp -r or-tools_arm64_*/include/* /usr/local/include - lipo or-tools*/lib/libortools.9.11.dylib -output /usr/local/lib/libortools.9.11.dylib -create - cd /usr/local/lib - ln -s libortools.9.11.dylib libortools.9.dylib - ln -s libortools.9.dylib libortools.dylib - - - name: Download the source distribution from GitHub Actions artifacts - uses: actions/download-artifact@v4 - with: - name: source-dist - - name: Unzip the source distribution - run: | - tar xf *.tar.gz - rm *.tar.gz - - - name: Build the wheel - run: python3 -m build --wheel --outdir local-dist lincs-* - - name: Make the wheel machine-independent - run: delocate-wheel --wheel-dir dist local-dist/*.whl - - name: Check the wheel - run: twine check dist/*.whl - - - name: Upload the wheel to GitHub Actions artifacts - uses: actions/upload-artifact@v4 - with: - name: wheel-dist-${{ matrix.python_version }}-macos - path: dist - check: runs-on: ${{ matrix.os }} needs: - build-for-linux - - build-for-windows - - build-for-macos strategy: fail-fast: false matrix: os: - ubuntu-20.04 - - ubuntu-22.04 - - ubuntu-24.04 - - windows-2019 - - windows-2022 - - macos-12 - - macos-13 - - macos-14 - - macos-15 - python_version: ['3.8', '3.13'] + python_version: ['3.8'] exclude: # Older Python versions don't build 'universal2' wheels, so they can't run on the M1 runner that run macOS 14 and 15 - os: macos-14 @@ -304,8 +114,3 @@ jobs: - name: Run lincs run: lincs --help - - run: lincs generate classification-problem 3 2 --output-problem problem.yml - - run: lincs generate classification-model problem.yml --output-model model.yml - - run: lincs generate classified-alternatives problem.yml model.yml 100 --output-alternatives learning-set.csv - - run: lincs learn classification-model problem.yml learning-set.csv --output-model learned-model.yml - - run: lincs classification-accuracy problem.yml learned-model.yml learning-set.csv diff --git a/doc-sources/get-started/get-started.ipynb b/doc-sources/get-started/get-started.ipynb index badac712..d7e65b41 100644 --- a/doc-sources/get-started/get-started.ipynb +++ b/doc-sources/get-started/get-started.ipynb @@ -80,7 +80,7 @@ } ], "source": [ - "lincs generate classification-problem 4 3 --output-problem problem.yml\n", + "lincs generate classification-problem 4 3 --output-problem problem.yml --random-seed 40\n", "cat problem.yml" ] }, @@ -147,7 +147,7 @@ } ], "source": [ - "lincs generate classification-model problem.yml --output-model model.yml\n", + "lincs generate classification-model problem.yml --output-model model.yml --random-seed 41\n", "cat model.yml" ] }, @@ -222,7 +222,7 @@ } ], "source": [ - "lincs generate classified-alternatives problem.yml model.yml 1000 --output-alternatives learning-set.csv\n", + "lincs generate classified-alternatives problem.yml model.yml 1000 --output-alternatives learning-set.csv --random-seed 42\n", "head -n 7 learning-set.csv" ] }, @@ -281,7 +281,7 @@ } ], "source": [ - "lincs learn classification-model problem.yml learning-set.csv --output-model trained-model.yml\n", + "lincs learn classification-model problem.yml learning-set.csv --output-model trained-model.yml --mrsort.weights-profiles-breed.accuracy-heuristic.random-seed 43\n", "cat trained-model.yml" ] }, @@ -296,7 +296,7 @@ }, "outputs": [], "source": [ - "lincs generate classified-alternatives problem.yml model.yml 3000 --output-alternatives testing-set.csv" + "lincs generate classified-alternatives problem.yml model.yml 3000 --output-alternatives testing-set.csv --random-seed 44\n" ] }, { @@ -335,7 +335,7 @@ ], "source": [ "lincs classify problem.yml trained-model.yml testing-set.csv --output-alternatives reclassified-testing-set.csv\n", - "diff testing-set.csv reclassified-testing-set.csv" + "diff testing-set.csv reclassified-testing-set.csv | tail -n +5\n" ] }, { diff --git a/doc-sources/user-guide/alglib-learning/alglib-learning.ipynb b/doc-sources/user-guide/alglib-learning/alglib-learning.ipynb index 29da7fc9..47044c5c 100644 --- a/doc-sources/user-guide/alglib-learning/alglib-learning.ipynb +++ b/doc-sources/user-guide/alglib-learning/alglib-learning.ipynb @@ -49,7 +49,7 @@ ], "source": [ "lincs learn classification-model problem.yml learning-set.csv \\\n", - " --mrsort.weights-profiles-breed.linear-program.solver alglib" + " --mrsort.weights-profiles-breed.linear-program.solver alglib --mrsort.weights-profiles-breed.accuracy-heuristic.random-seed 43\n" ] } ], diff --git a/doc-sources/user-guide/gpu-learning/gpu-learning.ipynb b/doc-sources/user-guide/gpu-learning/gpu-learning.ipynb index 74aa74e3..f6070bc7 100644 --- a/doc-sources/user-guide/gpu-learning/gpu-learning.ipynb +++ b/doc-sources/user-guide/gpu-learning/gpu-learning.ipynb @@ -49,7 +49,7 @@ ], "source": [ "lincs learn classification-model problem.yml learning-set.csv \\\n", - " --mrsort.weights-profiles-breed.accuracy-heuristic.processor gpu" + " --mrsort.weights-profiles-breed.accuracy-heuristic.processor gpu --mrsort.weights-profiles-breed.accuracy-heuristic.random-seed 43\n" ] } ], diff --git a/doc-sources/user-guide/synthetic-data/synthetic-data.ipynb b/doc-sources/user-guide/synthetic-data/synthetic-data.ipynb index adf266e3..50e04ae8 100644 --- a/doc-sources/user-guide/synthetic-data/synthetic-data.ipynb +++ b/doc-sources/user-guide/synthetic-data/synthetic-data.ipynb @@ -46,7 +46,7 @@ } ], "source": [ - "lincs generate classification-problem 4 3" + "lincs generate classification-problem 4 3 --random-seed 57 | tee problem.yml\n" ] }, { @@ -84,7 +84,7 @@ } ], "source": [ - "lincs generate classification-model problem.yml" + "lincs generate classification-model problem.yml --random-seed 58 | tee model.yml\n" ] }, { @@ -207,7 +207,7 @@ } ], "source": [ - "lincs generate classified-alternatives problem.yml model.yml 100" + "lincs generate classified-alternatives problem.yml model.yml 100 --random-seed 59 | tee learning-set.csv\n" ] }, { @@ -245,7 +245,7 @@ } ], "source": [ - "lincs learn classification-model problem.yml learning-set.csv" + "lincs learn classification-model problem.yml learning-set.csv --mrsort.weights-profiles-breed.accuracy-heuristic.random-seed 60\n" ] } ], diff --git a/lincs/__init__.py b/lincs/__init__.py index 9c61ccfe..45675e7c 100644 --- a/lincs/__init__.py +++ b/lincs/__init__.py @@ -8,30 +8,6 @@ It contains general information (version, GPU availability, *etc.*) and items of general usage (*e.g.* the exception for invalid data). """ -# General exceptions -from liblincs import DataValidationException, LearningFailureException - -# General utilities -from liblincs import UniformRandomBitsGenerator - -# Classification -from . import classification - # General information __version__ = "2.0.0a7.dev0" -has_gpu = hasattr(classification, "ImproveProfilesWithAccuracyHeuristicOnGpu") - -try: - del visualization -except NameError: - pass - -try: - del description -except NameError: - pass - -try: - del command_line_interface -except NameError: - pass +has_gpu = False diff --git a/lincs/classification.py b/lincs/classification.py index f16b3d61..69c4ce50 100644 --- a/lincs/classification.py +++ b/lincs/classification.py @@ -9,54 +9,6 @@ # @todo(Feature, later) Provide __repr__ and __str__ where applicable -# I/O -from liblincs import Criterion, Category, Problem -from liblincs import AcceptedValues, SufficientCoalitions, Model -from liblincs import Performance, Alternative, Alternatives - -# Generation (incl. misclassification) -from liblincs import BalancedAlternativesGenerationException -from liblincs import generate_classification_problem as generate_problem -from liblincs import generate_mrsort_classification_model as generate_mrsort_model -from liblincs import generate_classified_alternatives as generate_alternatives -from liblincs import misclassify_alternatives - -# Classification -from liblincs import ClassificationResult -from liblincs import classify_alternatives - -# Learning -from liblincs import PreprocessedLearningSet - -# Learning - weights-profiles-breed -from liblincs import LearnMrsortByWeightsProfilesBreed -from liblincs import InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion -from liblincs import OptimizeWeightsUsingGlop, OptimizeWeightsUsingAlglib -from liblincs import ImproveProfilesWithAccuracyHeuristicOnCpu -try: - from liblincs import ImproveProfilesWithAccuracyHeuristicOnGpu -except ImportError: - pass -from liblincs import ReinitializeLeastAccurate -from liblincs import TerminateAtAccuracy -from liblincs import TerminateAfterSeconds, TerminateAfterSecondsWithoutProgress -from liblincs import TerminateAfterIterations, TerminateAfterIterationsWithoutProgress -from liblincs import TerminateWhenAny - -# Learning - SAT by coalitions -from liblincs import LearnUcncsBySatByCoalitionsUsingMinisat - -# Learning - SAT by separation -from liblincs import LearnUcncsBySatBySeparationUsingMinisat - -# Learning - max-SAT by coalitions -from liblincs import LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat - -# Learning - max-SAT by separation -from liblincs import LearnUcncsByMaxSatBySeparationUsingEvalmaxsat - -from .visualization import visualize_classification_model as visualize_model -from .description import describe_classification_problem as describe_problem -from .description import describe_classification_model as describe_model +from liblincs import * # @todo(Feature, later) Accept learning and training set as Pandas DataFrame? diff --git a/lincs/description.py b/lincs/description.py deleted file mode 100644 index be255b92..00000000 --- a/lincs/description.py +++ /dev/null @@ -1,324 +0,0 @@ -from typing import Iterable -import unittest - -from .classification import Problem, Criterion, Category, Model, AcceptedValues, SufficientCoalitions - - -def describe_classification_problem(problem: Problem) -> Iterable[str]: - """ - Generate a human-readable description of a classification problem. - """ - - categories_count = len(problem.ordered_categories) - assert categories_count >= 2 - criteria_count = len(problem.criteria) - assert criteria_count >= 1 - - category_names = [f'"{category.name}"' for category in problem.ordered_categories] - category_names_joined = ", ".join(category_names[:-1]) + " and " + category_names[-1] - yield f"This a classification problem into {categories_count} ordered categories named {category_names_joined}." - yield f"The best category is {category_names[-1]} and the worst category is {category_names[0]}." - - if criteria_count == 1: - yield "There is 1 classification criterion." - else: - yield f"There are {criteria_count} classification criteria (in no particular order)." - for criterion in problem.criteria: - if criterion.is_real: - values = criterion.real_values - yield f'Criterion "{criterion.name}" takes real values between {values.min_value:.1f} and {values.max_value:.1f} included.' - if values.is_increasing: - yield f'Higher values of "{criterion.name}" are known to be better.' - elif values.is_decreasing: - yield f'Lower values of "{criterion.name}" are known to be better.' - else: - assert values.is_single_peaked - yield f'Intermediate values of "{criterion.name}" are known to be better.' - elif criterion.is_integer: - values = criterion.integer_values - yield f'Criterion "{criterion.name}" takes integer values between {values.min_value} and {values.max_value} included.' - if values.is_increasing: - yield f'Higher values of "{criterion.name}" are known to be better.' - elif values.is_decreasing: - yield f'Lower values of "{criterion.name}" are known to be better.' - else: - assert values.is_single_peaked - yield f'Intermediate values of "{criterion.name}" are known to be better.' - else: - assert criterion.is_enumerated - values = criterion.enumerated_values - yield f'Criterion "{criterion.name}" takes values in the following set: {", ".join(f"{value}" for value in values.ordered_values)}.' - yield f'The best value for criterion "{criterion.name}" is "{values.ordered_values[-1]}" and the worst value is "{values.ordered_values[0]}".' - - -class DescribeClassificationProblemTestCase(unittest.TestCase): - maxDiff = None - - def _test(self, problem, expected): - self.assertEqual(list(describe_classification_problem(problem)), expected) - - def test_simplest(self): - self._test( - Problem( - [ - Criterion("Criterion", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ), - [ - 'This a classification problem into 2 ordered categories named "Bad" and "Good".', - 'The best category is "Good" and the worst category is "Bad".', - 'There is 1 classification criterion.', - 'Criterion "Criterion" takes real values between 0.0 and 1.0 included.', - 'Higher values of "Criterion" are known to be better.' - ] - ) - - def test_many_categories(self): - self._test( - Problem( - [ - Criterion("Criterion", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Worsestest"), Category("Interm 1"), Category("Interm 2"), Category("Interm 3"), Category("Bestestest")], - ), - [ - 'This a classification problem into 5 ordered categories named "Worsestest", "Interm 1", "Interm 2", "Interm 3" and "Bestestest".', - 'The best category is "Bestestest" and the worst category is "Worsestest".', - 'There is 1 classification criterion.', - 'Criterion "Criterion" takes real values between 0.0 and 1.0 included.', - 'Higher values of "Criterion" are known to be better.', - ] - ) - - def test_criteria_variety(self): - self._test( - Problem( - [ - Criterion("Increasing real criterion", Criterion.RealValues(Criterion.PreferenceDirection.increasing, -5.2, 10.3)), - Criterion("Decreasing real criterion", Criterion.RealValues(Criterion.PreferenceDirection.decreasing, 5, 15)), - Criterion("Increasing integer criterion", Criterion.IntegerValues(Criterion.PreferenceDirection.increasing, 0, 10)), - Criterion("Decreasing integer criterion", Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 4, 16)), - Criterion("Enumerated criterion", Criterion.EnumeratedValues(["A", "B", "C"])), - Criterion("Single-peaked real criterion", Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 5, 15)), - Criterion("Single-peaked integer criterion", Criterion.IntegerValues(Criterion.PreferenceDirection.single_peaked, 0, 10)), - ], - [Category("Bad"), Category("Good")], - ), - [ - 'This a classification problem into 2 ordered categories named "Bad" and "Good".', - 'The best category is "Good" and the worst category is "Bad".', - 'There are 7 classification criteria (in no particular order).', - 'Criterion "Increasing real criterion" takes real values between -5.2 and 10.3 included.', - 'Higher values of "Increasing real criterion" are known to be better.', - 'Criterion "Decreasing real criterion" takes real values between 5.0 and 15.0 included.', - 'Lower values of "Decreasing real criterion" are known to be better.', - 'Criterion "Increasing integer criterion" takes integer values between 0 and 10 included.', - 'Higher values of "Increasing integer criterion" are known to be better.', - 'Criterion "Decreasing integer criterion" takes integer values between 4 and 16 included.', - 'Lower values of "Decreasing integer criterion" are known to be better.', - 'Criterion "Enumerated criterion" takes values in the following set: A, B, C.', - 'The best value for criterion "Enumerated criterion" is "C" and the worst value is "A".', - 'Criterion "Single-peaked real criterion" takes real values between 5.0 and 15.0 included.', - 'Intermediate values of "Single-peaked real criterion" are known to be better.', - 'Criterion "Single-peaked integer criterion" takes integer values between 0 and 10 included.', - 'Intermediate values of "Single-peaked integer criterion" are known to be better.', - ] - ) - - -def describe_classification_model(problem: Problem, model: Model) -> Iterable[str]: - """ - Generate a human-readable description of a classification model. - """ - - criteria_count = len(problem.criteria) - assert len(model.accepted_values) == criteria_count - assert criteria_count > 0 - categories_count = len(problem.ordered_categories) - boundaries_count = categories_count - 1 - assert boundaries_count > 0 - assert len(model.sufficient_coalitions) == boundaries_count - - def comma_and(s): - s = list(s) - if len(s) == 1: - return s[0] - elif len(s) == 2: - return " and ".join(s) - else: - return ", ".join(s[:-1]) + ", and " + s[-1] # https://en.wikipedia.org/wiki/Serial_comma - - def make_upset_roots(upset_roots): - for coalition in upset_roots: - criterion_names = [] - for criterion_index in coalition: - criterion = problem.criteria[criterion_index] - criterion_names.append(f'"{criterion.name}"') - yield f' - {comma_and(criterion_names)}' - - def make_profile(accepted_values, boundary_index): - for criterion_index, criterion in enumerate(problem.criteria): - if accepted_values[criterion_index].is_thresholds: - if criterion.is_real: - assert len(accepted_values[criterion_index].real_thresholds.thresholds) == boundaries_count - values = criterion.real_values - constraint = "at least" if values.is_increasing else "at most" - yield f'{constraint} {accepted_values[criterion_index].real_thresholds.thresholds[boundary_index]:.2f} on criterion "{criterion.name}"' - elif criterion.is_integer: - assert len(accepted_values[criterion_index].integer_thresholds.thresholds) == boundaries_count - values = criterion.integer_values - constraint = "at least" if values.is_increasing else "at most" - yield f'{constraint} {accepted_values[criterion_index].integer_thresholds.thresholds[boundary_index]} on criterion "{criterion.name}"' - else: - assert criterion.is_enumerated - assert len(accepted_values[criterion_index].enumerated_thresholds.thresholds) == boundaries_count - yield f'at least "{accepted_values[criterion_index].enumerated_thresholds.thresholds[boundary_index]}" on criterion "{criterion.name}"' - else: - accepted_values[criterion_index].is_intervals - if criterion.is_real: - assert len(accepted_values[criterion_index].real_intervals.intervals) == boundaries_count - interval = accepted_values[criterion_index].real_intervals.intervals[boundary_index] - yield f'between {interval[0]:.2f} and {interval[1]:.2f} on criterion "{criterion.name}"' - else: - assert criterion.is_integer - assert len(accepted_values[criterion_index].integer_intervals.intervals) == boundaries_count - interval = accepted_values[criterion_index].integer_intervals.intervals[boundary_index] - yield f'between {interval[0]} and {interval[1]} on criterion "{criterion.name}"' - - is_uc = all(sufficient_coalitions == model.sufficient_coalitions[0] for sufficient_coalitions in model.sufficient_coalitions[1:]) - if is_uc: - first_sufficient_coalitions = model.sufficient_coalitions[0] - if first_sufficient_coalitions.is_weights: - yield "This is a MR-Sort (a.k.a. 1-Uc-NCS) model: an NCS model where the sufficient coalitions are specified using the same criterion weights for all boundaries." - yield "The weights associated to each criterion are:" - assert len(first_sufficient_coalitions.weights.criterion_weights) == criteria_count - for criterion, weight in zip(problem.criteria, first_sufficient_coalitions.weights.criterion_weights): - yield f' - Criterion "{criterion.name}": {weight:.2f}' - yield "To get into an upper category, an alternative must be accepted by the following boundaries on a set of criteria whose weights add up to at least 1:" - else: - assert first_sufficient_coalitions.is_roots - yield "This is a Uc-NCS model: an NCS model with the same sufficient coalitions for all boundaries." - yield "The sufficient coalitions of criteria are the following, as well as any of their unions:" - yield from make_upset_roots(first_sufficient_coalitions.roots.upset_roots) - yield "To get into an upper category, an alternative must be accepted by the following boundaries on a sufficient coalition of criteria:" - for boundary_index, category in enumerate(problem.ordered_categories[1:]): - yield f' - For category "{category.name}": {comma_and(make_profile(model.accepted_values, boundary_index))}' - else: - yield "This is a generic NCS model; sufficient coalitions are specified for each boundary." - for boundary_index, (category, sufficient_coalitions) in enumerate(zip(problem.ordered_categories[1:], model.sufficient_coalitions)): - if sufficient_coalitions.is_weights: - yield f'To get into category "{category.name}", an alternative must be accepted by the following boundaries on a set of criteria whose weights add up to at least 1:' - for profile, weight in zip(make_profile(model.accepted_values, boundary_index), sufficient_coalitions.weights.criterion_weights): - yield f' - {profile} (weight: {weight:.2f})' - else: - assert sufficient_coalitions.is_roots - yield f'The sufficient coalitions for category "{category.name}" are the following, as well as any of their unions:' - yield from make_upset_roots(sufficient_coalitions.roots.upset_roots) - yield f'To get into category "{category.name}", an alternative must be accepted by the following boundaries on a sufficient coalition of criteria: {comma_and(make_profile(model.accepted_values, boundary_index))}' - - -class DescribeClassificationModelTestCase(unittest.TestCase): - maxDiff = None - - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - Criterion("Criterion 2", Criterion.RealValues(Criterion.PreferenceDirection.decreasing, 0, 1)), - Criterion("Criterion 3", Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 0, 8)), - Criterion("Criterion 4", Criterion.RealValues(Criterion.PreferenceDirection.decreasing, 0, 1)), - ], - [ - Category("Bad"), - Category("Intermediate"), - Category("Good"), - ], - ) - - def _test(self, model, expected): - self.assertEqual(list(describe_classification_model(self.problem, model)), expected) - - def test_mrsort(self): - self._test( - Model( - self.problem, - [ - AcceptedValues(AcceptedValues.RealThresholds([0.2, 0.7])), - AcceptedValues(AcceptedValues.RealThresholds([0.8, 0.7])), - AcceptedValues(AcceptedValues.RealIntervals([(1, 7), (3, 5)])), - AcceptedValues(AcceptedValues.RealThresholds([0.7, 0.3])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Weights([0.7, 0.5, 0.4, 0.2])), - SufficientCoalitions(SufficientCoalitions.Weights([0.7, 0.5, 0.4, 0.2])), - ], - ), - [ - 'This is a MR-Sort (a.k.a. 1-Uc-NCS) model: an NCS model where the sufficient coalitions are specified using the same criterion weights for all boundaries.', - 'The weights associated to each criterion are:', - ' - Criterion "Criterion 1": 0.70', - ' - Criterion "Criterion 2": 0.50', - ' - Criterion "Criterion 3": 0.40', - ' - Criterion "Criterion 4": 0.20', - 'To get into an upper category, an alternative must be accepted by the following boundaries on a set of criteria whose weights add up to at least 1:', - ' - For category "Intermediate": at least 0.20 on criterion "Criterion 1", at most 0.80 on criterion "Criterion 2", between 1.00 and 7.00 on criterion "Criterion 3", and at most 0.70 on criterion "Criterion 4"', - ' - For category "Good": at least 0.70 on criterion "Criterion 1", at most 0.70 on criterion "Criterion 2", between 3.00 and 5.00 on criterion "Criterion 3", and at most 0.30 on criterion "Criterion 4"' - ], - ) - - def test_ucncs(self): - self._test( - Model( - self.problem, - [ - AcceptedValues(AcceptedValues.RealThresholds([0.2, 0.7])), - AcceptedValues(AcceptedValues.RealThresholds([0.8, 0.7])), - AcceptedValues(AcceptedValues.RealIntervals([(1, 7), (3, 5)])), - AcceptedValues(AcceptedValues.RealThresholds([0.7, 0.3])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Roots(self.problem, [[0, 1], [0, 2], [1, 2, 3]])), - SufficientCoalitions(SufficientCoalitions.Roots(self.problem, [[0, 1], [0, 2], [1, 2, 3]])), - ], - ), - [ - 'This is a Uc-NCS model: an NCS model with the same sufficient coalitions for all boundaries.', - 'The sufficient coalitions of criteria are the following, as well as any of their unions:', - ' - "Criterion 1" and "Criterion 2"', - ' - "Criterion 1" and "Criterion 3"', - ' - "Criterion 2", "Criterion 3", and "Criterion 4"', - 'To get into an upper category, an alternative must be accepted by the following boundaries on a sufficient coalition of criteria:', - ' - For category "Intermediate": at least 0.20 on criterion "Criterion 1", at most 0.80 on criterion "Criterion 2", between 1.00 and 7.00 on criterion "Criterion 3", and at most 0.70 on criterion "Criterion 4"', - ' - For category "Good": at least 0.70 on criterion "Criterion 1", at most 0.70 on criterion "Criterion 2", between 3.00 and 5.00 on criterion "Criterion 3", and at most 0.30 on criterion "Criterion 4"' - ], - ) - - def test_mixed(self): - self._test( - Model( - self.problem, - [ - AcceptedValues(AcceptedValues.RealThresholds([0.2, 0.7])), - AcceptedValues(AcceptedValues.RealThresholds([0.8, 0.7])), - AcceptedValues(AcceptedValues.RealIntervals([(1, 7), (3, 5)])), - AcceptedValues(AcceptedValues.RealThresholds([0.7, 0.3])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Roots(self.problem, [[0, 1], [0, 2], [1, 2, 3]])), - SufficientCoalitions(SufficientCoalitions.Weights([0.7, 0.5, 0.4, 0.2])), - ], - ), - [ - 'This is a generic NCS model; sufficient coalitions are specified for each boundary.', - 'The sufficient coalitions for category "Intermediate" are the following, as well as any of their unions:', - ' - "Criterion 1" and "Criterion 2"', - ' - "Criterion 1" and "Criterion 3"', - ' - "Criterion 2", "Criterion 3", and "Criterion 4"', - 'To get into category "Intermediate", an alternative must be accepted by the following boundaries on a sufficient coalition of criteria: at least 0.20 on criterion "Criterion 1", at most 0.80 on criterion "Criterion 2", between 1.00 and 7.00 on criterion "Criterion 3", and at most 0.70 on criterion "Criterion 4"', - 'To get into category "Good", an alternative must be accepted by the following boundaries on a set of criteria whose weights add up to at least 1:', - ' - at least 0.70 on criterion "Criterion 1" (weight: 0.70)', - ' - at most 0.70 on criterion "Criterion 2" (weight: 0.50)', - ' - between 3.00 and 5.00 on criterion "Criterion 3" (weight: 0.40)', - ' - at most 0.30 on criterion "Criterion 4" (weight: 0.20)' - ] - ) diff --git a/lincs/liblincs/classification.cpp b/lincs/liblincs/classification.cpp deleted file mode 100644 index 61a9086f..00000000 --- a/lincs/liblincs/classification.cpp +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "classification.hpp" - -#include -#include - -#include "chrones.hpp" -#include "unreachable.hpp" -#include "vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace lincs { - -bool accepted_by_criterion( - const Problem& problem, - const Model& model, - const Alternatives& alternatives, - const unsigned boundary_index, - const unsigned alternative_index, - const unsigned criterion_index -) { - const auto& performance = alternatives.get_alternatives()[alternative_index].get_profile()[criterion_index]; - const auto& criterion = problem.get_criteria()[criterion_index]; - return dispatch( - model.get_accepted_values()[criterion_index].get(), - [&model, &performance, &criterion, boundary_index](const AcceptedValues::RealThresholds& accepted_values) { - const float value = performance.get_real().get_value(); - const std::optional threshold = accepted_values.get_thresholds()[boundary_index]; - if (threshold) { - switch (criterion.get_real_values().get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - return value >= *threshold; - case Criterion::PreferenceDirection::decreasing: - return value <= *threshold; - case Criterion::PreferenceDirection::single_peaked: - assert(false); - } - unreachable(); - } else { - return false; - } - }, - [&model, &performance, &criterion, boundary_index](const AcceptedValues::IntegerThresholds& accepted_values) { - const int value = performance.get_integer().get_value(); - const std::optional threshold = accepted_values.get_thresholds()[boundary_index]; - if (threshold) { - switch (criterion.get_integer_values().get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - return value >= *threshold; - case Criterion::PreferenceDirection::decreasing: - return value <= *threshold; - case Criterion::PreferenceDirection::single_peaked: - assert(false); - } - unreachable(); - } else { - return false; - } - }, - [&model, &performance, &criterion, boundary_index](const AcceptedValues::EnumeratedThresholds& accepted_values) { - const auto& ranks = criterion.get_enumerated_values().get_value_ranks(); - const std::string& value = performance.get_enumerated().get_value(); - const std::optional& threshold = accepted_values.get_thresholds()[boundary_index]; - if (threshold) { - return ranks.at(value) >= ranks.at(*threshold); - } else { - return false; - } - }, - [&model, &performance, &criterion, boundary_index](const AcceptedValues::RealIntervals& accepted_values) -> bool { - assert(criterion.get_real_values().get_preference_direction() == Criterion::PreferenceDirection::single_peaked); - const float value = performance.get_real().get_value(); - const auto& interval = accepted_values.get_intervals()[boundary_index]; - if (interval) { - return value >= interval->first && value <= interval->second; - } else { - return false; - } - }, - [&model, &performance, &criterion, boundary_index](const AcceptedValues::IntegerIntervals& accepted_values) -> bool { - assert(criterion.get_integer_values().get_preference_direction() == Criterion::PreferenceDirection::single_peaked); - const int value = performance.get_integer().get_value(); - const auto& interval = accepted_values.get_intervals()[boundary_index]; - if (interval) { - return value >= interval->first && value <= interval->second; - } else { - return false; - } - } - ); -} - -bool accepted_by_category( - const Problem& problem, - const Model& model, - const Alternatives& alternatives, - const unsigned boundary_index, - const unsigned alternative_index -) { - const unsigned criteria_count = problem.get_criteria().size(); - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned boundaries_count = categories_count - 1; - - assert(model.get_accepted_values().size() == criteria_count); - assert(model.get_sufficient_coalitions().size() == boundaries_count); - assert(boundary_index < boundaries_count); - - return std::visit( - [&problem, &model, &alternatives, criteria_count, boundary_index, alternative_index](const auto& sufficient_coalitions) { - boost::dynamic_bitset<> accepted_criteria(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - if (accepted_by_criterion(problem, model, alternatives, boundary_index, alternative_index, criterion_index)) { - accepted_criteria[criterion_index] = true; - } - } - return sufficient_coalitions.accept(accepted_criteria); - }, - model.get_sufficient_coalitions()[boundary_index].get() - ); -} - -ClassificationResult classify_alternatives(const Problem& problem, const Model& model, Alternatives* alternatives) { - CHRONE(); - - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned alternatives_count = alternatives->get_alternatives().size(); - - ClassificationResult result{0, 0}; - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - unsigned category_index; - for (category_index = categories_count - 1; category_index != 0; --category_index) { - if (accepted_by_category(problem, model, *alternatives, category_index - 1, alternative_index)) { - break; - } - } - - if (alternatives->get_alternatives()[alternative_index].get_category_index() == category_index) { - ++result.unchanged; - } else { - alternatives->get_writable_alternatives()[alternative_index].set_category_index(category_index); - ++result.changed; - } - } - - return result; -} - -unsigned count_correctly_classified_alternatives(const Problem& problem, const Model& model, const Alternatives& alternatives) { - CHRONE(); - - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned alternatives_count = alternatives.get_alternatives().size(); - - unsigned result = 0; - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - unsigned category_index; - for (category_index = categories_count - 1; category_index != 0; --category_index) { - if (accepted_by_category(problem, model, alternatives, category_index - 1, alternative_index)) { - break; - } - } - - if (alternatives.get_alternatives()[alternative_index].get_category_index() == category_index) { - ++result; - } - } - - return result; -} - -TEST_CASE("Basic classification using weights") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - }, - {SufficientCoalitions(SufficientCoalitions::Weights({0.3, 0.6, 0.8}))}, - }; - - Alternatives alternatives{problem, { - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - }}; - - auto result = classify_alternatives(problem, model, &alternatives); - - CHECK(alternatives.get_alternatives()[0].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[1].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[2].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[3].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[4].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[5].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[6].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[7].get_category_index() == 1); - CHECK(result.unchanged == 0); - CHECK(result.changed == 8); -} - -TEST_CASE("Basic classification using upset roots") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - }, - {SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0, 2}, {1, 2}}))}, - }; - - Alternatives alternatives{problem, { - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - }}; - - auto result = classify_alternatives(problem, model, &alternatives); - - CHECK(alternatives.get_alternatives()[0].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[1].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[2].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[3].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[4].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[5].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[6].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[7].get_category_index() == 1); - CHECK(result.unchanged == 0); - CHECK(result.changed == 8); -} - -TEST_CASE("Classification with decreasing criteria") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::decreasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::decreasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::decreasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - }, - {SufficientCoalitions(SufficientCoalitions::Weights({0.3, 0.6, 0.8}))}, - }; - - Alternatives alternatives{problem, { - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.51)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.51)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.51))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50)), Performance(Performance::Real(0.51)), Performance(Performance::Real(0.51))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.51)), Performance(Performance::Real(0.50)), Performance(Performance::Real(0.51))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.51)), Performance(Performance::Real(0.51)), Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.51)), Performance(Performance::Real(0.51)), Performance(Performance::Real(0.51))}, std::nullopt}, - }}; - - auto result = classify_alternatives(problem, model, &alternatives); - - CHECK(alternatives.get_alternatives()[0].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[1].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[2].get_category_index() == 1); - CHECK(alternatives.get_alternatives()[3].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[4].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[5].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[6].get_category_index() == 0); - CHECK(alternatives.get_alternatives()[7].get_category_index() == 0); - CHECK(result.unchanged == 0); - CHECK(result.changed == 8); -} - -TEST_CASE("Classification with unreachable thresholds") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Cat 1"}, {"Cat 2"}, {"Cat 3"}, {"Cat 4"}}, - }; - - Alternatives alternatives{problem, { - {"A", {Performance(Performance::Real(0.24))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.25))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.49))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.50))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.74))}, std::nullopt}, - {"A", {Performance(Performance::Real(0.75))}, std::nullopt}, - }}; - - classify_alternatives( - problem, - Model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.25, 0.5, 0.75})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({1})), - SufficientCoalitions(SufficientCoalitions::Weights({1})), - SufficientCoalitions(SufficientCoalitions::Weights({1})), - }, - }, - &alternatives); - - CHECK(*alternatives.get_alternatives()[0].get_category_index() == 0); - CHECK(*alternatives.get_alternatives()[1].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[2].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[3].get_category_index() == 2); - CHECK(*alternatives.get_alternatives()[4].get_category_index() == 2); - CHECK(*alternatives.get_alternatives()[5].get_category_index() == 3); - - classify_alternatives( - problem, - Model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.25, 0.5, std::nullopt})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({1})), - SufficientCoalitions(SufficientCoalitions::Weights({1})), - SufficientCoalitions(SufficientCoalitions::Weights({1})), - }, - }, - &alternatives); - - CHECK(*alternatives.get_alternatives()[0].get_category_index() == 0); - CHECK(*alternatives.get_alternatives()[1].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[2].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[3].get_category_index() == 2); - CHECK(*alternatives.get_alternatives()[4].get_category_index() == 2); - CHECK(*alternatives.get_alternatives()[5].get_category_index() == 2); -} - -TEST_CASE("Classification with single-peaked criteria") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, 0, 1)), - Criterion("Criterion 2", Criterion::IntegerValues(Criterion::PreferenceDirection::single_peaked, 0, 100)), - }, - { - {"Bad"}, - {"Average"}, - {"Good"}, - {"God-like (unreachable)"} - }, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealIntervals({std::make_pair(0.2, 0.8), std::make_pair(0.4, 0.6), std::nullopt})), - AcceptedValues(AcceptedValues::IntegerIntervals({std::make_pair(20, 80), std::make_pair(40, 60), std::nullopt})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - }, - }; - - Alternatives alternatives{problem, { - {"Good on both", {Performance(Performance::Real(0.5)), Performance(Performance::Integer(50))}, std::nullopt}, - {"Low on 1 => average", {Performance(Performance::Real(0.3)), Performance(Performance::Integer(50))}, std::nullopt}, - {"Low on 2 => average", {Performance(Performance::Real(0.5)), Performance(Performance::Integer(30))}, std::nullopt}, - {"Very low on 1 => bad", {Performance(Performance::Real(0.1)), Performance(Performance::Integer(50))}, std::nullopt}, - {"Very low on 2 => bad", {Performance(Performance::Real(0.5)), Performance(Performance::Integer(10))}, std::nullopt}, - {"High on 1 => average", {Performance(Performance::Real(0.7)), Performance(Performance::Integer(50))}, std::nullopt}, - {"High on 2 => average", {Performance(Performance::Real(0.5)), Performance(Performance::Integer(70))}, std::nullopt}, - {"Very high on 1 => bad", {Performance(Performance::Real(0.9)), Performance(Performance::Integer(50))}, std::nullopt}, - {"Very high on 2 => bad", {Performance(Performance::Real(0.5)), Performance(Performance::Integer(90))}, std::nullopt}, - }}; - - classify_alternatives(problem, model, &alternatives); - - CHECK(*alternatives.get_alternatives()[0].get_category_index() == 2); - CHECK(*alternatives.get_alternatives()[1].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[2].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[3].get_category_index() == 0); - CHECK(*alternatives.get_alternatives()[4].get_category_index() == 0); - CHECK(*alternatives.get_alternatives()[5].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[6].get_category_index() == 1); - CHECK(*alternatives.get_alternatives()[7].get_category_index() == 0); - CHECK(*alternatives.get_alternatives()[8].get_category_index() == 0); -} - -} // namespace lincs diff --git a/lincs/liblincs/classification.hpp b/lincs/liblincs/classification.hpp deleted file mode 100644 index a6c2f3be..00000000 --- a/lincs/liblincs/classification.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__CLASSIFICATION_HPP -#define LINCS__CLASSIFICATION_HPP - -#include "io.hpp" - - -namespace lincs { - -struct ClassificationResult { - unsigned unchanged; - unsigned changed; -}; - -ClassificationResult classify_alternatives(const Problem&, const Model&, Alternatives*); - -unsigned count_correctly_classified_alternatives(const Problem&, const Model&, const Alternatives&); - -} // namespace lincs - -#endif // LINCS__CLASSIFICATION_HPP diff --git a/lincs/liblincs/generation.cpp b/lincs/liblincs/generation.cpp deleted file mode 100644 index 9b24b7d8..00000000 --- a/lincs/liblincs/generation.cpp +++ /dev/null @@ -1,912 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "generation.hpp" - -#include -#include -#include -#include -#include - -#include "chrones.hpp" -#include "classification.hpp" - -#include "vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace { - -bool env_is_true(const char* name) { - const char* value = std::getenv(name); - return value && std::string(value) == "true"; -} - -const bool skip_long = env_is_true("LINCS_DEV_SKIP_LONG"); - -} // namespace - -namespace lincs { - -Problem generate_classification_problem( - const unsigned criteria_count, - const unsigned categories_count, - const unsigned random_seed, - bool normalized_min_max, - const std::vector& allowed_preference_directions, - const std::vector& allowed_value_types -) { - CHRONE(); - - std::mt19937 gen(random_seed); - std::uniform_real_distribution min_max_distribution(-100, 100); - assert(allowed_value_types.size() > 0); - std::uniform_int_distribution value_type_distribution(0, allowed_value_types.size() - 1); - assert(allowed_preference_directions.size() > 0); - std::uniform_int_distribution preference_direction_distribution(0, allowed_preference_directions.size() - 1); - - // Hopping through hoops to generate the same problem as in previous versions: - // - first call the RNG for min, max, and direction for each criterion - // - then call the RNG for value type for each criterion - // @todo(Project management, later) Re-explore my old idea of a tree of RNGs for procedural generation - std::vector> criteria_data; - criteria_data.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - float min_value = 0; - float max_value = 1; - if (!normalized_min_max) { - min_value = min_max_distribution(gen); - max_value = min_max_distribution(gen); - if (min_value > max_value) { - std::swap(min_value, max_value); - } - } - - const std::string name = "Criterion " + std::to_string(criterion_index + 1); - const Criterion::PreferenceDirection direction = allowed_preference_directions[preference_direction_distribution(gen)]; - criteria_data.emplace_back(name, min_value, max_value, direction); - } - - std::vector criteria; - criteria.reserve(criteria_count); - for (const auto [name, min_value, max_value, direction] : criteria_data) { - switch (allowed_value_types[value_type_distribution(gen)]) { - case Criterion::ValueType::real: - criteria.emplace_back(Criterion(name, Criterion::RealValues(direction, min_value, max_value))); - break; - case Criterion::ValueType::integer: - criteria.emplace_back(Criterion(name, Criterion::IntegerValues(direction, 100 * min_value, 100 * max_value))); - break; - case Criterion::ValueType::enumerated: - const unsigned values_count = std::uniform_int_distribution(2, 10)(gen); - std::vector values; - std::set unique_values; - values.reserve(values_count); - while (values.size() < values_count) { - const std::string value({ - "bgrtpd"[std::uniform_int_distribution(0, 5)(gen)], - "aeiou"[std::uniform_int_distribution(0, 4)(gen)], - "zrt"[std::uniform_int_distribution(0, 2)(gen)], - }); - if (unique_values.insert(value).second) { - values.push_back(value); - } - } - criteria.emplace_back(Criterion(name, Criterion::EnumeratedValues(values))); - break; - } - } - - std::vector categories; - categories.reserve(categories_count); - categories.emplace_back("Worst category"); - assert(categories_count >= 2); - for (unsigned category_index = 1; category_index < categories_count - 1; ++category_index) { - categories.emplace_back("Intermediate category " + std::to_string(category_index)); - } - categories.emplace_back("Best category"); - - return Problem{criteria, categories}; -} - -TEST_CASE("Generate problem") { - Problem problem = generate_classification_problem( - 5, - 4, - 14, - false, - { - Criterion::PreferenceDirection::increasing, - Criterion::PreferenceDirection::decreasing, - Criterion::PreferenceDirection::single_peaked, - }, - { - Criterion::ValueType::real, - Criterion::ValueType::integer, - Criterion::ValueType::enumerated, - }); - - std::ostringstream oss; - problem.dump(oss); - CHECK(oss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: integer - preference_direction: single-peaked - min_value: 278 - max_value: 8437 - - name: Criterion 2 - value_type: integer - preference_direction: decreasing - min_value: 3181 - max_value: 7408 - - name: Criterion 3 - value_type: integer - preference_direction: increasing - min_value: -9839 - max_value: -7019 - - name: Criterion 4 - value_type: real - preference_direction: increasing - min_value: -59.7428513 - max_value: 91.520752 - - name: Criterion 5 - value_type: enumerated - ordered_values: [tez, tuz, boz, get, ret, pet, duz, baz, pit] -ordered_categories: - - name: Worst category - - name: Intermediate category 1 - - name: Intermediate category 2 - - name: Best category -)"); -} - -Model generate_mrsort_classification_model(const Problem& problem, const unsigned random_seed, const std::optional fixed_weights_sum) { - CHRONE(); - - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned boundaries_count = categories_count - 1; - const unsigned criteria_count = problem.get_criteria().size(); - - std::mt19937 gen(random_seed); - - typedef std::variant Performance; - std::vector> columns(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - dispatch( - problem.get_criteria()[criterion_index].get_values(), - [&gen, boundaries_count, &columns, criterion_index](const Criterion::RealValues& values) { - // Profile can take any values. We arbitrarily generate them uniformly - std::uniform_real_distribution values_distribution(values.get_min_value() + 0.01f, values.get_max_value() - 0.01f); - // (Values clamped strictly inside ']min, max[' to make it easier to generate balanced learning sets) - // For single-peaked criteria, we generate two columns: one for the left boundary and one for the right boundary - const unsigned values_count = (values.is_single_peaked() ? 2 : 1) * boundaries_count; - // Profiles must be ordered on each criterion, so we generate a random column... - std::vector column(values_count); - columns[criterion_index].resize(values_count); - std::generate( - column.begin(), column.end(), - [&values_distribution, &gen]() { return values_distribution(gen); }); - // ... sort it according to the criterion's preference direction... - std::sort(column.begin(), column.end(), [&values](float left, float right) { - switch (values.get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - case Criterion::PreferenceDirection::single_peaked: - return left < right; - case Criterion::PreferenceDirection::decreasing: - return left > right; - } - unreachable(); - }); - // ... and assign it. - for (unsigned boundary_index = 0; boundary_index != values_count; ++boundary_index) { - columns[criterion_index][boundary_index] = column[boundary_index]; - } - }, - [&gen, boundaries_count, &columns, criterion_index](const Criterion::IntegerValues& values) { - std::uniform_int_distribution values_distribution(values.get_min_value(), values.get_max_value()); - const unsigned values_count = (values.is_single_peaked() ? 2 : 1) * boundaries_count; - std::vector column(values_count); - columns[criterion_index].resize(values_count); - std::generate( - column.begin(), column.end(), - [&values_distribution, &gen]() { return values_distribution(gen); }); - std::sort(column.begin(), column.end(), [&values](int left, int right) { - switch (values.get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - case Criterion::PreferenceDirection::single_peaked: - return left < right; - case Criterion::PreferenceDirection::decreasing: - return left > right; - } - unreachable(); - }); - for (unsigned boundary_index = 0; boundary_index != values_count; ++boundary_index) { - columns[criterion_index][boundary_index] = column[boundary_index]; - } - }, - [&gen, boundaries_count, &columns, criterion_index](const Criterion::EnumeratedValues& values) { - std::uniform_int_distribution values_distribution(0, values.get_ordered_values().size() - 1); - const unsigned values_count = boundaries_count; - std::vector ranks(values_count); - columns[criterion_index].resize(values_count); - std::generate( - ranks.begin(), ranks.end(), - [&values_distribution, &gen]() { return values_distribution(gen); }); - std::sort(ranks.begin(), ranks.end(), [](unsigned left, unsigned right) { return right >= left; }); - for (unsigned boundary_index = 0; boundary_index != values_count; ++boundary_index) { - columns[criterion_index][boundary_index] = values.get_ordered_values()[ranks[boundary_index]]; - } - } - ); - } - - // Weights are a bit trickier. - // We first generate partial sums of weights... - std::uniform_real_distribution partial_sums_distribution(0.0f, 1.f); - std::vector partial_sums(criteria_count + 1); - partial_sums[0] = 0; // First partial sum is zero - std::generate( - std::next(partial_sums.begin()), std::prev(partial_sums.end()), - [&partial_sums_distribution, &gen]() { return partial_sums_distribution(gen); }); - partial_sums[criteria_count] = 1; // Last partial sum is one - // ... sort them... - std::sort(partial_sums.begin(), partial_sums.end()); - // ... and use consecutive differences as (normalized) weights - std::vector normalized_weights(criteria_count); - std::transform( - partial_sums.begin(), std::prev(partial_sums.end()), - std::next(partial_sums.begin()), - normalized_weights.begin(), - [](float left, float right) { return right - left; }); - // Finally, we denormalize weights so that they add up to a pseudo-random value not less than 1 - assert(!fixed_weights_sum || *fixed_weights_sum >= 1); - const float weights_sum = fixed_weights_sum ? *fixed_weights_sum : 1.f / std::uniform_real_distribution(0.f, 1.f)(gen); - std::vector denormalized_weights(criteria_count); - std::transform( - normalized_weights.begin(), normalized_weights.end(), - denormalized_weights.begin(), - [weights_sum](float w) { return w * weights_sum; }); - - std::vector accepted_values; - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - accepted_values.push_back(dispatch( - problem.get_criteria()[criterion_index].get_values(), - [boundaries_count, &columns, criterion_index](const Criterion::RealValues& values) { - if (values.is_single_peaked()) { - std::vector>> intervals; - intervals.reserve(boundaries_count); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - intervals.push_back(std::make_pair( - std::get(columns[criterion_index][boundary_index]), - std::get(columns[criterion_index][2 * boundaries_count - boundary_index - 1]) - )); - } - return AcceptedValues(AcceptedValues::RealIntervals(intervals)); - } else { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - thresholds.push_back(std::get(columns[criterion_index][boundary_index])); - } - return AcceptedValues(AcceptedValues::RealThresholds(thresholds)); - } - }, - [boundaries_count, &columns, criterion_index](const Criterion::IntegerValues& values) { - if (values.is_single_peaked()) { - std::vector>> intervals; - intervals.reserve(boundaries_count); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - intervals.push_back(std::make_pair( - std::get(columns[criterion_index][boundary_index]), - std::get(columns[criterion_index][2 * boundaries_count - boundary_index - 1]) - )); - } - return AcceptedValues(AcceptedValues::IntegerIntervals(intervals)); - } else { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - thresholds.push_back(std::get(columns[criterion_index][boundary_index])); - } - return AcceptedValues(AcceptedValues::IntegerThresholds(thresholds)); - } - }, - [boundaries_count, &columns, criterion_index](const Criterion::EnumeratedValues&) { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - thresholds.push_back(std::get(columns[criterion_index][boundary_index])); - } - return AcceptedValues(AcceptedValues::EnumeratedThresholds(thresholds)); - } - )); - } - - std::vector sufficient_coalitions; - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - sufficient_coalitions.emplace_back(SufficientCoalitions(SufficientCoalitions::Weights(denormalized_weights))); - } - - return Model(problem, accepted_values, sufficient_coalitions); -} - -TEST_CASE("Generate MR-Sort model - random weights sum") { - Problem problem = generate_classification_problem(3, 2, 42); - Model model = generate_mrsort_classification_model(problem, 42); - - std::ostringstream oss; - model.dump(problem, oss); - CHECK(oss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.377049327] - - kind: thresholds - thresholds: [0.790612161] - - kind: thresholds - thresholds: [0.941700041] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.235266, 0.703559637, 0.343733728] -)"); -} - -TEST_CASE("Generate MR-Sort model - fixed weights sum") { - Problem problem = generate_classification_problem(3, 2, 42); - Model model = generate_mrsort_classification_model(problem, 42, 2); - - std::ostringstream oss; - model.dump(problem, oss); - CHECK(oss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.377049327] - - kind: thresholds - thresholds: [0.790612161] - - kind: thresholds - thresholds: [0.941700041] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.366869569, 1.09711826, 0.536012173] -)"); -} - -TEST_CASE("Generate MR-Sort model - integer criteria") { - Problem problem = generate_classification_problem( - 2, 2, - 535747649, - false, - {Criterion::PreferenceDirection::increasing, Criterion::PreferenceDirection::decreasing}, - {Criterion::ValueType::integer}); - Model model = generate_mrsort_classification_model(problem, 116273751); - std::ostringstream oss; - model.dump(problem, oss); - CHECK(oss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [-1219] - - kind: thresholds - thresholds: [1634] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.620512545, 1.0907892] -)"); -} - -TEST_CASE("Generate MR-Sort model - enumerated criteria") { - Problem problem = generate_classification_problem( - 2, 2, - 520326314, - false, - {Criterion::PreferenceDirection::increasing}, // @todo(Project management, later) Support an empty set of allowed preference directions - {Criterion::ValueType::enumerated}); - Model model = generate_mrsort_classification_model(problem, 511376872); - std::ostringstream oss; - model.dump(problem, oss); - CHECK(oss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [got] - - kind: thresholds - thresholds: [bir] -sufficient_coalitions: - - kind: weights - criterion_weights: [101.793587, 45.5191078] -)"); -} - -TEST_CASE("Generate MR-Sort model - single-peaked criteria") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, 0, 1)), - Criterion("Criterion 2", Criterion::IntegerValues(Criterion::PreferenceDirection::single_peaked, 100, 200)), - }, - { - {"Worst category"}, - {"Intermediate category 1"}, - {"Intermediate category 2"}, - {"Best category"}, - }, - }; - Model model = generate_mrsort_classification_model(problem, 12); - std::ostringstream oss; - model.dump(problem, oss); - CHECK(oss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: intervals - intervals: [[0.0947055891, 0.865919411], [0.161079586, 0.735248744], [0.268048704, 0.447297305]] - - kind: intervals - intervals: [[101, 192], [103, 173], [135, 153]] -sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [3.04875612, 0.336062104] - - *coalitions - - *coalitions -)"); -} - -Alternatives generate_uniform_classified_alternatives( - const Problem& problem, - const Model& model, - const unsigned alternatives_count, - std::mt19937& gen -) { - CHRONE(); - - const unsigned criteria_count = problem.get_criteria().size(); - - std::vector alternatives; - alternatives.reserve(alternatives_count); - - // We don't do anything to ensure homogeneous repartition among categories. - // We just generate random profiles uniformly in [min, max] for each criterion - std::map> real_values_distributions; - std::map> int_values_distributions; - std::map> enum_values_distributions; - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - dispatch( - problem.get_criteria()[criterion_index].get_values(), - [&real_values_distributions, criterion_index](const Criterion::RealValues& values) { - real_values_distributions[criterion_index] = std::uniform_real_distribution(values.get_min_value(), values.get_max_value()); - }, - [&int_values_distributions, criterion_index](const Criterion::IntegerValues& values) { - int_values_distributions[criterion_index] = std::uniform_int_distribution(values.get_min_value(), values.get_max_value()); - }, - [&enum_values_distributions, criterion_index](const Criterion::EnumeratedValues& values) { - enum_values_distributions[criterion_index] = std::uniform_int_distribution(0, values.get_ordered_values().size() - 1); - } - ); - } - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - std::vector profile; - profile.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - profile.push_back(dispatch( - problem.get_criteria()[criterion_index].get_values(), - [&real_values_distributions, &gen, criterion_index](const Criterion::RealValues&) { - return Performance(Performance::Real(real_values_distributions[criterion_index](gen))); - }, - [&int_values_distributions, &gen, criterion_index](const Criterion::IntegerValues&) { - return Performance(Performance::Integer(int_values_distributions[criterion_index](gen))); - }, - [&enum_values_distributions, &gen, criterion_index](const Criterion::EnumeratedValues& values) { - return Performance(Performance::Enumerated(values.get_ordered_values()[enum_values_distributions[criterion_index](gen)])); - } - )); - } - - alternatives.push_back(Alternative{"", profile, std::nullopt}); - } - - Alternatives alts{problem, alternatives}; - classify_alternatives(problem, model, &alts); - - return alts; -} - -unsigned min_category_size(const unsigned alternatives_count, const unsigned categories_count, const float max_imbalance) { - assert(max_imbalance >= 0); - assert(max_imbalance <= 1); - - return std::floor(alternatives_count * (1 - max_imbalance) / categories_count); -} - -unsigned max_category_size(const unsigned alternatives_count, const unsigned categories_count, const float max_imbalance) { - assert(max_imbalance >= 0); - assert(max_imbalance <= 1); - - return std::ceil(alternatives_count * (1 + max_imbalance) / categories_count); -} - -TEST_CASE("Balanced category sizes") { - CHECK(min_category_size(100, 2, 0) == 50); - CHECK(max_category_size(100, 2, 0) == 50); - CHECK(min_category_size(100, 2, 1) == 0); - CHECK(max_category_size(100, 2, 1) == 100); - - CHECK(min_category_size(100, 2, 0.2) == 40); - CHECK(max_category_size(100, 2, 0.2) == 61); // Should be 60, but floating point arithmetics... - - CHECK(min_category_size(100'000, 2, 0.2) == 40000); - CHECK(max_category_size(100'000, 2, 0.2) == 60001); // Should be 60000 - - CHECK(min_category_size(150, 3, 0.2) == 40); - CHECK(max_category_size(150, 3, 0.2) == 60); - - CHECK(min_category_size(100, 2, 0.3) == 35); - CHECK(max_category_size(100, 2, 0.3) == 65); - - CHECK(min_category_size(99, 2, 0.2) == 39); - CHECK(max_category_size(99, 2, 0.2) == 60); -} - -Alternatives generate_balanced_classified_alternatives( - const Problem& problem, - const Model& model, - const unsigned alternatives_count, - const float max_imbalance, - std::mt19937& gen -) { - CHRONE(); - - assert(max_imbalance >= 0); - assert(max_imbalance <= 1); - - const unsigned categories_count = problem.get_ordered_categories().size(); - - // These parameters are somewhat arbitrary and not really critical, - // but changing there values *does* change the generated set, because of the two-steps process below: - // the same alternatives are generated in the same order, but they treated differently here. - - // How long to insist before accepting failure when we can't find any alternative for a given category - const int max_iterations_with_no_effect_with_empty_category = 100; - - // How long to insist before accepting failure when we have found at least one alternative for each category - const int max_iterations_with_no_effect_with_all_categories_populated = 1'000; - - // Size ratio to call 'uniform_learning_set'. Small values imply calling it more, and large values - // imply discarding more alternatives - const int multiplier = 10; - - const unsigned min_size = min_category_size(alternatives_count, categories_count, max_imbalance); - const unsigned max_size = max_category_size(alternatives_count, categories_count, max_imbalance); - - std::vector alternatives; - alternatives.reserve(alternatives_count); - std::vector histogram(categories_count, 0); - - int max_iterations_with_no_effect = max_iterations_with_no_effect_with_empty_category; - - // Step 1: fill all categories to exactly the min size - // (skip if min size is zero) - int iterations_with_no_effect = 0; - while (min_size > 0) { - ++iterations_with_no_effect; - - Alternatives candidates = generate_uniform_classified_alternatives(problem, model, multiplier * alternatives_count, gen); - - for (const auto& candidate : candidates.get_alternatives()) { - assert(candidate.get_category_index()); - const unsigned category_index = *candidate.get_category_index(); - if (histogram[category_index] < min_size) { - alternatives.push_back(candidate); - ++histogram[category_index]; - iterations_with_no_effect = 0; - } - } - - if (std::all_of(histogram.begin(), histogram.end(), [min_size](const auto size) { return size >= min_size; })) { - // Success - break; - } - - if (std::all_of(histogram.begin(), histogram.end(), [](const auto size) { return size > 0; })) { - max_iterations_with_no_effect = max_iterations_with_no_effect_with_all_categories_populated; - } - - if (iterations_with_no_effect > max_iterations_with_no_effect) { - throw BalancedAlternativesGenerationException(histogram); - } - } - - // Step 2: reach target size, keeping all categories below or at the max size - iterations_with_no_effect = 0; - while (true) { - ++iterations_with_no_effect; - - Alternatives candidates = generate_uniform_classified_alternatives(problem, model, multiplier * alternatives_count, gen); - - for (const auto& candidate : candidates.get_alternatives()) { - assert(candidate.get_category_index()); - const unsigned category_index = *candidate.get_category_index(); - if (histogram[category_index] < max_size) { - alternatives.push_back(candidate); - ++histogram[category_index]; - iterations_with_no_effect = 0; - } - - if (alternatives.size() == alternatives_count) { - assert(std::all_of( - histogram.begin(), histogram.end(), - [min_size, max_size](const auto size) { return size >= min_size && size <= max_size; })); - return Alternatives(problem, alternatives); - } - } - - if (iterations_with_no_effect > max_iterations_with_no_effect) { - throw BalancedAlternativesGenerationException(histogram); - } - } -} - -Alternatives generate_classified_alternatives( - const Problem& problem, - const Model& model, - const unsigned alternatives_count, - const unsigned random_seed, - const std::optional max_imbalance -) { - CHRONE(); - - std::mt19937 gen(random_seed); - - Alternatives alternatives = max_imbalance ? - generate_balanced_classified_alternatives(problem, model, alternatives_count, *max_imbalance, gen) : - generate_uniform_classified_alternatives(problem, model, alternatives_count, gen); - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - alternatives.get_writable_alternatives()[alternative_index].set_name("Alternative " + std::to_string(alternative_index + 1)); - } - - return alternatives; -} - -TEST_CASE("Generate uniform alternative - integer criterion") { - Problem problem = generate_classification_problem( - 1, 2, - 42, - false, - {Criterion::PreferenceDirection::increasing}, - {Criterion::ValueType::integer}); - Model model = generate_mrsort_classification_model(problem, 43); - Alternatives alternatives = generate_classified_alternatives(problem, model, 1, 44); - - CHECK(alternatives.get_alternatives()[0].get_profile()[0].get_integer().get_value() == 4537); -} - -TEST_CASE("Generate uniform alternative - enumerated criterion") { - Problem problem = generate_classification_problem( - 1, 2, - 42, - false, - {Criterion::PreferenceDirection::increasing}, - {Criterion::ValueType::enumerated}); - Model model = generate_mrsort_classification_model(problem, 43); - Alternatives alternatives = generate_classified_alternatives(problem, model, 1, 44); - - CHECK(alternatives.get_alternatives()[0].get_profile()[0].get_enumerated().get_value() == "put"); -} - -void check_histogram(const Problem& problem, const Model& model, const std::optional max_imbalance, const unsigned a, const unsigned b) { - const unsigned alternatives_count = 100; - - REQUIRE(problem.get_ordered_categories().size() == 2); - REQUIRE(a + b == alternatives_count); - - Alternatives alternatives = generate_classified_alternatives(problem, model, alternatives_count, 42, max_imbalance); - - std::vector histogram(2, 0); - for (const auto& alternative : alternatives.get_alternatives()) { - ++histogram[*alternative.get_category_index()]; - } - CHECK(histogram[0] == a); - CHECK(histogram[1] == b); -} - -TEST_CASE("Generate balanced classified alternatives") { - Problem problem = generate_classification_problem(3, 2, 42); - Model model = generate_mrsort_classification_model(problem, 42, 2); - - check_histogram(problem, model, std::nullopt, 80, 20); - check_histogram(problem, model, 0.5, 63, 37); - check_histogram(problem, model, 0.2, 56, 44); - check_histogram(problem, model, 0.1, 54, 46); - check_histogram(problem, model, 0.0, 50, 50); -} - -TEST_CASE("Generate balanced classified alternatives - names are correct") { - Problem problem = generate_classification_problem(3, 2, 42); - Model model = generate_mrsort_classification_model(problem, 42, 2); - Alternatives alternatives = generate_classified_alternatives(problem, model, 100, 42, 0.); - - CHECK(alternatives.get_alternatives()[99].get_name() == "Alternative 100"); -} - -TEST_CASE("Generate balanced classified alternatives - many seeds") { - // Assert that we can generate a balanced learning set for all generated models - - const unsigned alternatives_seed = 42; // If we succeed with this arbitrary seed, we're confident we'll succeed with any seed - const int max_model_seed = skip_long ? 10 : 100; - - // (dynamic OpenMP scheduling because iteration durations vary a lot) - #pragma omp parallel for collapse(3) schedule(dynamic, 1) - for (int criteria_count = 1; criteria_count < 7; ++criteria_count) { - for (int categories_count = 2; categories_count < 7; ++categories_count) { - for (int model_seed = 0; model_seed < max_model_seed; ++model_seed) { - Problem problem = generate_classification_problem(criteria_count, categories_count, 42); - - CAPTURE(criteria_count); - CAPTURE(categories_count); - CAPTURE(model_seed); - - Model model = generate_mrsort_classification_model(problem, model_seed); - - // There *are* failures for larger numbers of criteria or categories, - // but there is not much I can imagine doing to avoid that. - bool expect_success = true; - // Known failures: when the first (resp. last) profile and threshold are low (resp. high), - // it's too difficult to find random alternatives in the first (resp. last) category. - if (criteria_count == 3 && categories_count == 4 && model_seed == 24) expect_success = false; - if (criteria_count == 5 && categories_count == 5 && model_seed == 45) expect_success = false; - if (criteria_count == 5 && categories_count == 6 && model_seed == 8) expect_success = false; - if (criteria_count == 6 && categories_count == 2 && model_seed == 87) expect_success = false; - if (criteria_count == 6 && categories_count == 4 && model_seed == 21) expect_success = false; - if (criteria_count == 6 && categories_count == 4 && model_seed == 43) expect_success = false; - if (criteria_count == 6 && categories_count == 4 && model_seed == 52) expect_success = false; - if (criteria_count == 6 && categories_count == 5 && model_seed == 8) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 11) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 14) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 26) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 29) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 42) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 54) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 76) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 78) expect_success = false; - if (criteria_count == 6 && categories_count == 6 && model_seed == 96) expect_success = false; - - try { - Alternatives alternatives = generate_classified_alternatives(problem, model, 100, alternatives_seed, 0); - CHECK(expect_success); - } catch (BalancedAlternativesGenerationException& e) { - CHECK(!expect_success); - } - } - } - } -} - -TEST_CASE("Random min/max") { - Problem problem = generate_classification_problem(2, 2, 42, false); - Model model = generate_mrsort_classification_model(problem, 42); - Alternatives alternatives = generate_classified_alternatives(problem, model, 1, 44); - - CHECK(problem.get_criteria()[0].get_real_values().get_min_value() == doctest::Approx(-25.092)); - CHECK(problem.get_criteria()[0].get_real_values().get_max_value() == doctest::Approx(59.3086)); - CHECK(*model.get_accepted_values()[0].get_real_thresholds().get_thresholds()[0] == doctest::Approx(6.52194)); - CHECK(alternatives.get_alternatives()[0].get_profile()[0].get_real().get_value() == doctest::Approx(45.3692)); - - CHECK(problem.get_criteria()[1].get_real_values().get_min_value() == doctest::Approx(-63.313)); - CHECK(problem.get_criteria()[1].get_real_values().get_max_value() == doctest::Approx(46.3988)); - CHECK(*model.get_accepted_values()[1].get_real_thresholds().get_thresholds()[0] == doctest::Approx(24.0712)); - CHECK(alternatives.get_alternatives()[0].get_profile()[1].get_real().get_value() == doctest::Approx(-15.8581)); -} - -TEST_CASE("Decreasing criterion") { - Problem problem = generate_classification_problem( - 1, 3, - 44, - true, - {Criterion::PreferenceDirection::increasing, Criterion::PreferenceDirection::decreasing} - ); - Model model = generate_mrsort_classification_model(problem, 42); - Alternatives alternatives = generate_classified_alternatives(problem, model, 10, 44); - - CHECK(problem.get_criteria()[0].get_real_values().get_preference_direction() == Criterion::PreferenceDirection::decreasing); - // Profiles are in decreasing order - CHECK(*model.get_accepted_values()[0].get_real_thresholds().get_thresholds()[0] == doctest::Approx(0.790612)); - CHECK(*model.get_accepted_values()[0].get_real_thresholds().get_thresholds()[1] == doctest::Approx(0.377049)); - - CHECK(alternatives.get_alternatives()[0].get_profile()[0].get_real().get_value() == doctest::Approx(0.834842)); - CHECK(*alternatives.get_alternatives()[0].get_category_index() == 0); - - CHECK(alternatives.get_alternatives()[1].get_profile()[0].get_real().get_value() == doctest::Approx(0.432542)); - CHECK(*alternatives.get_alternatives()[1].get_category_index() == 1); - - CHECK(alternatives.get_alternatives()[2].get_profile()[0].get_real().get_value() == doctest::Approx(0.104796)); - CHECK(*alternatives.get_alternatives()[2].get_category_index() == 2); -} - -TEST_CASE("Single-peaked criterion") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, 0, 1)), - }, - { - {"Bad"}, - {"Good"}, - }, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealIntervals({std::make_pair(0.3, 0.7)})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({1})), - }, - }; - - Alternatives alternatives = generate_classified_alternatives(problem, model, 10, 44); - - CHECK(alternatives.get_alternatives()[0].get_profile()[0].get_real().get_value() == doctest::Approx(0.834842)); - CHECK(*alternatives.get_alternatives()[0].get_category_index() == 0); - - CHECK(alternatives.get_alternatives()[1].get_profile()[0].get_real().get_value() == doctest::Approx(0.432542)); - CHECK(*alternatives.get_alternatives()[1].get_category_index() == 1); - - CHECK(alternatives.get_alternatives()[2].get_profile()[0].get_real().get_value() == doctest::Approx(0.104796)); - CHECK(*alternatives.get_alternatives()[2].get_category_index() == 0); -} - -TEST_CASE("Exploratory test: 'std::shuffle' *can* keep something in place") { - std::vector v(100); - std::iota(v.begin(), v.end(), 0); - - CHECK(v[76] == 76); - CHECK(v[77] == 77); - CHECK(v[78] == 78); - - std::mt19937 gen(0); - std::shuffle(v.begin(), v.end(), gen); - - CHECK(v[76] == 31); - CHECK(v[77] == 77); // Kept - CHECK(v[78] == 71); -} - -void misclassify_alternatives(const Problem& problem, Alternatives* alternatives, const unsigned count, const unsigned random_seed) { - CHRONE(); - - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned alternatives_count = alternatives->get_alternatives().size(); - - std::mt19937 gen(random_seed); - - std::vector alternative_indexes(alternatives_count); - std::iota(alternative_indexes.begin(), alternative_indexes.end(), 0); - std::shuffle(alternative_indexes.begin(), alternative_indexes.end(), gen); - alternative_indexes.resize(count); - - for (const unsigned alternative_index : alternative_indexes) { - auto& alternative = alternatives->get_writable_alternatives()[alternative_index]; - - // Choose new index in [0, alternative.get_category_index() - 1] U [alternative.get_category_index() + 1, categories_count - 1] - // => choose in [0, categories_count - 2] and increment if >= alternative.get_category_index() - unsigned new_category_index = std::uniform_int_distribution(0, categories_count - 2)(gen); - if (new_category_index >= *alternative.get_category_index()) { - ++new_category_index; - } - - alternative.set_category_index(new_category_index); - } -} - -TEST_CASE("Misclassify alternatives") { - Problem problem = generate_classification_problem(3, 2, 42); - Model model = generate_mrsort_classification_model(problem, 42, 2); - Alternatives alternatives = generate_classified_alternatives(problem, model, 100, 42, 0.2); - - misclassify_alternatives(problem, &alternatives, 10, 42); - - CHECK(classify_alternatives(problem, model, &alternatives).changed == 10); -} - -} // namespace lincs diff --git a/lincs/liblincs/generation.hpp b/lincs/liblincs/generation.hpp deleted file mode 100644 index 16f868b0..00000000 --- a/lincs/liblincs/generation.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__GENERATION_HPP -#define LINCS__GENERATION_HPP - -#include - -#include "io.hpp" - - -namespace lincs { - -// @todo(Feature, later) Use structures to hold generation options? -// This would allow calls like: -// generate_classification_problem(4, 3, 42, {.normalized_min_max = true}}) -// generate_mrsort_classification_model(problem, 42, {.fixed_weights_sum = 2.0f}}) - -Problem generate_classification_problem( - unsigned criteria_count, unsigned categories_count, - unsigned random_seed, - bool normalized_min_max=true, - const std::vector& allowed_preference_directions={Criterion::PreferenceDirection::increasing}, - const std::vector& allowed_value_types={Criterion::ValueType::real} -); - -Model generate_mrsort_classification_model( - const Problem&, unsigned random_seed, std::optional fixed_weights_sum = std::nullopt); - -struct BalancedAlternativesGenerationException : public std::runtime_error { - explicit BalancedAlternativesGenerationException(const std::vector& histogram_) : - std::runtime_error("Unable to generate balanced alternatives. Try increasing the allowed imbalance, or use a more lenient model?"), - histogram(histogram_) - {} - - std::vector histogram; -}; - -Alternatives generate_classified_alternatives( - const Problem&, - const Model&, - unsigned alternatives_count, - unsigned random_seed, - std::optional max_imbalance = std::nullopt -); - -void misclassify_alternatives(const Problem&, Alternatives*, unsigned misclassification_count, unsigned random_seed); - -} // namespace lincs - -#endif // LINCS__GENERATION_HPP diff --git a/lincs/liblincs/io.cpp b/lincs/liblincs/io.cpp deleted file mode 100644 index 174cd4f3..00000000 --- a/lincs/liblincs/io.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "io.hpp" diff --git a/lincs/liblincs/io.hpp b/lincs/liblincs/io.hpp deleted file mode 100644 index afb42917..00000000 --- a/lincs/liblincs/io.hpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2023 Vincent Jacques - -#ifndef LINCS__IO_HPP -#define LINCS__IO_HPP - -#include "io/alternatives.hpp" -#include "io/exception.hpp" -#include "io/problem.hpp" -#include "io/model.hpp" - -#endif // LINCS__IO_HPP diff --git a/lincs/liblincs/io/alternatives.cpp b/lincs/liblincs/io/alternatives.cpp deleted file mode 100644 index e477538e..00000000 --- a/lincs/liblincs/io/alternatives.cpp +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "alternatives.hpp" - -#include "../chrones.hpp" -#include "../vendored/rapidcsv.h" -#include "validation.hpp" - -#include "../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace lincs { - -// @todo(Project management, later) Consider taking 'alternatives_' by rvalue reference and moving it in 'alternatives' -Alternatives::Alternatives(const Problem& problem, const std::vector& alternatives_) : - alternatives(alternatives_) -{ - const unsigned criteria_count = problem.get_criteria().size(); - for (const auto& alternative : alternatives) { - validate( - alternative.get_profile().size() == problem.get_criteria().size(), - "The profile of an alternative must have as many performances as there are criteria in the problem"); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - const auto& criterion = problem.get_criteria()[criterion_index]; - const auto& performance = alternative.get_profile()[criterion_index]; - dispatch( - criterion.get_values(), - [&performance](const Criterion::RealValues& values) { - validate(performance.is_real(), "The type of the performance of an alternative must match the type of the real-valued criterion in the problem"); - validate(values.is_acceptable(performance.get_real().get_value()), "The performance of an alternative must be between the min and max values for the real-valued criterion in the problem"); - }, - [&performance](const Criterion::IntegerValues& values) { - validate(performance.is_integer(), "The type of the performance of an alternative must match the type of the integer-valued criterion in the problem"); - validate(values.is_acceptable(performance.get_integer().get_value()), "The performance of an alternative must be between the min and max values for the integer-valued criterion in the problem"); - }, - [&performance](const Criterion::EnumeratedValues& values) { - validate(performance.is_enumerated(), "The type of the performance of an alternative must match the type of the enumerated criterion in the problem"); - validate(values.is_acceptable(performance.get_enumerated().get_value()), "The performance of an alternative must be int the enumerated values for a criterion in the problem"); - } - ); - } - } -} - -void Alternatives::dump(const Problem& problem, std::ostream& os) const { - CHRONE(); - - const unsigned criteria_count = problem.get_criteria().size(); - const unsigned alternatives_count = alternatives.size(); - - rapidcsv::SeparatorParams separator_params; - separator_params.mHasCR = false; // Fix line ends on Windows (without this line, they are "\r\r\n") - - rapidcsv::Document doc( - std::string(), - rapidcsv::LabelParams(), - separator_params, - rapidcsv::ConverterParams(), - rapidcsv::LineReaderParams()); - - doc.SetColumnName(0, "name"); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - doc.SetColumnName(criterion_index + 1, problem.get_criteria()[criterion_index].get_name()); - } - doc.SetColumnName(criteria_count + 1, "category"); - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - const Alternative& alternative = alternatives[alternative_index]; - doc.SetCell(0, alternative_index, alternative.get_name()); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - dispatch( - alternative.get_profile()[criterion_index].get(), - [&doc, criterion_index, alternative_index](const Performance::Real& perf) { - doc.SetCell(criterion_index + 1, alternative_index, perf.get_value()); - }, - [&doc, criterion_index, alternative_index](const Performance::Integer& perf) { - doc.SetCell(criterion_index + 1, alternative_index, perf.get_value()); - }, - [&doc, criterion_index, alternative_index](const Performance::Enumerated& perf) { - doc.SetCell(criterion_index + 1, alternative_index, perf.get_value()); - } - ); - } - if (alternative.get_category_index()) { - doc.SetCell(criteria_count + 1, alternative_index, problem.get_ordered_categories()[*alternative.get_category_index()].get_name()); - } - } - - doc.Save(os); -} - -Alternatives Alternatives::load(const Problem& problem, std::istream& is) { - CHRONE(); - - const unsigned criteria_count = problem.get_criteria().size(); - std::map category_indexes; - for (const auto& category: problem.get_ordered_categories()) { - category_indexes[category.get_name()] = category_indexes.size(); - } - - // I don't know why constructing the rapidcsv::Document directly from 'is' sometimes results in an empty document. - // So, read the whole stream into a string and construct the document from that. - std::string s(std::istreambuf_iterator(is), {}); - std::istringstream iss(s); - rapidcsv::Document doc( - iss, - rapidcsv::LabelParams(), - rapidcsv::SeparatorParams(), - rapidcsv::ConverterParams(), - rapidcsv::LineReaderParams(true, '#') // Skip comments - ); - - const ssize_t name_column_index = doc.GetColumnIdx("name"); - if (name_column_index < 0) { - throw DataValidationException("Missing column: name"); - } - - std::vector criterion_column_indexes; - criterion_column_indexes.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - ssize_t column_index = doc.GetColumnIdx(problem.get_criteria()[criterion_index].get_name()); - if (column_index < 0) { - throw DataValidationException("Mismatch: criterion from the problem file not found in the alternatives file"); - } - criterion_column_indexes.emplace_back(column_index); - } - - const ssize_t category_column_index = doc.GetColumnIdx("category"); - if (category_column_index < 0) { - throw DataValidationException("Missing column: category"); - } - - std::vector alternatives; - const unsigned alternatives_count = doc.GetRowCount(); - alternatives.reserve(alternatives_count); - for (unsigned row_index = 0; row_index != alternatives_count; ++row_index) { - std::string name = doc.GetCell(name_column_index, row_index); - std::vector profile; - profile.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - switch (problem.get_criteria()[criterion_index].get_value_type()) { - case Criterion::ValueType::real: - profile.push_back(Performance(Performance::Real(doc.GetCell(criterion_column_indexes[criterion_index], row_index)))); - break; - case Criterion::ValueType::integer: - profile.push_back(Performance(Performance::Integer(doc.GetCell(criterion_column_indexes[criterion_index], row_index)))); - break; - case Criterion::ValueType::enumerated: - profile.push_back(Performance(Performance::Enumerated(doc.GetCell(criterion_column_indexes[criterion_index], row_index)))); - break; - } - } - std::string category = doc.GetCell(category_column_index, row_index); - std::optional category_index; - if (category != "") { - auto it = category_indexes.find(category); - if (it == category_indexes.end()) { - throw DataValidationException("Mismatch: category in the alternatives file not found in the problem file"); - } - category_index = it->second; - } - alternatives.emplace_back(name, profile, category_index); - } - - return Alternatives{problem, alternatives}; -} - -TEST_CASE("Dump then load preserves data - real criterion") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - Alternatives alternatives( - problem, - { - {"Alt 1", {Performance(Performance::Real(0.5))}, 0}, - {"Alt 2", {Performance(Performance::Real(0.75))}, 1}, - } - ); - - std::stringstream ss; - alternatives.dump(problem, ss); - - CHECK(ss.str() == R"(name,"Criterion 1",category -"Alt 1",0.5,"Category 1" -"Alt 2",0.75,"Category 2" -)"); - - CHECK(Alternatives::load(problem, ss) == alternatives); -} - -TEST_CASE("Dump then load preserves data - numerical values requiring more decimal digits") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - Alternatives alternatives(problem, { - {"Alt 1", {Performance(Performance::Real(0x1.259b36p-6))}, 0}, - {"Alt 2", {Performance(Performance::Real(0x1.652bf4p-2))}, 1}, - {"Alt 3", {Performance(Performance::Real(0x1.87662ap-3))}, 1}, - }); - - std::stringstream ss; - alternatives.dump(problem, ss); - - CHECK(ss.str() == R"(name,"Criterion 1",category -"Alt 1",0.017920306,"Category 1" -"Alt 2",0.34880048,"Category 2" -"Alt 3",0.191112831,"Category 2" -)"); - - CHECK(Alternatives::load(problem, ss) == alternatives); -} - -TEST_CASE("Dump then load preserves data - integer criterion") { - Problem problem( - {Criterion("Criterion 1", Criterion::IntegerValues(Criterion::PreferenceDirection::increasing, 0, 10))}, - {{"Category 1"}, {"Category 2"}} - ); - - Alternatives alternatives( - problem, - { - {"Alt 1", {Performance(Performance::Integer(5))}, 0}, - {"Alt 2", {Performance(Performance::Integer(6))}, 1}, - } - ); - - std::stringstream ss; - alternatives.dump(problem, ss); - - CHECK(ss.str() == R"(name,"Criterion 1",category -"Alt 1",5,"Category 1" -"Alt 2",6,"Category 2" -)"); - - CHECK(Alternatives::load(problem, ss) == alternatives); -} - -TEST_CASE("Dump then load preserves data - enumerated criterion") { - Problem problem{ - {Criterion("Criterion 1", Criterion::EnumeratedValues({"a", "b b", "c", "d"}))}, - {{"Category 1"}, {"Category 2"}}, - }; - - Alternatives alternatives( - problem, - { - {"Alt 1", {Performance(Performance::Enumerated("a"))}, 0}, - {"Alt 2", {Performance(Performance::Enumerated("b b"))}, 1}, - } - ); - - std::stringstream ss; - alternatives.dump(problem, ss); - - CHECK(ss.str() == R"(name,"Criterion 1",category -"Alt 1",a,"Category 1" -"Alt 2","b b","Category 2" -)"); - - CHECK(Alternatives::load(problem, ss) == alternatives); -} - -TEST_CASE("Validation error - name column") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(namee,"Criterion 1",category -"Alt 1",0.5, -)"); - - CHECK_THROWS_WITH_AS( - Alternatives::load(problem, iss), - "Missing column: name", - DataValidationException); -} - -TEST_CASE("Validation error - category column") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(name,"Criterion 1",categoryy -"Alt 1",0.5, -)"); - - CHECK_THROWS_WITH_AS( - Alternatives::load(problem, iss), - "Missing column: category", - DataValidationException); -} - -TEST_CASE("Validation error - criterion name") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(name,"Criterion A",category -"Alt 1",0.5, -)"); - - CHECK_THROWS_WITH_AS( - Alternatives::load(problem, iss), - "Mismatch: criterion from the problem file not found in the alternatives file", - DataValidationException); -} - -TEST_CASE("Validation error - category name") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(name,"Criterion 1",category -"Alt 1",0.5,Category 3 -)"); - - CHECK_THROWS_WITH_AS( - Alternatives::load(problem, iss), - "Mismatch: category in the alternatives file not found in the problem file", - DataValidationException); -} - -} // namespace lincs diff --git a/lincs/liblincs/io/alternatives.hpp b/lincs/liblincs/io/alternatives.hpp deleted file mode 100644 index 8317c0dd..00000000 --- a/lincs/liblincs/io/alternatives.hpp +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__IO__ALTERNATIVES_HPP -#define LINCS__IO__ALTERNATIVES_HPP - -#include -#include -#include -#include - -#include "../internal.hpp" -#include "problem.hpp" - - -namespace lincs { - -class Performance { - public: - class Real { - public: - Real(float value_) : value(value_) {} - - public: - bool operator==(const Real& other) const { return value == other.value; } - - public: - float get_value() const { return value; } - - private: - float value; - }; - - class Integer { - public: - Integer(int value_) : value(value_) {} - - public: - bool operator==(const Integer& other) const { return value == other.value; } - - public: - int get_value() const { return value; } - - private: - int value; - }; - - class Enumerated { - public: - Enumerated(std::string value_) : value(value_) {} - - public: - bool operator==(const Enumerated& other) const { return value == other.value; } - - public: - std::string get_value() const { return value; } - - private: - std::string value; - }; - - typedef std::variant Self; - - public: - Performance(const Self& self_) : self(self_) {} - - // Copyable and movable - Performance(const Performance&) = default; - Performance& operator=(const Performance&) = default; - Performance(Performance&&) = default; - Performance& operator=(Performance&&) = default; - - public: - bool operator==(const Performance& other) const { - return self == other.self; - } - - public: - Criterion::ValueType get_value_type() const { - return dispatch( - self, - [](const Real&) { return Criterion::ValueType::real; }, - [](const Integer&) { return Criterion::ValueType::integer; }, - [](const Enumerated&) { return Criterion::ValueType::enumerated; } - ); - } - const Self& get() const { return self; } - - bool is_real() const { return get_value_type() == Criterion::ValueType::real; } - Real get_real() const { return std::get(self); } - - bool is_integer() const { return get_value_type() == Criterion::ValueType::integer; } - Integer get_integer() const { return std::get(self); } - - bool is_enumerated() const { return get_value_type() == Criterion::ValueType::enumerated; } - Enumerated get_enumerated() const { return std::get(self); } - - private: - Self self; -}; - -class Alternative { - public: - Alternative( - const std::string& name_, - const std::vector& profile_, - const std::optional& category_index_ - ) : - name(name_), - profile(profile_), - category_index(category_index_) - {} - - public: - bool operator==(const Alternative& other) const { - return name == other.name && profile == other.profile && category_index == other.category_index; - } - - public: - const std::string& get_name() const { return name; } - void set_name(const std::string& name_) { name = name_; } - - const std::vector& get_profile() const { return profile; } - - const std::optional& get_category_index() const { return category_index; } - void set_category_index(const std::optional& category_index_) { category_index = category_index_; } - - private: - std::string name; - std::vector profile; - std::optional category_index; -}; - -class Alternatives { - public: - Alternatives(const Problem&, const std::vector&); - - Alternatives(Internal, const std::vector& alternatives_) : alternatives(alternatives_) {} - - public: - bool operator==(const Alternatives& other) const { - return alternatives == other.alternatives; - } - - public: - void dump(const Problem&, std::ostream&) const; - static Alternatives load(const Problem&, std::istream&); - - public: - const std::vector& get_alternatives() const { return alternatives; } - std::vector& get_writable_alternatives() { return alternatives; } - - private: - std::vector alternatives; -}; - -} // namespace lincs - -#endif // LINCS__IO__ALTERNATIVES_HPP diff --git a/lincs/liblincs/io/exception.cpp b/lincs/liblincs/io/exception.cpp deleted file mode 100644 index 2833dfde..00000000 --- a/lincs/liblincs/io/exception.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2023 Vincent Jacques - -#include "exception.hpp" diff --git a/lincs/liblincs/io/exception.hpp b/lincs/liblincs/io/exception.hpp deleted file mode 100644 index 969f8de7..00000000 --- a/lincs/liblincs/io/exception.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2023 Vincent Jacques - -#ifndef LINCS__IO__EXCEPTION_HPP -#define LINCS__IO__EXCEPTION_HPP - -#include - - -namespace lincs { - -struct DataValidationException : public std::runtime_error { - DataValidationException(const std::string& message) : std::runtime_error(message) {} -}; - -inline void validate(const bool ok, const std::string& message) { - if (!ok) { - throw DataValidationException(message); - } -} - -} // namespace lincs - -#endif // LINCS__IO__EXCEPTION_HPP diff --git a/lincs/liblincs/io/model.cpp b/lincs/liblincs/io/model.cpp deleted file mode 100644 index 276e0acc..00000000 --- a/lincs/liblincs/io/model.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "model.hpp" - -#include - -#include "../chrones.hpp" -#include "../classification.hpp" -#include "../unreachable.hpp" -#include "../vendored/magic_enum.hpp" -#include "../vendored/yaml-cpp/yaml.h" -#include "validation.hpp" - -#include "../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -TEST_CASE("libyaml-cpp uses sufficient precision for floats") { - // This test passes with libyaml-cpp version 0.7 but fails with version 0.6 - - const float f = 0x1.c78b0cp-2f; - - std::stringstream ss; - YAML::Emitter out(ss); - out << f; - - CHECK(ss.str() == "0.444866359"); - - CHECK(YAML::Load(ss).as() == 0x1.c78b0cp-2f); // No approximation: no loss of precision -} - -namespace YAML { - -template -Emitter& operator<<(Emitter& out, const std::optional& o) { - if (o) { - out << *o; - } else { - out << Null; - } - return out; -} - -template -struct convert> { - static bool decode(const Node& node, std::optional& rhs) { - if (node.IsNull()) { - rhs.reset(); - } else { - rhs = node.as(); - } - return true; - } -}; - -} - -namespace lincs { - -const std::string Model::json_schema(R"($schema: https://json-schema.org/draft/2020-12/schema -title: NCS classification model -type: object -properties: - kind: - type: string - const: ncs-classification-model - format_version: - type: integer - const: 1 - accepted_values: - description: For each criterion in the classification problem, a way to determine the accepted values for each category. - type: array - items: - type: object - oneOf: - - properties: - kind: - type: string - const: thresholds - thresholds: - description: For each category but the lowest, the threshold to be accepted in that category according to that criterion. - type: array - minItems: 1 - required: - - kind - - thresholds - additionalProperties: false - - properties: - kind: - type: string - const: intervals - intervals: - description: For each category but the lowest, the interval of values to be accepted in that category according to that criterion. - type: array - minItems: 1 - items: - oneOf: - - type: 'null' - - type: array - minItems: 2 - maxItems: 2 - items: - type: number - required: - - kind - - intervals - additionalProperties: false - minItems: 1 - sufficient_coalitions: - description: For each category but the lowest, a description of the sufficient coalitions for that category. - type: array - items: - type: object - oneOf: - - properties: - kind: - type: string - const: weights - criterion_weights: - type: array - items: - type: number - minItems: 1 - required: - - kind - - criterion_weights - additionalProperties: false - - properties: - kind: - type: string - const: roots - upset_roots: - type: array - items: - type: array - items: - type: integer - minItems: 0 - minItems: 0 - required: - - kind - - upset_roots - additionalProperties: false - minItems: 1 -required: - - kind - - format_version - - accepted_values - - sufficient_coalitions -additionalProperties: false -)"); - -namespace { - -std::istringstream schema_iss(Model::json_schema); -YAML::Node schema = YAML::Load(schema_iss); -JsonValidator validator(schema); - -} // namespace - -std::vector> SufficientCoalitions::Roots::get_upset_roots_as_vectors() const { - std::vector> roots; - - roots.reserve(upset_roots.size()); - for (const auto& upset_root : upset_roots) { - std::vector& root = roots.emplace_back(); - for (unsigned criterion_index = 0; criterion_index != upset_root.size(); ++criterion_index) { - if (upset_root[criterion_index]) { - root.emplace_back(criterion_index); - } - } - } - - return roots; -} - -Model::Model(const Problem& problem, const std::vector& accepted_values_, const std::vector& sufficient_coalitions_) : - accepted_values(accepted_values_), - sufficient_coalitions(sufficient_coalitions_) -{ - const unsigned criteria_count = problem.get_criteria().size(); - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned boundaries_count = categories_count - 1; - validate(accepted_values.size() == criteria_count, "The number of accepted values descriptors in the model must be equal to the number of criteria in the problem"); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - const auto& criterion = problem.get_criteria()[criterion_index]; - validate(accepted_values[criterion_index].get_value_type() == criterion.get_value_type(), "The value type of an accepted values descriptor must be the same as the value type of the corresponding criterion"); - dispatch( - accepted_values[criterion_index].get(), - [&criterion, criterion_index, boundaries_count](const AcceptedValues::RealThresholds& thresholds) { - validate(thresholds.get_thresholds().size() == boundaries_count, "The number of real thresholds in an accepted values descriptor must be one less than the number of categories in the problem"); - const auto& criterion_values = criterion.get_real_values(); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const std::optional threshold = thresholds.get_thresholds()[boundary_index]; - if (threshold) { - validate(criterion_values.is_acceptable(*threshold), "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding real criterion"); - } - } - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - const std::optional previous_threshold = thresholds.get_thresholds()[boundary_index - 1]; - const std::optional threshold = thresholds.get_thresholds()[boundary_index]; - if (previous_threshold) { - if (threshold) { - switch (criterion_values.get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - validate(*threshold >= *previous_threshold, "The real thresholds in an accepted values descriptor must be in preference order"); - break; - case Criterion::PreferenceDirection::decreasing: - validate(*threshold <= *previous_threshold, "The real thresholds in an accepted values descriptor must be in preference order"); - break; - default: - validate(false, "Thresholds accepted values descriptors are only supported for monotonic criteria"); - break; - } - } - } else { - validate(!threshold, "After a null threshold, all subsequent thresholds must be null"); - } - } - }, - [&criterion, criterion_index, boundaries_count](const AcceptedValues::IntegerThresholds& thresholds) { - validate(thresholds.get_thresholds().size() == boundaries_count, "The number of integer thresholds in an accepted values descriptor must be one less than the number of categories in the problem"); - const auto& criterion_values = criterion.get_integer_values(); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const std::optional threshold = thresholds.get_thresholds()[boundary_index]; - if (threshold) { - validate(criterion_values.is_acceptable(*threshold), "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding integer criterion"); - } - } - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - const std::optional previous_threshold = thresholds.get_thresholds()[boundary_index - 1]; - const std::optional threshold = thresholds.get_thresholds()[boundary_index]; - if (previous_threshold) { - if (threshold) { - switch (criterion_values.get_preference_direction()) { - case Criterion::PreferenceDirection::increasing: - validate(*threshold >= *previous_threshold, "The integer thresholds in an accepted values descriptor must be in preference order"); - break; - case Criterion::PreferenceDirection::decreasing: - validate(*threshold <= *previous_threshold, "The integer thresholds in an accepted values descriptor must be in preference order"); - break; - default: - validate(false, "Thresholds accepted values descriptors are only supported for monotonic criteria"); - break; - } - } - } else { - validate(!threshold, "After a null threshold, all subsequent thresholds must be null"); - } - } - }, - [&criterion, criterion_index, boundaries_count](const AcceptedValues::EnumeratedThresholds& thresholds) { - validate(thresholds.get_thresholds().size() == boundaries_count, "The number of enumerated thresholds in an accepted values descriptor must be one less than the number of categories in the problem"); - const auto& criterion_values = criterion.get_enumerated_values(); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const std::optional& threshold = thresholds.get_thresholds()[boundary_index]; - if (threshold) { - validate(criterion_values.is_acceptable(*threshold), "Each threshold in an accepted values descriptor must be in the enumerated values for the corresponding criterion"); - } - } - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - const std::optional& previous_threshold = thresholds.get_thresholds()[boundary_index - 1]; - const std::optional& threshold = thresholds.get_thresholds()[boundary_index]; - if (previous_threshold) { - if (threshold) { - validate( - criterion_values.get_value_rank(*threshold) >= criterion_values.get_value_rank(*previous_threshold), - "The enumerated thresholds in an accepted values descriptor must be in preference order" - ); - } - } else { - validate(!threshold, "After a null threshold, all subsequent thresholds must be null"); - } - } - }, - [&criterion, criterion_index, boundaries_count](const AcceptedValues::RealIntervals& intervals) { - validate(intervals.get_intervals().size() == boundaries_count, "The number of real intervals in an accepted values descriptor must be one less than the number of categories in the problem"); - const auto& criterion_values = criterion.get_real_values(); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const auto interval = intervals.get_intervals()[boundary_index]; - if (interval) { - validate( - criterion_values.is_acceptable(interval->first) && criterion_values.is_acceptable(interval->second), - "Both ends of each interval in an accepted values descriptor must be between the min and max values for the corresponding real criterion"); - } - } - validate(criterion_values.get_preference_direction() == Criterion::PreferenceDirection::single_peaked, "Intervals accepted values descriptors are only supported for single-peaked criteria"); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const auto interval = intervals.get_intervals()[boundary_index]; - if (interval) { - validate( - interval->first <= interval->second, - "The ends of intervals accepted values descriptors for real criteria must be in order"); - } - } - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - const auto previous_interval = intervals.get_intervals()[boundary_index - 1]; - const auto interval = intervals.get_intervals()[boundary_index]; - if (previous_interval) { - if (interval) { - validate( - previous_interval->first <= interval->first - && previous_interval->second >= interval->second, - "Intervals accepted values descriptors for real criteria must be nested"); - } - } else { - validate(!interval, "After a null interval, all subsequent intervals must be null"); - } - } - }, - [&criterion, criterion_index, boundaries_count](const AcceptedValues::IntegerIntervals& intervals) { - validate(intervals.get_intervals().size() == boundaries_count, "The number of integer intervals in an accepted values descriptor must be one less than the number of categories in the problem"); - const auto& criterion_values = criterion.get_integer_values(); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const auto interval = intervals.get_intervals()[boundary_index]; - if (interval) { - validate( - criterion_values.is_acceptable(interval->first) && criterion_values.is_acceptable(interval->second), - "Both ends of each interval in an accepted values descriptor must be between the min and max values for the corresponding integer criterion"); - } - } - validate(criterion_values.get_preference_direction() == Criterion::PreferenceDirection::single_peaked, "Intervals accepted values descriptors are only supported for single-peaked criteria"); - for (unsigned boundary_index = 0; boundary_index != boundaries_count; ++boundary_index) { - const auto interval = intervals.get_intervals()[boundary_index]; - if (interval) { - validate( - interval->first <= interval->second, - "The ends of intervals accepted values descriptors for integer criteria must be in order"); - } - } - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - const auto previous_interval = intervals.get_intervals()[boundary_index - 1]; - const auto interval = intervals.get_intervals()[boundary_index]; - if (previous_interval) { - if (interval) { - validate( - previous_interval->first <= interval->first - && previous_interval->second >= interval->second, - "Intervals accepted values descriptors for integer criteria must be nested"); - } - } else { - validate(!interval, "After a null interval, all subsequent intervals must be null"); - } - } - } - ); - }; - - validate(sufficient_coalitions.size() == boundaries_count, "The number of sufficient coalitions in the model must be one less than the number of categories in the problem"); - for (const auto& sufficient_coalitions_ : sufficient_coalitions) { - dispatch( - sufficient_coalitions_.get(), - [criteria_count](const SufficientCoalitions::Weights& weights) { - validate(weights.get_criterion_weights().size() == criteria_count, "The number of criterion weights in a sufficient coalitions descriptor must be equal to the number of criteria in the problem"); - }, - [&](const SufficientCoalitions::Roots& roots) { - for (const auto& root: roots.get_upset_roots_as_bitsets()) { - validate(root.size() == criteria_count, "The maximum number of elements in a root in a sufficient coalitions descriptor must be equal to the number of criteria in the problem"); - } - } - ); - } - for (unsigned coalition_index = 0; coalition_index != unsigned(1 << criteria_count); ++coalition_index) { - boost::dynamic_bitset<> coalition(criteria_count, coalition_index); - for (unsigned boundary_index = 1; boundary_index != boundaries_count; ++boundary_index) { - bool accepted_by_upper = std::visit( - [&coalition](const auto& sufficient_coalitions_) { - return sufficient_coalitions_.accept(coalition); - }, - sufficient_coalitions[boundary_index].get() - ); - if (accepted_by_upper) { - const bool accepted_by_lower = std::visit( - [&coalition](const auto& sufficient_coalitions_) { - return sufficient_coalitions_.accept(coalition); - }, - sufficient_coalitions[boundary_index - 1].get() - ); - validate(accepted_by_lower, "Sufficient coalitions must be imbricated"); - } - } - } -} - -void Model::dump(const Problem& problem, std::ostream& os) const { - CHRONE(); - - #ifdef NDEBUG - YAML::Emitter out(os); - #else - std::stringstream ss; - YAML::Emitter out(ss); - #endif - - out.SetNullFormat(YAML::EMITTER_MANIP::LowerNull); - - bool use_coalitions_alias = - sufficient_coalitions.size() > 1 - && std::all_of(std::next(sufficient_coalitions.begin()), sufficient_coalitions.end(), [&](const SufficientCoalitions& suff_coals) { - return suff_coals == sufficient_coalitions.front(); - }); - - out << YAML::BeginMap; - out << YAML::Key << "kind" << YAML::Value << "ncs-classification-model"; - out << YAML::Key << "format_version" << YAML::Value << 1; - - out << YAML::Key << "accepted_values" << YAML::Value << YAML::BeginSeq; - for (unsigned criterion_index = 0; criterion_index != problem.get_criteria().size(); ++criterion_index) { - out << YAML::BeginMap; - dispatch( - accepted_values[criterion_index].get(), - [&out](const AcceptedValues::RealThresholds& thresholds) { - out << YAML::Key << "kind" << YAML::Value << "thresholds"; - out << YAML::Key << "thresholds" << YAML::Value << YAML::Flow; - out << thresholds.get_thresholds(); - }, - [&out](const AcceptedValues::IntegerThresholds& thresholds) { - out << YAML::Key << "kind" << YAML::Value << "thresholds"; - out << YAML::Key << "thresholds" << YAML::Value << YAML::Flow; - out << thresholds.get_thresholds(); - }, - [&out](const AcceptedValues::EnumeratedThresholds& thresholds) { - out << YAML::Key << "kind" << YAML::Value << "thresholds"; - out << YAML::Key << "thresholds" << YAML::Value << YAML::Flow; - out << thresholds.get_thresholds(); - }, - [&out](const AcceptedValues::RealIntervals& intervals) { - out << YAML::Key << "kind" << YAML::Value << "intervals"; - out << YAML::Key << "intervals" << YAML::Value << YAML::Flow << YAML::BeginSeq; - for (const auto& interval : intervals.get_intervals()) { - if (interval) { - out << YAML::BeginSeq << interval->first << interval->second << YAML::EndSeq; - } else { - out << YAML::Null; - } - } - out << YAML::EndSeq; - }, - [&out](const AcceptedValues::IntegerIntervals& intervals) { - out << YAML::Key << "kind" << YAML::Value << "intervals"; - out << YAML::Key << "intervals" << YAML::Value << YAML::Flow << YAML::BeginSeq; - for (const auto& interval : intervals.get_intervals()) { - if (interval) { - out << YAML::BeginSeq << interval->first << interval->second << YAML::EndSeq; - } else { - out << YAML::Null; - } - } - out << YAML::EndSeq; - } - ); - out << YAML::EndMap; - } - out << YAML::EndSeq; - - out << YAML::Key << "sufficient_coalitions" << YAML::Value << YAML::BeginSeq; - for (unsigned boundary_index = 0; boundary_index != sufficient_coalitions.size(); ++boundary_index) { - const SufficientCoalitions& sufficient_coalitions_ = sufficient_coalitions[boundary_index]; - if (use_coalitions_alias && boundary_index == 0) { - out << YAML::Anchor("coalitions"); - } - if (!use_coalitions_alias || boundary_index == 0) { - out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "kind" << YAML::Value << std::string(magic_enum::enum_name(sufficient_coalitions_.get_kind())); - dispatch( - sufficient_coalitions_.get(), - [&out](const SufficientCoalitions::Weights& weights) { - out << YAML::Key << "criterion_weights" << YAML::Value << YAML::Flow << weights.get_criterion_weights(); - }, - [&out](const SufficientCoalitions::Roots& roots) { - out << YAML::Key << "upset_roots" << YAML::Value; - const std::vector> upset_roots = roots.get_upset_roots_as_vectors(); - if (upset_roots.empty()) { - out << YAML::Flow; - } - out << YAML::BeginSeq; - for (const std::vector& upset_root : upset_roots) { - out << YAML::Flow << upset_root; - } - out << YAML::EndSeq; - } - ); - out << YAML::EndMap; - } else if (use_coalitions_alias) { - out << YAML::Value << YAML::Alias("coalitions"); - } - } - out << YAML::EndSeq; - out << YAML::EndMap; - - #ifndef NDEBUG - validator.validate(YAML::Load(ss)); - os << ss.str(); - #endif - - os << '\n'; -} - -SufficientCoalitions load_sufficient_coalitions(const Problem& problem, const YAML::Node& node) { - switch (*magic_enum::enum_cast(node["kind"].as())) { - case SufficientCoalitions::Kind::weights: - return SufficientCoalitions(SufficientCoalitions::Weights(node["criterion_weights"].as>())); - case SufficientCoalitions::Kind::roots: - return SufficientCoalitions(SufficientCoalitions::Roots(problem, node["upset_roots"].as>>())); - } - unreachable(); -} - -Model Model::load(const Problem& problem, std::istream& is) { - CHRONE(); - - const unsigned criteria_count = problem.get_criteria().size(); - const unsigned categories_count = problem.get_ordered_categories().size(); - const unsigned boundaries_count = categories_count - 1; - - YAML::Node node = YAML::Load(is); - - validator.validate(node); - - const YAML::Node& yaml_accepted_values = node["accepted_values"]; - validate(yaml_accepted_values.size() == criteria_count, "The number of accepted values descriptors in the model must be equal to the number of criteria in the problem"); - std::vector accepted_values; - accepted_values.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != yaml_accepted_values.size(); ++criterion_index) { - const Criterion& criterion = problem.get_criteria()[criterion_index]; - const YAML::Node& yaml_acc_vals = yaml_accepted_values[criterion_index]; - if (yaml_acc_vals["kind"].as() == "thresholds") { - const YAML::Node& thresholds = yaml_acc_vals["thresholds"]; - - accepted_values.push_back(dispatch( - criterion.get_values(), - [&thresholds, boundaries_count](const Criterion::RealValues&) { - return AcceptedValues(AcceptedValues::RealThresholds(thresholds.as>>())); - }, - [&thresholds, boundaries_count](const Criterion::IntegerValues&) { - return AcceptedValues(AcceptedValues::IntegerThresholds(thresholds.as>>())); - }, - [&thresholds, boundaries_count](const Criterion::EnumeratedValues&) { - return AcceptedValues(AcceptedValues::EnumeratedThresholds(thresholds.as>>())); - } - )); - } else { - assert(yaml_acc_vals["kind"].as() == "intervals"); - - const YAML::Node& intervals = yaml_acc_vals["intervals"]; - accepted_values.push_back(dispatch( - criterion.get_values(), - [&intervals, boundaries_count](const Criterion::RealValues&) { - return AcceptedValues(AcceptedValues::RealIntervals(intervals.as>>>())); - }, - [&intervals, boundaries_count](const Criterion::IntegerValues&) { - return AcceptedValues(AcceptedValues::IntegerIntervals(intervals.as>>>())); - }, - [](const Criterion::EnumeratedValues&) -> AcceptedValues { - unreachable(); - } - )); - } - } - - const YAML::Node& yaml_sufficient_coalitions = node["sufficient_coalitions"]; - std::vector sufficient_coalitions; - sufficient_coalitions.reserve(boundaries_count); - for (const YAML::Node& yaml_suff_coals : yaml_sufficient_coalitions) { - sufficient_coalitions.push_back(load_sufficient_coalitions(problem, yaml_suff_coals)); - } - - return Model(problem, accepted_values, sufficient_coalitions); -} - -TEST_CASE("dumping then loading model preserves data - weights") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - {AcceptedValues(AcceptedValues::RealThresholds({0.4}))}, - {SufficientCoalitions(SufficientCoalitions::Weights({0.7}))}, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.400000006] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.699999988] -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - roots") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.4})), - AcceptedValues(AcceptedValues::RealThresholds({0.5})), - AcceptedValues(AcceptedValues::RealThresholds({0.6})), - }, - {SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1, 2}}))}, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.400000006] - - kind: thresholds - thresholds: [0.5] - - kind: thresholds - thresholds: [0.600000024] -sufficient_coalitions: - - kind: roots - upset_roots: - - [0] - - [1, 2] -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - numerical values requiring more decimal digits") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0x1.259b36p-6})), - AcceptedValues(AcceptedValues::RealThresholds({0x1.652bf4p-2})), - AcceptedValues(AcceptedValues::RealThresholds({0x1.87662ap-3})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({0x1.c78b0cp-2, 0x1.1d7974p-2, 0x1.b22782p-2})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.017920306] - - kind: thresholds - thresholds: [0.34880048] - - kind: thresholds - thresholds: [0.191112831] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.444866359, 0.278783619, 0.423978835] -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - integer criterion") { - Problem problem{ - {Criterion("Criterion 1", Criterion::IntegerValues(Criterion::PreferenceDirection::increasing, 0, 100))}, - {{"Category 1"}, {"Category 2"}, {"Category 3"}}, - }; - - Model model{ - problem, - {AcceptedValues(AcceptedValues::IntegerThresholds({40, 60}))}, - { - SufficientCoalitions(SufficientCoalitions::Weights({0.75})), - SufficientCoalitions(SufficientCoalitions::Weights({0.75})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [40, 60] -sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [0.75] - - *coalitions -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - null thresholds") { - Problem problem{ - { - Criterion("Real", Criterion::RealValues(Criterion::PreferenceDirection::increasing, -1, 1)), - Criterion("Integer", Criterion::IntegerValues(Criterion::PreferenceDirection::increasing, 0, 100)), - }, - {{"Cat 1"}, {"Cat 2"}, {"Cat 3"}, {"Cat 4"}, {"Cat 5"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({-0.5, 0, std::nullopt, std::nullopt})), - AcceptedValues(AcceptedValues::IntegerThresholds({20, 40, 60, std::nullopt})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [-0.5, 0, null, null] - - kind: thresholds - thresholds: [20, 40, 60, null] -sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [0.5, 0.5] - - *coalitions - - *coalitions - - *coalitions -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - enumerated criterion") { - Problem problem{ - {Criterion("Criterion 1", Criterion::EnumeratedValues({"F", "E", "D", "C", "B", "A"}))}, - {{"Category 1"}, {"Category 2"}, {"Category 3"}}, - }; - - Model model{ - problem, - {AcceptedValues(AcceptedValues::EnumeratedThresholds({"D", "B"}))}, - { - SufficientCoalitions(SufficientCoalitions::Weights({0.75})), - SufficientCoalitions(SufficientCoalitions::Weights({0.75})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [D, B] -sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [0.75] - - *coalitions -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping then loading model preserves data - single-peaked criteria") { - Problem problem{ - { - Criterion("Real", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, -10, 10)), - Criterion("Integer", Criterion::IntegerValues(Criterion::PreferenceDirection::single_peaked, 0, 100)), - }, - {{"Cat 1"}, {"Cat 2"}, {"Cat 3"}, {"Cat 4"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealIntervals({std::make_pair(-8.5, 8.5), std::make_pair(-3.5, 5.5), std::nullopt})), - AcceptedValues(AcceptedValues::IntegerIntervals({std::make_pair(20, 80), std::make_pair(40, 60), std::nullopt})), - }, - { - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - SufficientCoalitions(SufficientCoalitions::Weights({0.5, 0.5})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: intervals - intervals: [[-8.5, 8.5], [-3.5, 5.5], null] - - kind: intervals - intervals: [[20, 80], [40, 60], null] -sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [0.5, 0.5] - - *coalitions - - *coalitions -)"); - - // CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping empty roots uses flow style") { - Problem problem{ - { - Criterion("Criterion", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - Model model{ - problem, - {AcceptedValues(AcceptedValues::RealThresholds({0.5}))}, - {SufficientCoalitions(SufficientCoalitions::Roots(problem, {}))}, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.5] -sufficient_coalitions: - - kind: roots - upset_roots: [] -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping uses references to avoid duplication of sufficient coalitions") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}, {"Category 3"}, {"Category 4"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.2, 0.4, 0.6})), - AcceptedValues(AcceptedValues::RealThresholds({0.3, 0.5, 0.7})), - AcceptedValues(AcceptedValues::RealThresholds({0.4, 0.6, 0.8})), - }, - { - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1, 2}})), - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1, 2}})), - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1, 2}})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.200000003, 0.400000006, 0.600000024] - - kind: thresholds - thresholds: [0.300000012, 0.5, 0.699999988] - - kind: thresholds - thresholds: [0.400000006, 0.600000024, 0.800000012] -sufficient_coalitions: - - &coalitions - kind: roots - upset_roots: - - [0] - - [1, 2] - - *coalitions - - *coalitions -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("dumping doesn't use references when coalitions differ") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 3", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}, {"Category 3"}, {"Category 4"}}, - }; - - Model model{ - problem, - { - AcceptedValues(AcceptedValues::RealThresholds({0.2, 0.4, 0.6})), - AcceptedValues(AcceptedValues::RealThresholds({0.3, 0.5, 0.7})), - AcceptedValues(AcceptedValues::RealThresholds({0.4, 0.6, 0.8})), - }, - { - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{}})), - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1}, {2}})), - SufficientCoalitions(SufficientCoalitions::Roots(problem, {{0}, {1, 2}})), - }, - }; - - std::stringstream ss; - model.dump(problem, ss); - - CHECK(ss.str() == R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.200000003, 0.400000006, 0.600000024] - - kind: thresholds - thresholds: [0.300000012, 0.5, 0.699999988] - - kind: thresholds - thresholds: [0.400000006, 0.600000024, 0.800000012] -sufficient_coalitions: - - kind: roots - upset_roots: - - [] - - kind: roots - upset_roots: - - [0] - - [1] - - [2] - - kind: roots - upset_roots: - - [0] - - [1, 2] -)"); - - CHECK(Model::load(problem, ss) == model); -} - -TEST_CASE("Parsing error") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss("*"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - "yaml-cpp: error at line 1, column 2: alias not found after *", - YAML::Exception); -} - -TEST_CASE("Validation error - not an object") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss("42"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - R"(JSON validation failed: - - : Value type not permitted by 'type' constraint.)", - DataValidationException); -} - -TEST_CASE("Validation error - missing weights") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.5] -sufficient_coalitions: - - kind: weights -)"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - R"(JSON validation failed: - - [sufficient_coalitions] [0]: Missing required property 'criterion_weights'. - - [sufficient_coalitions] [0]: Failed to validate against child schema #0. - - [sufficient_coalitions] [0] [kind]: Failed to match expected value set by 'const' constraint. - - [sufficient_coalitions] [0]: Failed to validate against schema associated with property name 'kind'. - - [sufficient_coalitions] [0]: Missing required property 'upset_roots'. - - [sufficient_coalitions] [0]: Failed to validate against child schema #1. - - [sufficient_coalitions] [0]: Failed to validate against any child schemas allowed by oneOf constraint. - - [sufficient_coalitions]: Failed to validate item #0 in array. - - : Failed to validate against schema associated with property name 'sufficient_coalitions'.)", - DataValidationException); -} - -TEST_CASE("Validation error - size mismatch - accepted_values") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.4] - - kind: thresholds - thresholds: [0.4] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.7] -)"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - "The number of accepted values descriptors in the model must be equal to the number of criteria in the problem", - DataValidationException); -} - -TEST_CASE("Validation error - size mismatch - sufficient_coalitions") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.4] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.7] - - kind: weights - criterion_weights: [0.7] -)"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - "The number of sufficient coalitions in the model must be one less than the number of categories in the problem", - DataValidationException); -} - -TEST_CASE("Validation error - size mismatch - thresholds") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::istringstream iss(R"(kind: ncs-classification-model -format_version: 1 -accepted_values: - - kind: thresholds - thresholds: [0.4, 0.5] -sufficient_coalitions: - - kind: weights - criterion_weights: [0.7] -)"); - - CHECK_THROWS_WITH_AS( - Model::load(problem, iss), - "The number of real thresholds in an accepted values descriptor must be one less than the number of categories in the problem", - DataValidationException); -} - -} // namespace lincs diff --git a/lincs/liblincs/io/model.hpp b/lincs/liblincs/io/model.hpp deleted file mode 100644 index f6014228..00000000 --- a/lincs/liblincs/io/model.hpp +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__IO__MODEL_HPP -#define LINCS__IO__MODEL_HPP - -#include -#include - -#include - -#include "../internal.hpp" -#include "problem.hpp" - - -namespace lincs { - -class AcceptedValues { - public: - class RealThresholds { - public: - RealThresholds(const std::vector>& thresholds_) : thresholds(thresholds_) {} - - public: - bool operator==(const RealThresholds& other) const { - return thresholds == other.thresholds; - } - - public: - const std::vector>& get_thresholds() const { return thresholds; } - - private: - std::vector> thresholds; - }; - - class IntegerThresholds { - public: - IntegerThresholds(const std::vector>& thresholds_) : thresholds(thresholds_) {} - - public: - bool operator==(const IntegerThresholds& other) const { - return thresholds == other.thresholds; - } - - public: - const std::vector>& get_thresholds() const { return thresholds; } - - private: - std::vector> thresholds; - }; - - class EnumeratedThresholds { - public: - EnumeratedThresholds(const std::vector>& thresholds_) : thresholds(thresholds_) {} - - public: - bool operator==(const EnumeratedThresholds& other) const { - return thresholds == other.thresholds; - } - - public: - const std::vector>& get_thresholds() const { return thresholds; } - - private: - std::vector> thresholds; - }; - - class RealIntervals { - public: - RealIntervals(const std::vector>>& intervals_) : intervals(intervals_) {} - - public: - bool operator==(const RealIntervals& other) const { - return intervals == other.intervals; - } - - public: - const std::vector>>& get_intervals() const { return intervals; } - - private: - std::vector>> intervals; - }; - - class IntegerIntervals { - public: - IntegerIntervals(const std::vector>>& intervals_) : intervals(intervals_) {} - - public: - bool operator==(const IntegerIntervals& other) const { - return intervals == other.intervals; - } - - public: - const std::vector>>& get_intervals() const { return intervals; } - - private: - std::vector>> intervals; - }; - - // WARNING: keep the enum and the variant consistent with 'Criterion::ValueType', 'get_kind', and 'get_value_type' - enum class Kind { thresholds, intervals }; - typedef std::variant< - RealThresholds, - IntegerThresholds, - EnumeratedThresholds, - RealIntervals, - IntegerIntervals - > Self; - - public: - AcceptedValues(const Self& self_) : self(self_) {} - - // Copyable and movable - AcceptedValues(const AcceptedValues&) = default; - AcceptedValues& operator=(const AcceptedValues&) = default; - AcceptedValues(AcceptedValues&&) = default; - AcceptedValues& operator=(AcceptedValues&&) = default; - - public: - bool operator==(const AcceptedValues& other) const { - return self == other.self; - } - - public: - Kind get_kind() const { - return dispatch( - self, - [](const RealThresholds&) { return Kind::thresholds; }, - [](const IntegerThresholds&) { return Kind::thresholds; }, - [](const EnumeratedThresholds&) { return Kind::thresholds; }, - [](const RealIntervals&) { return Kind::intervals; }, - [](const IntegerIntervals&) { return Kind::intervals; } - ); - } - Criterion::ValueType get_value_type() const { - return dispatch( - self, - [](const RealThresholds&) { return Criterion::ValueType::real; }, - [](const IntegerThresholds&) { return Criterion::ValueType::integer; }, - [](const EnumeratedThresholds&) { return Criterion::ValueType::enumerated; }, - [](const RealIntervals&) { return Criterion::ValueType::real; }, - [](const IntegerIntervals&) { return Criterion::ValueType::integer; } - ); - } - const Self& get() const { return self; } - - bool is_real() const { return get_value_type() == Criterion::ValueType::real; } - bool is_integer() const { return get_value_type() == Criterion::ValueType::integer; } - bool is_enumerated() const { return get_value_type() == Criterion::ValueType::enumerated; } - - bool is_thresholds() const { return get_kind() == Kind::thresholds; } - bool is_intervals() const { return get_kind() == Kind::intervals; } - - const RealThresholds& get_real_thresholds() const { - return std::get(self); - } - - const IntegerThresholds& get_integer_thresholds() const { - return std::get(self); - } - - const EnumeratedThresholds& get_enumerated_thresholds() const { - return std::get(self); - } - - const RealIntervals& get_real_intervals() const { - return std::get(self); - } - - const IntegerIntervals& get_integer_intervals() const { - return std::get(self); - } - - private: - Self self; -}; - -class SufficientCoalitions { - // Sufficient coalitions form an https://en.wikipedia.org/wiki/Upper_set in the set of parts of the set of criteria. - // This upset can be defined: - // - by the weights of the criteria - // - explicitly by its roots - - public: - class Weights { - public: - Weights(const std::vector& criterion_weights_) : criterion_weights(criterion_weights_) { - for (auto w : criterion_weights) { - validate(w >= 0, "Criterion weights must be non-negative"); - } - } - - public: - bool operator==(const Weights& other) const { - return criterion_weights == other.criterion_weights; - } - - public: - const std::vector& get_criterion_weights() const { return criterion_weights; } - - bool accept(const boost::dynamic_bitset<>& coalition) const { - float sum = 0; - for (unsigned criterion_index = 0; criterion_index < criterion_weights.size(); ++criterion_index) { - if (coalition[criterion_index]) { - sum += criterion_weights[criterion_index]; - } - } - return sum >= 1; - } - - private: - std::vector criterion_weights; // Indexed by [criterion_index] - }; - - class Roots { - public: - Roots(const Problem& problem, const std::vector>& upset_roots_) : - Roots(Internal(), problem.get_criteria().size(), upset_roots_) {} - - Roots(Internal, const std::vector>& upset_roots_) : - upset_roots(upset_roots_) {} - - Roots(Internal, const unsigned criteria_count, const std::vector>& upset_roots_) { - upset_roots.reserve(upset_roots_.size()); - for (const auto& root: upset_roots_) { - boost::dynamic_bitset<>& upset_root = upset_roots.emplace_back(criteria_count); - for (unsigned criterion_index: root) { - validate(criterion_index < criteria_count, "An element index in a root in a sufficient coalitions descriptor must be less than the number of criteria in the problem"); - upset_root[criterion_index] = true; - } - } - } - - public: - bool operator==(const Roots& other) const { - return upset_roots == other.upset_roots; - } - - public: - std::vector> get_upset_roots_as_vectors() const; - - std::vector> get_upset_roots_as_bitsets() const { - return upset_roots; - } - - bool accept(const boost::dynamic_bitset<>& coalition) const { - for (const auto& root: upset_roots) { - if ((coalition & root) == root) { - return true; - } - } - return false; - } - - private: - std::vector> upset_roots; // Indexed by [root_coalition_index][criterion_index] and true if the criterion is in the coalition - }; - - enum class Kind { weights, roots }; - typedef std::variant Self; - - public: - SufficientCoalitions(const Self& self_) : self(self_) {} - - public: - // Copyable and movable - SufficientCoalitions(const SufficientCoalitions&) = default; - SufficientCoalitions& operator=(const SufficientCoalitions&) = default; - SufficientCoalitions(SufficientCoalitions&&) = default; - SufficientCoalitions& operator=(SufficientCoalitions&&) = default; - - public: - bool operator==(const SufficientCoalitions& other) const { - return self == other.self; - } - - public: - Kind get_kind() const { - return dispatch( - self, - [](const Weights&) { return Kind::weights; }, - [](const Roots&) { return Kind::roots; } - ); - } - const Self& get() const { return self; } - - bool is_weights() const { return get_kind() == Kind::weights; } - const Weights& get_weights() const { return std::get(self); } - - bool is_roots() const { return get_kind() == Kind::roots; } - const Roots& get_roots() const { return std::get(self); } - - private: - Self self; -}; - -class Model { - public: - Model(const Problem&, const std::vector&, const std::vector&); - - Model(Internal, const std::vector& accepted_values_, const std::vector& sufficient_coalitions_) : - accepted_values(accepted_values_), - sufficient_coalitions(sufficient_coalitions_) - {} - - // Copyable and movable - Model(const Model&) = default; - Model& operator=(const Model&) = default; - Model(Model&&) = default; - Model& operator=(Model&&) = default; - - public: - bool operator==(const Model& other) const { - return accepted_values == other.accepted_values && sufficient_coalitions == other.sufficient_coalitions; - } - - public: - const std::vector& get_accepted_values() const { return accepted_values; } - const std::vector& get_sufficient_coalitions() const { return sufficient_coalitions; } - - public: - static const std::string json_schema; - void dump(const Problem&, std::ostream&) const; - static Model load(const Problem&, std::istream&); - - private: - std::vector accepted_values; - std::vector sufficient_coalitions; -}; - -} // namespace lincs - -#endif // LINCS__IO__MODEL_HPP diff --git a/lincs/liblincs/io/problem.cpp b/lincs/liblincs/io/problem.cpp deleted file mode 100644 index bbdb38a2..00000000 --- a/lincs/liblincs/io/problem.cpp +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "problem.hpp" - -#include - -#include "../chrones.hpp" -#include "../vendored/magic_enum.hpp" -#include "../vendored/yaml-cpp/yaml.h" -#include "validation.hpp" - -#include "../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace lincs { - -const std::string Problem::json_schema(R"($schema: https://json-schema.org/draft/2020-12/schema -title: Classification problem -type: object -properties: - kind: - type: string - const: classification-problem - format_version: - type: integer - const: 1 - criteria: - description: Structural information about criteria used in the classification problem. - type: array - items: - type: object - oneOf: - - properties: - name: - type: string - value_type: - type: string - enum: [real, integer] - preference_direction: - type: string - enum: [increasing, isotone, decreasing, antitone, single-peaked] - min_value: - type: number - max_value: - type: number - required: - - name - - value_type - - preference_direction - - min_value - - max_value - additionalProperties: false - - properties: - name: - type: string - value_type: - type: string - const: enumerated - ordered_values: - description: Ordered list of values that can be taken by the criterion. - type: array - items: - type: string - minItems: 1 - required: - - name - - value_type - - ordered_values - additionalProperties: false - minItems: 1 - ordered_categories: - description: Structural information about categories in the classification problem, ordered from the worst to the best. - type: array - items: - type: object - properties: - name: - type: string - required: - - name - additionalProperties: false - minItems: 2 -required: - - kind - - format_version - - criteria - - ordered_categories -additionalProperties: false -)"); - -namespace { - -std::istringstream schema_iss(Problem::json_schema); -YAML::Node schema = YAML::Load(schema_iss); -JsonValidator validator(schema); - -} // namespace - -void dump_preference_direction(YAML::Emitter& out, Criterion::PreferenceDirection preference_direction) { - std::string s(magic_enum::enum_name(preference_direction)); - std::replace(s.begin(), s.end(), '_', '-'); - out << s; -} - -void Problem::dump(std::ostream& os) const { - CHRONE(); - - #ifdef NDEBUG - YAML::Emitter out(os); - #else - std::stringstream ss; - YAML::Emitter out(ss); - #endif - - YAML::Node node; - out << YAML::BeginMap; - out << YAML::Key << "kind" << YAML::Value << "classification-problem"; - out << YAML::Key << "format_version" << YAML::Value << 1; - - out << YAML::Key << "criteria" << YAML::Value << YAML::BeginSeq; - for (const auto& criterion : criteria) { - out << YAML::BeginMap; - out << YAML::Key << "name" << YAML::Value << criterion.get_name(); - out << YAML::Key << "value_type" << YAML::Value << std::string(magic_enum::enum_name(criterion.get_value_type())); - dispatch( - criterion.get_values(), - [&out](const Criterion::RealValues& values) { - out << YAML::Key << "preference_direction" << YAML::Value; - dump_preference_direction(out, values.get_preference_direction()); - out << YAML::Key << "min_value" << YAML::Value << values.get_min_value(); - out << YAML::Key << "max_value" << YAML::Value << values.get_max_value(); - }, - [&out](const Criterion::IntegerValues& values) { - out << YAML::Key << "preference_direction" << YAML::Value; - dump_preference_direction(out, values.get_preference_direction()); - out << YAML::Key << "min_value" << YAML::Value << values.get_min_value(); - out << YAML::Key << "max_value" << YAML::Value << values.get_max_value(); - }, - [&out](const Criterion::EnumeratedValues& values) { - out << YAML::Key << "ordered_values" << YAML::Value << YAML::Flow << values.get_ordered_values(); - } - ); - out << YAML::EndMap; - } - out << YAML::EndSeq; - - out << YAML::Key << "ordered_categories" << YAML::Value << YAML::BeginSeq; - for (const auto& category : ordered_categories) { - out << YAML::BeginMap; - out << YAML::Key << "name" << YAML::Value << category.get_name(); - out << YAML::EndMap; - } - out << YAML::EndSeq; - out << YAML::EndMap; - - #ifndef NDEBUG - validator.validate(YAML::Load(ss)); - os << ss.str(); - #endif - - os << '\n'; -} - -Criterion::PreferenceDirection load_preference_direction(const YAML::Node& node) { - std::string preference_direction = node.as(); - std::replace(preference_direction.begin(), preference_direction.end(), '-', '_'); - if (preference_direction == "isotone") { - return Criterion::PreferenceDirection::increasing; - } else if (preference_direction == "antitone") { - return Criterion::PreferenceDirection::decreasing; - } else { - return *magic_enum::enum_cast(preference_direction); - } -} - -Problem Problem::load(std::istream& is) { - CHRONE(); - - YAML::Node node = YAML::Load(is); - - validator.validate(node); - - std::vector criteria; - for (const YAML::Node& criterion_node : node["criteria"]) { - Criterion::ValueType value_type = *magic_enum::enum_cast(criterion_node["value_type"].as()); - switch (value_type) { - case Criterion::ValueType::real: - criteria.emplace_back( - criterion_node["name"].as(), - Criterion::RealValues( - load_preference_direction(criterion_node["preference_direction"]), - criterion_node["min_value"].as(), - criterion_node["max_value"].as())); - break; - case Criterion::ValueType::integer: - criteria.emplace_back( - criterion_node["name"].as(), - Criterion::IntegerValues( - load_preference_direction(criterion_node["preference_direction"]), - criterion_node["min_value"].as(), - criterion_node["max_value"].as())); - break; - case Criterion::ValueType::enumerated: - criteria.emplace_back( - criterion_node["name"].as(), - Criterion::EnumeratedValues( - criterion_node["ordered_values"].as>())); - break; - } - } - - std::vector ordered_categories; - for (const YAML::Node& category_node : node["ordered_categories"]) { - ordered_categories.emplace_back(category_node["name"].as()); - } - - return Problem(criteria, ordered_categories); -} - -TEST_CASE("dumping then loading problem preserves data - real") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: real - preference_direction: increasing - min_value: 0 - max_value: 1 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("isotone and antitone dump as increasing and decreasing") { - Problem problem{ - { - Criterion("Isotone criterion", Criterion::RealValues(Criterion::PreferenceDirection::isotone, 0, 1)), - Criterion("Antitone criterion", Criterion::RealValues(Criterion::PreferenceDirection::antitone, 0, 1)), - }, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Isotone criterion - value_type: real - preference_direction: increasing - min_value: 0 - max_value: 1 - - name: Antitone criterion - value_type: real - preference_direction: decreasing - min_value: 0 - max_value: 1 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); -} - -TEST_CASE("isotone and antitone parse as increasing and decreasing") { - std::istringstream iss(R"(kind: classification-problem -format_version: 1 -criteria: - - name: Isotone criterion - value_type: real - preference_direction: isotone - min_value: 0 - max_value: 1 - - name: Antitone criterion - value_type: real - preference_direction: antitone - min_value: 0 - max_value: 1 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - Problem problem = Problem::load(iss); - - CHECK(problem.get_criteria()[0].get_real_values().get_preference_direction() == Criterion::PreferenceDirection::isotone); - CHECK(problem.get_criteria()[0].get_real_values().get_preference_direction() == Criterion::PreferenceDirection::increasing); - CHECK(problem.get_criteria()[1].get_real_values().get_preference_direction() == Criterion::PreferenceDirection::antitone); - CHECK(problem.get_criteria()[1].get_real_values().get_preference_direction() == Criterion::PreferenceDirection::decreasing); -} - -TEST_CASE("dumping then loading problem preserves data - real with infinite min/max") { - const float inf = std::numeric_limits::infinity(); - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::decreasing, -inf, inf))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: real - preference_direction: decreasing - min_value: -.inf - max_value: .inf -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("dumping then loading problem preserves data - integer") { - Problem problem{ - {Criterion("Criterion 1", Criterion::IntegerValues(Criterion::PreferenceDirection::increasing, 0, 20))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 20 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("dumping then loading problem preserves data - enumerated") { - Problem problem{ - {Criterion("Criterion 1", Criterion::EnumeratedValues({"F", "E", "D", "C", "B", "A"}))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: enumerated - ordered_values: [F, E, D, C, B, A] -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("dumping then loading problem preserves data - single-peaked real") { - Problem problem{ - {Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, 0.5, 20.5))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: real - preference_direction: single-peaked - min_value: 0.5 - max_value: 20.5 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("dumping then loading problem preserves data - single-peaked integer") { - Problem problem{ - {Criterion("Criterion 1", Criterion::IntegerValues(Criterion::PreferenceDirection::single_peaked, 0, 20))}, - {{"Category 1"}, {"Category 2"}}, - }; - - std::stringstream ss; - problem.dump(ss); - - CHECK(ss.str() == R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: integer - preference_direction: single-peaked - min_value: 0 - max_value: 20 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK(Problem::load(ss) == problem); -} - -TEST_CASE("Parsing error") { - std::istringstream iss("*"); - - CHECK_THROWS_WITH_AS( - Problem::load(iss), - "yaml-cpp: error at line 1, column 2: alias not found after *", - YAML::Exception); -} - -TEST_CASE("Validation error - not an object") { - std::istringstream iss("42"); - - CHECK_THROWS_WITH_AS( - Problem::load(iss), - "JSON validation failed:\n - : Value type not permitted by 'type' constraint.", - DataValidationException); -} - -TEST_CASE("Validation error - bad enum") { - std::istringstream iss(R"(kind: classification-problem -format_version: 1 -criteria: - - name: Criterion 1 - value_type: invalid - preference_direction: increasing - min_value: 0 - max_value: 1 -ordered_categories: - - name: Category 1 - - name: Category 2 -)"); - - CHECK_THROWS_WITH_AS( - Problem::load(iss), - R"(JSON validation failed: - - [criteria] [0] [value_type]: Failed to match against any enum values. - - [criteria] [0]: Failed to validate against schema associated with property name 'value_type'. - - [criteria] [0]: Failed to validate against child schema #0. - - [criteria] [0] [value_type]: Failed to match expected value set by 'const' constraint. - - [criteria] [0]: Failed to validate against schema associated with property name 'value_type'. - - [criteria] [0]: Object contains a property that could not be validated using 'properties' or 'additionalProperties' constraints: 'preference_direction'. - - [criteria] [0]: Missing required property 'ordered_values'. - - [criteria] [0]: Failed to validate against child schema #1. - - [criteria] [0]: Failed to validate against any child schemas allowed by oneOf constraint. - - [criteria]: Failed to validate item #0 in array. - - : Failed to validate against schema associated with property name 'criteria'.)", - DataValidationException); -} - -} // namespace lincs diff --git a/lincs/liblincs/io/problem.hpp b/lincs/liblincs/io/problem.hpp deleted file mode 100644 index d363a0b8..00000000 --- a/lincs/liblincs/io/problem.hpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__IO__PROBLEM_HPP -#define LINCS__IO__PROBLEM_HPP - -#include -#include -#include -#include - -#include "../variant-dispatch.hpp" -#include "../unreachable.hpp" -#include "exception.hpp" - - -namespace lincs { - -class Criterion { - public: - enum class PreferenceDirection { - increasing, - isotone=increasing, - decreasing, - antitone=decreasing, - single_peaked, - // @todo(Feature, later) Add unknown - }; - - class RealValues { - public: - RealValues(PreferenceDirection preference_direction_, float min_value_, float max_value_) : preference_direction(preference_direction_), min_value(min_value_), max_value(max_value_) { - validate(min_value <= max_value, "The min and max values of a real-valued criterion must be ordered."); - } - - public: - bool operator==(const RealValues& other) const { - return preference_direction == other.preference_direction && min_value == other.min_value && max_value == other.max_value; - } - - public: - PreferenceDirection get_preference_direction() const { return preference_direction; } - - bool is_increasing() const { return preference_direction == PreferenceDirection::increasing; } - - bool is_decreasing() const { return preference_direction == PreferenceDirection::decreasing; } - - bool is_single_peaked() const { return preference_direction == PreferenceDirection::single_peaked; } - - float get_min_value() const { return min_value; } - - float get_max_value() const { return max_value; } - - bool is_acceptable(float value) const { return min_value <= value && value <= max_value; } - - private: - PreferenceDirection preference_direction; - float min_value; - float max_value; - }; - - class IntegerValues { - public: - IntegerValues(PreferenceDirection preference_direction_, int min_value_, int max_value_) : preference_direction(preference_direction_), min_value(min_value_), max_value(max_value_) { - validate(min_value <= max_value, "The min and max values of an integer-valued criterion must be ordered."); - } - - public: - bool operator==(const IntegerValues& other) const { - return preference_direction == other.preference_direction && min_value == other.min_value && max_value == other.max_value; - } - - public: - PreferenceDirection get_preference_direction() const { return preference_direction; } - - bool is_increasing() const { return preference_direction == PreferenceDirection::increasing; } - - bool is_decreasing() const { return preference_direction == PreferenceDirection::decreasing; } - - bool is_single_peaked() const { return preference_direction == PreferenceDirection::single_peaked; } - - int get_min_value() const { return min_value; } - - int get_max_value() const { return max_value; } - - bool is_acceptable(int value) const { return min_value <= value && value <= max_value; } - - private: - PreferenceDirection preference_direction; - int min_value; - int max_value; - }; - - class EnumeratedValues { - public: - EnumeratedValues(const std::vector& ordered_values_) : ordered_values(ordered_values_), value_ranks() { - validate(ordered_values.size() >= 2, "An enumerated criterion must have at least 2 values"); - for (unsigned i = 0; i < ordered_values.size(); ++i) { - value_ranks[ordered_values[i]] = i; - } - } - - public: - bool operator==(const EnumeratedValues& other) const { - return ordered_values == other.ordered_values; // No need to compare value_ranks - } - - public: - const std::vector& get_ordered_values() const { return ordered_values; } - - const std::map& get_value_ranks() const { return value_ranks; } - - unsigned get_value_rank(const std::string& value) const { return value_ranks.at(value); } - - bool is_acceptable(const std::string& value) const { return value_ranks.count(value) == 1; } - - private: - std::vector ordered_values; - std::map value_ranks; - }; - - enum class ValueType { real, integer, enumerated }; - typedef std::variant Values; - - public: - Criterion(const std::string& name_, Values values_) : name(name_), values(values_) {} - - public: - bool operator==(const Criterion& other) const { - return name == other.name && values == other.values; - } - - public: - const std::string& get_name() const { return name; } - - ValueType get_value_type() const { - return dispatch( - values, - [](const RealValues&) { return ValueType::real; }, - [](const IntegerValues&) { return ValueType::integer; }, - [](const EnumeratedValues&) { return ValueType::enumerated; } - ); - } - const Values& get_values() const { return values; } - - bool is_real() const { return get_value_type() == ValueType::real; } - const RealValues& get_real_values() const { return std::get(values); } - - bool is_integer() const { return get_value_type() == ValueType::integer; } - const IntegerValues& get_integer_values() const { return std::get(values); } - - bool is_enumerated() const { return get_value_type() == ValueType::enumerated; } - const EnumeratedValues& get_enumerated_values() const { return std::get(values); } - - private: - std::string name; - Values values; -}; - -class Category { - public: - Category(const std::string& name_): name(name_) {} - - public: - bool operator==(const Category& other) const { return name == other.name; } - - public: - const std::string& get_name() const { return name; } - - private: - std::string name; -}; - -class Problem { - public: - Problem(const std::vector& criteria_, const std::vector& ordered_categories_): criteria(criteria_), ordered_categories(ordered_categories_) { - validate(criteria.size() >= 1, "A problem must have at least one criterion"); - validate(ordered_categories.size() >= 2, "A problem must have at least 2 categories"); - } - - public: - bool operator==(const Problem& other) const { - return criteria == other.criteria && ordered_categories == other.ordered_categories; - } - - public: - const std::vector& get_criteria() const { return criteria; } - const std::vector& get_ordered_categories() const { return ordered_categories; } - - public: - static const std::string json_schema; - void dump(std::ostream&) const; - static Problem load(std::istream&); - - private: - std::vector criteria; - std::vector ordered_categories; -}; - -} // namespace lincs - -#endif // LINCS__IO__PROBLEM_HPP diff --git a/lincs/liblincs/io/validation.cpp b/lincs/liblincs/io/validation.cpp deleted file mode 100644 index d3e3a1e8..00000000 --- a/lincs/liblincs/io/validation.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "validation.hpp" - -#include "../chrones.hpp" -#include "../vendored/valijson/adapters/yaml_cpp_adapter.hpp" -#include "../vendored/valijson/schema_parser.hpp" -#include "../vendored/valijson/validator.hpp" - - -namespace lincs { - -JsonValidator::JsonValidator(const YAML::Node& schema_node) { - valijson::SchemaParser schema_parser; - valijson::adapters::YamlCppAdapter schema_adapter(schema_node); - schema_parser.populateSchema(schema_adapter, schema); -} - -void JsonValidator::validate(const YAML::Node& document) const { - CHRONE(); - - valijson::adapters::YamlCppAdapter document_adapter(document); - - valijson::Validator validator; - valijson::ValidationResults results; - if (!validator.validate(schema, document_adapter, &results)) { - std::ostringstream oss; - oss << "JSON validation failed:"; - - valijson::ValidationResults::Error error; - while (results.popError(error)) { - oss << "\n -"; - for (const std::string &contextElement : error.context) { - oss << " " << contextElement; - } - oss << ": " << error.description; - } - - throw DataValidationException(oss.str()); - } -} - -} // namespace lincs diff --git a/lincs/liblincs/io/validation.hpp b/lincs/liblincs/io/validation.hpp deleted file mode 100644 index b9fbef59..00000000 --- a/lincs/liblincs/io/validation.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__IO__VALIDATION_HPP -#define LINCS__IO__VALIDATION_HPP - -#include "../vendored/valijson/schema.hpp" -#include "../vendored/yaml-cpp/yaml.h" -#include "exception.hpp" - - -namespace lincs { - -class JsonValidator { - public: - JsonValidator(const YAML::Node& schema); - - void validate(const YAML::Node& document) const; - - private: - valijson::Schema schema; -}; - -} // namespace lincs - -#endif // LINCS__IO__VALIDATION_HPP diff --git a/lincs/liblincs/learning.cpp b/lincs/liblincs/learning.cpp deleted file mode 100644 index b67d72d5..00000000 --- a/lincs/liblincs/learning.cpp +++ /dev/null @@ -1,1810 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "learning.hpp" - -#include - -#include "classification.hpp" // Only for tests -#include "generation.hpp" // Only for tests -#include "learning/exception.hpp" - -#include "vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace { - -bool env_is_true(const char* name) { - const char* value = std::getenv(name); - return value && std::string(value) == "true"; -} - -const bool forbid_gpu = env_is_true("LINCS_DEV_FORBID_GPU"); -const bool skip_long = env_is_true("LINCS_DEV_SKIP_LONG"); -const bool skip_wpb = env_is_true("LINCS_DEV_SKIP_WPB"); -const bool skip_wpb_glop = skip_wpb || env_is_true("LINCS_DEV_SKIP_WPB_GLOP"); -const bool skip_wpb_alglib = skip_wpb || env_is_true("LINCS_DEV_SKIP_WPB_ALGLIB"); -const bool skip_sat = env_is_true("LINCS_DEV_SKIP_SAT"); -const bool skip_max_sat = env_is_true("LINCS_DEV_SKIP_MAX_SAT"); -const bool coverage = env_is_true("LINCS_DEV_COVERAGE"); -const unsigned default_seeds_count = coverage ? 1 : (skip_long ? 10 : 100); - -template -void check_exact_learning(const lincs::Problem& problem, const unsigned seed, const bool should_succeed) { - lincs::Model model = lincs::generate_mrsort_classification_model(problem, seed); - lincs::Alternatives learning_set = lincs::generate_classified_alternatives(problem, model, 200, seed); - - T learning(problem, learning_set); - - lincs::Model learned_model = learning.perform(); - - const unsigned changed = lincs::classify_alternatives(problem, learned_model, &learning_set).changed; - if (should_succeed) { - CHECK(changed == 0); - } else { - CHECK(changed != 0); - } -} - -template -void check_exact_learnings( - const unsigned criteria_count, - const unsigned categories_count, - const std::vector& allowed_preference_directions, - const std::vector& allowed_value_types, - const std::set bad_seeds -) { - lincs::Problem problem = lincs::generate_classification_problem( - criteria_count, categories_count, - 41, - false, - allowed_preference_directions, - allowed_value_types); - - for (unsigned seed = 0; seed != default_seeds_count; ++seed) { - CAPTURE(seed); - check_exact_learning(problem, seed, bad_seeds.find(seed) == bad_seeds.end()); - } -} - -template -void check_non_exact_learning(const lincs::Problem& problem, const unsigned seed, const bool should_succeed) { - // @todo(Project management, later) Should we use 'fixed_weights_sum'? Would it make the tests more significant? (By avoiding cases where one or a few criteria convey all the useful information) - lincs::Model model = lincs::generate_mrsort_classification_model(problem, seed); - lincs::Alternatives learning_set = lincs::generate_classified_alternatives(problem, model, 200, seed); - lincs::misclassify_alternatives(problem, &learning_set, 10, seed); - - T learning(problem, learning_set); - - lincs::Model learned_model = learning.perform(); - - // The original model would classify with .changed == 10, so the best model must have .changed <= 10 - const unsigned changed = lincs::classify_alternatives(problem, learned_model, &learning_set).changed; - if (should_succeed) { - CHECK(changed <= 10); - } else { - CHECK(changed > 10); - } -} - -template -void check_non_exact_learnings( - const unsigned criteria_count, - const unsigned categories_count, - const std::vector& allowed_preference_directions, - const std::vector& allowed_value_types, - const std::set bad_seeds -) { - lincs::Problem problem = lincs::generate_classification_problem( - criteria_count, categories_count, - 41, - false, - allowed_preference_directions, - allowed_value_types); - - for (unsigned seed = 0; seed != default_seeds_count; ++seed) { - CAPTURE(seed); - check_non_exact_learning(problem, seed, bad_seeds.find(seed) == bad_seeds.end()); - } -} - -struct AccuracyObserver : lincs::LearnMrsortByWeightsProfilesBreed::Observer { - AccuracyObserver(const ModelsBeingLearned& models_being_learned_) : - models_being_learned(models_being_learned_), - accuracies() - {} - - void after_iteration() override { - accuracies.push_back(models_being_learned.get_best_accuracy()); - } - - void before_return() override { - accuracies.push_back(models_being_learned.get_best_accuracy()); - } - - const ModelsBeingLearned& models_being_learned; - std::vector accuracies; -}; - -} // namespace - -namespace lincs { - -namespace { - -template -class BasicWpb { - struct CpuWrapper { - CpuWrapper(const Problem& problem, const Alternatives& learning_set) : - preprocessed_learning_set(problem, learning_set), - models_being_learned(preprocessed_learning_set, LearnMrsortByWeightsProfilesBreed::default_models_count, 44), - profiles_initialization_strategy(preprocessed_learning_set, models_being_learned), - weights_optimization_strategy(preprocessed_learning_set, models_being_learned), - profiles_improvement_strategy(preprocessed_learning_set, models_being_learned), - breeding_strategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, LearnMrsortByWeightsProfilesBreed::default_models_count / 2), - termination_strategy_accuracy(models_being_learned, target_accuracy), - termination_strategy_progress(models_being_learned, 50), - termination_strategy({&termination_strategy_accuracy, &termination_strategy_progress}), - observer(models_being_learned), - observers{&observer}, - learning( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - observers - ) - {} - - auto perform() { return learning.perform(); } - - PreprocessedLearningSet preprocessed_learning_set; - LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned models_being_learned; - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion profiles_initialization_strategy; - OptimizeWeightsUsingGlop weights_optimization_strategy; - ImproveProfilesWithAccuracyHeuristicOnCpu profiles_improvement_strategy; - ReinitializeLeastAccurate breeding_strategy; - TerminateAtAccuracy termination_strategy_accuracy; - TerminateAfterIterationsWithoutProgress termination_strategy_progress; - TerminateWhenAny termination_strategy; - AccuracyObserver observer; - std::vector observers; - LearnMrsortByWeightsProfilesBreed learning; - }; - - #ifdef LINCS_HAS_NVCC - struct GpuWrapper { - GpuWrapper(const Problem& problem, const Alternatives& learning_set) : - preprocessed_learning_set(problem, learning_set), - models_being_learned(LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned(preprocessed_learning_set, LearnMrsortByWeightsProfilesBreed::default_models_count, 44)), - profiles_initialization_strategy(preprocessed_learning_set, models_being_learned), - weights_optimization_strategy(preprocessed_learning_set, models_being_learned), - profiles_improvement_strategy(preprocessed_learning_set, models_being_learned), - breeding_strategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, LearnMrsortByWeightsProfilesBreed::default_models_count / 2), - termination_strategy_accuracy(models_being_learned, target_accuracy), - termination_strategy_progress(models_being_learned, 50), - termination_strategy({&termination_strategy_accuracy, &termination_strategy_progress}), - observer(models_being_learned), - observers{&observer}, - learning( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - observers - ) - {} - - auto perform() { return learning.perform(); } - - PreprocessedLearningSet preprocessed_learning_set; - LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned models_being_learned; - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion profiles_initialization_strategy; - OptimizeWeightsUsingGlop weights_optimization_strategy; - ImproveProfilesWithAccuracyHeuristicOnGpu profiles_improvement_strategy; - ReinitializeLeastAccurate breeding_strategy; - TerminateAtAccuracy termination_strategy_accuracy; - TerminateAfterIterationsWithoutProgress termination_strategy_progress; - TerminateWhenAny termination_strategy; - AccuracyObserver observer; - std::vector observers; - LearnMrsortByWeightsProfilesBreed learning; - }; - - public: - class Wrapper { - public: - Wrapper(const Problem& problem_, const Alternatives& learning_set_) : - problem(problem_), - learning_set(learning_set_) - {} - - public: - auto perform() { - CpuWrapper cpu_wrapper(problem, learning_set); - std::optional cpu_model; - try { - cpu_model = cpu_wrapper.perform(); - } catch (const LearningFailureException&) { /* Nothing */ } - const bool cpu_success = cpu_model.has_value(); - - if (forbid_gpu) { - if (cpu_success) { - return *cpu_model; - } else { - throw LearningFailureException("CPU failed"); - } - } else { - GpuWrapper gpu_wrapper(problem, learning_set); - std::optional gpu_model; - try { - gpu_model = gpu_wrapper.perform(); - } catch (const LearningFailureException&) { /* Nothing */ } - bool gpu_success = gpu_model.has_value(); - - CHECK(cpu_wrapper.observer.accuracies == gpu_wrapper.observer.accuracies); - if (cpu_wrapper.observer.accuracies != gpu_wrapper.observer.accuracies) { - std::cerr << "CPU accuracies:"; - for (unsigned accuracy: cpu_wrapper.observer.accuracies) { - std::cerr << " " << accuracy; - } - std::cerr << std::endl; - std::cerr << "GPU accuracies:"; - for (unsigned accuracy: gpu_wrapper.observer.accuracies) { - std::cerr << " " << accuracy; - } - std::cerr << std::endl; - } - - if (cpu_success == gpu_success) { - if (cpu_success) { - CHECK(*cpu_model == *gpu_model); - return *cpu_model; - } else { - throw LearningFailureException("Both CPU and GPU failed"); - } - } else { - if (cpu_success) { - FAIL("CPU succeeded but GPU failed"); - return *cpu_model; - } else { - FAIL("GPU succeeded but CPU failed"); - return *gpu_model; - } - } - } - } - - private: - const Problem& problem; - const Alternatives& learning_set; - }; - #else - public: - typedef CpuWrapper Wrapper; - #endif -}; - -class AlglibWpbWrapper { - public: - AlglibWpbWrapper(const Problem& problem, const Alternatives& learning_set) : - preprocessed_learning_set(problem, learning_set), - models_being_learned(preprocessed_learning_set, LearnMrsortByWeightsProfilesBreed::default_models_count, 44), - profiles_initialization_strategy(preprocessed_learning_set, models_being_learned), - weights_optimization_strategy(preprocessed_learning_set, models_being_learned), - profiles_improvement_strategy(preprocessed_learning_set, models_being_learned), - breeding_strategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, LearnMrsortByWeightsProfilesBreed::default_models_count / 2), - termination_strategy(models_being_learned, 50), - learning( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy - ) - {} - - public: - auto perform() { return learning.perform(); } - - private: - PreprocessedLearningSet preprocessed_learning_set; - LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned models_being_learned; - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion profiles_initialization_strategy; - OptimizeWeightsUsingAlglib weights_optimization_strategy; - ImproveProfilesWithAccuracyHeuristicOnCpu profiles_improvement_strategy; - ReinitializeLeastAccurate breeding_strategy; - TerminateAfterIterationsWithoutProgress termination_strategy; - LearnMrsortByWeightsProfilesBreed learning; -}; - -} // namespace - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {10}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {9}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {10}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {36, 50, 62, 59}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {43, 47, 48}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {41, 90, 95}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {5, 59}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {55}); -} - -TEST_CASE("Basic (and GPU) WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {6, 25}); -} - -TEST_CASE("Basic (and GPU) WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - discrete criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {11, 90}); -} - -TEST_CASE("Basic (and GPU) WPB learning - discrete criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - single-peaked real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - single-peaked real criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {15, 52, 62, 63, 89, 95}); -} - -TEST_CASE("Basic (and GPU) WPB learning - single-peaked real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 3, 5, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {1, 14, 20, 23, 73, 81, 91}); -} - -TEST_CASE("Basic (and GPU) WPB learning - single-peaked real criteria - long" * doctest::skip(skip_wpb_glop || skip_long)) { - check_exact_learnings::Wrapper>( - 7, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {1, 12, 19, 26, 47, 50, 53, 61, 71, 73, 81, 83}); -} - -TEST_CASE("Basic (and GPU) WPB learning - single-peaked integer criteria" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::integer}, - {}); -} - -TEST_CASE("Basic (and GPU) WPB learning - all" * doctest::skip(skip_wpb_glop)) { - check_exact_learnings::Wrapper>( - 3, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing, lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real, lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {10}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {9}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {10}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria" * doctest::skip(skip_wpb_alglib)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {55, 59}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Alglib WPB learning - real criteria - long" * doctest::skip(skip_wpb_alglib || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {55}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - single-peaked real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - single-peaked real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - single-peaked real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - single-peaked real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - single-peaked integer criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::integer}, - {}); -} - -TEST_CASE("SAT by coalitions using Minisat learning - all" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing, lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real, lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - single-peaked real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - single-peaked real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - single-peaked real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - single-peaked real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - single-peaked integer criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::integer}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - all - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing, lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real, lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by coalitions using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - single-peaked real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - single-peaked real criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - single-peaked real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - single-peaked real criteria - long" * doctest::skip(skip_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - single-peaked integer criteria" * doctest::skip(skip_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::integer}, - {}); -} - -TEST_CASE("SAT by separation using Minisat learning - all" * doctest::skip(skip_sat)) { - check_exact_learnings( - 3, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing, lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real, lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - single-peaked real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - single-peaked real criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - single-peaked real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - single-peaked real criteria - exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - single-peaked integer criteria - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::integer}, - {}); -} - -TEST_CASE("Max-SAT by separation using Minisat learning - all - exact" * doctest::skip(skip_max_sat)) { - check_exact_learnings( - 3, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing, lincs::Criterion::PreferenceDirection::single_peaked}, - {lincs::Criterion::ValueType::real, lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact" * doctest::skip(skip_max_sat)) { - check_non_exact_learnings( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 4, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 7, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Max-SAT by separation using EvalMaxSat learning - real criteria - non-exact - long" * doctest::skip(skip_max_sat || skip_long)) { - check_non_exact_learnings( - 3, 5, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {11, 21, 45, 62, 65, 74, 77, 84}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {9, 25, 45, 53, 84}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {11, 21, 45, 62, 65, 74, 77, 84}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - real criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::real}, - {}); -} - -TEST_CASE("Non-exact WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -TEST_CASE("Non-exact WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 3, 2, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {6}); -} - -TEST_CASE("Non-exact WPB learning - discrete criteria" * doctest::skip(skip_wpb_glop)) { - check_non_exact_learnings::Wrapper>( - 1, 3, - {lincs::Criterion::PreferenceDirection::increasing, lincs::Criterion::PreferenceDirection::decreasing}, - {lincs::Criterion::ValueType::integer, lincs::Criterion::ValueType::enumerated}, - {}); -} - -} // namespace lincs diff --git a/lincs/liblincs/learning.hpp b/lincs/liblincs/learning.hpp deleted file mode 100644 index 80ad929d..00000000 --- a/lincs/liblincs/learning.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING_HPP -#define LINCS__LEARNING_HPP - -#include "learning/exception.hpp" -#include "learning/mrsort-by-weights-profiles-breed.hpp" -#include "learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.hpp" -#include "learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.hpp" -#include "learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.hpp" -#include "learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.hpp" -#include "learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/after-iterations.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/after-iterations-without-progress.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/after-seconds.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/after-seconds-without-progress.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.hpp" -#include "learning/mrsort-by-weights-profiles-breed/terminate/composite.hpp" -#include "learning/ucncs-by-max-sat-by-coalitions.hpp" -#include "learning/ucncs-by-max-sat-by-separation.hpp" -#include "learning/ucncs-by-sat-by-coalitions.hpp" -#include "learning/ucncs-by-sat-by-separation.hpp" -#include "linear-programming/alglib.hpp" -#include "linear-programming/glop.hpp" -#include "sat/eval-max-sat.hpp" -#include "sat/minisat.hpp" - -namespace lincs { - typedef MaxSatCoalitionsUcncsLearning LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat; - typedef MaxSatSeparationUcncsLearning LearnUcncsByMaxSatBySeparationUsingEvalmaxsat; - typedef OptimizeWeightsUsingLinearProgram OptimizeWeightsUsingAlglib; - typedef OptimizeWeightsUsingLinearProgram OptimizeWeightsUsingGlop; - typedef SatCoalitionsUcncsLearning LearnUcncsBySatByCoalitionsUsingMinisat; - typedef SatSeparationUcncsLearning LearnUcncsBySatBySeparationUsingMinisat; -} // namespace lincs - -#endif // LINCS__LEARNING_HPP diff --git a/lincs/liblincs/learning/exception.cpp b/lincs/liblincs/learning/exception.cpp deleted file mode 100644 index 02e05bd1..00000000 --- a/lincs/liblincs/learning/exception.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "exception.hpp" diff --git a/lincs/liblincs/learning/exception.hpp b/lincs/liblincs/learning/exception.hpp deleted file mode 100644 index 1a5d8637..00000000 --- a/lincs/liblincs/learning/exception.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__EXCEPTION_HPP -#define LINCS__LEARNING__EXCEPTION_HPP - -#include - - -namespace lincs { - -struct LearningFailureException : public std::runtime_error { - LearningFailureException(const char* message) : std::runtime_error(message) {} -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__EXCEPTION_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.cpp deleted file mode 100644 index 844cc148..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "mrsort-by-weights-profiles-breed.hpp" - -#ifndef NDEBUG -#include -#endif -#include -#include - -#include "../chrones.hpp" -#include "../unreachable.hpp" -#include "exception.hpp" - - -namespace lincs { - -LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::ModelsBeingLearned( - const PreprocessedLearningSet& preprocessed_learning_set_, - const unsigned models_count_, - const unsigned random_seed -) : - preprocessed_learning_set(preprocessed_learning_set_), - models_count(models_count_), - random_generators(models_count), - iteration_index(0), - model_indexes(models_count), - accuracies(models_count, zeroed), - low_profile_ranks(models_count, preprocessed_learning_set.boundaries_count, preprocessed_learning_set.criteria_count, uninitialized), - single_peaked_criteria_count(count_single_peaked_criteria()), - high_profile_rank_indexes(preprocessed_learning_set.criteria_count, uninitialized), - high_profile_ranks(models_count, preprocessed_learning_set.boundaries_count, single_peaked_criteria_count, uninitialized), - weights(models_count, preprocessed_learning_set.criteria_count, uninitialized), - best_model_accuracy(0), - best_model_low_profile_ranks(preprocessed_learning_set.boundaries_count, preprocessed_learning_set.criteria_count, uninitialized), - best_model_high_profile_ranks(preprocessed_learning_set.boundaries_count, single_peaked_criteria_count, uninitialized), - best_model_weights(preprocessed_learning_set.criteria_count, uninitialized) -{ - CHRONE(); - - std::iota(model_indexes.begin(), model_indexes.end(), 0); - - for (unsigned model_index = 0; model_index != models_count; ++model_index) { - random_generators[model_index].seed(random_seed * (model_index + 1)); - } - - unsigned count = 0; - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - if (preprocessed_learning_set.single_peaked[criterion_index]) { - high_profile_rank_indexes[criterion_index] = count; - ++count; - } - } - assert(high_profile_ranks.s0() == count); -} - -unsigned LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::count_single_peaked_criteria() const { - unsigned count = 0; - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - if (preprocessed_learning_set.single_peaked[criterion_index]) { - ++count; - } - } - return count; -} - -Model LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::make_model( - ArrayView2D low_profile_ranks, - ArrayView2D high_profile_ranks, - ArrayView1D weights -) const { - CHRONE(); - - std::vector model_weights; - model_weights.reserve(preprocessed_learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - model_weights.push_back(weights[criterion_index]); - } - SufficientCoalitions coalitions = SufficientCoalitions(SufficientCoalitions::Weights(model_weights)); - - std::vector boundaries; - boundaries.reserve(preprocessed_learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != preprocessed_learning_set.boundaries_count; ++boundary_index) { - std::vector>> boundary_profile; - boundary_profile.reserve(preprocessed_learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - const unsigned low_profile_rank = low_profile_ranks[boundary_index][criterion_index]; - if (preprocessed_learning_set.single_peaked[criterion_index]) { - const unsigned high_profile_rank = high_profile_ranks[boundary_index][high_profile_rank_indexes[criterion_index]]; - boundary_profile.push_back(std::make_pair(low_profile_rank, high_profile_rank)); - } else { - boundary_profile.push_back(low_profile_rank); - } - } - boundaries.emplace_back(boundary_profile, coalitions); - } - - return preprocessed_learning_set.post_process(boundaries); -} - -#ifndef NDEBUG -bool LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::model_is_correct(const unsigned model_index) const { - try { - make_model(low_profile_ranks[model_index], high_profile_ranks[model_index], weights[model_index]); - } catch (const DataValidationException& e) { - std::cerr << "Model " << model_index << " is incorrect: " << e.what() << std::endl; - return false; - } - return true; -} - -bool LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::models_are_correct() const { - for (unsigned model_index = 0; model_index != models_count; ++model_index) { - if (!model_is_correct(model_index)) { - return false; - } - } - return true; -} -#endif - - -Model LearnMrsortByWeightsProfilesBreed::perform() { - CHRONE(); - - if (models_being_learned.single_peaked_criteria_count != 0) { - if (!profiles_initialization_strategy.supports_single_peaked_criteria) { - throw LearningFailureException("This profiles initialization strategy doesn't support single-peaked criteria."); - } - if (!weights_optimization_strategy.supports_single_peaked_criteria) { - throw LearningFailureException("This weights optimization strategy doesn't support single-peaked criteria."); - } - if (!profiles_improvement_strategy.supports_single_peaked_criteria) { - throw LearningFailureException("This profiles improvement strategy doesn't support single-peaked criteria."); - } - if (!breeding_strategy.supports_single_peaked_criteria) { - throw LearningFailureException("This breeding strategy doesn't support single-peaked criteria."); - } - } - - profiles_initialization_strategy.initialize_profiles(0, models_being_learned.models_count); - weights_optimization_strategy.optimize_weights(0, models_being_learned.models_count); - - assert(models_being_learned.models_are_correct()); - - while (true) { - // @todo(Performance, later) Consider keeping the common part of all LPs in memory, and use it as a base for the LPs. - // (The part that comes from the structure of the problem, and the part that comes from the learing set: they are always the same.) - - // @todo(Performance, later) Consider modifying the linear programs instead of regenerating them. - // We know what profiles have changed since the last iteration, so maybe we could just update the constraints. - - // @todo(Performance, later) Consider stopping the LP optimization after the first phase, - // i.e. when we have the first feasible solution. Maybe we don't need the optimal solution? - - profiles_improvement_strategy.improve_profiles(0, models_being_learned.models_count); - weights_optimization_strategy.optimize_weights(0, models_being_learned.models_count); - - assert(models_being_learned.models_are_correct()); - - // Sort model_indexes by increasing model accuracy - for (unsigned model_index = 0; model_index != models_being_learned.models_count; ++model_index) { - models_being_learned.accuracies[model_index] = compute_accuracy(model_index); - } - std::sort( - models_being_learned.model_indexes.begin(), models_being_learned.model_indexes.end(), - [this](unsigned left_model_index, unsigned right_model_index) { - return models_being_learned.accuracies[left_model_index] < models_being_learned.accuracies[right_model_index]; - } - ); - - // Keep the best model - const unsigned best_model_index = models_being_learned.model_indexes.back(); - const unsigned current_best_accuracy = models_being_learned.accuracies[best_model_index]; - if (current_best_accuracy > models_being_learned.best_model_accuracy) { - models_being_learned.best_model_accuracy = models_being_learned.accuracies[best_model_index]; - copy(models_being_learned.low_profile_ranks[best_model_index], ref(models_being_learned.best_model_low_profile_ranks)); - copy(models_being_learned.high_profile_ranks[best_model_index], ref(models_being_learned.best_model_high_profile_ranks)); - copy(models_being_learned.weights[best_model_index], ref(models_being_learned.best_model_weights)); - } - - // Succeed? - if (models_being_learned.get_best_accuracy() == preprocessed_learning_set.alternatives_count || termination_strategy.terminate()) { - for (auto observer : observers) { - observer->before_return(); - } - return models_being_learned.get_best_model(); - } - - // Breed - // @todo(Feature, later) Keep the best model and reinit half of the others - breeding_strategy.breed(); - - // Observe - for (auto observer : observers) { - observer->after_iteration(); - } - - ++models_being_learned.iteration_index; - } - - unreachable(); -} - -unsigned LearnMrsortByWeightsProfilesBreed::compute_accuracy(const unsigned model_index) { - unsigned accuracy = 0; - - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - if (is_correctly_assigned(model_index, alternative_index)) { - ++accuracy; - } - } - - return accuracy; -} - -bool LearnMrsortByWeightsProfilesBreed::is_correctly_assigned( - const unsigned model_index, - const unsigned alternative_index -) { - const unsigned expected_assignment = preprocessed_learning_set.assignments[alternative_index]; - const unsigned actual_assignment = get_assignment(preprocessed_learning_set, models_being_learned, model_index, alternative_index); - - return actual_assignment == expected_assignment; -} - -bool LearnMrsortByWeightsProfilesBreed::is_accepted( - const PreprocessedLearningSet& preprocessed_learning_set, - const LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned& models_being_learned, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned alternative_index -) { - const unsigned alternative_rank = preprocessed_learning_set.performance_ranks[criterion_index][alternative_index]; - const unsigned low_profile_rank = models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index]; - if (preprocessed_learning_set.single_peaked[criterion_index]) { - const unsigned high_profile_rank = models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]]; - return low_profile_rank <= alternative_rank && alternative_rank <= high_profile_rank; - } else { - return low_profile_rank <= alternative_rank; - } -} - -unsigned LearnMrsortByWeightsProfilesBreed::get_assignment(const PreprocessedLearningSet& preprocessed_learning_set, const ModelsBeingLearned& models_being_learned, const unsigned model_index, const unsigned alternative_index) { - // @todo(Performance, later) Evaluate if it's worth storing and updating the models' assignments - // (instead of recomputing them here) - // Same question in accuracy-heuristic-on-gpu.cu - assert(model_index < models_being_learned.models_count); - assert(alternative_index < preprocessed_learning_set.alternatives_count); - - // Not parallelizable in this form because the loop gets interrupted by a return. But we could rewrite it - // to always perform all its iterations, and then it would be yet another map-reduce, with the reduce - // phase keeping the maximum 'category_index' that passes the weight threshold. - for (unsigned category_index = preprocessed_learning_set.categories_count - 1; category_index != 0; --category_index) { - const unsigned boundary_index = category_index - 1; - float accepted_weight = 0; - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - if (is_accepted(preprocessed_learning_set, models_being_learned, model_index, boundary_index, criterion_index, alternative_index)) { - accepted_weight += models_being_learned.weights[model_index][criterion_index]; - } - } - if (accepted_weight >= 1) { - return category_index; - } - } - return 0; -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.hpp deleted file mode 100644 index 9319142f..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed.hpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED_HPP - -#include - -#include "../io.hpp" -#include "pre-processing.hpp" -#include "../vendored/lov-e.hpp" - - -namespace lincs { - -class LearnMrsortByWeightsProfilesBreed { - public: - static const unsigned default_models_count = 9; - - struct ModelsBeingLearned; - struct ProfilesInitializationStrategy; - struct WeightsOptimizationStrategy; - struct ProfilesImprovementStrategy; - struct BreedingStrategy; - struct TerminationStrategy; - struct Observer; - - public: - LearnMrsortByWeightsProfilesBreed( - const PreprocessedLearningSet& preprocessed_learning_set_, - ModelsBeingLearned& models_being_learned_, - ProfilesInitializationStrategy& profiles_initialization_strategy_, - WeightsOptimizationStrategy& weights_optimization_strategy_, - ProfilesImprovementStrategy& profiles_improvement_strategy_, - BreedingStrategy& breeding_strategy_, - TerminationStrategy& termination_strategy_, - const std::vector& observers_ = {} - ) : - preprocessed_learning_set(preprocessed_learning_set_), - models_being_learned(models_being_learned_), - profiles_initialization_strategy(profiles_initialization_strategy_), - weights_optimization_strategy(weights_optimization_strategy_), - profiles_improvement_strategy(profiles_improvement_strategy_), - breeding_strategy(breeding_strategy_), - termination_strategy(termination_strategy_), - observers(observers_) - {} - - public: - Model perform(); - - private: - unsigned compute_accuracy(unsigned model_index); - bool is_correctly_assigned(unsigned model_index, unsigned alternative_index); - - public: - static bool is_accepted(const PreprocessedLearningSet& preprocessed_learning_set, const ModelsBeingLearned&, unsigned model_index, unsigned boundary_index, unsigned criterion_index, unsigned alternative_index); - static unsigned get_assignment(const PreprocessedLearningSet& preprocessed_learning_set, const ModelsBeingLearned&, unsigned model_index, unsigned alternative_index); - - private: - const PreprocessedLearningSet& preprocessed_learning_set; - ModelsBeingLearned& models_being_learned; - ProfilesInitializationStrategy& profiles_initialization_strategy; - WeightsOptimizationStrategy& weights_optimization_strategy; - ProfilesImprovementStrategy& profiles_improvement_strategy; - BreedingStrategy& breeding_strategy; - TerminationStrategy& termination_strategy; - std::vector observers; -}; - -struct LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned { - const PreprocessedLearningSet& preprocessed_learning_set; - const unsigned models_count; - std::vector random_generators; // [model_index] - unsigned iteration_index; - std::vector model_indexes; // [model_index_index]: this is a reordering of the models' indexes - Array1D accuracies; // [model_index] - Array3D low_profile_ranks; // [model_index][boundary_index][criterion_index] - const unsigned single_peaked_criteria_count; - Array1D high_profile_rank_indexes; // [criterion_index], meaningful only for single-peaked criteria (i.e. when single_peaked[criterion_index] is true) - Array3D high_profile_ranks; // [model_index][boundary_index][high_profile_rank_indexes[criterion_index]] - Array2D weights; // [model_index][criterion_index] - // @todo(Performance, later) Add models' ages - - unsigned best_model_accuracy; - Array2D best_model_low_profile_ranks; // [boundary_index][criterion_index] - Array2D best_model_high_profile_ranks; // [boundary_index][high_profile_rank_indexes[criterion_index]] - Array1D best_model_weights; // [criterion_index] - - ModelsBeingLearned(const PreprocessedLearningSet& preprocessed_learning_set, unsigned models_count, unsigned random_seed); - - unsigned get_best_accuracy() const { return best_model_accuracy; } - Model get_best_model() const { return make_model(best_model_low_profile_ranks, best_model_high_profile_ranks, best_model_weights); } - - private: - Model make_model(ArrayView2D low_profile_ranks, ArrayView2D high_profile_ranks, ArrayView1D weights) const; - - public: - #ifndef NDEBUG - bool model_is_correct(unsigned model_index) const; - bool models_are_correct() const; - #endif - - private: - unsigned count_single_peaked_criteria() const; -}; - -struct LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - ProfilesInitializationStrategy(bool supports_single_peaked_criteria_ = false) : supports_single_peaked_criteria(supports_single_peaked_criteria_) {} - - virtual ~ProfilesInitializationStrategy() {} - - virtual void initialize_profiles(unsigned model_indexes_begin, unsigned model_indexes_end) = 0; - - const bool supports_single_peaked_criteria; -}; - -struct LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - WeightsOptimizationStrategy(bool supports_single_peaked_criteria_ = false) : supports_single_peaked_criteria(supports_single_peaked_criteria_) {} - - virtual ~WeightsOptimizationStrategy() {} - - virtual void optimize_weights(unsigned model_indexes_begin, unsigned model_indexes_end) = 0; - - const bool supports_single_peaked_criteria; -}; - -struct LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - ProfilesImprovementStrategy(bool supports_single_peaked_criteria_ = false) : supports_single_peaked_criteria(supports_single_peaked_criteria_) {} - - virtual ~ProfilesImprovementStrategy() {} - - virtual void improve_profiles(unsigned model_indexes_begin, unsigned model_indexes_end) = 0; - - const bool supports_single_peaked_criteria; -}; - -struct LearnMrsortByWeightsProfilesBreed::BreedingStrategy { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - BreedingStrategy(bool supports_single_peaked_criteria_ = false) : supports_single_peaked_criteria(supports_single_peaked_criteria_) {} - - virtual ~BreedingStrategy() {} - - virtual void breed() = 0; - - const bool supports_single_peaked_criteria; -}; - -struct LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - virtual ~TerminationStrategy() {} - - virtual bool terminate() = 0; -}; - -struct LearnMrsortByWeightsProfilesBreed::Observer { - typedef LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned ModelsBeingLearned; - - virtual ~Observer() {} - - virtual void after_iteration() = 0; - virtual void before_return() = 0; -}; - -} // namespace lincs - - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.cpp deleted file mode 100644 index b66d0670..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "reinitialize-least-accurate.hpp" - -#include "../../../chrones.hpp" - - -namespace lincs { - -void ReinitializeLeastAccurate::breed() { - CHRONE(); - - profiles_initialization_strategy.initialize_profiles(0, count); - weights_optimization_strategy.optimize_weights(0, count); -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.hpp deleted file mode 100644 index dfd46678..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/breed/reinitialize-least-accurate.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__BREED__REINITIALIZE_LEAST_ACCURATE_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__BREED__REINITIALIZE_LEAST_ACCURATE_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class ReinitializeLeastAccurate : public LearnMrsortByWeightsProfilesBreed::BreedingStrategy { - public: - explicit ReinitializeLeastAccurate( - ModelsBeingLearned& models_being_learned_, - LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy& profiles_initialization_strategy_, - LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy& weights_optimization_strategy_, - unsigned count_ - ) : - LearnMrsortByWeightsProfilesBreed::BreedingStrategy(true), - models_being_learned(models_being_learned_), - profiles_initialization_strategy(profiles_initialization_strategy_), - weights_optimization_strategy(weights_optimization_strategy_), - count(count_) - {} - - public: - void breed() override; - - private: - ModelsBeingLearned& models_being_learned; - LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy& profiles_initialization_strategy; - LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy& weights_optimization_strategy; - unsigned count; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__BREED__REINITIALIZE_LEAST_ACCURATE_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.cpp deleted file mode 100644 index fbc18c17..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.cpp +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "accuracy-heuristic-on-cpu.hpp" - -#include "../../../chrones.hpp" -#include "../../../randomness-utils.hpp" - - -namespace lincs { - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_profiles( - const unsigned model_indexes_begin, - const unsigned model_indexes_end -) { - CHRONE(); - - const int model_indexes_end_ = model_indexes_end; - - #pragma omp parallel for - for (int model_indexes_index = model_indexes_begin; model_indexes_index < model_indexes_end_; ++model_indexes_index) { - const unsigned model_index = models_being_learned.model_indexes[model_indexes_index]; - improve_model_profiles(model_index); - } -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_model_profiles(const unsigned model_index) { - Array1D criterion_indexes(preprocessed_learning_set.criteria_count, uninitialized); - // Not worth parallelizing because criteria_count is typically small - for (unsigned crit_idx_idx = 0; crit_idx_idx != preprocessed_learning_set.criteria_count; ++crit_idx_idx) { - criterion_indexes[crit_idx_idx] = crit_idx_idx; - } - - // Not parallel because iteration N+1 relies on side effect in iteration N - // (We could challenge this aspect of the algorithm described by Sobrie) - for (unsigned boundary_index = 0; boundary_index != preprocessed_learning_set.boundaries_count; ++boundary_index) { - shuffle(models_being_learned.random_generators[model_index], ref(criterion_indexes)); - improve_boundary_profiles(model_index, boundary_index, criterion_indexes); - } -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_boundary_profiles( - const unsigned model_index, - const unsigned boundary_index, - ArrayView1D criterion_indexes -) { - // Not parallel because iteration N+1 relies on side effect in iteration N - // (We could challenge this aspect of the algorithm described by Sobrie) - for (unsigned crit_idx_idx = 0; crit_idx_idx != preprocessed_learning_set.criteria_count; ++crit_idx_idx) { - if (preprocessed_learning_set.single_peaked[criterion_indexes[crit_idx_idx]]) { - improve_low_profile_then_high_profile(model_index, boundary_index, criterion_indexes[crit_idx_idx]); - } else { - improve_low_profile_only(model_index, boundary_index, criterion_indexes[crit_idx_idx]); - } - } -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_low_profile_then_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index -) { - assert(preprocessed_learning_set.single_peaked[criterion_index]); - - improve_low_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == 0 ? - 0 : - models_being_learned.low_profile_ranks[model_index][boundary_index - 1][criterion_index], - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]]: - models_being_learned.low_profile_ranks[model_index][boundary_index + 1][criterion_index] - ); - - improve_high_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] : - models_being_learned.high_profile_ranks[model_index][boundary_index + 1][models_being_learned.high_profile_rank_indexes[criterion_index]], - boundary_index == 0 ? - preprocessed_learning_set.values_counts[criterion_index] - 1 : - models_being_learned.high_profile_ranks[model_index][boundary_index - 1][models_being_learned.high_profile_rank_indexes[criterion_index]] - ); -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_low_profile_only( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index -) { - improve_low_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == 0 ? - 0 : - models_being_learned.low_profile_ranks[model_index][boundary_index - 1][criterion_index], - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - preprocessed_learning_set.values_counts[criterion_index] - 1 : - models_being_learned.low_profile_ranks[model_index][boundary_index + 1][criterion_index] - ); -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_low_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned lowest_destination_rank, - const unsigned highest_destination_rank -) { - assert(lowest_destination_rank <= highest_destination_rank); - if (lowest_destination_rank == highest_destination_rank) { - assert(models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] == lowest_destination_rank); - } else { - unsigned best_destination_rank = models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index]; - float best_desirability = Desirability().value(); - - if (highest_destination_rank - lowest_destination_rank >= max_destinations_count) { - // We could try uniformly spread-out destinations instead of uniform random ones - for (unsigned destination_index = 0; destination_index != max_destinations_count; ++destination_index) { - const unsigned destination_rank = std::uniform_int_distribution(lowest_destination_rank, highest_destination_rank)(models_being_learned.random_generators[model_index]); - const float desirability = compute_move_desirability_for_low_profile( - model_index, - boundary_index, - criterion_index, - destination_rank).value(); - // Single-key reduce (divide and conquer?) (atomic compare-and-swap?) - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - } else { - for (unsigned destination_rank = lowest_destination_rank; destination_rank <= highest_destination_rank; ++destination_rank) { - const float desirability = compute_move_desirability_for_low_profile( - model_index, - boundary_index, - criterion_index, - destination_rank).value(); - // Single-key reduce (divide and conquer?) (atomic compare-and-swap?) - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - } - - // @todo(Project management, later) Desirability can be as high as 2. The [0, 1] interval is a weird choice. - if (std::uniform_real_distribution(0, 1)(models_being_learned.random_generators[model_index]) <= best_desirability) { - models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] = best_destination_rank; - } - } -} - -Desirability ImproveProfilesWithAccuracyHeuristicOnCpu::compute_move_desirability_for_low_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank -) { - Desirability d; - - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - update_move_desirability_for_low_profile( - model_index, - boundary_index, - criterion_index, - destination_rank, - alternative_index, - &d); - } - - return d; -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::update_move_desirability_for_low_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank, - const unsigned alternative_index, - Desirability* desirability -) { - const unsigned current_rank = models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index]; - const float weight = models_being_learned.weights[model_index][criterion_index]; - - const unsigned alternative_rank = preprocessed_learning_set.performance_ranks[criterion_index][alternative_index]; - const unsigned learning_assignment = preprocessed_learning_set.assignments[alternative_index]; - const unsigned model_assignment = LearnMrsortByWeightsProfilesBreed::get_assignment(preprocessed_learning_set, models_being_learned, model_index, alternative_index); - - // @todo(Project management, later) Factorize with get_assignment - // (Same remark in accuracy-heuristic-on-gpu.cu) - float accepted_weight = 0; - // There is a 'criterion_index' parameter above, *and* a local 'crit_index' just here - for (unsigned crit_index = 0; crit_index != preprocessed_learning_set.criteria_count; ++crit_index) { - if (LearnMrsortByWeightsProfilesBreed::is_accepted(preprocessed_learning_set, models_being_learned, model_index, boundary_index, crit_index, alternative_index)) { - accepted_weight += models_being_learned.weights[model_index][crit_index]; - } - } - - // These imbricated conditionals could be factorized, but this form has the benefit - // of being a direct translation of the top of page 78 of Sobrie's thesis. - // Correspondance: - // - learning_assignment: bottom index of A* - // - model_assignment: top index of A* - // - boundary_index: h - // - destination_value: b_j +/- \delta - // - current_value: b_j - // - alternative_value: a_j - // - accepted_weight: \sigma - // - weight: w_j - // - 1: \lambda - if (destination_rank > current_rank) { - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight < 1 - ) { - ++desirability->v; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight >= 1 - ) { - ++desirability->w; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight < 1 - ) { - ++desirability->q; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && destination_rank > alternative_rank - && alternative_rank >= current_rank - ) { - ++desirability->r; - } - if ( - learning_assignment < boundary_index - && model_assignment > boundary_index - && destination_rank > alternative_rank - && alternative_rank >= current_rank - ) { - ++desirability->t; - } - } else { - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight >= 1 - ) { - ++desirability->v; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight < 1 - ) { - ++desirability->w; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight >= 1 - ) { - ++desirability->q; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && alternative_rank >= destination_rank - && current_rank > alternative_rank - ) { - ++desirability->r; - } - if ( - learning_assignment > boundary_index + 1 - && model_assignment < boundary_index + 1 - && alternative_rank > destination_rank - && current_rank >= alternative_rank - ) { - ++desirability->t; - } - } -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::improve_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned lowest_destination_rank, - const unsigned highest_destination_rank -) { - assert(preprocessed_learning_set.single_peaked[criterion_index]); - assert(lowest_destination_rank <= highest_destination_rank); - if (lowest_destination_rank == highest_destination_rank) { - assert(models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]] == lowest_destination_rank); - } else { - unsigned best_destination_rank = models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]]; - float best_desirability = Desirability().value(); - - if (highest_destination_rank - lowest_destination_rank >= max_destinations_count) { - for (unsigned destination_index = 0; destination_index != max_destinations_count; ++destination_index) { - const unsigned destination_rank = std::uniform_int_distribution(lowest_destination_rank, highest_destination_rank)(models_being_learned.random_generators[model_index]); - const float desirability = compute_move_desirability_for_high_profile( - model_index, - boundary_index, - criterion_index, - destination_rank).value(); - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - } else { - for (unsigned destination_rank = lowest_destination_rank; destination_rank <= highest_destination_rank; ++destination_rank) { - const float desirability = compute_move_desirability_for_high_profile( - model_index, - boundary_index, - criterion_index, - destination_rank).value(); - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - } - - if (std::uniform_real_distribution(0, 1)(models_being_learned.random_generators[model_index]) <= best_desirability) { - models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]] = best_destination_rank; - } - } -} - -Desirability ImproveProfilesWithAccuracyHeuristicOnCpu::compute_move_desirability_for_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank -) { - Desirability d; - - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - update_move_desirability_for_high_profile( - model_index, - boundary_index, - criterion_index, - destination_rank, - alternative_index, - &d); - } - - return d; -} - -void ImproveProfilesWithAccuracyHeuristicOnCpu::update_move_desirability_for_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank, - const unsigned alternative_index, - Desirability* desirability -) { - assert(preprocessed_learning_set.single_peaked[criterion_index]); - const unsigned current_rank = models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]]; - const float weight = models_being_learned.weights[model_index][criterion_index]; - - const unsigned alternative_rank = preprocessed_learning_set.performance_ranks[criterion_index][alternative_index]; - const unsigned learning_assignment = preprocessed_learning_set.assignments[alternative_index]; - const unsigned model_assignment = LearnMrsortByWeightsProfilesBreed::get_assignment(preprocessed_learning_set, models_being_learned, model_index, alternative_index); - - float accepted_weight = 0; - // There is a 'criterion_index' parameter above, *and* a local 'crit_index' just here - for (unsigned crit_index = 0; crit_index != preprocessed_learning_set.criteria_count; ++crit_index) { - if (LearnMrsortByWeightsProfilesBreed::is_accepted(preprocessed_learning_set, models_being_learned, model_index, boundary_index, crit_index, alternative_index)) { - accepted_weight += models_being_learned.weights[model_index][crit_index]; - } - } - - // Similar to 'update_move_desirability_for_low_profile' but inequalities involving 'destination_rank' and/or 'current_rank' are reversed - if (destination_rank < current_rank) { - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight < 1 - ) { - ++desirability->v; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight >= 1 - ) { - ++desirability->w; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight < 1 - ) { - ++desirability->q; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && destination_rank < alternative_rank - && alternative_rank <= current_rank - ) { - ++desirability->r; - } - if ( - learning_assignment < boundary_index - && model_assignment > boundary_index - && destination_rank < alternative_rank - && alternative_rank <= current_rank - ) { - ++desirability->t; - } - } else { - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight >= 1 - ) { - ++desirability->v; - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight < 1 - ) { - ++desirability->w; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight >= 1 - ) { - ++desirability->q; - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && alternative_rank <= destination_rank - && current_rank < alternative_rank - ) { - ++desirability->r; - } - if ( - learning_assignment > boundary_index + 1 - && model_assignment < boundary_index + 1 - && alternative_rank < destination_rank - && current_rank <= alternative_rank - ) { - ++desirability->t; - } - } -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.hpp deleted file mode 100644 index e3d58b8b..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-cpu.hpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_CPU_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_CPU_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" -#include "accuracy-heuristic/desirability.hpp" - - -namespace lincs { - -class ImproveProfilesWithAccuracyHeuristicOnCpu : public LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy { - public: - explicit ImproveProfilesWithAccuracyHeuristicOnCpu(const PreprocessedLearningSet& preprocessed_learning_set_, ModelsBeingLearned& models_being_learned_) : - LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy(true), - preprocessed_learning_set(preprocessed_learning_set_), - models_being_learned(models_being_learned_) - {} - - public: - void improve_profiles(unsigned model_indexes_begin, unsigned model_indexes_end) override; - - private: - void improve_model_profiles(unsigned model_index); - - void improve_boundary_profiles( - unsigned model_index, - unsigned boundary_index, - ArrayView1D criterion_indexes - ); - - void improve_low_profile_then_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index - ); - - void improve_low_profile_only( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index - ); - - void improve_low_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned lowest_destination_rank, - unsigned highest_destination_rank - ); - - Desirability compute_move_desirability_for_low_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned destination_rank - ); - - void update_move_desirability_for_low_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned destination_rank, - unsigned alternative_index, - Desirability* desirability - ); - - void improve_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned lowest_destination_rank, - unsigned highest_destination_rank - ); - - Desirability compute_move_desirability_for_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned destination_rank - ); - - void update_move_desirability_for_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned destination_rank, - unsigned alternative_index, - Desirability* desirability - ); - - private: - const PreprocessedLearningSet& preprocessed_learning_set; - ModelsBeingLearned& models_being_learned; - - static const unsigned max_destinations_count = 64; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_CPU_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.cu b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.cu deleted file mode 100644 index 0a8eba4b..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.cu +++ /dev/null @@ -1,736 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "accuracy-heuristic-on-gpu.hpp" - -#include "../../../chrones.hpp" -#include "../../../randomness-utils.hpp" - - -namespace { - -// Block size set to less than 1024 because we use more than 64 registers per thread and my GPU has only 64K registers -typedef GridFactory2D<256, 2> grid; - -__device__ -bool is_accepted( - const ArrayView2D performance_ranks, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned alternative_index -) { - const unsigned alternative_rank = performance_ranks[criterion_index][alternative_index]; - const unsigned low_profile_rank = low_profile_ranks[model_index][boundary_index][criterion_index]; - if (single_peaked[criterion_index]) { - const unsigned high_profile_rank = high_profile_ranks[model_index][boundary_index][high_profile_rank_indexes[criterion_index]]; - return low_profile_rank <= alternative_rank && alternative_rank <= high_profile_rank; - } else { - return low_profile_rank <= alternative_rank; - } -} - -__device__ -unsigned get_assignment( - const ArrayView2D performance_ranks, - const ArrayView2D weights, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned alternative_index -) { - const unsigned criteria_count = performance_ranks.s1(); - const unsigned categories_count = low_profile_ranks.s1() + 1; - - // Not parallelizable in this form because the loop gets interrupted by a return. But we could rewrite it - // to always perform all its iterations, and then it would be yet another map-reduce, with the reduce - // phase keeping the maximum 'category_index' that passes the weight threshold. - for (unsigned category_index = categories_count - 1; category_index != 0; --category_index) { - const unsigned boundary_index = category_index - 1; - float accepted_weight = 0; - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - if (is_accepted(performance_ranks, single_peaked, low_profile_ranks, high_profile_rank_indexes, high_profile_ranks, model_index, boundary_index, criterion_index, alternative_index)) { - accepted_weight += weights[model_index][criterion_index]; - } - } - if (accepted_weight >= 1) { - return category_index; - } - } - return 0; -} - -__device__ -void update_move_desirability_for_low_profile( - const ArrayView2D performance_ranks, - const ArrayView1D assignments, - const ArrayView2D weights, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank, - const unsigned alternative_index, - lincs::Desirability* desirability -) { - const unsigned alternatives_count = performance_ranks.s0(); - const unsigned criteria_count = performance_ranks.s1(); - - const unsigned current_rank = low_profile_ranks[model_index][boundary_index][criterion_index]; - const float weight = weights[model_index][criterion_index]; - - const unsigned alternative_rank = performance_ranks[criterion_index][alternative_index]; - const unsigned learning_assignment = assignments[alternative_index]; - const unsigned model_assignment = get_assignment( - performance_ranks, - weights, - single_peaked, - low_profile_ranks, - high_profile_rank_indexes, - high_profile_ranks, - model_index, - alternative_index); - - float accepted_weight = 0; - // There is a 'criterion_index' parameter above, *and* a local 'crit_index' just here - for (unsigned crit_index = 0; crit_index != criteria_count; ++crit_index) { - if (is_accepted(performance_ranks, single_peaked, low_profile_ranks, high_profile_rank_indexes, high_profile_ranks, model_index, boundary_index, crit_index, alternative_index)) { - accepted_weight += weights[model_index][crit_index]; - } - } - - if (destination_rank > current_rank) { - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight < 1 - ) { - atomicInc(&desirability->v, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight >= 1 - ) { - atomicInc(&desirability->w, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index + 1 - && destination_rank > alternative_rank - && alternative_rank >= current_rank - && accepted_weight - weight < 1 - ) { - atomicInc(&desirability->q, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && destination_rank > alternative_rank - && alternative_rank >= current_rank - ) { - atomicInc(&desirability->r, alternatives_count); - } - if ( - learning_assignment < boundary_index - && model_assignment > boundary_index - && destination_rank > alternative_rank - && alternative_rank >= current_rank - ) { - atomicInc(&desirability->t, alternatives_count); - } - } else { - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight >= 1 - ) { - atomicInc(&desirability->v, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight < 1 - ) { - atomicInc(&desirability->w, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index - && alternative_rank > destination_rank - && current_rank > alternative_rank - && accepted_weight + weight >= 1 - ) { - atomicInc(&desirability->q, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && alternative_rank >= destination_rank - && current_rank > alternative_rank - ) { - atomicInc(&desirability->r, alternatives_count); - } - if ( - learning_assignment > boundary_index + 1 - && model_assignment < boundary_index + 1 - && alternative_rank > destination_rank - && current_rank >= alternative_rank - ) { - atomicInc(&desirability->t, alternatives_count); - } - } -} - -// @todo(Performance, later) investigate how sharing preliminary computations done in all threads could improve perf -__global__ -void compute_move_desirabilities_for_low_profile__kernel( - const ArrayView2D performance_ranks, - const ArrayView1D assignments, - const ArrayView2D weights, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned actual_destinations_count, - const ArrayView1D destination_ranks, - ArrayView1D desirabilities -) { - const unsigned alt_index = grid::x(); - assert(alt_index < performance_ranks.s0() + grid::blockDim().x); - const unsigned destination_index = grid::y(); - assert(destination_index < actual_destinations_count + grid::blockDim().y); - - // Map (embarrassingly parallel) - if (alt_index < performance_ranks.s0() && destination_index < actual_destinations_count) { - update_move_desirability_for_low_profile( - performance_ranks, - assignments, - weights, - single_peaked, - low_profile_ranks, - high_profile_rank_indexes, - high_profile_ranks, - model_index, - boundary_index, - criterion_index, - destination_ranks[destination_index], - alt_index, - &desirabilities[destination_index]); - } -} - -__global__ -void apply_best_move_for_low_profile__kernel( - const ArrayView3D low_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned actual_destinations_count, - const ArrayView1D destination_ranks, - const ArrayView1D desirabilities, - const float desirability_threshold -) { - // Single-key reduce - // Could maybe be parallelized using divide and conquer? Or atomic compare-and-swap? - unsigned best_destination_rank = destination_ranks[0]; - float best_desirability = desirabilities[0].value(); - for (unsigned destination_index = 1; destination_index < actual_destinations_count; ++destination_index) { - const unsigned destination_rank = destination_ranks[destination_index]; - const float desirability = desirabilities[destination_index].value(); - - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - - if (best_desirability >= desirability_threshold) { - low_profile_ranks[model_index][boundary_index][criterion_index] = best_destination_rank; - } -} - -__device__ -void update_move_desirability_for_high_profile( - const ArrayView2D performance_ranks, - const ArrayView1D assignments, - const ArrayView2D weights, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned destination_rank, - const unsigned alternative_index, - lincs::Desirability* desirability -) { - const unsigned alternatives_count = performance_ranks.s0(); - const unsigned criteria_count = performance_ranks.s1(); - - const unsigned current_rank = high_profile_ranks[model_index][boundary_index][high_profile_rank_indexes[criterion_index]]; - const float weight = weights[model_index][criterion_index]; - - const unsigned alternative_rank = performance_ranks[criterion_index][alternative_index]; - const unsigned learning_assignment = assignments[alternative_index]; - const unsigned model_assignment = get_assignment( - performance_ranks, - weights, - single_peaked, - low_profile_ranks, - high_profile_rank_indexes, - high_profile_ranks, - model_index, - alternative_index); - - float accepted_weight = 0; - // There is a 'criterion_index' parameter above, *and* a local 'crit_index' just here - for (unsigned crit_index = 0; crit_index != criteria_count; ++crit_index) { - if (is_accepted(performance_ranks, single_peaked, low_profile_ranks, high_profile_rank_indexes, high_profile_ranks, model_index, boundary_index, crit_index, alternative_index)) { - accepted_weight += weights[model_index][crit_index]; - } - } - - if (destination_rank < current_rank) { - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight < 1 - ) { - atomicInc(&desirability->v, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight >= 1 - ) { - atomicInc(&desirability->w, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index + 1 - && destination_rank < alternative_rank - && alternative_rank <= current_rank - && accepted_weight - weight < 1 - ) { - atomicInc(&desirability->q, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && destination_rank < alternative_rank - && alternative_rank <= current_rank - ) { - atomicInc(&desirability->r, alternatives_count); - } - if ( - learning_assignment < boundary_index - && model_assignment > boundary_index - && destination_rank < alternative_rank - && alternative_rank <= current_rank - ) { - atomicInc(&desirability->t, alternatives_count); - } - } else { - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight >= 1 - ) { - atomicInc(&desirability->v, alternatives_count); - } - if ( - learning_assignment == boundary_index + 1 - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight < 1 - ) { - atomicInc(&desirability->w, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index - && alternative_rank < destination_rank - && current_rank < alternative_rank - && accepted_weight + weight >= 1 - ) { - atomicInc(&desirability->q, alternatives_count); - } - if ( - learning_assignment == boundary_index - && model_assignment == boundary_index + 1 - && alternative_rank <= destination_rank - && current_rank < alternative_rank - ) { - atomicInc(&desirability->r, alternatives_count); - } - if ( - learning_assignment > boundary_index + 1 - && model_assignment < boundary_index + 1 - && alternative_rank < destination_rank - && current_rank <= alternative_rank - ) { - atomicInc(&desirability->t, alternatives_count); - } - } -} - -// @todo(Performance, later) investigate how sharing preliminary computations done in all threads could improve perf -__global__ -void compute_move_desirabilities_for_high_profile__kernel( - const ArrayView2D performance_ranks, - const ArrayView1D assignments, - const ArrayView2D weights, - const ArrayView1D single_peaked, - const ArrayView3D low_profile_ranks, - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned actual_destinations_count, - const ArrayView1D destination_ranks, - ArrayView1D desirabilities -) { - const unsigned alt_index = grid::x(); - assert(alt_index < performance_ranks.s0() + grid::blockDim().x); - const unsigned destination_index = grid::y(); - assert(destination_index < actual_destinations_count + grid::blockDim().y); - - // Map (embarrassingly parallel) - if (alt_index < performance_ranks.s0() && destination_index < actual_destinations_count) { - update_move_desirability_for_high_profile( - performance_ranks, - assignments, - weights, - single_peaked, - low_profile_ranks, - high_profile_rank_indexes, - high_profile_ranks, - model_index, - boundary_index, - criterion_index, - destination_ranks[destination_index], - alt_index, - &desirabilities[destination_index]); - } -} - -__global__ -void apply_best_move_for_high_profile__kernel( - const ArrayView1D high_profile_rank_indexes, - const ArrayView3D high_profile_ranks, - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned actual_destinations_count, - const ArrayView1D destination_ranks, - const ArrayView1D desirabilities, - const float desirability_threshold -) { - // Single-key reduce - // Could maybe be parallelized using divide and conquer? Or atomic compare-and-swap? - unsigned best_destination_rank = destination_ranks[0]; - float best_desirability = desirabilities[0].value(); - for (unsigned destination_index = 1; destination_index < actual_destinations_count; ++destination_index) { - const unsigned destination_rank = destination_ranks[destination_index]; - const float desirability = desirabilities[destination_index].value(); - - if (desirability > best_desirability) { - best_desirability = desirability; - best_destination_rank = destination_rank; - } - } - - if (best_desirability >= desirability_threshold) { - high_profile_ranks[model_index][boundary_index][high_profile_rank_indexes[criterion_index]] = best_destination_rank; - } -} - -} // namespace - -namespace lincs { - -ImproveProfilesWithAccuracyHeuristicOnGpu::GpuModelsBeingLearned::GpuModelsBeingLearned(const PreprocessedLearningSet& preprocessed_learning_set, const ModelsBeingLearned& host_models_being_learned) : - performance_ranks(preprocessed_learning_set.performance_ranks.template clone_to()), - assignments(preprocessed_learning_set.assignments.template clone_to()), - single_peaked(preprocessed_learning_set.single_peaked.template clone_to()), - weights(host_models_being_learned.models_count, preprocessed_learning_set.criteria_count, uninitialized), - low_profile_ranks(host_models_being_learned.models_count, preprocessed_learning_set.boundaries_count, preprocessed_learning_set.criteria_count, uninitialized), - high_profile_rank_indexes(host_models_being_learned.high_profile_rank_indexes.template clone_to()), - high_profile_ranks(host_models_being_learned.models_count, preprocessed_learning_set.boundaries_count, host_models_being_learned.high_profile_ranks.s0(), uninitialized), - desirabilities(host_models_being_learned.models_count, ImproveProfilesWithAccuracyHeuristicOnGpu::max_destinations_count, uninitialized), - destination_ranks(host_models_being_learned.models_count, ImproveProfilesWithAccuracyHeuristicOnGpu::max_destinations_count, uninitialized) -{} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_profiles( - const unsigned model_indexes_begin, - const unsigned model_indexes_end -) { - CHRONE(); - - // Get optimized weights - copy(host_models_being_learned.weights, ref(gpu_models_being_learned.weights)); - // Get (re-)initialized profiles - copy(host_models_being_learned.low_profile_ranks, ref(gpu_models_being_learned.low_profile_ranks)); - copy(host_models_being_learned.high_profile_ranks, ref(gpu_models_being_learned.high_profile_ranks)); - - #pragma omp parallel for - for (int model_indexes_index = model_indexes_begin; model_indexes_index < model_indexes_end; ++model_indexes_index) { - const unsigned model_index = host_models_being_learned.model_indexes[model_indexes_index]; - improve_model_profiles(model_index); - } - - // Set improved profiles - copy(gpu_models_being_learned.low_profile_ranks, ref(host_models_being_learned.low_profile_ranks)); - copy(gpu_models_being_learned.high_profile_ranks, ref(host_models_being_learned.high_profile_ranks)); -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_model_profiles(const unsigned model_index) { - Array1D criterion_indexes(preprocessed_learning_set.criteria_count, uninitialized); - // Not worth parallelizing because models_being_learned.criteria_count is typically small - for (unsigned crit_idx_idx = 0; crit_idx_idx != preprocessed_learning_set.criteria_count; ++crit_idx_idx) { - criterion_indexes[crit_idx_idx] = crit_idx_idx; - } - - // Not parallel because iteration N+1 relies on side effect in iteration N - // (We could challenge this aspect of the algorithm described by Sobrie) - for (unsigned boundary_index = 0; boundary_index != preprocessed_learning_set.boundaries_count; ++boundary_index) { - shuffle(host_models_being_learned.random_generators[model_index], ref(criterion_indexes)); - improve_boundary_profiles(model_index, boundary_index, criterion_indexes); - } -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_boundary_profiles( - const unsigned model_index, - const unsigned boundary_index, - const ArrayView1D criterion_indexes -) { - // Not parallel because iteration N+1 relies on side effect in iteration N - // (We could challenge this aspect of the algorithm described by Sobrie) - for (unsigned crit_idx_idx = 0; crit_idx_idx != preprocessed_learning_set.criteria_count; ++crit_idx_idx) { - if (preprocessed_learning_set.single_peaked[criterion_indexes[crit_idx_idx]]) { - improve_low_profile_then_high_profile(model_index, boundary_index, criterion_indexes[crit_idx_idx]); - } else { - improve_low_profile_only(model_index, boundary_index, criterion_indexes[crit_idx_idx]); - } - } -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_low_profile_then_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index -) { - assert(preprocessed_learning_set.single_peaked[criterion_index]); - - improve_low_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == 0 ? - 0 : - host_models_being_learned.low_profile_ranks[model_index][boundary_index - 1][criterion_index], - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - host_models_being_learned.high_profile_ranks[model_index][boundary_index][host_models_being_learned.high_profile_rank_indexes[criterion_index]]: - host_models_being_learned.low_profile_ranks[model_index][boundary_index + 1][criterion_index] - ); - - improve_high_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - host_models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] : - host_models_being_learned.high_profile_ranks[model_index][boundary_index + 1][host_models_being_learned.high_profile_rank_indexes[criterion_index]], - boundary_index == 0 ? - preprocessed_learning_set.values_counts[criterion_index] - 1 : - host_models_being_learned.high_profile_ranks[model_index][boundary_index - 1][host_models_being_learned.high_profile_rank_indexes[criterion_index]] - ); -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_low_profile_only( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index -) { - improve_low_profile( - model_index, - boundary_index, - criterion_index, - boundary_index == 0 ? - 0 : - host_models_being_learned.low_profile_ranks[model_index][boundary_index - 1][criterion_index], - boundary_index == preprocessed_learning_set.boundaries_count - 1 ? - preprocessed_learning_set.values_counts[criterion_index] - 1 : - host_models_being_learned.low_profile_ranks[model_index][boundary_index + 1][criterion_index] - ); -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_low_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned lowest_destination_rank, - const unsigned highest_destination_rank -) { - assert(lowest_destination_rank <= highest_destination_rank); - if (lowest_destination_rank == highest_destination_rank) { - assert(host_models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] == lowest_destination_rank); - } else { - Array1D host_destination_ranks(max_destinations_count, uninitialized); - unsigned actual_destinations_count = 0; - if (highest_destination_rank - lowest_destination_rank >= max_destinations_count) { - for (unsigned destination_index = 0; destination_index != max_destinations_count; ++destination_index) { - host_destination_ranks[destination_index] = std::uniform_int_distribution(lowest_destination_rank, highest_destination_rank)(host_models_being_learned.random_generators[model_index]); - } - actual_destinations_count = max_destinations_count; - } else { - for (unsigned destination_rank = lowest_destination_rank; destination_rank <= highest_destination_rank; ++destination_rank) { - ++actual_destinations_count; - const unsigned destination_index = destination_rank - lowest_destination_rank; - host_destination_ranks[destination_index] = destination_rank; - } - assert(actual_destinations_count == highest_destination_rank - lowest_destination_rank + 1); - } - - copy(host_destination_ranks, ref(gpu_models_being_learned.destination_ranks[model_index])); - gpu_models_being_learned.desirabilities[model_index].fill_with_zeros(); - Grid grid = grid::make(preprocessed_learning_set.alternatives_count, actual_destinations_count); - compute_move_desirabilities_for_low_profile__kernel<<>>( - gpu_models_being_learned.performance_ranks, - gpu_models_being_learned.assignments, - gpu_models_being_learned.weights, - gpu_models_being_learned.single_peaked, - gpu_models_being_learned.low_profile_ranks, - gpu_models_being_learned.high_profile_rank_indexes, - gpu_models_being_learned.high_profile_ranks, - model_index, - boundary_index, - criterion_index, - actual_destinations_count, - gpu_models_being_learned.destination_ranks[model_index], - ref(gpu_models_being_learned.desirabilities[model_index])); - check_last_cuda_error_sync_stream(cudaStreamDefault); - - apply_best_move_for_low_profile__kernel<<<1, 1>>>( - ref(gpu_models_being_learned.low_profile_ranks), - model_index, - boundary_index, - criterion_index, - actual_destinations_count, - gpu_models_being_learned.destination_ranks[model_index], - gpu_models_being_learned.desirabilities[model_index], - std::uniform_real_distribution(0, 1)(host_models_being_learned.random_generators[model_index])); - check_last_cuda_error_sync_stream(cudaStreamDefault); - - // @todo(Performance, later) Can we group this copying somehow? - // Currently we copy just one float from device memory to host memory - // (because just one float is potentialy modified by 'apply_best_move_for_low_profile__kernel', - // and we need it back on the device for the next iteration) - - // Lov-e-CUDA doesn't provide a way to copy scalars, so we're back to the basics, using cudaMemcpy directly and doing pointer arithmetic. - check_cuda_error(cudaMemcpy( - host_models_being_learned.low_profile_ranks[model_index][boundary_index].data() + criterion_index, - gpu_models_being_learned.low_profile_ranks[model_index][boundary_index].data() + criterion_index, - 1 * sizeof(unsigned), - cudaMemcpyDeviceToHost)); - } -} - -void ImproveProfilesWithAccuracyHeuristicOnGpu::improve_high_profile( - const unsigned model_index, - const unsigned boundary_index, - const unsigned criterion_index, - const unsigned lowest_destination_rank, - const unsigned highest_destination_rank -) { - assert(preprocessed_learning_set.single_peaked[criterion_index]); - assert(lowest_destination_rank <= highest_destination_rank); - if (lowest_destination_rank == highest_destination_rank) { - assert(host_models_being_learned.high_profile_ranks[model_index][boundary_index][host_models_being_learned.high_profile_rank_indexes[criterion_index]] == lowest_destination_rank); - } else { - Array1D host_destination_ranks(max_destinations_count, uninitialized); - unsigned actual_destinations_count = 0; - if (highest_destination_rank - lowest_destination_rank >= max_destinations_count) { - for (unsigned destination_index = 0; destination_index != max_destinations_count; ++destination_index) { - host_destination_ranks[destination_index] = std::uniform_int_distribution(lowest_destination_rank, highest_destination_rank)(host_models_being_learned.random_generators[model_index]); - } - actual_destinations_count = max_destinations_count; - } else { - for (unsigned destination_rank = lowest_destination_rank; destination_rank <= highest_destination_rank; ++destination_rank) { - ++actual_destinations_count; - const unsigned destination_index = destination_rank - lowest_destination_rank; - host_destination_ranks[destination_index] = destination_rank; - } - assert(actual_destinations_count == highest_destination_rank - lowest_destination_rank + 1); - } - - copy(host_destination_ranks, ref(gpu_models_being_learned.destination_ranks[model_index])); - gpu_models_being_learned.desirabilities[model_index].fill_with_zeros(); - Grid grid = grid::make(preprocessed_learning_set.alternatives_count, actual_destinations_count); - compute_move_desirabilities_for_high_profile__kernel<<>>( - gpu_models_being_learned.performance_ranks, - gpu_models_being_learned.assignments, - gpu_models_being_learned.weights, - gpu_models_being_learned.single_peaked, - gpu_models_being_learned.low_profile_ranks, - gpu_models_being_learned.high_profile_rank_indexes, - gpu_models_being_learned.high_profile_ranks, - model_index, - boundary_index, - criterion_index, - actual_destinations_count, - gpu_models_being_learned.destination_ranks[model_index], - ref(gpu_models_being_learned.desirabilities[model_index])); - check_last_cuda_error_sync_stream(cudaStreamDefault); - - apply_best_move_for_high_profile__kernel<<<1, 1>>>( - gpu_models_being_learned.high_profile_rank_indexes, - ref(gpu_models_being_learned.high_profile_ranks), - model_index, - boundary_index, - criterion_index, - actual_destinations_count, - gpu_models_being_learned.destination_ranks[model_index], - gpu_models_being_learned.desirabilities[model_index], - std::uniform_real_distribution(0, 1)(host_models_being_learned.random_generators[model_index])); - check_last_cuda_error_sync_stream(cudaStreamDefault); - - assert(host_models_being_learned.high_profile_rank_indexes[criterion_index] < host_models_being_learned.high_profile_ranks.s0()); - check_cuda_error(cudaMemcpy( - host_models_being_learned.high_profile_ranks[model_index][boundary_index].data() + host_models_being_learned.high_profile_rank_indexes[criterion_index], - gpu_models_being_learned.high_profile_ranks[model_index][boundary_index].data() + host_models_being_learned.high_profile_rank_indexes[criterion_index], - 1 * sizeof(unsigned), - cudaMemcpyDeviceToHost)); - } -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.hpp deleted file mode 100644 index b5d7e37c..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic-on-gpu.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_GPU_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_GPU_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" -#include "accuracy-heuristic/desirability.hpp" - - -namespace lincs { - -#ifdef LINCS_HAS_NVCC - -class ImproveProfilesWithAccuracyHeuristicOnGpu : public LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy { - private: - struct GpuModelsBeingLearned { - GpuModelsBeingLearned(const PreprocessedLearningSet&, const ModelsBeingLearned&); - - Array2D performance_ranks; // Indexed by [criterion_index][alternative_index] - Array1D assignments; // [alternative_index] - Array1D single_peaked; // [criterion_index] - Array2D weights; // [criterion_index][model_index] - Array3D low_profile_ranks; // [criterion_index][boundary_index][model_index] - Array1D high_profile_rank_indexes; // [criterion_index] - Array3D high_profile_ranks; // [criterion_index][boundary_index][high_profile_rank_indexes[criterion_index]] - - Array2D desirabilities; // [model_index][desination_index] - Array2D destination_ranks; // [model_index][desination_index] - }; - - public: - explicit ImproveProfilesWithAccuracyHeuristicOnGpu(const PreprocessedLearningSet& preprocessed_learning_set, ModelsBeingLearned& host_models_being_learned_) : - LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy(true), - preprocessed_learning_set(preprocessed_learning_set), - host_models_being_learned(host_models_being_learned_), - gpu_models_being_learned(preprocessed_learning_set, host_models_being_learned) - {} - - public: - void improve_profiles(unsigned model_indexes_begin, unsigned model_indexes_end) override; - - private: - void improve_model_profiles(unsigned model_index); - - void improve_boundary_profiles( - unsigned model_index, - unsigned boundary_index, - ArrayView1D criterion_indexes - ); - - void improve_low_profile_then_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index - ); - - void improve_low_profile_only( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index - ); - - void improve_low_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned lowest_destination_rank, - unsigned highest_destination_rank - ); - - void improve_high_profile( - unsigned model_index, - unsigned boundary_index, - unsigned criterion_index, - unsigned lowest_destination_rank, - unsigned highest_destination_rank - ); - - private: - const PreprocessedLearningSet& preprocessed_learning_set; - ModelsBeingLearned& host_models_being_learned; - GpuModelsBeingLearned gpu_models_being_learned; - - static const unsigned max_destinations_count = 64; -}; - -#endif // LINCS_HAS_NVCC - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC_ON_GPU_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic/desirability.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic/desirability.hpp deleted file mode 100644 index aae48c6a..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/improve-profiles/accuracy-heuristic/desirability.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC__DESIRABILITY_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC__DESIRABILITY_HPP - -#include "../../../../vendored/lov-e.hpp" - - -namespace lincs { - -struct Desirability { - static constexpr float zero_value = 0; - - unsigned v = 0; - unsigned w = 0; - unsigned q = 0; - unsigned r = 0; - unsigned t = 0; - - #ifdef __CUDACC__ - __host__ __device__ - #endif - float value() const { - if (v + w + t + q + r == 0) { - return zero_value; - } else { - return (2 * v + w + 0.1 * t) / (v + w + t + 5 * q + r); - } - } -}; - -} // namespace lincs - -template<> -__inline__ -lincs::Desirability* Host::alloc(const std::size_t n) { - return Host::force_alloc(n); -} - -template<> -__inline__ -void Host::memset(const std::size_t n, const char v, lincs::Desirability* const p) { - Host::force_memset(n, v, p); -} - -#ifdef LINCS_HAS_NVCC - -template<> -__inline__ -lincs::Desirability* Device::alloc(const std::size_t n) { - return Device::force_alloc(n); -} - -template<> -__inline__ -void Device::memset(const std::size_t n, const char v, lincs::Desirability* const p) { - Device::force_memset(n, v, p); -} - -#endif // LINCS_HAS_NVCC - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__IMPROVE_PROFILES__ACCURACY_HEURISTIC__DESIRABILITY_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.cpp deleted file mode 100644 index 29aa6bde..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "probabilistic-maximal-discrimination-power-per-criterion.hpp" - -#include "../../../chrones.hpp" -#include "../../../generation.hpp" // Only for tests - -#include "../../../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace lincs { - -InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion::InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(const PreprocessedLearningSet& preprocessed_learning_set_, ModelsBeingLearned& models_being_learned_) : - LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy(true), - preprocessed_learning_set(preprocessed_learning_set_), - models_being_learned(models_being_learned_) -{ - CHRONE(); - - low_rank_generators.reserve(preprocessed_learning_set.criteria_count); - high_rank_generators.reserve(preprocessed_learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - auto& low_rank_generator = low_rank_generators.emplace_back(); - low_rank_generator.reserve(preprocessed_learning_set.boundaries_count); - auto& high_rank_generator = high_rank_generators.emplace_back(); - high_rank_generator.reserve(preprocessed_learning_set.boundaries_count); - - for (unsigned boundary_index = 0; boundary_index != preprocessed_learning_set.boundaries_count; ++boundary_index) { - low_rank_generator.emplace_back(get_candidate_probabilities_for_low_ranks(criterion_index, boundary_index)); - high_rank_generator.emplace_back(get_candidate_probabilities_for_high_ranks(criterion_index, boundary_index)); - } - } -} - -std::map InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion::get_candidate_probabilities_for_low_ranks( - unsigned criterion_index, - unsigned boundary_index -) { - CHRONE(); - - std::vector candidates_worse; - // The size used for 'reserve' is a few times larger than the actual final size, - // so we're allocating too much memory. As it's temporary, I don't think it's too bad. - // If 'initialize' ever becomes the focus for our optimization effort, we should measure. - candidates_worse.reserve(preprocessed_learning_set.alternatives_count); - std::vector candidates_better; - candidates_better.reserve(preprocessed_learning_set.alternatives_count); - // This loop could/should be done once outside this function - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - const unsigned rank = preprocessed_learning_set.performance_ranks[criterion_index][alternative_index]; - const unsigned assignment = preprocessed_learning_set.assignments[alternative_index]; - if (assignment == boundary_index) { - candidates_worse.push_back(rank); - } else if (assignment == boundary_index + 1) { - candidates_better.push_back(rank); - } - } - - if (candidates_better.empty() && candidates_worse.empty()) { - return {{{0, 1.0}}}; - } else { - std::map rank_probabilities; - - for (auto candidates : { candidates_worse, candidates_better }) { - for (auto candidate_rank : candidates) { - const bool already_evaluated = rank_probabilities.find(candidate_rank) != rank_probabilities.end(); - if (already_evaluated) { - // Candidate value has already been evaluated (because it appears several times) - continue; - } - - unsigned correctly_classified_count = 0; - // @todo(Performance, later) Could we somehow sort 'candidates_worse' and 'candidates_better' and walk the values only once? - // (Transforming this O(n²) loop in O(n*log n) + O(n)) - for (auto rank : candidates_worse) { - const bool is_better = candidate_rank > rank; - if (is_better) { - ++correctly_classified_count; - } - } - for (auto rank : candidates_better) { - const bool is_better = rank >= candidate_rank; - if (is_better) { - ++correctly_classified_count; - } - } - const double probability = static_cast(correctly_classified_count) / candidates.size(); - rank_probabilities[candidate_rank] = probability; - } - } - - assert(!rank_probabilities.empty()); - return rank_probabilities; - } -} - -std::map InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion::get_candidate_probabilities_for_high_ranks( - unsigned criterion_index, - unsigned boundary_index -) { - CHRONE(); - - std::vector candidates_worse; - // The size used for 'reserve' is a few times larger than the actual final size, - // so we're allocating too much memory. As it's temporary, I don't think it's too bad. - // If 'initialize' ever becomes the focus for our optimization effort, we should measure. - candidates_worse.reserve(preprocessed_learning_set.alternatives_count); - std::vector candidates_better; - candidates_better.reserve(preprocessed_learning_set.alternatives_count); - // This loop could/should be done once outside this function - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - const unsigned rank = preprocessed_learning_set.performance_ranks[criterion_index][alternative_index]; - const unsigned assignment = preprocessed_learning_set.assignments[alternative_index]; - if (assignment == boundary_index) { - candidates_worse.push_back(rank); - } else if (assignment == boundary_index + 1) { - candidates_better.push_back(rank); - } - } - - if (candidates_better.empty() && candidates_worse.empty()) { - return {{{preprocessed_learning_set.values_counts[criterion_index] - 1, 1.0}}}; - } else { - std::map rank_probabilities; - - for (auto candidates : { candidates_worse, candidates_better }) { - for (auto candidate_rank : candidates) { - const bool already_evaluated = rank_probabilities.find(candidate_rank) != rank_probabilities.end(); - if (already_evaluated) { - // Candidate value has already been evaluated (because it appears several times) - continue; - } - - unsigned correctly_classified_count = 0; - // @todo(Performance, later) Could we somehow sort 'candidates_worse' and 'candidates_better' and walk the values only once? - // (Transforming this O(n²) loop in O(n*log n) + O(n)) - for (auto rank : candidates_worse) { - const bool is_better = candidate_rank < rank; - if (is_better) { - ++correctly_classified_count; - } - } - for (auto rank : candidates_better) { - const bool is_better = rank <= candidate_rank; - if (is_better) { - ++correctly_classified_count; - } - } - const double probability = static_cast(correctly_classified_count) / candidates.size(); - rank_probabilities[candidate_rank] = probability; - } - } - - assert(!rank_probabilities.empty()); - return rank_probabilities; - } -} - -void InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion::initialize_profiles( - const unsigned model_indexes_begin, - const unsigned model_indexes_end -) { - CHRONE(); - - // @todo(Performance, later) Parallelize these loops? - // Embarrassingly parallel - for (unsigned model_indexes_index = model_indexes_begin; model_indexes_index < model_indexes_end; ++model_indexes_index) { - const unsigned model_index = models_being_learned.model_indexes[model_indexes_index]; - - // Embarrassingly parallel - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - // Not parallel because of the profiles ordering constraint - for (unsigned category_index = preprocessed_learning_set.categories_count - 1; category_index != 0; --category_index) { - const unsigned boundary_index = category_index - 1; - unsigned low_rank = low_rank_generators[criterion_index][boundary_index](models_being_learned.random_generators[model_index]); - - // Enforce profiles ordering constraint (1/2) - if (boundary_index != preprocessed_learning_set.boundaries_count - 1) { - low_rank = std::min(low_rank, models_being_learned.low_profile_ranks[model_index][boundary_index + 1][criterion_index]); - } - - models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] = low_rank; - - if (preprocessed_learning_set.single_peaked[criterion_index]) { - unsigned high_rank = high_rank_generators[criterion_index][boundary_index](models_being_learned.random_generators[model_index]); - - // Enforce profiles ordering constraint (2/2) - if (boundary_index == preprocessed_learning_set.boundaries_count - 1) { - high_rank = std::max(high_rank, low_rank); - } else { - high_rank = std::max(high_rank, models_being_learned.high_profile_ranks[model_index][boundary_index + 1][models_being_learned.high_profile_rank_indexes[criterion_index]]); - } - - models_being_learned.high_profile_ranks[model_index][boundary_index][models_being_learned.high_profile_rank_indexes[criterion_index]] = high_rank; - } - } - } - } -} - -TEST_CASE("Initialize profiles - respect ordering") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::increasing, 0, 1)), - Criterion("Criterion 2", Criterion::RealValues(Criterion::PreferenceDirection::decreasing, 0, 1)), - }, - { - Category("Category 1"), - Category("Category 2"), - Category("Category 3"), - } - }; - Model model = generate_mrsort_classification_model(problem, 42); - auto learning_set = generate_classified_alternatives(problem, model, 1000, 42, 0.1); - PreprocessedLearningSet preprocessed_learning_set(problem, learning_set); - LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned models_being_learned(preprocessed_learning_set, 1, 42); - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion initializer(preprocessed_learning_set, models_being_learned); - - for (unsigned iteration = 0; iteration != 10; ++iteration) { - initializer.initialize_profiles(0, 1); - // Both CHECKs fail at least once when the 'Enforce profiles ordering constraint (1/2)' code is removed - CHECK(models_being_learned.low_profile_ranks[0][0][0] <= models_being_learned.low_profile_ranks[0][1][0]); - CHECK(models_being_learned.low_profile_ranks[0][0][1] <= models_being_learned.low_profile_ranks[0][1][1]); - } -} - -TEST_CASE("Initialize profiles - respect ordering - single-peaked criteria") { - Problem problem{ - { - Criterion("Criterion 1", Criterion::RealValues(Criterion::PreferenceDirection::single_peaked, 0, 1)), - }, - { - Category("Category 1"), - Category("Category 2"), - Category("Category 3"), - } - }; - Model model = generate_mrsort_classification_model(problem, 42); - auto learning_set = generate_classified_alternatives(problem, model, 1000, 42, 0.1); - PreprocessedLearningSet preprocessed_learning_set(problem, learning_set); - LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned models_being_learned(preprocessed_learning_set, 1, 42); - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion initializer(preprocessed_learning_set, models_being_learned); - - for (unsigned iteration = 0; iteration != 10; ++iteration) { - initializer.initialize_profiles(0, 1); - // This CHECK fails at least once when the 'Enforce profiles ordering constraint (1/2)' code is removed - CHECK(models_being_learned.low_profile_ranks[0][0][0] <= models_being_learned.low_profile_ranks[0][1][0]); - // Both CHECKs fail at least once when the 'Enforce profiles ordering constraint (2/2)' code is removed - CHECK(models_being_learned.low_profile_ranks[0][1][0] <= models_being_learned.high_profile_ranks[0][1][0]); - CHECK(models_being_learned.high_profile_ranks[0][1][0] <= models_being_learned.high_profile_ranks[0][0][0]); - } -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.hpp deleted file mode 100644 index 3d6710c4..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/initialize-profiles/probabilistic-maximal-discrimination-power-per-criterion.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__INITIALIZE_PROFILES__PROBABILISTIC_MAXIMAL_DISCRIMINATION_POWER_PER_CRITERION_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__INITIALIZE_PROFILES__PROBABILISTIC_MAXIMAL_DISCRIMINATION_POWER_PER_CRITERION_HPP - -#include - -#include "../../mrsort-by-weights-profiles-breed.hpp" -#include "../../../randomness-utils.hpp" - -namespace lincs { - -class InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion : public LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy { - public: - InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(const PreprocessedLearningSet& preprocessed_learning_set, ModelsBeingLearned& models_being_learned_); - - public: - void initialize_profiles(unsigned model_indexes_begin, unsigned model_indexes_end) override; - - private: - std::map get_candidate_probabilities_for_low_ranks( - unsigned criterion_index, - unsigned boundary_index - ); - - std::map get_candidate_probabilities_for_high_ranks( - unsigned criterion_index, - unsigned boundary_index - ); - - private: - const PreprocessedLearningSet& preprocessed_learning_set; - ModelsBeingLearned& models_being_learned; - std::vector>> low_rank_generators; - std::vector>> high_rank_generators; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__INITIALIZE_PROFILES__PROBABILISTIC_MAXIMAL_DISCRIMINATION_POWER_PER_CRITERION_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.cpp deleted file mode 100644 index fa58bdca..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "linear-program.hpp" - -#include "../../../chrones.hpp" -#include "../../../linear-programming/alglib.hpp" -#include "../../../linear-programming/glop.hpp" - - -namespace lincs { - -template -void OptimizeWeightsUsingLinearProgram::optimize_weights( - const unsigned model_indexes_begin, - const unsigned model_indexes_end -) { - CHRONE(); - - const int model_indexes_end_ = model_indexes_end; - - #pragma omp parallel for - for (int model_indexes_index = model_indexes_begin; model_indexes_index < model_indexes_end_; ++model_indexes_index) { - const unsigned model_index = models_being_learned.model_indexes[model_indexes_index]; - optimize_model_weights(model_index); - } -} - -template -void OptimizeWeightsUsingLinearProgram::optimize_model_weights(unsigned model_index) { - const float epsilon = 1e-6; - LinearProgram program; - - std::vector weight_variables; // Indexed by [criterion_index] - std::vector x_variables; // [alternative_index] - std::vector xp_variables; // [alternative_index] - std::vector y_variables; // [alternative_index] - std::vector yp_variables; // [alternative_index] - - weight_variables.reserve(preprocessed_learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - weight_variables.push_back(program.create_variable()); - } - - x_variables.reserve(preprocessed_learning_set.alternatives_count); - xp_variables.reserve(preprocessed_learning_set.alternatives_count); - y_variables.reserve(preprocessed_learning_set.alternatives_count); - yp_variables.reserve(preprocessed_learning_set.alternatives_count); - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - x_variables.push_back(program.create_variable()); - xp_variables.push_back(program.create_variable()); - y_variables.push_back(program.create_variable()); - yp_variables.push_back(program.create_variable()); - } - - program.mark_all_variables_created(); - - for (unsigned alternative_index = 0; alternative_index != preprocessed_learning_set.alternatives_count; ++alternative_index) { - program.set_objective_coefficient(xp_variables[alternative_index], 1); - program.set_objective_coefficient(yp_variables[alternative_index], 1); - - const unsigned category_index = preprocessed_learning_set.assignments[alternative_index]; - - if (category_index != 0) { // Except bottom category - const unsigned boundary_index = category_index - 1; // Profile below category - auto c = program.create_constraint(); - c.set_bounds(1, 1); - c.set_coefficient(x_variables[alternative_index], -1); - c.set_coefficient(xp_variables[alternative_index], 1); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - if (LearnMrsortByWeightsProfilesBreed::is_accepted(preprocessed_learning_set, models_being_learned, model_index, boundary_index, criterion_index, alternative_index)) { - c.set_coefficient(weight_variables[criterion_index], 1); - } - } - } - - if (category_index != preprocessed_learning_set.categories_count - 1) { // Except top category - const unsigned boundary_index = category_index; // Profile above category - auto c = program.create_constraint(); - c.set_bounds(1 - epsilon, 1 - epsilon); - c.set_coefficient(y_variables[alternative_index], 1); - c.set_coefficient(yp_variables[alternative_index], -1); - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - if (LearnMrsortByWeightsProfilesBreed::is_accepted(preprocessed_learning_set, models_being_learned, model_index, boundary_index, criterion_index, alternative_index)) { - c.set_coefficient(weight_variables[criterion_index], 1); - } - } - } - } - - auto values = program.solve()->assignments; - - for (unsigned criterion_index = 0; criterion_index != preprocessed_learning_set.criteria_count; ++criterion_index) { - models_being_learned.weights[model_index][criterion_index] = values[weight_variables[criterion_index]]; - } -} - -template class OptimizeWeightsUsingLinearProgram; -template class OptimizeWeightsUsingLinearProgram; - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.hpp deleted file mode 100644 index a1195764..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/optimize-weights/linear-program.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__OPTIMIZE_WEIGHTS__LINEAR_PROGRAM_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__OPTIMIZE_WEIGHTS__LINEAR_PROGRAM_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -template -class OptimizeWeightsUsingLinearProgram : public LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy { - public: - OptimizeWeightsUsingLinearProgram(const PreprocessedLearningSet& preprocessed_learning_set_, ModelsBeingLearned& models_being_learned_) : - LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy(true), - preprocessed_learning_set(preprocessed_learning_set_), - models_being_learned(models_being_learned_) - {} - - public: - void optimize_weights(unsigned model_indexes_begin, unsigned model_indexes_end) override; - - private: - void optimize_model_weights(unsigned model_index); - - private: - const PreprocessedLearningSet& preprocessed_learning_set; - ModelsBeingLearned& models_being_learned; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__OPTIMIZE_WEIGHTS__LINEAR_PROGRAM_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations-without-progress.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations-without-progress.hpp deleted file mode 100644 index 720e03bf..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations-without-progress.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_WITHOUT_PROGRESS_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_WITHOUT_PROGRESS_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateAfterIterationsWithoutProgress : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateAfterIterationsWithoutProgress( - const ModelsBeingLearned& models_being_learned_, - const unsigned max_iterations_count_ - ) : - models_being_learned(models_being_learned_), - max_iterations_count(max_iterations_count_), - last_progress_iteration_index(0), - previous_best_accuracy(0) - {} - - public: - bool terminate() override { - const unsigned new_best_accuracy = models_being_learned.get_best_accuracy(); - if (new_best_accuracy > previous_best_accuracy) { - last_progress_iteration_index = models_being_learned.iteration_index; - previous_best_accuracy = new_best_accuracy; - return false; - } else if (models_being_learned.iteration_index - last_progress_iteration_index >= max_iterations_count) { - return true; - } else { - return false; - } - } - - private: - const ModelsBeingLearned& models_being_learned; - const unsigned max_iterations_count; - unsigned last_progress_iteration_index; - unsigned previous_best_accuracy; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_WITHOUT_PROGRESS_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations.hpp deleted file mode 100644 index a7d4d718..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-iterations.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateAfterIterations : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateAfterIterations(const ModelsBeingLearned& models_being_learned_, const unsigned max_iterations_count_) : models_being_learned(models_being_learned_), max_iterations_count(max_iterations_count_) {} - - public: - bool terminate() override { - return models_being_learned.iteration_index >= max_iterations_count - 1; - } - - private: - const ModelsBeingLearned& models_being_learned; - const unsigned max_iterations_count; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_ITERATIONS_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds-without-progress.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds-without-progress.hpp deleted file mode 100644 index cfeb7c14..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds-without-progress.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_WITHOUT_PROGRESS_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_WITHOUT_PROGRESS_HPP - -#include - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateAfterSecondsWithoutProgress : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateAfterSecondsWithoutProgress( - const ModelsBeingLearned& models_being_learned_, - const float max_seconds_ - ) : - models_being_learned(models_being_learned_), - max_seconds(max_seconds_), - last_progress_at(std::chrono::steady_clock::now()), - previous_best_accuracy(0) - {} - - public: - bool terminate() override { - const unsigned new_best_accuracy = models_being_learned.get_best_accuracy(); - if (new_best_accuracy > previous_best_accuracy) { - last_progress_at = std::chrono::steady_clock::now(); - previous_best_accuracy = new_best_accuracy; - return false; - } else if (std::chrono::duration(std::chrono::steady_clock::now() - last_progress_at).count() > max_seconds) { - return true; - } else { - return false; - } - } - - private: - const ModelsBeingLearned& models_being_learned; - const float max_seconds; - std::chrono::steady_clock::time_point last_progress_at; - unsigned previous_best_accuracy; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_WITHOUT_PROGRESS_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds.hpp deleted file mode 100644 index 749adf31..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/after-seconds.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_HPP - -#include - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateAfterSeconds : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateAfterSeconds(const float max_seconds_) : max_seconds(max_seconds_), started_at(std::chrono::steady_clock::now()) {} - - public: - bool terminate() override { - return std::chrono::duration(std::chrono::steady_clock::now() - started_at).count() > max_seconds; - } - - private: - const float max_seconds; - const std::chrono::steady_clock::time_point started_at; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AFTER_SECONDS_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.cpp deleted file mode 100644 index cb20c6f7..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "at-accuracy.hpp" - - -namespace lincs { - -bool TerminateAtAccuracy::terminate() { - return models_being_learned.get_best_accuracy() >= target_accuracy; -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.hpp deleted file mode 100644 index aaa5ad7c..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/at-accuracy.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AT_ACCURACY_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AT_ACCURACY_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateAtAccuracy : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateAtAccuracy(ModelsBeingLearned& models_being_learned_, unsigned target_accuracy_) : models_being_learned(models_being_learned_), target_accuracy(target_accuracy_) {} - - public: - bool terminate() override; - - private: - const ModelsBeingLearned& models_being_learned; - const unsigned target_accuracy; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__AT_ACCURACY_HPP diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.cpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.cpp deleted file mode 100644 index 44ceea0b..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "composite.hpp" - - -namespace lincs { - -bool TerminateWhenAny::terminate() { - for (auto termination_strategy : termination_strategies) { - if (termination_strategy->terminate()) { - return true; - } - } - - return false; -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.hpp b/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.hpp deleted file mode 100644 index cfdde59b..00000000 --- a/lincs/liblincs/learning/mrsort-by-weights-profiles-breed/terminate/composite.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__COMPOSITE_HPP -#define LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__COMPOSITE_HPP - -#include "../../mrsort-by-weights-profiles-breed.hpp" - - -namespace lincs { - -class TerminateWhenAny : public LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - public: - explicit TerminateWhenAny(const std::vector& termination_strategies_) : termination_strategies(termination_strategies_) {} - - public: - bool terminate() override; - - private: - const std::vector termination_strategies; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__MRSORT_BY_WEIGHTS_PROFILES_BREED__TERMINATE__COMPOSITE_HPP diff --git a/lincs/liblincs/learning/pre-processing.cpp b/lincs/liblincs/learning/pre-processing.cpp deleted file mode 100644 index cafead4c..00000000 --- a/lincs/liblincs/learning/pre-processing.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "pre-processing.hpp" - -#include -#include -#include - - -namespace lincs { - -PreprocessedLearningSet::PreprocessedLearningSet( - const Problem& problem_, - const Alternatives& learning_set -) : - problem(problem_), - criteria_count(problem.get_criteria().size()), - categories_count(problem.get_ordered_categories().size()), - boundaries_count(categories_count - 1), - alternatives_count(learning_set.get_alternatives().size()), - real_sorted_values(), - integer_sorted_values(), - single_peaked(criteria_count, uninitialized), - values_counts(criteria_count, uninitialized), - performance_ranks(criteria_count, alternatives_count, uninitialized), - assignments(alternatives_count, uninitialized) -{ - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - dispatch( - problem.get_criteria()[criterion_index].get_values(), - [this, &learning_set, criterion_index](const Criterion::RealValues& values) { - const bool is_increasing = values.is_increasing() || values.is_single_peaked(); - assert(is_increasing || values.is_decreasing()); - - single_peaked[criterion_index] = values.is_single_peaked(); - - std::set unique_values; - - unique_values.insert(values.get_min_value()); - unique_values.insert(values.get_max_value()); - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - unique_values.insert(learning_set.get_alternatives()[alternative_index].get_profile()[criterion_index].get_real().get_value()); - } - const unsigned values_count = unique_values.size(); - values_counts[criterion_index] = values_count; - - real_sorted_values[criterion_index].resize(values_count); - std::map value_ranks_for_criterion; - for (const float value : unique_values) { - const unsigned value_rank = is_increasing ? value_ranks_for_criterion.size() : values_count - value_ranks_for_criterion.size() - 1; - real_sorted_values[criterion_index][value_rank] = value; - value_ranks_for_criterion[value] = value_rank; - } - assert(value_ranks_for_criterion.size() == values_counts[criterion_index]); - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - const float value = learning_set.get_alternatives()[alternative_index].get_profile()[criterion_index].get_real().get_value(); - const unsigned value_rank = value_ranks_for_criterion[value]; - performance_ranks[criterion_index][alternative_index] = value_rank; - } - }, - [this, &learning_set, criterion_index](const Criterion::IntegerValues& values) { - const bool is_increasing = values.is_increasing() || values.is_single_peaked(); - assert(is_increasing || values.is_decreasing()); - - single_peaked[criterion_index] = values.is_single_peaked(); - - std::set unique_values; - - unique_values.insert(values.get_min_value()); - unique_values.insert(values.get_max_value()); - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - unique_values.insert(learning_set.get_alternatives()[alternative_index].get_profile()[criterion_index].get_integer().get_value()); - } - const unsigned values_count = unique_values.size(); - values_counts[criterion_index] = values_count; - - integer_sorted_values[criterion_index].resize(values_count); - std::map value_ranks_for_criterion; - for (const int value : unique_values) { - const unsigned value_rank = is_increasing ? value_ranks_for_criterion.size() : values_count - value_ranks_for_criterion.size() - 1; - integer_sorted_values[criterion_index][value_rank] = value; - value_ranks_for_criterion[value] = value_rank; - } - assert(value_ranks_for_criterion.size() == values_counts[criterion_index]); - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - const int value = learning_set.get_alternatives()[alternative_index].get_profile()[criterion_index].get_integer().get_value(); - const unsigned value_rank = value_ranks_for_criterion[value]; - performance_ranks[criterion_index][alternative_index] = value_rank; - } - }, - [this, &learning_set, criterion_index](const Criterion::EnumeratedValues& values) { - values_counts[criterion_index] = values.get_ordered_values().size(); - - single_peaked[criterion_index] = false; - - std::map value_ranks_for_criterion; - for (const std::string& value : values.get_ordered_values()) { - const unsigned value_rank = value_ranks_for_criterion.size(); - value_ranks_for_criterion[value] = value_rank; - } - assert(value_ranks_for_criterion.size() == values_counts[criterion_index]); - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - const std::string value = learning_set.get_alternatives()[alternative_index].get_profile()[criterion_index].get_enumerated().get_value(); - const unsigned value_rank = value_ranks_for_criterion[value]; - performance_ranks[criterion_index][alternative_index] = value_rank; - } - } - ); - } - - for (unsigned alternative_index = 0; alternative_index != alternatives_count; ++alternative_index) { - assignments[alternative_index] = *learning_set.get_alternatives()[alternative_index].get_category_index(); - } -} - -Model PreprocessedLearningSet::post_process(const std::vector& boundaries) const { - assert(boundaries.size() == boundaries_count); - - std::vector accepted_values; - accepted_values.reserve(criteria_count); - for (unsigned criterion_index = 0; criterion_index != criteria_count; ++criterion_index) { - accepted_values.push_back(dispatch( - problem.get_criteria()[criterion_index].get_values(), - [this, &boundaries, criterion_index](const Criterion::RealValues& values) { - if (values.is_single_peaked()) { - std::vector>> intervals; - intervals.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - auto [low_rank, high_rank] = std::get>(boundary.profile_ranks[criterion_index]); - if (low_rank < values_counts[criterion_index] && high_rank < values_counts[criterion_index]) { - intervals.push_back(std::make_pair(real_sorted_values.at(criterion_index)[low_rank], real_sorted_values.at(criterion_index)[high_rank])); - } else { - intervals.emplace_back(std::nullopt); - } - } - return AcceptedValues(AcceptedValues::RealIntervals(intervals)); - } else { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - const unsigned rank = std::get(boundary.profile_ranks[criterion_index]); - if (rank < values_counts[criterion_index]) { - thresholds.push_back(real_sorted_values.at(criterion_index)[rank]); - } else { - // Past-the-end rank => this criterion cannot help reach this category - thresholds.push_back(std::nullopt); - } - } - return AcceptedValues(AcceptedValues::RealThresholds(thresholds)); - } - }, - [this, &boundaries, criterion_index](const Criterion::IntegerValues& values) { - if (values.is_single_peaked()) { - std::vector>> intervals; - intervals.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - auto [low_rank, high_rank] = std::get>(boundary.profile_ranks[criterion_index]); - // Handle past-the-end ranks - low_rank = std::min(low_rank, values_counts[criterion_index] - 1); - high_rank = std::min(high_rank, values_counts[criterion_index] - 1); - intervals.push_back(std::make_pair(integer_sorted_values.at(criterion_index)[low_rank], integer_sorted_values.at(criterion_index)[high_rank])); - } - return AcceptedValues(AcceptedValues::IntegerIntervals(intervals)); - } else { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - unsigned rank = std::get(boundary.profile_ranks[criterion_index]); - if (rank < values_counts[criterion_index]) { - thresholds.push_back(integer_sorted_values.at(criterion_index)[rank]); - } else { - thresholds.push_back(std::nullopt); - } - } - return AcceptedValues(AcceptedValues::IntegerThresholds(thresholds)); - } - }, - [this, &boundaries, criterion_index](const Criterion::EnumeratedValues& values) { - std::vector> thresholds; - thresholds.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - unsigned rank = std::get(boundary.profile_ranks[criterion_index]); - if (rank < values_counts[criterion_index]) { - thresholds.push_back(values.get_ordered_values()[rank]); - } else { - thresholds.push_back(std::nullopt); - } - } - return AcceptedValues(AcceptedValues::EnumeratedThresholds(thresholds)); - })); - } - - std::vector sufficient_coalitions; - sufficient_coalitions.reserve(boundaries_count); - for (const auto& boundary: boundaries) { - sufficient_coalitions.emplace_back(boundary.sufficient_coalitions); - } - - return Model{problem, accepted_values, sufficient_coalitions}; -} - -} // namespace lincs diff --git a/lincs/liblincs/learning/pre-processing.hpp b/lincs/liblincs/learning/pre-processing.hpp deleted file mode 100644 index b7b9bc27..00000000 --- a/lincs/liblincs/learning/pre-processing.hpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__PRE_PROCESSING_HPP -#define LINCS__LEARNING__PRE_PROCESSING_HPP - -#include -#include - -#include "../vendored/lov-e.hpp" -#include "../io.hpp" - - -namespace lincs { - -struct PreprocessedBoundary { - std::vector>> profile_ranks; - SufficientCoalitions sufficient_coalitions; - - PreprocessedBoundary(const std::vector>>& profile_ranks_, const SufficientCoalitions& sufficient_coalitions_) : - profile_ranks(profile_ranks_), - sufficient_coalitions(sufficient_coalitions_) - {} -}; - -class PreprocessedLearningSet { - public: - // Not copyable - PreprocessedLearningSet(const PreprocessedLearningSet&) = delete; - PreprocessedLearningSet& operator=(const PreprocessedLearningSet&) = delete; - - // Movable - PreprocessedLearningSet(PreprocessedLearningSet&&) = default; - PreprocessedLearningSet& operator=(PreprocessedLearningSet&&) = default; - - PreprocessedLearningSet(const Problem&, const Alternatives&); - - public: - Model post_process(const std::vector&) const; - - private: - const Problem& problem; - public: - const unsigned criteria_count; - const unsigned categories_count; - const unsigned boundaries_count; - const unsigned alternatives_count; - private: - std::map> real_sorted_values; // Indexed by [criterion_index][value_rank] - std::map> integer_sorted_values; // Indexed by [criterion_index][value_rank] - public: - Array1D single_peaked; // [criterion_index] - Array1D values_counts; // [criterion_index] - Array2D performance_ranks; // [criterion_index][alternative_index] - Array1D assignments; // [alternative_index] -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__PRE_PROCESSING_HPP diff --git a/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.cpp b/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.cpp deleted file mode 100644 index 17d840ef..00000000 --- a/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.cpp +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "ucncs-by-max-sat-by-coalitions.hpp" - -#include -#include -#include - -#include "../chrones.hpp" -#include "../classification.hpp" -#include "../sat/eval-max-sat.hpp" -#include "exception.hpp" - - -namespace lincs { - -template -std::vector implies(V a, V b) { - // "A => B" <=> "-A or B" - return {-a, b}; -} - -template -Model MaxSatCoalitionsUcncsLearning::perform() { - CHRONE(); - - create_all_coalitions(); - create_variables(); - add_structural_constraints(); - add_learning_set_constraints(); - - std::optional> solution = sat.solve(); - - if (!solution) { - throw LearningFailureException("MaxSatCoalitions failed to find a solution."); - } - - return decode(*solution); -} - -template -void MaxSatCoalitionsUcncsLearning::create_all_coalitions() { - CHRONE(); - - all_coalitions.reserve(coalitions_count); - for (unsigned coalition_index = 0; coalition_index != coalitions_count; ++coalition_index) { - all_coalitions.emplace_back(learning_set.criteria_count, coalition_index); - } -} - -// This implementation was initially based on https://www.sciencedirect.com/science/article/abs/pii/S0377221721006858, -// specifically its section 5.1, with the special case for Uc-NCS at the end of the section. -// That article is a summary of this thesis: https://www.theses.fr/2022UPAST071. -// This implementation was then modified to handle single-peaked criteria (see clauses C1 below). -// See more comments in 'ucncs-by-sat-by-coalitions.cpp' - -template -void MaxSatCoalitionsUcncsLearning::create_variables() { - CHRONE(); - - // Variables "a" in the article - accepted.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - accepted[criterion_index].resize(learning_set.categories_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - accepted[criterion_index][boundary_index].resize(learning_set.values_counts[criterion_index]); - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - accepted[criterion_index][boundary_index][value_rank] = sat.create_variable(); - } - } - } - - // Variables "t" in the article - sufficient.resize(coalitions_count); - for (const Coalition& coalition : all_coalitions) { - sufficient[coalition.to_ulong()] = sat.create_variable(); - } - - // Variables "z" in the article - correct.resize(learning_set.alternatives_count); - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - correct[alternative_index] = sat.create_variable(); - } - - sat.mark_all_variables_created(); -} - -template -void MaxSatCoalitionsUcncsLearning::add_structural_constraints() { - CHRONE(); - - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - - if (learning_set.single_peaked[criterion_index]) { - if (values_count >= 3) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank_a = 0; value_rank_a != values_count - 2; ++value_rank_a) { - for (unsigned value_rank_c = value_rank_a + 2; value_rank_c != values_count; ++value_rank_c) { - sat.add_clause({ - -accepted[criterion_index][boundary_index][value_rank_a], - -accepted[criterion_index][boundary_index][value_rank_c], - accepted[criterion_index][boundary_index][value_rank_a + 1], - accepted[criterion_index][boundary_index][value_rank_c - 1], - }); - } - } - } - } - } else { - // Clauses "C1" in the article - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank = 1; value_rank != values_count; ++value_rank) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank - 1], - accepted[criterion_index][boundary_index][value_rank] - )); - } - } - } - } - - // Clauses "C2" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - for (unsigned boundary_index = 1; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank], - accepted[criterion_index][boundary_index - 1][value_rank] - )); - } - } - } - - // Clauses "C3" in the article - for (const auto& coalition_a : all_coalitions) { - for (const auto& coalition_b : all_coalitions) { - if (coalition_a.is_proper_subset_of(coalition_b)) { - sat.add_clause(implies(sufficient[coalition_a.to_ulong()], sufficient[coalition_b.to_ulong()])); - } - } - } - - // No need for clauses "C4" -} - -template -void MaxSatCoalitionsUcncsLearning::add_learning_set_constraints() { - CHRONE(); - - // Clauses "C5~" in the article - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - const unsigned category_index = learning_set.assignments[alternative_index]; - if (category_index == learning_set.categories_count - 1) { - continue; - } - - const unsigned boundary_index = category_index; - - for (const Coalition& coalition : all_coalitions) { - std::vector clause; - // Either the coalition is not sufficient... - clause.push_back(-sufficient[coalition.to_ulong()]); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - if (coalition[criterion_index]) { - const unsigned value_rank = learning_set.performance_ranks[criterion_index][alternative_index]; - assert(value_rank < accepted[criterion_index][boundary_index].size()); - // ... or the alternative is not accepted on at least one necessary criterion - clause.push_back(-accepted[criterion_index][boundary_index][value_rank]); - } - } - // ... or it's not correctly classified - clause.push_back(-correct[alternative_index]); - sat.add_clause(clause); - } - } - - // Clauses "C6~" in the article - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - const unsigned category_index = learning_set.assignments[alternative_index]; - if (category_index == 0) { - continue; - } - - const unsigned boundary_index = category_index - 1; - - for (const Coalition& coalition : all_coalitions) { - std::vector clause; - const Coalition coalition_complement = ~coalition; - clause.push_back(sufficient[coalition_complement.to_ulong()]); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - if (coalition[criterion_index]) { - const unsigned value_rank = learning_set.performance_ranks[criterion_index][alternative_index]; - assert(value_rank < accepted[criterion_index][boundary_index].size()); - clause.push_back(accepted[criterion_index][boundary_index][value_rank]); - } - } - clause.push_back(-correct[alternative_index]); - sat.add_clause(clause); - } - } - - // Clauses "goal" in the article - // Maximize the number of alternatives classified correctly - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - sat.add_weighted_clause({correct[alternative_index]}, goal_weight); - } -} - -template -Model MaxSatCoalitionsUcncsLearning::decode(const std::vector& solution) { - CHRONE(); - - std::vector roots; - for (const auto& coalition_a : all_coalitions) { - if (solution[sufficient[coalition_a.to_ulong()]]) { - bool coalition_a_is_root = true; - for (const auto& coalition_b : all_coalitions) { - if (solution[sufficient[coalition_b.to_ulong()]]) { - if (coalition_b.is_proper_subset_of(coalition_a)) { - coalition_a_is_root = false; - break; - } - } - } - if (coalition_a_is_root) { - roots.push_back(coalition_a); - } - } - } - - std::vector boundaries; - boundaries.reserve(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - std::vector>> profile_ranks(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - if (learning_set.single_peaked[criterion_index]) { - bool found = false; - unsigned low = 0; - unsigned high = values_count; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - if (!found) { - low = value_rank; - } - found = true; - high = value_rank; - } - } - if (found) { - profile_ranks[criterion_index] = std::make_pair(low, high); - } else { - profile_ranks[criterion_index] = std::make_pair(values_count, values_count); - } - } else { - bool found = false; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - profile_ranks[criterion_index] = value_rank; - found = true; - break; - } - } - if (!found) { - profile_ranks[criterion_index] = values_count; - } - } - } - - boundaries.emplace_back(profile_ranks, SufficientCoalitions(SufficientCoalitions::Roots(Internal(), roots))); - } - - const Model model = learning_set.post_process(boundaries); - #ifndef NDEBUG - unsigned expected_correct_count = 0; - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - if (solution[correct[alternative_index]]) { - ++expected_correct_count; - } - } - assert(count_correctly_classified_alternatives(input_problem, model, input_learning_set) == expected_correct_count); - #endif - return model; -} - -template class MaxSatCoalitionsUcncsLearning; - -} // namespace lincs diff --git a/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.hpp b/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.hpp deleted file mode 100644 index 2d473960..00000000 --- a/lincs/liblincs/learning/ucncs-by-max-sat-by-coalitions.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_COALITIONS_HPP -#define LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_COALITIONS_HPP - -#include "../io.hpp" -#include "pre-processing.hpp" - - -namespace lincs { - -template -class MaxSatCoalitionsUcncsLearning { - public: - template - MaxSatCoalitionsUcncsLearning(const Problem& problem, const Alternatives& learning_set_, U&&... u) : - #ifndef NDEBUG - input_problem(problem), - input_learning_set(learning_set_), - #endif - learning_set(problem, learning_set_), - coalitions_count(1 << learning_set.criteria_count), - goal_weight(1), - accepted(), - sufficient(), - sat(std::forward(u)...) - {} - - // Not copyable - MaxSatCoalitionsUcncsLearning(const MaxSatCoalitionsUcncsLearning&) = delete; - MaxSatCoalitionsUcncsLearning& operator=(const MaxSatCoalitionsUcncsLearning&) = delete; - // Could be made movable if needed - MaxSatCoalitionsUcncsLearning(MaxSatCoalitionsUcncsLearning&&) = delete; - MaxSatCoalitionsUcncsLearning& operator=(MaxSatCoalitionsUcncsLearning&&) = delete; - - public: - Model perform(); - - private: - void create_all_coalitions(); - void create_variables(); - void add_structural_constraints(); - void add_learning_set_constraints(); - Model decode(const std::vector& solution); - - private: - #ifndef NDEBUG - const Problem& input_problem; - const Alternatives& input_learning_set; - #endif - PreprocessedLearningSet learning_set; - const unsigned coalitions_count; - typedef boost::dynamic_bitset<> Coalition; - // See more comments in 'ucncs-by-sat-by-coalitions.hpp' - std::vector all_coalitions; - const typename MaxSatProblem::weight_type goal_weight; - std::vector>> accepted; - std::vector sufficient; - // correct[alternative_index]: alternative is correctly classified - std::vector correct; - MaxSatProblem sat; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_COALITIONS_HPP diff --git a/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.cpp b/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.cpp deleted file mode 100644 index ea6b3189..00000000 --- a/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.cpp +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "ucncs-by-max-sat-by-separation.hpp" - -#include -#include -#include -#include - -#include "../chrones.hpp" -#include "../classification.hpp" -#include "../sat/eval-max-sat.hpp" -#include "exception.hpp" - - -namespace lincs { - -template -std::vector implies(V a, V b) { - // "A => B" <=> "-A or B" - return {-a, b}; -} - -template -Model MaxSatSeparationUcncsLearning::perform() { - CHRONE(); - - partition_alternatives(); - create_variables(); - add_structural_constraints(); - add_learning_set_constraints(); - - std::optional> solution = sat.solve(); - - if (!solution) { - throw LearningFailureException("MaxSatSeparation failed to find a solution."); - } - - return decode(*solution); -} - -template -void MaxSatSeparationUcncsLearning::partition_alternatives() { - CHRONE(); - - better_alternative_indexes.resize(learning_set.categories_count); - worse_alternative_indexes.resize(learning_set.categories_count); - for (unsigned category_index = 0; category_index != learning_set.categories_count; ++category_index) { - better_alternative_indexes[category_index].reserve(learning_set.alternatives_count); - worse_alternative_indexes[category_index].reserve(learning_set.alternatives_count); - } - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - for (unsigned category_index = 0; category_index != learning_set.assignments[alternative_index]; ++category_index) { - better_alternative_indexes[category_index].push_back(alternative_index); - } - for (unsigned category_index = learning_set.assignments[alternative_index]; category_index != learning_set.categories_count; ++category_index) { - worse_alternative_indexes[category_index].push_back(alternative_index); - } - } - for (unsigned category_index = 0; category_index != learning_set.categories_count; ++category_index) { - assert(better_alternative_indexes[category_index].size() + worse_alternative_indexes[category_index].size() == learning_set.alternatives_count); - } -} - -// This implementation was initially based on https://www.sciencedirect.com/science/article/abs/pii/S0377221721006858, -// specifically its section B2. That article is a summary of this thesis: https://www.theses.fr/2022UPAST071. -// This implementation was then modified to handle single-peaked criteria (see clauses P'1 below). -// See more comments in 'ucncs-by-sat-by-coalitions.cpp' - -template -void MaxSatSeparationUcncsLearning::create_variables() { - CHRONE(); - - // Variables "a" in the article - accepted.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - accepted[criterion_index].resize(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - accepted[criterion_index][boundary_index].resize(learning_set.values_counts[criterion_index]); - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - accepted[criterion_index][boundary_index][value_rank] = sat.create_variable(); - } - } - } - - // Variables "s" in the article - separates.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - separates[criterion_index].resize(learning_set.boundaries_count); - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - separates[criterion_index][boundary_index_a].resize(learning_set.boundaries_count); - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - separates[criterion_index][boundary_index_a][boundary_index_b].resize(learning_set.alternatives_count); - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index].resize(learning_set.alternatives_count); - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index] = sat.create_variable(); - } - } - } - } - } - - // Variables "z" in the article - correct.resize(learning_set.alternatives_count); - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - correct[alternative_index] = sat.create_variable(); - } - - // Variables "y" in the article - proper.resize(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - proper[boundary_index].resize(learning_set.alternatives_count); - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - proper[boundary_index][alternative_index] = sat.create_variable(); - } - } - - sat.mark_all_variables_created(); -} - -template -void MaxSatSeparationUcncsLearning::add_structural_constraints() { - CHRONE(); - - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - - if (learning_set.single_peaked[criterion_index]) { - if (values_count >= 3) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank_a = 0; value_rank_a != values_count - 2; ++value_rank_a) { - for (unsigned value_rank_c = value_rank_a + 2; value_rank_c != values_count; ++value_rank_c) { - sat.add_clause({ - -accepted[criterion_index][boundary_index][value_rank_a], - -accepted[criterion_index][boundary_index][value_rank_c], - accepted[criterion_index][boundary_index][value_rank_a + 1], - accepted[criterion_index][boundary_index][value_rank_c - 1], - }); - } - } - } - } - } else { - // Clauses "P'1" in the article - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank = 1; value_rank != values_count; ++value_rank) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank - 1], - accepted[criterion_index][boundary_index][value_rank] - )); - } - } - } - } - - // Clauses "P'2" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - for (unsigned boundary_index = 1; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank], - accepted[criterion_index][boundary_index - 1][value_rank] - )); - } - } - } -} - -template -void MaxSatSeparationUcncsLearning::add_learning_set_constraints() { - CHRONE(); - - // Clauses "P'C3" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - const unsigned bad_value_rank = learning_set.performance_ranks[criterion_index][bad_alternative_index]; - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - sat.add_clause(implies( - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index], - -accepted[criterion_index][boundary_index_a][bad_value_rank] - )); - } - } - } - } - } - - // Clauses "P'C4" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - const unsigned good_value_rank = learning_set.performance_ranks[criterion_index][good_alternative_index]; - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - sat.add_clause(implies( - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index], - accepted[criterion_index][boundary_index_b][good_value_rank] - )); - } - } - } - } - } - - // Clauses "P'C5~" in the article - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - std::vector clause; - clause.reserve(learning_set.criteria_count + 2); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - clause.push_back(separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index]); - } - clause.push_back(-proper[boundary_index_a][bad_alternative_index]); - clause.push_back(-proper[boundary_index_b][good_alternative_index]); - sat.add_clause(clause); - } - } - } - } - - // Clauses "P'yz~" in the article - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_clause(implies( - correct[alternative_index], - proper[boundary_index][alternative_index] - )); - } - } - - // Maximize the number of alternatives classified correctly - // Clauses "goal" in the article - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - sat.add_weighted_clause({correct[alternative_index]}, goal_weight); - } - // Clauses "subgoals" in the article - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_weighted_clause({proper[boundary_index][alternative_index]}, subgoal_weight); - } - } -} - -template -Model MaxSatSeparationUcncsLearning::decode(const std::vector& solution) { - CHRONE(); - - std::vector>>> profile_ranks(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - std::vector>>& ranks = profile_ranks[boundary_index]; - ranks.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - if (learning_set.single_peaked[criterion_index]) { - bool found = false; - unsigned low = 0; - unsigned high = values_count; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - if (!found) { - low = value_rank; - } - found = true; - high = value_rank; - } - } - if (found) { - ranks[criterion_index] = std::make_pair(low, high); - } else { - ranks[criterion_index] = std::make_pair(values_count, values_count); - } - } else { - bool found = false; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - ranks[criterion_index] = value_rank; - found = true; - break; - } - } - if (!found) { - ranks[criterion_index] = values_count; - } - } - } - } - - std::set> sufficient_coalitions; - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index]) { - if (!solution[correct[good_alternative_index]]) { - // Alternative is not correctly classified, it does not participate - continue; - } - - boost::dynamic_bitset<> coalition(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned performance_rank = learning_set.performance_ranks[criterion_index][good_alternative_index]; - const auto profile_rank = profile_ranks[boundary_index][criterion_index]; - const bool is_accepted = ([&]() { - if (learning_set.single_peaked[criterion_index]) { - const auto [low, high] = std::get>(profile_rank); - return low <= performance_rank && performance_rank <= high; - } else { - const unsigned rank = std::get(profile_rank); - return performance_rank >= rank; - } - })(); - if (is_accepted) { - coalition.set(criterion_index); - } - } - sufficient_coalitions.insert(coalition); - } - } - std::vector> roots; - for (const auto& coalition_a : sufficient_coalitions) { - bool coalition_a_is_root = true; - for (const auto& coalition_b : sufficient_coalitions) { - if (coalition_b.is_proper_subset_of(coalition_a)) { - coalition_a_is_root = false; - break; - } - } - if (coalition_a_is_root) { - roots.push_back(coalition_a); - } - } - - std::vector boundaries; - boundaries.reserve(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - boundaries.emplace_back(profile_ranks[boundary_index], SufficientCoalitions(SufficientCoalitions::Roots(Internal(), roots))); - } - - const Model model = learning_set.post_process(boundaries); - #ifndef NDEBUG - unsigned expected_correct_count = 0; - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - if (solution[correct[alternative_index]]) { - ++expected_correct_count; - } - } - assert(count_correctly_classified_alternatives(input_problem, model, input_learning_set) == expected_correct_count); - #endif - return model; -} - -template class MaxSatSeparationUcncsLearning; - -} // namespace lincs diff --git a/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.hpp b/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.hpp deleted file mode 100644 index 4d747791..00000000 --- a/lincs/liblincs/learning/ucncs-by-max-sat-by-separation.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_SEPARATION_HPP -#define LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_SEPARATION_HPP - -#include "../io.hpp" -#include "pre-processing.hpp" - - -namespace lincs { - -template -class MaxSatSeparationUcncsLearning { - public: - template - MaxSatSeparationUcncsLearning(const Problem& problem, const Alternatives& learning_set_, U&&... u) : - #ifndef NDEBUG - input_problem(problem), - input_learning_set(learning_set_), - #endif - learning_set(problem, learning_set_), - subgoal_weight(1), - goal_weight(learning_set.boundaries_count * learning_set.alternatives_count), - better_alternative_indexes(), - worse_alternative_indexes(), - accepted(), - separates(), - sat(std::forward(u)...) - {} - - public: - Model perform(); - - private: - void sort_values(); - void partition_alternatives(); - void create_variables(); - void add_structural_constraints(); - void add_learning_set_constraints(); - Model decode(const std::vector& solution); - - private: - #ifndef NDEBUG - const Problem& input_problem; - const Alternatives& input_learning_set; - #endif - PreprocessedLearningSet learning_set; - const typename MaxSatProblem::weight_type subgoal_weight; - const typename MaxSatProblem::weight_type goal_weight; - // See more comments in 'ucncs-by-sat-by-coalitions.hpp' and 'ucncs-by-sat-by-separation.hpp' - std::vector> better_alternative_indexes; - std::vector> worse_alternative_indexes; - std::vector>> accepted; - std::vector>>>> separates; - std::vector correct; - std::vector> proper; - MaxSatProblem sat; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__UCNCS_BY_MAX_SAT_BY_SEPARATION_HPP diff --git a/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.cpp b/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.cpp deleted file mode 100644 index 693aa544..00000000 --- a/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "ucncs-by-sat-by-coalitions.hpp" - -#include -#include -#include - -#include "../chrones.hpp" -#include "../classification.hpp" -#include "../sat/minisat.hpp" -#include "exception.hpp" - - -namespace lincs { - -// @todo(Project management, later) Factorize common parts of all SAT approaches -// For example: -// - 'decode' is almost identical between the 'by separation' approaches -// - 'decode' is identical between the 'by coalitions' approaches -// - 'add_structural_constraints' are identical between the 'by coalitions' approaches -// - 'add_structural_constraints' are identical between the 'by separation' approaches -// - 'add_structural_constraints' have a common part between all approaches -// - 'add_learning_set_constraints' have a common part between the 'by separation' approaches -// But: -// - 'add_learning_set_constraints' are very similar, but fundamentally different between 'by coalitions' approaches - -template -std::vector implies(V a, V b) { - // "A => B" <=> "-A or B" - return {-a, b}; -} - -template -Model SatCoalitionsUcncsLearning::perform() { - CHRONE(); - - create_all_coalitions(); - create_variables(); - add_structural_constraints(); - add_learning_set_constraints(); - - std::optional> solution = sat.solve(); - - if (!solution) { - throw LearningFailureException("SatCoalitions failed to find a solution."); - } - - return decode(*solution); -} - -template -void SatCoalitionsUcncsLearning::create_all_coalitions() { - CHRONE(); - - all_coalitions.reserve(coalitions_count); - for (unsigned coalition_index = 0; coalition_index != coalitions_count; ++coalition_index) { - all_coalitions.emplace_back(learning_set.criteria_count, coalition_index); - } -} - -// This implementation was initially based on https://www.sciencedirect.com/science/article/abs/pii/S0377221721006858, -// specifically its "Definition 4.1", with the special case for Uc-NCS at the end of section 4.1. -// That article is a summary of this thesis: https://www.theses.fr/2022UPAST071. -// This implementation was then modified to handle single-peaked criteria (see clauses C1 below). - -template -void SatCoalitionsUcncsLearning::create_variables() { - CHRONE(); - - // Variables "a" in the article - accepted.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - accepted[criterion_index].resize(learning_set.categories_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - accepted[criterion_index][boundary_index].resize(learning_set.values_counts[criterion_index]); - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - accepted[criterion_index][boundary_index][value_rank] = sat.create_variable(); - } - } - } - - // Variables "t" in the article - sufficient.resize(coalitions_count); - for (const Coalition& coalition : all_coalitions) { - sufficient[coalition.to_ulong()] = sat.create_variable(); - } - - sat.mark_all_variables_created(); -} - -template -void SatCoalitionsUcncsLearning::add_structural_constraints() { - CHRONE(); - - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - - if (learning_set.single_peaked[criterion_index]) { - // In this branch, "accepted" means "inside the interval" - - if (values_count >= 3) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank_a = 0; value_rank_a != values_count - 2; ++value_rank_a) { - for (unsigned value_rank_c = value_rank_a + 2; value_rank_c != values_count; ++value_rank_c) { - sat.add_clause({ - -accepted[criterion_index][boundary_index][value_rank_a], - -accepted[criterion_index][boundary_index][value_rank_c], - // These two variables are the same when value_rank_c == value_rank_a + 2, but it doesn't hurt - accepted[criterion_index][boundary_index][value_rank_a + 1], - accepted[criterion_index][boundary_index][value_rank_c - 1], - }); - } - } - } - } - } else { - // In this branch, "accepted" means "above the profile" - - // Clauses "C1" in the article - // Values are ordered so if a value is above a profile, then values above it are also above that profile - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank = 1; value_rank != values_count; ++value_rank) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank - 1], - accepted[criterion_index][boundary_index][value_rank] - )); - } - } - } - } - - // Clauses "C2" in the article - // Boundaries are ordered so if a value is accepted by a boundary, then it is also accepted by less strict boundaries - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - for (unsigned boundary_index = 1; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank], - accepted[criterion_index][boundary_index - 1][value_rank] - )); - } - } - } - - // Clauses "C3" in the article - // Coalitions form an upset so if a coalition is sufficient, then all coalitions that include it are sufficient too - // @todo(Performance, later) Optimize this nested loop using the fact that a is included in b - // Or even better, add constraints only for the transitive reduction of the inclusion relation - // Same in "max-SAT by coalitions" approach - for (const auto& coalition_a : all_coalitions) { - for (const auto& coalition_b : all_coalitions) { - if (coalition_a.is_proper_subset_of(coalition_b)) { - sat.add_clause(implies(sufficient[coalition_a.to_ulong()], sufficient[coalition_b.to_ulong()])); - } - } - } - - // No need for clauses "C4", as stated in the special case for Uc-NCS -} - -template -void SatCoalitionsUcncsLearning::add_learning_set_constraints() { - CHRONE(); - - // Clauses "C5" in the article - // Alternatives are not accepted by the boundary of the category better than theirs - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - const unsigned category_index = learning_set.assignments[alternative_index]; - if (category_index == learning_set.categories_count - 1) { - continue; - } - - // This boundary barely doesn't accept the alternative, so it can't accept the alternative on a sufficient coalition - const unsigned boundary_index = category_index; - - for (const Coalition& coalition : all_coalitions) { - std::vector clause; - // Either the coalition is not sufficient... - clause.push_back(-sufficient[coalition.to_ulong()]); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - if (coalition[criterion_index]) { - const unsigned value_rank = learning_set.performance_ranks[criterion_index][alternative_index]; - assert(value_rank < accepted[criterion_index][boundary_index].size()); - // ... or the alternative is not accepted on at least one necessary criterion - clause.push_back(-accepted[criterion_index][boundary_index][value_rank]); - } - } - sat.add_clause(clause); - } - } - - // Clauses "C6" in the article - // Alternatives are accepted by the boundary of their category - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - const unsigned category_index = learning_set.assignments[alternative_index]; - if (category_index == 0) { - continue; - } - - // This boundary barely accepts the alternative, so it has to accept the alternative on a sufficient coalition - const unsigned boundary_index = category_index - 1; - - for (const Coalition& coalition : all_coalitions) { - std::vector clause; - const Coalition coalition_complement = ~coalition; - clause.push_back(sufficient[coalition_complement.to_ulong()]); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - if (coalition[criterion_index]) { - const unsigned value_rank = learning_set.performance_ranks[criterion_index][alternative_index]; - assert(value_rank < accepted[criterion_index][boundary_index].size()); - clause.push_back(accepted[criterion_index][boundary_index][value_rank]); - } - } - sat.add_clause(clause); - } - } -} - -template -Model SatCoalitionsUcncsLearning::decode(const std::vector& solution) { - CHRONE(); - - std::vector roots; - for (const auto& coalition_a : all_coalitions) { - if (solution[sufficient[coalition_a.to_ulong()]]) { - bool coalition_a_is_root = true; - // @todo(Performance, later) Optimize this search for actual roots; it may be something like a transitive reduction - // Same in "max-SAT by coalitions" approach - // Same in "SAT by separation" approach - // Same in "max-SAT by separation" approach - for (const auto& coalition_b : all_coalitions) { - if (solution[sufficient[coalition_b.to_ulong()]]) { - if (coalition_b.is_proper_subset_of(coalition_a)) { - coalition_a_is_root = false; - break; - } - } - } - if (coalition_a_is_root) { - roots.push_back(coalition_a); - } - } - } - - std::vector boundaries; - boundaries.reserve(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - std::vector>> profile_ranks(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - if (learning_set.single_peaked[criterion_index]) { - // In this branch, "accepted" means "inside the interval" - - bool found = false; - unsigned low = 0; - unsigned high = values_count; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - if (!found) { - low = value_rank; - } - found = true; - high = value_rank; - } - } - if (found) { - profile_ranks[criterion_index] = std::make_pair(low, high); - } else { - // Past-the-end rank - profile_ranks[criterion_index] = std::make_pair(values_count, values_count); - } - } else { - // In this branch, "accepted" means "above the profile" - - bool found = false; - // @todo(Performance, later) Replace next loop with a binary search - // Same in "max-SAT by coalitions" approach - // Same in "SAT by separation" approach - // Same in "max-SAT by separation" approach - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - profile_ranks[criterion_index] = value_rank; - found = true; - break; - } - } - if (!found) { - // Past-the-end rank - profile_ranks[criterion_index] = values_count; - } - } - } - - boundaries.emplace_back(profile_ranks, SufficientCoalitions(SufficientCoalitions::Roots(Internal(), roots))); - } - - const Model model = learning_set.post_process(boundaries); - assert(count_correctly_classified_alternatives(input_problem, model, input_learning_set) == learning_set.alternatives_count); - return model; -} - -template class SatCoalitionsUcncsLearning; - -} // namespace lincs diff --git a/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.hpp b/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.hpp deleted file mode 100644 index 717baeed..00000000 --- a/lincs/liblincs/learning/ucncs-by-sat-by-coalitions.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__UCNCS_BY_SAT_BY_COALITIONS_HPP -#define LINCS__LEARNING__UCNCS_BY_SAT_BY_COALITIONS_HPP - -#include "../io.hpp" -#include "pre-processing.hpp" - - -namespace lincs { - -template -class SatCoalitionsUcncsLearning { - public: - template - SatCoalitionsUcncsLearning(const Problem& problem, const Alternatives& learning_set_, U&&... u) : - #ifndef NDEBUG - input_problem(problem), - input_learning_set(learning_set_), - #endif - learning_set(problem, learning_set_), - coalitions_count(1 << learning_set.criteria_count), - accepted(), - sufficient(), - sat(std::forward(u)...) - {} - - // Not copyable - SatCoalitionsUcncsLearning(const SatCoalitionsUcncsLearning&) = delete; - SatCoalitionsUcncsLearning& operator=(const SatCoalitionsUcncsLearning&) = delete; - // Could be made movable if needed - SatCoalitionsUcncsLearning(SatCoalitionsUcncsLearning&&) = delete; - SatCoalitionsUcncsLearning& operator=(SatCoalitionsUcncsLearning&&) = delete; - - public: - Model perform(); - - private: - void create_all_coalitions(); - void create_variables(); - void add_structural_constraints(); - void add_learning_set_constraints(); - Model decode(const std::vector& solution); - - private: - #ifndef NDEBUG - const Problem& input_problem; - const Alternatives& input_learning_set; - #endif - PreprocessedLearningSet learning_set; - const unsigned coalitions_count; - // @todo(Performance, later) Dematerialize 'all_coalitions': - // use a more abstract class that can be used in place of the current std::vector> - // Same in "max-SAT by coalitions" - typedef boost::dynamic_bitset<> Coalition; - std::vector all_coalitions; - // accepted[criterion_index][boundary_index][value_rank]: value is accepted by boundary on criterion (above profile for monotonous criteria, inside interval for single-peaked criteria) - std::vector>> accepted; - // sufficient[coalition.to_ulong()]: coalition is sufficient - std::vector sufficient; - SatProblem sat; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__UCNCS_BY_SAT_BY_COALITIONS_HPP diff --git a/lincs/liblincs/learning/ucncs-by-sat-by-separation.cpp b/lincs/liblincs/learning/ucncs-by-sat-by-separation.cpp deleted file mode 100644 index 6c8f9b12..00000000 --- a/lincs/liblincs/learning/ucncs-by-sat-by-separation.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "ucncs-by-sat-by-separation.hpp" - -#include -#include -#include -#include - -#include "../chrones.hpp" -#include "../classification.hpp" -#include "../sat/minisat.hpp" -#include "exception.hpp" - - -namespace lincs { - -template -std::vector implies(V a, V b) { - // "A => B" <=> "-A or B" - return {-a, b}; -} - -template -Model SatSeparationUcncsLearning::perform() { - CHRONE(); - - partition_alternatives(); - create_variables(); - add_structural_constraints(); - add_learning_set_constraints(); - - std::optional> solution = sat.solve(); - - if (!solution) { - throw LearningFailureException("SatSeparation failed to find a solution."); - } - - return decode(*solution); -} - -template -void SatSeparationUcncsLearning::partition_alternatives() { - CHRONE(); - - better_alternative_indexes.resize(learning_set.categories_count); - worse_alternative_indexes.resize(learning_set.categories_count); - for (unsigned category_index = 0; category_index != learning_set.categories_count; ++category_index) { - better_alternative_indexes[category_index].reserve(learning_set.alternatives_count); - worse_alternative_indexes[category_index].reserve(learning_set.alternatives_count); - } - for (unsigned alternative_index = 0; alternative_index != learning_set.alternatives_count; ++alternative_index) { - for (unsigned category_index = 0; category_index != learning_set.assignments[alternative_index]; ++category_index) { - better_alternative_indexes[category_index].push_back(alternative_index); - } - for (unsigned category_index = learning_set.assignments[alternative_index]; category_index != learning_set.categories_count; ++category_index) { - worse_alternative_indexes[category_index].push_back(alternative_index); - } - } - for (unsigned category_index = 0; category_index != learning_set.categories_count; ++category_index) { - assert(better_alternative_indexes[category_index].size() + worse_alternative_indexes[category_index].size() == learning_set.alternatives_count); - } -} - -// This implementation was initially based on https://www.sciencedirect.com/science/article/abs/pii/S0377221721006858, -// specifically its "Definition A.2", which references its "Definition 4.4". -// These definitions are based on its "Theorem 4.2". -// That article is a summary of this thesis: https://www.theses.fr/2022UPAST071. -// This implementation was then modified to handle single-peaked criteria (see clauses P'1 below). -// See more comments in 'ucncs-by-sat-by-coalitions.cpp' and 'ucncs-by-sat-by-separation.cpp'. - -template -void SatSeparationUcncsLearning::create_variables() { - CHRONE(); - - // Variables "a" in the article - accepted.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - accepted[criterion_index].resize(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - accepted[criterion_index][boundary_index].resize(learning_set.values_counts[criterion_index]); - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - accepted[criterion_index][boundary_index][value_rank] = sat.create_variable(); - } - } - } - - // Variables "s" in the article - separates.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - separates[criterion_index].resize(learning_set.boundaries_count); - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - separates[criterion_index][boundary_index_a].resize(learning_set.boundaries_count); - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - separates[criterion_index][boundary_index_a][boundary_index_b].resize(learning_set.alternatives_count); - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index].resize(learning_set.alternatives_count); - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index] = sat.create_variable(); - } - } - } - } - } - - sat.mark_all_variables_created(); -} - -template -void SatSeparationUcncsLearning::add_structural_constraints() { - CHRONE(); - - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - - if (learning_set.single_peaked[criterion_index]) { - if (values_count >= 3) { - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank_a = 0; value_rank_a != values_count - 2; ++value_rank_a) { - for (unsigned value_rank_c = value_rank_a + 2; value_rank_c != values_count; ++value_rank_c) { - sat.add_clause({ - -accepted[criterion_index][boundary_index][value_rank_a], - -accepted[criterion_index][boundary_index][value_rank_c], - accepted[criterion_index][boundary_index][value_rank_a + 1], - accepted[criterion_index][boundary_index][value_rank_c - 1], - }); - } - } - } - } - } else { - // Clauses "P'1" in the article - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned value_rank = 1; value_rank != values_count; ++value_rank) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank - 1], - accepted[criterion_index][boundary_index][value_rank] - )); - } - } - } - } - - // Clauses "P'2" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned value_rank = 0; value_rank != learning_set.values_counts[criterion_index]; ++value_rank) { - for (unsigned boundary_index = 1; boundary_index != learning_set.boundaries_count; ++boundary_index) { - sat.add_clause(implies( - accepted[criterion_index][boundary_index][value_rank], - accepted[criterion_index][boundary_index - 1][value_rank] - )); - } - } - } -} - -template -void SatSeparationUcncsLearning::add_learning_set_constraints() { - CHRONE(); - - // Clauses "P'C3" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - const unsigned bad_value_rank = learning_set.performance_ranks[criterion_index][bad_alternative_index]; - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - sat.add_clause(implies( - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index], - -accepted[criterion_index][boundary_index_a][bad_value_rank] - )); - } - } - } - } - } - - // Clauses "P'C4" in the article - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - const unsigned good_value_rank = learning_set.performance_ranks[criterion_index][good_alternative_index]; - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - sat.add_clause(implies( - separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index], - accepted[criterion_index][boundary_index_b][good_value_rank] - )); - } - } - } - } - } - - // Clauses "P'C5" in the article - for (unsigned boundary_index_a = 0; boundary_index_a != learning_set.boundaries_count; ++boundary_index_a) { - for (unsigned boundary_index_b = 0; boundary_index_b != learning_set.boundaries_count; ++boundary_index_b) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index_b]) { - for (unsigned bad_alternative_index : worse_alternative_indexes[boundary_index_a]) { - std::vector clause; - clause.reserve(learning_set.criteria_count + 1); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - clause.push_back(separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index]); - } - sat.add_clause(clause); - } - } - } - } -} - -template -Model SatSeparationUcncsLearning::decode(const std::vector& solution) { - CHRONE(); - - std::vector>>> profile_ranks(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - std::vector>>& ranks = profile_ranks[boundary_index]; - ranks.resize(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned values_count = learning_set.values_counts[criterion_index]; - if (learning_set.single_peaked[criterion_index]) { - bool found = false; - unsigned low = 0; - unsigned high = values_count; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - if (!found) { - low = value_rank; - } - found = true; - high = value_rank; - } - } - if (found) { - ranks[criterion_index] = std::make_pair(low, high); - } else { - ranks[criterion_index] = std::make_pair(values_count, values_count); - } - } else { - bool found = false; - for (unsigned value_rank = 0; value_rank != values_count; ++value_rank) { - if (solution[accepted[criterion_index][boundary_index][value_rank]]) { - ranks[criterion_index] = value_rank; - found = true; - break; - } - } - if (!found) { - ranks[criterion_index] = values_count; - } - } - } - } - - std::set> sufficient_coalitions; - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - for (unsigned good_alternative_index : better_alternative_indexes[boundary_index]) { - boost::dynamic_bitset<> coalition(learning_set.criteria_count); - for (unsigned criterion_index = 0; criterion_index != learning_set.criteria_count; ++criterion_index) { - const unsigned performance_rank = learning_set.performance_ranks[criterion_index][good_alternative_index]; - const auto profile_rank = profile_ranks[boundary_index][criterion_index]; - const bool is_accepted = ([&]() { - if (learning_set.single_peaked[criterion_index]) { - const auto [low, high] = std::get>(profile_rank); - return low <= performance_rank && performance_rank <= high; - } else { - const unsigned rank = std::get(profile_rank); - return performance_rank >= rank; - } - })(); - if (is_accepted) { - coalition.set(criterion_index); - } - } - sufficient_coalitions.insert(coalition); - } - } - std::vector> roots; - for (const auto& coalition_a : sufficient_coalitions) { - bool coalition_a_is_root = true; - for (const auto& coalition_b : sufficient_coalitions) { - if (coalition_b.is_proper_subset_of(coalition_a)) { - coalition_a_is_root = false; - break; - } - } - if (coalition_a_is_root) { - roots.push_back(coalition_a); - } - } - - std::vector boundaries; - boundaries.reserve(learning_set.boundaries_count); - for (unsigned boundary_index = 0; boundary_index != learning_set.boundaries_count; ++boundary_index) { - boundaries.emplace_back(profile_ranks[boundary_index], SufficientCoalitions(SufficientCoalitions::Roots(Internal(), roots))); - } - - const Model model = learning_set.post_process(boundaries); - assert(count_correctly_classified_alternatives(input_problem, model, input_learning_set) == learning_set.alternatives_count); - return model; -} - -template class SatSeparationUcncsLearning; - -} // namespace lincs diff --git a/lincs/liblincs/learning/ucncs-by-sat-by-separation.hpp b/lincs/liblincs/learning/ucncs-by-sat-by-separation.hpp deleted file mode 100644 index 6e501159..00000000 --- a/lincs/liblincs/learning/ucncs-by-sat-by-separation.hpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LEARNING__UCNCS_BY_SAT_BY_SEPARATION_HPP -#define LINCS__LEARNING__UCNCS_BY_SAT_BY_SEPARATION_HPP - -#include "../io.hpp" -#include "pre-processing.hpp" - - -namespace lincs { - -template -class SatSeparationUcncsLearning { - public: - template - SatSeparationUcncsLearning(const Problem& problem, const Alternatives& learning_set_, U&&... u) : - #ifndef NDEBUG - input_problem(problem), - input_learning_set(learning_set_), - #endif - learning_set(problem, learning_set_), - better_alternative_indexes(), - worse_alternative_indexes(), - accepted(), - separates(), - sat(std::forward(u)...) - {} - - public: - Model perform(); - - private: - void partition_alternatives(); - void create_variables(); - void add_structural_constraints(); - void add_learning_set_constraints(); - Model decode(const std::vector& solution); - - private: - #ifndef NDEBUG - const Problem& input_problem; - const Alternatives& input_learning_set; - #endif - PreprocessedLearningSet learning_set; - // Alternatives better than category k - std::vector> better_alternative_indexes; - // Alternatives in category k or worse - std::vector> worse_alternative_indexes; - // See more comments in 'ucncs-by-sat-by-coalitions.hpp' - std::vector>> accepted; - // separates[criterion_index][boundary_index_a][boundary_index_b][good_alternative_index][bad_alternative_index]: - // criterion separates alternatives 'good' and 'bad' with regards to profiles 'a' and 'b' - std::vector>>>> separates; - SatProblem sat; -}; - -} // namespace lincs - -#endif // LINCS__LEARNING__UCNCS_BY_SAT_BY_SEPARATION_HPP diff --git a/lincs/liblincs/liblincs-module/converters.cpp b/lincs/liblincs/liblincs-module/converters.cpp deleted file mode 100644 index 17140593..00000000 --- a/lincs/liblincs/liblincs-module/converters.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include -#include -#include -#include - -#include "../lincs.hpp" -#include "../vendored/lov-e.hpp" -#include "../vendored/pybind11/pybind11.h" -#include "../vendored/pybind11/stl.h" - - -namespace py = pybind11; - -namespace lincs { - -void enroll_standard_converters(py::module& m) { - py::class_( - m, - "UniformRandomBitsGenerator", - "Random number generator." - ) - .def( - "__call__", - &std::mt19937::operator(), - "Generate the next pseudo-random integer." - ) - ; -} - -} // namespace lincs - -namespace lincs { - -void enroll_love_converters(py::module& m) { - py::class_>(m, "Array1D") - .def("__len__", &Array1D::s0) - .def("__getitem__", [](const Array1D& c, unsigned i) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - return c[i]; - }) - .def("__setitem__", [](Array1D& c, unsigned i, bool v) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - c[i] = v; - }) - ; - py::class_>(m, "Array1D") - .def("__len__", &Array1D::s0) - .def("__getitem__", [](const Array1D& c, unsigned i) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - return c[i]; - }) - .def("__setitem__", [](Array1D& c, unsigned i, unsigned v) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - c[i] = v; - }) - ; - py::class_>(m, "ArrayView1D") - .def("__len__", &ArrayView1D::s0) - .def("__getitem__", [](const ArrayView1D& c, unsigned i) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - return c[i]; - }) - .def("__setitem__", [](ArrayView1D& c, unsigned i, unsigned v) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - c[i] = v; - }) - ; - py::class_>(m, "Array2D") - .def("__len__", &Array2D::s1) - .def("__getitem__", [](const Array2D& c, unsigned i) { - if (i >= c.s1()) { - throw pybind11::index_error(); - } - return c[i]; - }) - ; - py::class_>(m, "ArrayView2D") - .def("__len__", &ArrayView2D::s1) - .def("__getitem__", [](const ArrayView2D& c, unsigned i) { - if (i >= c.s1()) { - throw pybind11::index_error(); - } - return c[i]; - }) - ; - py::class_>(m, "Array3D") - .def("__len__", &Array3D::s2) - .def("__getitem__", [](const Array3D& c, unsigned i) { - if (i >= c.s2()) { - throw pybind11::index_error(); - } - return c[i]; - }) - ; - py::class_>(m, "ArrayView1D") - .def("__len__", &ArrayView1D::s0) - .def("__getitem__", [](const ArrayView1D& c, unsigned i) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - return c[i]; - }) - .def("__setitem__", [](ArrayView1D& c, unsigned i, float v) { - if (i >= c.s0()) { - throw pybind11::index_error(); - } - c[i] = v; - }) - ; - py::class_>(m, "Array2D") - .def("__len__", &Array2D::s1) - .def("__getitem__", [](const Array2D& c, unsigned i) { - if (i >= c.s1()) { - throw pybind11::index_error(); - } - return c[i]; - }) - ; -} - -void enroll_converters(py::module& m) { - enroll_love_converters(m); - enroll_standard_converters(m); -} - -} // namespace lincs diff --git a/lincs/liblincs/liblincs-module/generation-functions.cpp b/lincs/liblincs/liblincs-module/generation-functions.cpp deleted file mode 100644 index 460b923e..00000000 --- a/lincs/liblincs/liblincs-module/generation-functions.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "../classification.hpp" -#include "../generation.hpp" -#include "../vendored/pybind11/pybind11.h" -#include "../vendored/pybind11/stl.h" - - -namespace py = pybind11; -using namespace pybind11::literals; - -namespace lincs { - -void define_generation_functions(py::module& m) { - m.def( - "generate_classification_problem", - &lincs::generate_classification_problem, - "criteria_count"_a, "categories_count"_a, "random_seed"_a, "normalized_min_max"_a=true, "allowed_preference_directions"_a=std::vector{lincs::Criterion::PreferenceDirection::increasing}, "allowed_value_types"_a=std::vector{lincs::Criterion::ValueType::real}, - "Generate a :py:class:`Problem` with ``criteria_count`` criteria and ``categories_count`` categories." - ); - m.def( - "generate_mrsort_classification_model", - &lincs::generate_mrsort_classification_model, - "problem"_a, "random_seed"_a, "fixed_weights_sum"_a=std::optional(), - "Generate an MR-Sort model for the provided :py:class:`Problem`." - ); - - py::register_exception(m, "BalancedAlternativesGenerationException"); - - m.def( - "generate_classified_alternatives", - &lincs::generate_classified_alternatives, - "problem"_a, "model"_a, "alternatives_count"_a, "random_seed"_a, "max_imbalance"_a=std::optional(), - "Generate a set of ``alternatives_count`` pseudo-random alternatives for the provided :py:class:`Problem`, classified according to the provided :py:class:`Model`." - ); - m.def( - "misclassify_alternatives", - &lincs::misclassify_alternatives, - "problem"_a, "alternatives"_a, "count"_a, "random_seed"_a, - "Misclassify ``count`` alternatives from the provided :py:class:`Alternatives`." - ); - - py::class_(m, "ClassificationResult", "Return type for ``classify_alternatives``.") - .def_readonly("changed", &lincs::ClassificationResult::changed, "Number of alternatives that were not in the same category before and after classification.") - .def_readonly("unchanged", &lincs::ClassificationResult::unchanged, "Number of alternatives that were in the same category before and after classification.") - ; - m.def( - "classify_alternatives", - &lincs::classify_alternatives, - "problem"_a, "model"_a, "alternatives"_a, - "Classify the provided :py:class:`Alternatives` according to the provided :py:class:`Model`." - ); -} - -} // namespace lincs diff --git a/lincs/liblincs/liblincs-module/io-classes.cpp b/lincs/liblincs/liblincs-module/io-classes.cpp deleted file mode 100644 index 5b1e38f6..00000000 --- a/lincs/liblincs/liblincs-module/io-classes.cpp +++ /dev/null @@ -1,786 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include -#include - -#include "../io.hpp" -#include "../vendored/magic_enum.hpp" -#include "../vendored/pybind11/pybind11.h" -#include "../vendored/pybind11/operators.h" -#include "../vendored/pybind11/stl.h" - - -namespace py = pybind11; -using namespace pybind11::literals; - -namespace { - -class PythonOutputDevice : public boost::iostreams::sink { - public: - explicit PythonOutputDevice(py::object out_file_) : out_file(out_file_) {} - - std::streamsize write(const char* s, std::streamsize n) { - out_file.attr("write")(std::string(s, n)); - return n; - } - - private: - py::object out_file; -}; - -void dump_problem(const lincs::Problem& problem, py::object& out_file) { - boost::iostreams::stream out_stream(out_file); - problem.dump(out_stream); -} - -void dump_model(const lincs::Model& model, const lincs::Problem& problem, py::object& out_file) { - boost::iostreams::stream out_stream(out_file); - model.dump(problem, out_stream); -} - -void dump_alternatives(const lincs::Alternatives& alternatives, const lincs::Problem& problem, py::object& out_file) { - boost::iostreams::stream out_stream(out_file); - alternatives.dump(problem, out_stream); -} - -class PythonInputDevice : public boost::iostreams::source { - public: - explicit PythonInputDevice(py::object in_file_) : in_file(in_file_) {} - - std::streamsize read(char* s, std::streamsize n) { - std::string str = in_file.attr("read")(n).cast(); - std::copy(str.begin(), str.end(), s); - return str.size(); - } - - private: - py::object in_file; -}; - -lincs::Problem load_problem(py::object& in_file) { - boost::iostreams::stream in_stream(in_file); - return lincs::Problem::load(in_stream); -} - -lincs::Model load_model(const lincs::Problem& problem, py::object& in_file) { - boost::iostreams::stream in_stream(in_file); - return lincs::Model::load(problem, in_stream); -} - -lincs::Alternatives load_alternatives(const lincs::Problem& problem, py::object& in_file) { - boost::iostreams::stream in_stream(in_file); - return lincs::Alternatives::load(problem, in_stream); -} - -template -auto auto_enum(Scope& scope, const char* name, const char* docstring = nullptr) { - auto e = py::enum_(scope, name, docstring); - for(T value : magic_enum::enum_values()) { - e.value(std::string(magic_enum::enum_name(value)).c_str(), value); - } - return e; -} - -// Inspired by https://stackoverflow.com/a/57643845/905845 -template -V variant_cast(const py::object& obj) { - if constexpr (I < std::variant_size_v) { - try { - return obj.cast>(); - } catch (py::cast_error&) { - return variant_cast(obj); - } - } - throw py::cast_error(); -} - -} // namespace - -namespace lincs { - -void define_problem_classes(py::module& m) { - auto criterion_class = py::class_( - m, - "Criterion", - "A classification criterion, to be used in a classification :py:class:`Problem`." - ) - .def_property_readonly("name", &lincs::Criterion::get_name, "The name of the criterion.") - .def_property_readonly("value_type", &lincs::Criterion::get_value_type, "The type of values for this criterion.") - .def_property_readonly("is_real", &lincs::Criterion::is_real, "``True`` if the criterion is real-valued.") - .def_property_readonly("is_integer", &lincs::Criterion::is_integer, "``True`` if the criterion is integer-valued.") - .def_property_readonly("is_enumerated", &lincs::Criterion::is_enumerated, "``True`` if the criterion takes enumerated values.") - // @todo(Project management, later) Expose all our 'std::variant's as 'Union's; this is easy now that we use pybind11 - // @todo(Project management, even later, when we drop Python 3.9) Deprecate the discriminated accessors like below, and rely on on 'match/case' (available since Python 3.10). - .def_property_readonly("real_values", &lincs::Criterion::get_real_values, "Descriptor of the real values allowed for this criterion, accessible if ``is_real``.") - .def_property_readonly("integer_values", &lincs::Criterion::get_integer_values, "Descriptor of the integer values allowed for this criterion, accessible if ``is_integer``.") - .def_property_readonly("enumerated_values", &lincs::Criterion::get_enumerated_values, "Descriptor of the enumerated values allowed for this criterion, accessible if ``is_enumerated``.") - .def(py::pickle( - [](const lincs::Criterion& criterion) { - return std::visit( - [&criterion](const auto& values) { return py::make_tuple(criterion.get_name(), values); }, - criterion.get_values() - ); - }, - [](py::tuple t) { - return lincs::Criterion(t[0].cast(), variant_cast(t[1])); - } - )) - .def(py::self == py::self) // Private, undocumented, used only for our tests - ; - - auto_enum( - criterion_class, - "ValueType", - "The different types of values for a criterion." - ); - - auto_enum( - criterion_class, - "PreferenceDirection", - "What values are preferred for a criterion." - ) - .value("isotone", lincs::Criterion::PreferenceDirection::isotone) - .value("antitone", lincs::Criterion::PreferenceDirection::antitone) - ; - - py::class_( - criterion_class, - "RealValues", - "Descriptor of the real values allowed for a criterion." - ) - .def( - py::init(), - "preference_direction"_a, "min_value"_a, "max_value"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("preference_direction", &lincs::Criterion::RealValues::get_preference_direction, "The preference direction for this criterion.") - .def_property_readonly("is_increasing", &lincs::Criterion::RealValues::is_increasing, "``True`` if the criterion has increasing preference direction.") - .def_property_readonly("is_decreasing", &lincs::Criterion::RealValues::is_decreasing, "``True`` if the criterion has decreasing preference direction.") - .def_property_readonly("is_single_peaked", &lincs::Criterion::RealValues::is_single_peaked, "``True`` if the criterion has single-peaked preference direction.") - .def_property_readonly("min_value", &lincs::Criterion::RealValues::get_min_value, "The minimum value allowed for this criterion.") - .def_property_readonly("max_value", &lincs::Criterion::RealValues::get_max_value, "The maximum value allowed for this criterion.") - .def(py::pickle( - [](const lincs::Criterion::RealValues& values) { - return py::make_tuple(values.get_preference_direction(), values.get_min_value(), values.get_max_value()); - }, - [](py::tuple t) { - return lincs::Criterion::RealValues(t[0].cast(), t[1].cast(), t[2].cast()); - } - )) - ; - - py::class_( - criterion_class, - "IntegerValues", - "Descriptor of the integer values allowed for a criterion." - ) - .def( - py::init(), - "preference_direction"_a, "min_value"_a, "max_value"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("preference_direction", &lincs::Criterion::IntegerValues::get_preference_direction, "The preference direction for this criterion.") - .def_property_readonly("is_increasing", &lincs::Criterion::IntegerValues::is_increasing, "``True`` if the criterion has increasing preference direction.") - .def_property_readonly("is_decreasing", &lincs::Criterion::IntegerValues::is_decreasing, "``True`` if the criterion has decreasing preference direction.") - .def_property_readonly("is_single_peaked", &lincs::Criterion::IntegerValues::is_single_peaked, "``True`` if the criterion has single-peaked preference direction.") - .def_property_readonly("min_value", &lincs::Criterion::IntegerValues::get_min_value, "The minimum value allowed for this criterion.") - .def_property_readonly("max_value", &lincs::Criterion::IntegerValues::get_max_value, "The maximum value allowed for this criterion.") - .def(py::pickle( - [](const lincs::Criterion::IntegerValues& values) { - return py::make_tuple(values.get_preference_direction(), values.get_min_value(), values.get_max_value()); - }, - [](py::tuple t) { - return lincs::Criterion::IntegerValues(t[0].cast(), t[1].cast(), t[2].cast()); - } - )) - ; - - criterion_class.attr("EnumeratedValues") = py::class_( - criterion_class, - "EnumeratedValues", - "Descriptor of the enumerated values allowed for a criterion." - ) - .def(py::init>(), - "ordered_values"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("ordered_values", &lincs::Criterion::EnumeratedValues::get_ordered_values, "The values for this criterion, from the worst to the best.") - .def("get_value_rank", &lincs::Criterion::EnumeratedValues::get_value_rank, "value"_a, "Get the rank of a given value.") - .def(py::pickle( - [](const lincs::Criterion::EnumeratedValues& values) { - return py::make_tuple(values.get_ordered_values()); - }, - [](py::tuple t) { - return lincs::Criterion::EnumeratedValues(t[0].cast>()); - } - )) - ; - - criterion_class - .def( - py::init(), - "name"_a, "values"_a, - "Constructor for real-valued criterion." - ) - .def( - py::init(), - "name"_a, "values"_a, - "Constructor for integer-valued criterion." - ) - .def( - py::init(), - "name"_a, "values"_a, - "Constructor for criterion with enumerated values." - ) - ; - - py::class_( - m, - "Category", - "A category of a classification :py:class:`Problem`." - ) - .def( - py::init(), - "name"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("name", &lincs::Category::get_name, "The name of this category.") - .def(py::pickle( - [](const lincs::Category& category) { - return py::make_tuple(category.get_name()); - }, - [](py::tuple t) { - return lincs::Category(t[0].cast()); - } - )) - ; - - auto problem_class = py::class_( - m, - "Problem", - "A classification problem, with criteria and categories." - ) - .def( - py::init, std::vector>(), - "criteria"_a, "ordered_categories"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("criteria", &lincs::Problem::get_criteria, "The criteria of this problem.") - .def_property_readonly("ordered_categories", &lincs::Problem::get_ordered_categories, "The categories of this problem, from the worst to the best.") - .def( - "dump", - &dump_problem, - "out"_a, - "Dump the problem to the provided ``.write``-supporting file-like object, in YAML format." - ) - .def_static( - "load", - &load_problem, - "in"_a, - "Load a problem from the provided ``.read``-supporting file-like object, in YAML format." - ) - .def(py::pickle( - [](const lincs::Problem& problem) { - return py::make_tuple( - problem.get_criteria(), - problem.get_ordered_categories() - ); - }, - [](py::tuple t) { - return lincs::Problem( - t[0].cast>(), - t[1].cast>() - ); - } - )) - ; - problem_class.attr("JSON_SCHEMA") = lincs::Problem::json_schema; -} - -void define_model_classes(py::module& m) { - auto accepted_values_class = py::class_( - m, - "AcceptedValues", - "The values accepted by a model for a criterion." - ) - .def_property_readonly("value_type", &lincs::AcceptedValues::get_value_type, "The type of values for the corresponding criterion.") - .def_property_readonly("is_real", &lincs::AcceptedValues::is_real, "``True`` if the corresponding criterion is real-valued.") - .def_property_readonly("is_integer", &lincs::AcceptedValues::is_integer, "``True`` if the corresponding criterion is integer-valued.") - .def_property_readonly("is_enumerated", &lincs::AcceptedValues::is_enumerated, "``True`` if the corresponding criterion takes enumerated values.") - .def_property_readonly("kind", &lincs::AcceptedValues::get_kind, "The kind of descriptor for these accepted values.") - .def_property_readonly("is_thresholds", &lincs::AcceptedValues::is_thresholds, "``True`` if the descriptor is a set of thresholds.") - .def_property_readonly("is_intervals", &lincs::AcceptedValues::is_intervals, "``True`` if the descriptor is a set of intervals.") - .def_property_readonly("real_thresholds", &lincs::AcceptedValues::get_real_thresholds, "Descriptor of the real thresholds, accessible if ``is_real and is_thresholds``.") - .def_property_readonly("integer_thresholds", &lincs::AcceptedValues::get_integer_thresholds, "Descriptor of the integer thresholds, accessible if ``is_integer and is_thresholds``.") - .def_property_readonly("enumerated_thresholds", &lincs::AcceptedValues::get_enumerated_thresholds, "Descriptor of the enumerated thresholds, accessible if ``is_enumerated and is_thresholds``.") - .def_property_readonly("real_intervals", &lincs::AcceptedValues::get_real_intervals, "Descriptor of the real intervals, accessible if ``is_real and is_intervals``.") - .def_property_readonly("integer_intervals", &lincs::AcceptedValues::get_integer_intervals, "Descriptor of the integer intervals, accessible if ``is_integer and is_intervals``.") - .def(py::pickle( - [](const lincs::AcceptedValues& accepted_values) { - return std::visit( - [&accepted_values](const auto& thresholds) { return py::make_tuple(thresholds); }, - accepted_values.get() - ); - }, - [](py::tuple t) { - return lincs::AcceptedValues(variant_cast(t[0])); - } - )) - ; - - auto_enum( - accepted_values_class, - "Kind", - "The different kinds of descriptors for accepted values." - ); - - py::class_( - accepted_values_class, - "RealThresholds", - "Descriptor for thresholds for an real-valued criterion." - ) - .def( - py::init>&>(), - "thresholds"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("thresholds", &lincs::AcceptedValues::RealThresholds::get_thresholds, "The thresholds for this descriptor.") - .def(py::pickle( - [](const lincs::AcceptedValues::RealThresholds& thresholds) { - return py::make_tuple(thresholds.get_thresholds()); - }, - [](py::tuple t) { - return lincs::AcceptedValues::RealThresholds(t[0].cast>>()); - } - )) - ; - - py::class_( - accepted_values_class, - "IntegerThresholds", - "Descriptor for thresholds for an integer-valued criterion." - ) - .def( - py::init>&>(), - "thresholds"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("thresholds", &lincs::AcceptedValues::IntegerThresholds::get_thresholds, "The thresholds for this descriptor.") - .def(py::pickle( - [](const lincs::AcceptedValues::IntegerThresholds& thresholds) { - return py::make_tuple(thresholds.get_thresholds()); - }, - [](py::tuple t) { - return lincs::AcceptedValues::IntegerThresholds(t[0].cast>>()); - } - )) - ; - - py::class_( - accepted_values_class, - "EnumeratedThresholds", - "Descriptor for thresholds for a criterion taking enumerated values." - ) - .def( - py::init>&>(), - "thresholds"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("thresholds", &lincs::AcceptedValues::EnumeratedThresholds::get_thresholds, "The thresholds for this descriptor.") - .def(py::pickle( - [](const lincs::AcceptedValues::EnumeratedThresholds& thresholds) { - return py::make_tuple(thresholds.get_thresholds()); - }, - [](py::tuple t) { - return lincs::AcceptedValues::EnumeratedThresholds(t[0].cast>>()); - } - )) - ; - - py::class_( - accepted_values_class, - "RealIntervals", - "Descriptor for intervals for an real-valued criterion." - ) - .def( - py::init>>&>(), - "intervals"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("intervals", &lincs::AcceptedValues::RealIntervals::get_intervals, "The intervals for this descriptor.") - .def(py::pickle( - [](const lincs::AcceptedValues::RealIntervals& intervals) { - return py::make_tuple(intervals.get_intervals()); - }, - [](py::tuple t) { - return lincs::AcceptedValues::RealIntervals(t[0].cast>>>()); - } - )) - ; - - py::class_( - accepted_values_class, - "IntegerIntervals", - "Descriptor for intervals for an integer-valued criterion." - ) - .def( - py::init>>&>(), - "intervals"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("intervals", &lincs::AcceptedValues::IntegerIntervals::get_intervals, "The intervals for this descriptor.") - .def(py::pickle( - [](const lincs::AcceptedValues::IntegerIntervals& intervals) { - return py::make_tuple(intervals.get_intervals()); - }, - [](py::tuple t) { - return lincs::AcceptedValues::IntegerIntervals(t[0].cast>>>()); - } - )) - ; - - accepted_values_class - .def( - py::init(), - "values"_a, - "Constructor for thresholds on a real-valued criterion." - ) - .def( - py::init(), - "values"_a, - "Constructor for thresholds on an integer-valued criterion." - ) - .def( - py::init(), - "values"_a, - "Constructor for thresholds on an enumerated criterion." - ) - .def( - py::init(), - "values"_a, - "Constructor for intervals on a real-valued criterion." - ) - .def( - py::init(), - "values"_a, - "Constructor for intervals on an integer-valued criterion." - ) - ; - - auto sufficient_coalitions_class = py::class_( - m, - "SufficientCoalitions", - "The coalitions of sufficient criteria to accept an alternative in a category." - ) - .def_property_readonly("kind", &lincs::SufficientCoalitions::get_kind, "The kind of descriptor for these sufficient coalitions.") - .def_property_readonly("is_weights", &lincs::SufficientCoalitions::is_weights, "``True`` if the descriptor is a set of weights.") - .def_property_readonly("is_roots", &lincs::SufficientCoalitions::is_roots, "``True`` if the descriptor is a set of roots.") - .def_property_readonly("weights", &lincs::SufficientCoalitions::get_weights, "Descriptor of the weights, accessible if ``is_weights``.") - .def_property_readonly("roots", &lincs::SufficientCoalitions::get_roots, "Descriptor of the roots, accessible if ``is_roots``.") - .def(py::pickle( - [](const lincs::SufficientCoalitions& sufficient_coalitions) { - return std::visit( - [&sufficient_coalitions](const auto& descriptor) { return py::make_tuple(descriptor); }, - sufficient_coalitions.get() - ); - }, - [](py::tuple t) { - return lincs::SufficientCoalitions(variant_cast(t[0])); - } - )) - .def(py::self == py::self) - ; - - auto_enum( - sufficient_coalitions_class, - "Kind", - "The different kinds of descriptors for sufficient coalitions." - ); - - py::class_( - sufficient_coalitions_class, - "Weights", - "Descriptor for sufficient coalitions defined by weights." - ) - .def( - py::init&>(), - "criterion_weights"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("criterion_weights", &lincs::SufficientCoalitions::Weights::get_criterion_weights, "The weights for each criterion.") - .def(py::pickle( - [](const lincs::SufficientCoalitions::Weights& weights) { - return py::make_tuple(weights.get_criterion_weights()); - }, - [](py::tuple t) { - return lincs::SufficientCoalitions::Weights(t[0].cast>()); - } - )) - ; - - py::class_( - sufficient_coalitions_class, - "Roots", - "Descriptor for sufficient coalitions defined by roots." - ) - .def( - py::init>&>(), - "problem"_a, "upset_roots"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("upset_roots", &lincs::SufficientCoalitions::Roots::get_upset_roots_as_vectors, "The roots of the upset of sufficient coalitions.") - .def(py::pickle( - [](const lincs::SufficientCoalitions::Roots& roots) { - const auto& bitsets = roots.get_upset_roots_as_bitsets(); - if (bitsets.empty()) { - return py::make_tuple(0, std::vector>()); - } else { - return py::make_tuple(bitsets[0].size(), roots.get_upset_roots_as_vectors()); - } - }, - [](py::tuple t) { - return lincs::SufficientCoalitions::Roots( - lincs::Internal(), - t[0].cast(), - t[1].cast>>() - ); - } - )) - ; - - sufficient_coalitions_class - .def( - py::init(), - "weights"_a, - "Constructor for sufficient coalitions defined by weights." - ) - .def( - py::init(), - "roots"_a, - "Constructor for sufficient coalitions defined by roots." - ) - ; - - auto model_class = py::class_( - m, - "Model", - "An NCS classification model." - ) - .def( - py::init&, const std::vector&>(), - "problem"_a, "accepted_values"_a, "sufficient_coalitions"_a, - "The :py:class:`Model` being initialized must correspond to the given :py:class:`Problem`. Other parameters map exactly to attributes with identical names." - ) - .def_property_readonly("accepted_values", &lincs::Model::get_accepted_values, "The accepted values for each criterion.") - .def_property_readonly("sufficient_coalitions", &lincs::Model::get_sufficient_coalitions, "The sufficient coalitions for each category.") - .def( - "dump", - &dump_model, - "problem"_a, "out"_a, - "Dump the model to the provided ``.write``-supporting file-like object, in YAML format." - ) - .def_static( - "load", - &load_model, - "problem"_a, "in"_a, - "Load a model for the provided ``Problem``, from the provided ``.read``-supporting file-like object, in YAML format." - ) - .def(py::pickle( - [](const lincs::Model& model) { - return py::make_tuple( - model.get_accepted_values(), - model.get_sufficient_coalitions() - ); - }, - [](py::tuple t) { - return lincs::Model( - lincs::Internal(), - t[0].cast>(), - t[1].cast>() - ); - } - )) - ; - model_class.attr("JSON_SCHEMA") = lincs::Model::json_schema; -} - -void define_alternative_classes(py::module& m) { - auto performance_class = py::class_( - m, - "Performance", - "The performance of an alternative on a criterion." - ) - .def_property_readonly("value_type", &lincs::Performance::get_value_type, "The type of values for the corresponding criterion.") - .def_property_readonly("is_real", &lincs::Performance::is_real, "``True`` if the corresponding criterion is real-valued.") - .def_property_readonly("is_integer", &lincs::Performance::is_integer, "``True`` if the corresponding criterion is integer-valued.") - .def_property_readonly("is_enumerated", &lincs::Performance::is_enumerated, "``True`` if the corresponding criterion takes enumerated values.") - .def_property_readonly("real", &lincs::Performance::get_real, "The real performance, accessible if ``is_real``.") - .def_property_readonly("integer", &lincs::Performance::get_integer, "The integer performance, accessible if ``is_integer``.") - .def_property_readonly("enumerated", &lincs::Performance::get_enumerated, "The enumerated performance, accessible if ``is_enumerated``.") - .def(py::pickle( - [](const lincs::Performance& performance) { - return std::visit( - [&performance](const auto& perf) { return py::make_tuple(perf); }, - performance.get() - ); - }, - [](py::tuple t) { - return lincs::Performance(variant_cast(t[0])); - } - )) - ; - - py::class_( - performance_class, - "Real", - "A performance for a real-valued criterion." - ) - .def( - py::init(), - "value"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("value", &lincs::Performance::Real::get_value, "The numerical value of the real performance.") - .def(py::pickle( - [](const lincs::Performance::Real& real) { - return py::make_tuple(real.get_value()); - }, - [](py::tuple t) { - return lincs::Performance::Real(t[0].cast()); - } - )) - ; - - py::class_( - performance_class, - "Integer", - "A performance for an integer-valued criterion." - ) - .def( - py::init(), - "value"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("value", &lincs::Performance::Integer::get_value, "The numerical value of the integer performance.") - .def(py::pickle( - [](const lincs::Performance::Integer& integer) { - return py::make_tuple(integer.get_value()); - }, - [](py::tuple t) { - return lincs::Performance::Integer(t[0].cast()); - } - )) - ; - - py::class_( - performance_class, - "Enumerated", - "A performance for a criterion taking enumerated values." - ) - .def( - py::init(), - "value"_a, - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("value", &lincs::Performance::Enumerated::get_value, "The string value of the enumerated performance.") - .def(py::pickle( - [](const lincs::Performance::Enumerated& enumerated) { - return py::make_tuple(enumerated.get_value()); - }, - [](py::tuple t) { - return lincs::Performance::Enumerated(t[0].cast()); - } - )) - ; - - performance_class - .def( - py::init(), - "performance"_a, - "Constructor for a real-valued performance." - ) - .def( - py::init(), - "performance"_a, - "Constructor for an integer-valued performance." - ) - .def( - py::init(), - "performance"_a, - "Constructor for an enumerated performance." - ) - ; - - py::class_( - m, - "Alternative", - "An alternative, with its performance on each criterion, maybe classified." - ) - .def( - py::init, std::optional>(), - "name"_a, "profile"_a, "category_index"_a=std::optional(), - "Parameters map exactly to attributes with identical names." - ) - .def_property_readonly("name", &lincs::Alternative::get_name, "The name of the alternative.") - .def_property_readonly("profile", &lincs::Alternative::get_profile, "The performance profile of the alternative.") - .def_property("category_index", &lincs::Alternative::get_category_index, &lincs::Alternative::set_category_index, "The index of the category of the alternative, if it is classified.") - .def(py::pickle( - [](const lincs::Alternative& alternative) { - return py::make_tuple(alternative.get_name(), alternative.get_profile(), alternative.get_category_index()); - }, - [](py::tuple t) { - return lincs::Alternative( - t[0].cast(), - t[1].cast>(), - t[2].cast>() - ); - } - )) - ; - - py::class_( - m, - "Alternatives", - "A set of alternatives, maybe classified." - ) - .def( - py::init&>(), - "problem"_a, "alternatives"_a, - "The :py:class:`Alternatives` being initialized must correspond to the given :py:class:`Problem`. Other parameters map exactly to attributes with identical names." - ) - .def_property_readonly("alternatives", &lincs::Alternatives::get_alternatives, "The :py:class:`Alternative` objects in this set.") - .def( - "dump", - &dump_alternatives, - "problem"_a, "out"_a, - "Dump the set of alternatives to the provided ``.write``-supporting file-like object, in CSV format." - ) - .def_static( - "load", - &load_alternatives, - "problem"_a, "in"_a, - "Load a set of alternatives (classified or not) from the provided ``.read``-supporting file-like object, in CSV format." - ) - .def(py::pickle( - [](const lincs::Alternatives& alternatives) { - return py::make_tuple(alternatives.get_alternatives()); - }, - [](py::tuple t) { - return lincs::Alternatives( - lincs::Internal(), - t[0].cast>() - ); - } - )) - ; -} - -void define_io_classes(py::module& m) { - py::register_exception(m, "DataValidationException"); - - define_problem_classes(m); - define_model_classes(m); - define_alternative_classes(m); -} - -} // namespace lincs diff --git a/lincs/liblincs/liblincs-module/learning-classes.cpp b/lincs/liblincs/liblincs-module/learning-classes.cpp deleted file mode 100644 index 135efa5a..00000000 --- a/lincs/liblincs/liblincs-module/learning-classes.cpp +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "../learning.hpp" -#include "../vendored/pybind11/pybind11.h" -#include "../vendored/pybind11/stl.h" - - -namespace py = pybind11; -using namespace pybind11::literals; - -namespace lincs { - -void define_learning_classes(py::module& m) { - py::register_exception(m, "LearningFailureException"); - - auto learn_wbp_class = py::class_( - m, - "LearnMrsortByWeightsProfilesBreed", - "The approach described in Olivier Sobrie's PhD thesis to learn MR-Sort models." - ) - .def("perform", &lincs::LearnMrsortByWeightsProfilesBreed::perform, "Actually perform the learning and return the learned model.") - ; - - py::class_( - m, - "PreprocessedLearningSet", - "A representation of a learning set with its data normalized as ranks (unsigned integers)." - ) - .def( - py::init(), - "problem"_a, "learning_set"_a, - "Constructor, pre-processing the learning set into a simpler form for learning.", - py::keep_alive<1, 2>() - // No reference kept on 'learning_set' => no py::keep_alive<1, 3>() - ) - .def_readonly("criteria_count", &lincs::PreprocessedLearningSet::criteria_count, "Number of criteria in the :py:class:`Problem`.") - .def_readonly("categories_count", &lincs::PreprocessedLearningSet::categories_count, "Number of categories in the :py:class:`Problem`.") - .def_readonly("boundaries_count", &lincs::PreprocessedLearningSet::boundaries_count, "Number of boundaries in the :py:class:`Problem`, *i.e* ``categories_count - 1``.") - .def_readonly("alternatives_count", &lincs::PreprocessedLearningSet::alternatives_count, "Number of alternatives in the ``learning_set``.") - .def_readonly("single_peaked", &lincs::PreprocessedLearningSet::single_peaked, "Indexed by ``[criterion_index]``. Whether each criterion is single-peaked or not.") - .def_readonly("values_counts", &lincs::PreprocessedLearningSet::values_counts, "Indexed by ``[criterion_index]``. Number of different values for each criterion, in the ``learning_set`` and min and max values for numerical criteria.") - .def_readonly("performance_ranks", &lincs::PreprocessedLearningSet::performance_ranks, "Indexed by ``[criterion_index][alternative_index]``. Rank of each alternative in the ``learning_set`` for each criterion.") - .def_readonly("assignments", &lincs::PreprocessedLearningSet::assignments, "Indexed by ``[alternative_index]``. Category index of each alternative in the ``learning_set``.") - ; - - py::class_( - learn_wbp_class, - "ModelsBeingLearned", - "Data shared by all the strategies used in this learning." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_count"_a, "random_seed"_a, - "Constructor, allocating but not initializing data about models about to be learned.", - py::keep_alive<1, 2>() - ) - .def_readonly("models_count", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::models_count, "The number of in-progress models for this learning.") - .def_readonly("random_generators", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::random_generators, "Indexed by ``[model_index]``. Random number generators associated to each in-progress model.") - .def_readonly("iteration_index", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::iteration_index, "The index of the current iteration of the WPB algorithm.") - .def_readonly("model_indexes", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::model_indexes, "Indexed by ``0`` to ``models_count - 1``. Indexes of in-progress models ordered by increasing accuracy.") - .def_readonly("accuracies", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::accuracies, "Indexed by ``[model_index]``. Accuracy of each in-progress model.") - .def_readonly("low_profile_ranks", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::low_profile_ranks, "Indexed by ``[model_index][boundary_index][criterion_index]``. The current rank of each low profile, for each model and criterion.") - .def_readonly("high_profile_rank_indexes", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::high_profile_rank_indexes, "Indexed by ``[criterion_index]``. The index in ``high_profile_ranks``, for each single-peaked criterion.") - .def_readonly("high_profile_ranks", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::high_profile_ranks, "Indexed by ``[model_index][boundary_index][high_profile_rank_indexes[criterion_index]]``. The current rank of each high profile, for each model and single-peaked criterion.") - .def_readonly("weights", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::weights, "Indexed by ``[model_index][criterion_index]``. The current MR-Sort weight of each criterion for each model.") - .def("get_best_accuracy", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::get_best_accuracy, "Return the accuracy of the best model so far.") - .def("get_best_model", &lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned::get_best_model, "Return the best model so far.") - ; - - struct PyProfilesInitializationStrategy : lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy { - using lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy::ProfilesInitializationStrategy; - void initialize_profiles(const unsigned begin, const unsigned end) override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy, - initialize_profiles, - begin, end - ); - } - }; - - py::class_( - learn_wbp_class, - "ProfilesInitializationStrategy", - "Abstract base class for profiles initialization strategies." - ) - .def(py::init(), py::arg("supports_single_peaked_criteria") = false) - .def( - "initialize_profiles", - &lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy::initialize_profiles, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Method to override. Should initialize all ``low_profile_ranks`` and ``high_profile_ranks`` of models at indexes in ``[model_indexes[i] for i in range(model_indexes_begin, model_indexes_end)]``." - ) - ; - - struct PyWeightsOptimizationStrategy : lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy { - using lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy::WeightsOptimizationStrategy; - void optimize_weights(const unsigned begin, const unsigned end) override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy, - optimize_weights, - begin, end - ); - } - }; - - py::class_( - learn_wbp_class, - "WeightsOptimizationStrategy", - "Abstract base class for weights optimization strategies." - ) - .def(py::init(), py::arg("supports_single_peaked_criteria") = false) - .def( - "optimize_weights", - &lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy::optimize_weights, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Method to override. Should optimize ``weights`` of models at indexes in ``[model_indexes[i] for i in range(model_indexes_begin, model_indexes_end)]``." - ) - ; - - struct PyProfilesImprovementStrategy : lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy { - using lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy::ProfilesImprovementStrategy; - void improve_profiles(const unsigned begin, const unsigned end) override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy, - improve_profiles, - begin, end - ); - } - }; - - py::class_( - learn_wbp_class, - "ProfilesImprovementStrategy", - "Abstract base class for profiles improvement strategies." - ) - .def(py::init(), py::arg("supports_single_peaked_criteria") = false) - .def( - "improve_profiles", - &lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy::improve_profiles, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Method to override. Should improve ``low_profile_ranks`` and ``high_profile_ranks`` of models at indexes in ``[model_indexes[i] for i in range(model_indexes_begin, model_indexes_end)]``." - ) - ; - - struct PyBreedingStrategy : lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy { - using lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy::BreedingStrategy; - void breed() override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy, - breed - ); - } - }; - - py::class_( - learn_wbp_class, - "BreedingStrategy", - "Abstract base class for breeding strategies." - ) - .def(py::init(), py::arg("supports_single_peaked_criteria") = false) - .def( - "breed", - &lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy::breed, - "Method to override." - ) - ; - - struct PyTerminationStrategy : lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy { - using lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy::TerminationStrategy; - bool terminate() override { - PYBIND11_OVERRIDE_PURE( - bool, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy, - terminate - ); - } - }; - - py::class_( - learn_wbp_class, - "TerminationStrategy", - "Abstract base class for termination strategies." - ) - .def(py::init<>()) - .def( - "terminate", - &lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy::terminate, - "Method to override. Should return ``True`` if the learning should stop, ``False`` otherwise." - ) - ; - - struct PyObserver : lincs::LearnMrsortByWeightsProfilesBreed::Observer { - using lincs::LearnMrsortByWeightsProfilesBreed::Observer::Observer; - void after_iteration() override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::Observer, - after_iteration - ); - } - void before_return() override { - PYBIND11_OVERRIDE_PURE( - void, - lincs::LearnMrsortByWeightsProfilesBreed::Observer, - before_return - ); - } - }; - - py::class_( - learn_wbp_class, - "Observer", - "Abstract base class for observation strategies." - ) - .def(py::init<>()) - .def( - "after_iteration", - &lincs::LearnMrsortByWeightsProfilesBreed::Observer::after_iteration, - "Method to override. Called after each iteration. Should not change anything in the learning data." - ) - .def( - "before_return", - &lincs::LearnMrsortByWeightsProfilesBreed::Observer::before_return, - "Method to override. Called just before returning the learned model. Should not change anything in the learning data." - ) - ; - - learn_wbp_class - .def( - py::init< - const PreprocessedLearningSet&, - lincs::LearnMrsortByWeightsProfilesBreed::ModelsBeingLearned&, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy&, - lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy&, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy&, - lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy&, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy&, - std::vector - >(), - "preprocessed_learning_set"_a, - "models_being_learned"_a, - "profiles_initialization_strategy"_a, - "weights_optimization_strategy"_a, - "profiles_improvement_strategy"_a, - "breeding_strategy"_a, - "termination_strategy"_a, - "observers"_a=std::vector{}, - "Constructor accepting the strategies to use for each step of the learning.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>(), - py::keep_alive<1, 4>(), - py::keep_alive<1, 5>(), - py::keep_alive<1, 6>(), - py::keep_alive<1, 7>(), - py::keep_alive<1, 8>(), - py::keep_alive<1, 9>() - ) - ; - - py::class_< - lincs::InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesInitializationStrategy - >( - m, - "InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion", - "The profiles initialization strategy described in Olivier Sobrie's PhD thesis." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_being_learned"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>() - ) - .def( - "initialize_profiles", - &lincs::InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion::initialize_profiles, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Overrides the base method." - ) - ; - - py::class_< - lincs::OptimizeWeightsUsingGlop, - lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy - >( - m, - "OptimizeWeightsUsingGlop", - "The weights optimization strategy described in Olivier Sobrie's PhD thesis. The linear program is solved using GLOP." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_being_learned"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>() - ) - .def( - "optimize_weights", - &lincs::OptimizeWeightsUsingGlop::optimize_weights, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Overrides the base method." - ) - ; - - py::class_< - lincs::OptimizeWeightsUsingAlglib, - lincs::LearnMrsortByWeightsProfilesBreed::WeightsOptimizationStrategy - >( - m, - "OptimizeWeightsUsingAlglib", - "The weights optimization strategy described in Olivier Sobrie's PhD thesis. The linear program is solved using AlgLib." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_being_learned"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>() - ) - .def( - "optimize_weights", - &lincs::OptimizeWeightsUsingAlglib::optimize_weights, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Overrides the base method." - ) - ; - - py::class_< - lincs::ImproveProfilesWithAccuracyHeuristicOnCpu, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy - >( - m, - "ImproveProfilesWithAccuracyHeuristicOnCpu", - "The profiles improvement strategy described in Olivier Sobrie's PhD thesis. Run on the CPU." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_being_learned"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>() - ) - .def( - "improve_profiles", - &lincs::ImproveProfilesWithAccuracyHeuristicOnCpu::improve_profiles, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Overrides the base method." - ) - ; - - #ifdef LINCS_HAS_NVCC - py::class_< - lincs::ImproveProfilesWithAccuracyHeuristicOnGpu, - lincs::LearnMrsortByWeightsProfilesBreed::ProfilesImprovementStrategy - >( - m, - "ImproveProfilesWithAccuracyHeuristicOnGpu", - "The profiles improvement strategy described in Olivier Sobrie's PhD thesis. Run on the CUDA-capable GPU." - ) - .def( - py::init(), - "preprocessed_learning_set"_a, "models_being_learned"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>() - ) - .def( - "improve_profiles", - &lincs::ImproveProfilesWithAccuracyHeuristicOnGpu::improve_profiles, - "model_indexes_begin"_a, "model_indexes_end"_a, - "Overrides the base method." - ) - ; - #endif // LINCS_HAS_NVCC - - py::class_< - lincs::ReinitializeLeastAccurate, - lincs::LearnMrsortByWeightsProfilesBreed::BreedingStrategy - >( - m, - "ReinitializeLeastAccurate", - "The breeding strategy described in Olivier Sobrie's PhD thesis: re-initializes ``count`` in-progress models." - ) - .def( - py::init(), - "models_being_learned"_a, "profiles_initialization_strategy"_a, "weights_optimization_strategy"_a, "count"_a, - "Constructor. Keeps references to the profiles initialization strategy and the learning data.", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>(), - py::keep_alive<1, 4>() - ) - .def( - "breed", - &lincs::ReinitializeLeastAccurate::breed, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateAtAccuracy, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateAtAccuracy", - "Termination strategy. Terminates the learning when the best model reaches a given accuracy." - ) - .def( - py::init(), - "models_being_learned"_a, "target_accuracy"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>() - ) - .def( - "terminate", - &lincs::TerminateAtAccuracy::terminate, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateAfterIterations, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateAfterIterations", - "Termination strategy. Terminates the learning after a given number of iterations." - ) - .def( - py::init(), - "models_being_learned"_a, "max_iterations_count"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>() - ) - .def( - "terminate", - &lincs::TerminateAfterIterations::terminate, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateAfterIterationsWithoutProgress, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateAfterIterationsWithoutProgress", - "Termination strategy. Terminates the learning after a given number of iterations without progress." - ) - .def( - py::init(), - "models_being_learned"_a, "max_iterations_count"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>() - ) - .def( - "terminate", - &lincs::TerminateAfterIterationsWithoutProgress::terminate, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateAfterSeconds, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateAfterSeconds", - "Termination strategy. Terminates the learning after a given duration." - ) - .def( - py::init(), - "max_seconds"_a, - "Constructor." - ) - .def( - "terminate", - &lincs::TerminateAfterSeconds::terminate, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateAfterSecondsWithoutProgress, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateAfterSecondsWithoutProgress", - "Termination strategy. Terminates the learning after a given duration without progress." - ) - .def( - py::init(), - "models_being_learned"_a, "max_seconds"_a, - "Constructor. Keeps a reference to the learning data.", - py::keep_alive<1, 2>() - ) - .def( - "terminate", - &lincs::TerminateAfterSecondsWithoutProgress::terminate, - "Overrides the base method." - ) - ; - - py::class_< - lincs::TerminateWhenAny, - lincs::LearnMrsortByWeightsProfilesBreed::TerminationStrategy - >( - m, - "TerminateWhenAny", - "Termination strategy. Terminates the learning when one or more termination strategies decide to terminate." - ) - .def( - py::init>(), - "termination_strategies"_a, - "Constructor. Keeps references to each termination strategies.", - py::keep_alive<1, 2>() - ) - .def( - "terminate", - &lincs::TerminateWhenAny::terminate, - "Overrides the base method." - ) - ; - - - py::class_( - m, - "LearnUcncsBySatByCoalitionsUsingMinisat", - "The \"SAT by coalitions\" approach to learn Uc-NCS models." - ) - .def( - py::init(), - "problem"_a, "learning_set"_a, - "Constructor.", - py::keep_alive<1, 2>() - // No py::keep_alive<1, 3>() - ) - .def("perform", &lincs::LearnUcncsBySatByCoalitionsUsingMinisat::perform, "Actually perform the learning and return the learned model.") - ; - - py::class_( - m, - "LearnUcncsBySatBySeparationUsingMinisat", - "The \"SAT by separation\" approach to learn Uc-NCS models." - ) - .def( - py::init(), - "problem"_a, "learning_set"_a, - "Constructor.", - py::keep_alive<1, 2>() - // No py::keep_alive<1, 3>() - ) - .def("perform", &lincs::LearnUcncsBySatBySeparationUsingMinisat::perform, "Actually perform the learning and return the learned model.") - ; - - py::class_( - m, - "LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat", - "The \"max-SAT by coalitions\" approach to learn Uc-NCS models." - ) - .def( - py::init(), - "problem"_a, "learning_set"_a, "nb_minimize_threads"_a=0, "timeout_fast_minimize"_a=60, "coef_minimize_time"_a=2, - "Constructor.", - py::keep_alive<1, 2>() - // No py::keep_alive<1, 3>() - ) - .def("perform", &lincs::LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat::perform, "Actually perform the learning and return the learned model.") - ; - - py::class_( - m, - "LearnUcncsByMaxSatBySeparationUsingEvalmaxsat", - "The \"max-SAT by separation\" approach to learn Uc-NCS models." - ) - .def( - py::init(), - "problem"_a, "learning_set"_a, "nb_minimize_threads"_a=0, "timeout_fast_minimize"_a=60, "coef_minimize_time"_a=2, - "Constructor.", - py::keep_alive<1, 2>() - // No py::keep_alive<1, 3>() - ) - .def("perform", &lincs::LearnUcncsByMaxSatBySeparationUsingEvalmaxsat::perform, "Actually perform the learning and return the learned model.") - ; -} - -} // namespace lincs diff --git a/lincs/liblincs/liblincs-module/main.cpp b/lincs/liblincs/liblincs-module/main.cpp index 23b77c79..f22ed6d7 100644 --- a/lincs/liblincs/liblincs-module/main.cpp +++ b/lincs/liblincs/liblincs-module/main.cpp @@ -27,8 +27,4 @@ PYBIND11_MODULE(liblincs, m) { py::options options; options.disable_enum_members_docstring(); - lincs::enroll_converters(m); - lincs::define_io_classes(m); - lincs::define_generation_functions(m); - lincs::define_learning_classes(m); } diff --git a/lincs/liblincs/lincs.hpp b/lincs/liblincs/lincs.hpp index 7ba318bd..18d0b3f9 100644 --- a/lincs/liblincs/lincs.hpp +++ b/lincs/liblincs/lincs.hpp @@ -3,10 +3,10 @@ #ifndef LINCS__LINCS_HPP #define LINCS__LINCS_HPP -#include "classification.hpp" +// #include "classification.hpp" #include "generation.hpp" #include "io.hpp" -#include "learning.hpp" +// #include "learning.hpp" #include "randomness-utils.hpp" #endif // LINCS__LINCS_HPP diff --git a/lincs/liblincs/linear-programming/alglib.cpp b/lincs/liblincs/linear-programming/alglib.cpp deleted file mode 100644 index f948ffa6..00000000 --- a/lincs/liblincs/linear-programming/alglib.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "alglib.hpp" - -#include "../chrones.hpp" - - -namespace lincs { - -std::optional AlglibLinearProgram::solve() { - CHRONE(); - - alglib::real_1d_array c; - c.setcontent(objective_coefficients.size(), objective_coefficients.data()); - alglib::minlpsetcost(state, c); - - alglib::minlpoptimize(state); - alglib::real_1d_array x; - alglib::minlpreport rep; - alglib::minlpresults(state, x, rep); - if (rep.terminationtype >= 1 && rep.terminationtype <= 4) { - return solution_type{x, float(rep.f)}; - } else { - return {}; - } -} - -} // namespace lincs diff --git a/lincs/liblincs/linear-programming/alglib.hpp b/lincs/liblincs/linear-programming/alglib.hpp deleted file mode 100644 index 7fd3a450..00000000 --- a/lincs/liblincs/linear-programming/alglib.hpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LINEAR_PROGRAMMING__ALGLIB_HPP -#define LINCS__LINEAR_PROGRAMMING__ALGLIB_HPP - -#include -#include -#include - -#include "../vendored/alglib/optimization.h" - - -namespace lincs { - -class AlglibLinearProgram { - public: - AlglibLinearProgram() : next_variable_index(0), objective_coefficients(), state() {} - - typedef unsigned variable_type; - variable_type create_variable() { - assert(objective_coefficients.empty()); - return next_variable_index++; - } - - void mark_all_variables_created() { - assert(objective_coefficients.empty()); - alglib::minlpcreate(next_variable_index, state); - objective_coefficients.resize(next_variable_index); - - // Relax Alglib's default constraints to match GLOP's - const float infinity = std::numeric_limits::infinity(); - alglib::minlpsetbcall(state, 0, +infinity); - } - - void set_objective_coefficient(variable_type variable, float coefficient) { - assert(variable < objective_coefficients.size()); - objective_coefficients[variable] = coefficient; - } - - struct Constraint { - Constraint(alglib::minlpstate& state_) : state(state_) {} - ~Constraint() { - const unsigned nnz = coefficients.size(); - // @todo(Performance, later) Try using 'alglib::minlpsetbci' when 'nnz == 1' - // Maybe Alglib can be faster with box constraints than with general linear constraints? - alglib::integer_1d_array idxa; - idxa.setlength(nnz); - alglib::real_1d_array vala; - vala.setlength(nnz); - unsigned i = 0; - for (auto& [variable, coefficient] : coefficients) { - idxa[i] = variable; - vala[i] = coefficient; - ++i; - } - alglib::minlpaddlc2(state, idxa, vala, nnz, lower_bound, upper_bound); - } - - Constraint& set_bounds(float lower_bound_, float upper_bound_) { - lower_bound = lower_bound_; - upper_bound = upper_bound_; - return *this; - } - - Constraint& set_coefficient(variable_type variable, float coefficient) { - coefficients[variable] = coefficient; - return *this; - } - - private: - alglib::minlpstate& state; - float lower_bound; - float upper_bound; - std::map coefficients; - }; - - Constraint create_constraint() { - return Constraint(state); - } - - struct solution_type { - alglib::real_1d_array assignments; - float cost; - }; - std::optional solve(); - - private: - variable_type next_variable_index; - std::vector objective_coefficients; - alglib::minlpstate state; -}; - -} // namespace lincs - -#endif // LINCS__LINEAR_PROGRAMMING__ALGLIB_HPP diff --git a/lincs/liblincs/linear-programming/glop.cpp b/lincs/liblincs/linear-programming/glop.cpp deleted file mode 100644 index 1ae2588e..00000000 --- a/lincs/liblincs/linear-programming/glop.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "glop.hpp" - -#include "../chrones.hpp" - - -namespace lincs { - -std::optional GlopLinearProgram::solve() { - CHRONE(); - - operations_research::glop::LPSolver solver; - operations_research::glop::GlopParameters parameters; - parameters.set_provide_strong_optimal_guarantee(true); - solver.SetParameters(parameters); - - program.CleanUp(); - auto status = solver.Solve(program); - if (status == operations_research::glop::ProblemStatus::OPTIMAL) { - return solution_type{solver.variable_values(), float(solver.GetObjectiveValue())}; - } else { - return {}; - } -} - -} // namespace lincs diff --git a/lincs/liblincs/linear-programming/glop.hpp b/lincs/liblincs/linear-programming/glop.hpp deleted file mode 100644 index 2c20d2ad..00000000 --- a/lincs/liblincs/linear-programming/glop.hpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__LINEAR_PROGRAMMING__GLOP_HPP -#define LINCS__LINEAR_PROGRAMMING__GLOP_HPP - -#include - -#include -#undef CHECK -#undef CHECK_EQ -#undef CHECK_NE -#undef CHECK_LT -#undef CHECK_GT -#undef CHECK_LE -#undef CHECK_GE -#undef CHECK_NEAR -#undef LOG - - -namespace lincs { - -class GlopLinearProgram { - public: - typedef operations_research::glop::ColIndex variable_type; - variable_type create_variable() { - return program.CreateNewVariable(); - } - - void mark_all_variables_created() {} - - void set_objective_coefficient(variable_type variable, float coefficient) { - program.SetObjectiveCoefficient(variable, coefficient); - } - - struct Constraint { - Constraint(operations_research::glop::LinearProgram& program_) : program(program_), index(program_.CreateNewConstraint()) {} - - Constraint& set_bounds(float lower_bound, float upper_bound) { - program.SetConstraintBounds(index, lower_bound, upper_bound); - return *this; - } - - Constraint& set_coefficient(variable_type variable, float coefficient) { - program.SetCoefficient(index, variable, coefficient); - return *this; - } - - private: - operations_research::glop::LinearProgram& program; - operations_research::glop::RowIndex index; - }; - - Constraint create_constraint() { - return Constraint(program); - } - - struct solution_type { - operations_research::glop::DenseRow assignments; - float cost; - }; - std::optional solve(); - - private: - operations_research::glop::LinearProgram program; -}; - -} // namespace lincs - -#endif // LINCS__LINEAR_PROGRAMMING__GLOP_HPP diff --git a/lincs/liblincs/linear-programming/test-bug-0001-optimization-goes-too-far-during-phase-1.cpp b/lincs/liblincs/linear-programming/test-bug-0001-optimization-goes-too-far-during-phase-1.cpp deleted file mode 100644 index 0ab01fea..00000000 --- a/lincs/liblincs/linear-programming/test-bug-0001-optimization-goes-too-far-during-phase-1.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -TEST_CASE("Bug") { - test([](auto& linear_program) -> std::optional { - { - std::vector::variable_type> v; - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - linear_program.mark_all_variables_created(); - linear_program.set_objective_coefficient(v[0], 5.9987197); - linear_program.set_objective_coefficient(v[1], 2.9937017); - linear_program.create_constraint().set_bounds(1.0009933, infinity).set_coefficient(v[0], 0.9905185).set_coefficient(v[1], 1.0086309); - linear_program.create_constraint().set_bounds(0.999695, infinity).set_coefficient(v[0], 2.0089545).set_coefficient(v[1], -1.0012935); - linear_program.create_constraint().set_bounds(-infinity, 1.9964107).set_coefficient(v[1], 2.9984074); - } - const auto solution = linear_program.solve(); - if (solution) { - return solution->cost; - } else { - return std::nullopt; - } - }); -} diff --git a/lincs/liblincs/linear-programming/test-bug-0002-optimization-still-goes-too-far-during-phase-1.cpp b/lincs/liblincs/linear-programming/test-bug-0002-optimization-still-goes-too-far-during-phase-1.cpp deleted file mode 100644 index 9a03ee82..00000000 --- a/lincs/liblincs/linear-programming/test-bug-0002-optimization-still-goes-too-far-during-phase-1.cpp +++ /dev/null @@ -1,1426 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -TEST_CASE("Bug") { - test([](auto& linear_program) -> std::optional { - { - std::vector::variable_type> v; - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - linear_program.mark_all_variables_created(); - linear_program.set_objective_coefficient(v[8], 1); - linear_program.set_objective_coefficient(v[10], 1); - linear_program.set_objective_coefficient(v[12], 1); - linear_program.set_objective_coefficient(v[14], 1); - linear_program.set_objective_coefficient(v[16], 1); - linear_program.set_objective_coefficient(v[18], 1); - linear_program.set_objective_coefficient(v[20], 1); - linear_program.set_objective_coefficient(v[22], 1); - linear_program.set_objective_coefficient(v[24], 1); - linear_program.set_objective_coefficient(v[26], 1); - linear_program.set_objective_coefficient(v[28], 1); - linear_program.set_objective_coefficient(v[30], 1); - linear_program.set_objective_coefficient(v[32], 1); - linear_program.set_objective_coefficient(v[34], 1); - linear_program.set_objective_coefficient(v[36], 1); - linear_program.set_objective_coefficient(v[38], 1); - linear_program.set_objective_coefficient(v[40], 1); - linear_program.set_objective_coefficient(v[42], 1); - linear_program.set_objective_coefficient(v[44], 1); - linear_program.set_objective_coefficient(v[46], 1); - linear_program.set_objective_coefficient(v[48], 1); - linear_program.set_objective_coefficient(v[50], 1); - linear_program.set_objective_coefficient(v[52], 1); - linear_program.set_objective_coefficient(v[54], 1); - linear_program.set_objective_coefficient(v[56], 1); - linear_program.set_objective_coefficient(v[58], 1); - linear_program.set_objective_coefficient(v[60], 1); - linear_program.set_objective_coefficient(v[62], 1); - linear_program.set_objective_coefficient(v[64], 1); - linear_program.set_objective_coefficient(v[66], 1); - linear_program.set_objective_coefficient(v[68], 1); - linear_program.set_objective_coefficient(v[70], 1); - linear_program.set_objective_coefficient(v[72], 1); - linear_program.set_objective_coefficient(v[74], 1); - linear_program.set_objective_coefficient(v[76], 1); - linear_program.set_objective_coefficient(v[78], 1); - linear_program.set_objective_coefficient(v[80], 1); - linear_program.set_objective_coefficient(v[82], 1); - linear_program.set_objective_coefficient(v[84], 1); - linear_program.set_objective_coefficient(v[86], 1); - linear_program.set_objective_coefficient(v[88], 1); - linear_program.set_objective_coefficient(v[90], 1); - linear_program.set_objective_coefficient(v[92], 1); - linear_program.set_objective_coefficient(v[94], 1); - linear_program.set_objective_coefficient(v[96], 1); - linear_program.set_objective_coefficient(v[98], 1); - linear_program.set_objective_coefficient(v[100], 1); - linear_program.set_objective_coefficient(v[102], 1); - linear_program.set_objective_coefficient(v[104], 1); - linear_program.set_objective_coefficient(v[106], 1); - linear_program.set_objective_coefficient(v[108], 1); - linear_program.set_objective_coefficient(v[110], 1); - linear_program.set_objective_coefficient(v[112], 1); - linear_program.set_objective_coefficient(v[114], 1); - linear_program.set_objective_coefficient(v[116], 1); - linear_program.set_objective_coefficient(v[118], 1); - linear_program.set_objective_coefficient(v[120], 1); - linear_program.set_objective_coefficient(v[122], 1); - linear_program.set_objective_coefficient(v[124], 1); - linear_program.set_objective_coefficient(v[126], 1); - linear_program.set_objective_coefficient(v[128], 1); - linear_program.set_objective_coefficient(v[130], 1); - linear_program.set_objective_coefficient(v[132], 1); - linear_program.set_objective_coefficient(v[134], 1); - linear_program.set_objective_coefficient(v[136], 1); - linear_program.set_objective_coefficient(v[138], 1); - linear_program.set_objective_coefficient(v[140], 1); - linear_program.set_objective_coefficient(v[142], 1); - linear_program.set_objective_coefficient(v[144], 1); - linear_program.set_objective_coefficient(v[146], 1); - linear_program.set_objective_coefficient(v[148], 1); - linear_program.set_objective_coefficient(v[150], 1); - linear_program.set_objective_coefficient(v[152], 1); - linear_program.set_objective_coefficient(v[154], 1); - linear_program.set_objective_coefficient(v[156], 1); - linear_program.set_objective_coefficient(v[158], 1); - linear_program.set_objective_coefficient(v[160], 1); - linear_program.set_objective_coefficient(v[162], 1); - linear_program.set_objective_coefficient(v[164], 1); - linear_program.set_objective_coefficient(v[166], 1); - linear_program.set_objective_coefficient(v[168], 1); - linear_program.set_objective_coefficient(v[170], 1); - linear_program.set_objective_coefficient(v[172], 1); - linear_program.set_objective_coefficient(v[174], 1); - linear_program.set_objective_coefficient(v[176], 1); - linear_program.set_objective_coefficient(v[178], 1); - linear_program.set_objective_coefficient(v[180], 1); - linear_program.set_objective_coefficient(v[182], 1); - linear_program.set_objective_coefficient(v[184], 1); - linear_program.set_objective_coefficient(v[186], 1); - linear_program.set_objective_coefficient(v[188], 1); - linear_program.set_objective_coefficient(v[190], 1); - linear_program.set_objective_coefficient(v[192], 1); - linear_program.set_objective_coefficient(v[194], 1); - linear_program.set_objective_coefficient(v[196], 1); - linear_program.set_objective_coefficient(v[198], 1); - linear_program.set_objective_coefficient(v[200], 1); - linear_program.set_objective_coefficient(v[202], 1); - linear_program.set_objective_coefficient(v[204], 1); - linear_program.set_objective_coefficient(v[206], 1); - linear_program.set_objective_coefficient(v[208], 1); - linear_program.set_objective_coefficient(v[210], 1); - linear_program.set_objective_coefficient(v[212], 1); - linear_program.set_objective_coefficient(v[214], 1); - linear_program.set_objective_coefficient(v[216], 1); - linear_program.set_objective_coefficient(v[218], 1); - linear_program.set_objective_coefficient(v[220], 1); - linear_program.set_objective_coefficient(v[222], 1); - linear_program.set_objective_coefficient(v[224], 1); - linear_program.set_objective_coefficient(v[226], 1); - linear_program.set_objective_coefficient(v[228], 1); - linear_program.set_objective_coefficient(v[230], 1); - linear_program.set_objective_coefficient(v[232], 1); - linear_program.set_objective_coefficient(v[234], 1); - linear_program.set_objective_coefficient(v[236], 1); - linear_program.set_objective_coefficient(v[238], 1); - linear_program.set_objective_coefficient(v[240], 1); - linear_program.set_objective_coefficient(v[242], 1); - linear_program.set_objective_coefficient(v[244], 1); - linear_program.set_objective_coefficient(v[246], 1); - linear_program.set_objective_coefficient(v[248], 1); - linear_program.set_objective_coefficient(v[250], 1); - linear_program.set_objective_coefficient(v[252], 1); - linear_program.set_objective_coefficient(v[254], 1); - linear_program.set_objective_coefficient(v[256], 1); - linear_program.set_objective_coefficient(v[258], 1); - linear_program.set_objective_coefficient(v[260], 1); - linear_program.set_objective_coefficient(v[262], 1); - linear_program.set_objective_coefficient(v[264], 1); - linear_program.set_objective_coefficient(v[266], 1); - linear_program.set_objective_coefficient(v[268], 1); - linear_program.set_objective_coefficient(v[270], 1); - linear_program.set_objective_coefficient(v[272], 1); - linear_program.set_objective_coefficient(v[274], 1); - linear_program.set_objective_coefficient(v[276], 1); - linear_program.set_objective_coefficient(v[278], 1); - linear_program.set_objective_coefficient(v[280], 1); - linear_program.set_objective_coefficient(v[282], 1); - linear_program.set_objective_coefficient(v[284], 1); - linear_program.set_objective_coefficient(v[286], 1); - linear_program.set_objective_coefficient(v[288], 1); - linear_program.set_objective_coefficient(v[290], 1); - linear_program.set_objective_coefficient(v[292], 1); - linear_program.set_objective_coefficient(v[294], 1); - linear_program.set_objective_coefficient(v[296], 1); - linear_program.set_objective_coefficient(v[298], 1); - linear_program.set_objective_coefficient(v[300], 1); - linear_program.set_objective_coefficient(v[302], 1); - linear_program.set_objective_coefficient(v[304], 1); - linear_program.set_objective_coefficient(v[306], 1); - linear_program.set_objective_coefficient(v[308], 1); - linear_program.set_objective_coefficient(v[310], 1); - linear_program.set_objective_coefficient(v[312], 1); - linear_program.set_objective_coefficient(v[314], 1); - linear_program.set_objective_coefficient(v[316], 1); - linear_program.set_objective_coefficient(v[318], 1); - linear_program.set_objective_coefficient(v[320], 1); - linear_program.set_objective_coefficient(v[322], 1); - linear_program.set_objective_coefficient(v[324], 1); - linear_program.set_objective_coefficient(v[326], 1); - linear_program.set_objective_coefficient(v[328], 1); - linear_program.set_objective_coefficient(v[330], 1); - linear_program.set_objective_coefficient(v[332], 1); - linear_program.set_objective_coefficient(v[334], 1); - linear_program.set_objective_coefficient(v[336], 1); - linear_program.set_objective_coefficient(v[338], 1); - linear_program.set_objective_coefficient(v[340], 1); - linear_program.set_objective_coefficient(v[342], 1); - linear_program.set_objective_coefficient(v[344], 1); - linear_program.set_objective_coefficient(v[346], 1); - linear_program.set_objective_coefficient(v[348], 1); - linear_program.set_objective_coefficient(v[350], 1); - linear_program.set_objective_coefficient(v[352], 1); - linear_program.set_objective_coefficient(v[354], 1); - linear_program.set_objective_coefficient(v[356], 1); - linear_program.set_objective_coefficient(v[358], 1); - linear_program.set_objective_coefficient(v[360], 1); - linear_program.set_objective_coefficient(v[362], 1); - linear_program.set_objective_coefficient(v[364], 1); - linear_program.set_objective_coefficient(v[366], 1); - linear_program.set_objective_coefficient(v[368], 1); - linear_program.set_objective_coefficient(v[370], 1); - linear_program.set_objective_coefficient(v[372], 1); - linear_program.set_objective_coefficient(v[374], 1); - linear_program.set_objective_coefficient(v[376], 1); - linear_program.set_objective_coefficient(v[378], 1); - linear_program.set_objective_coefficient(v[380], 1); - linear_program.set_objective_coefficient(v[382], 1); - linear_program.set_objective_coefficient(v[384], 1); - linear_program.set_objective_coefficient(v[386], 1); - linear_program.set_objective_coefficient(v[388], 1); - linear_program.set_objective_coefficient(v[390], 1); - linear_program.set_objective_coefficient(v[392], 1); - linear_program.set_objective_coefficient(v[394], 1); - linear_program.set_objective_coefficient(v[396], 1); - linear_program.set_objective_coefficient(v[398], 1); - linear_program.set_objective_coefficient(v[400], 1); - linear_program.set_objective_coefficient(v[402], 1); - linear_program.set_objective_coefficient(v[404], 1); - linear_program.set_objective_coefficient(v[406], 1); - linear_program.set_objective_coefficient(v[408], 1); - linear_program.set_objective_coefficient(v[410], 1); - linear_program.set_objective_coefficient(v[412], 1); - linear_program.set_objective_coefficient(v[414], 1); - linear_program.set_objective_coefficient(v[416], 1); - linear_program.set_objective_coefficient(v[418], 1); - linear_program.set_objective_coefficient(v[420], 1); - linear_program.set_objective_coefficient(v[422], 1); - linear_program.set_objective_coefficient(v[424], 1); - linear_program.set_objective_coefficient(v[426], 1); - linear_program.set_objective_coefficient(v[428], 1); - linear_program.set_objective_coefficient(v[430], 1); - linear_program.set_objective_coefficient(v[432], 1); - linear_program.set_objective_coefficient(v[434], 1); - linear_program.set_objective_coefficient(v[436], 1); - linear_program.set_objective_coefficient(v[438], 1); - linear_program.set_objective_coefficient(v[440], 1); - linear_program.set_objective_coefficient(v[442], 1); - linear_program.set_objective_coefficient(v[444], 1); - linear_program.set_objective_coefficient(v[446], 1); - linear_program.set_objective_coefficient(v[448], 1); - linear_program.set_objective_coefficient(v[450], 1); - linear_program.set_objective_coefficient(v[452], 1); - linear_program.set_objective_coefficient(v[454], 1); - linear_program.set_objective_coefficient(v[456], 1); - linear_program.set_objective_coefficient(v[458], 1); - linear_program.set_objective_coefficient(v[460], 1); - linear_program.set_objective_coefficient(v[462], 1); - linear_program.set_objective_coefficient(v[464], 1); - linear_program.set_objective_coefficient(v[466], 1); - linear_program.set_objective_coefficient(v[468], 1); - linear_program.set_objective_coefficient(v[470], 1); - linear_program.set_objective_coefficient(v[472], 1); - linear_program.set_objective_coefficient(v[474], 1); - linear_program.set_objective_coefficient(v[476], 1); - linear_program.set_objective_coefficient(v[478], 1); - linear_program.set_objective_coefficient(v[480], 1); - linear_program.set_objective_coefficient(v[482], 1); - linear_program.set_objective_coefficient(v[484], 1); - linear_program.set_objective_coefficient(v[486], 1); - linear_program.set_objective_coefficient(v[488], 1); - linear_program.set_objective_coefficient(v[490], 1); - linear_program.set_objective_coefficient(v[492], 1); - linear_program.set_objective_coefficient(v[494], 1); - linear_program.set_objective_coefficient(v[496], 1); - linear_program.set_objective_coefficient(v[498], 1); - linear_program.set_objective_coefficient(v[500], 1); - linear_program.set_objective_coefficient(v[502], 1); - linear_program.set_objective_coefficient(v[504], 1); - linear_program.set_objective_coefficient(v[506], 1); - linear_program.set_objective_coefficient(v[508], 1); - linear_program.set_objective_coefficient(v[510], 1); - linear_program.set_objective_coefficient(v[512], 1); - linear_program.set_objective_coefficient(v[514], 1); - linear_program.set_objective_coefficient(v[516], 1); - linear_program.set_objective_coefficient(v[518], 1); - linear_program.set_objective_coefficient(v[520], 1); - linear_program.set_objective_coefficient(v[522], 1); - linear_program.set_objective_coefficient(v[524], 1); - linear_program.set_objective_coefficient(v[526], 1); - linear_program.set_objective_coefficient(v[528], 1); - linear_program.set_objective_coefficient(v[530], 1); - linear_program.set_objective_coefficient(v[532], 1); - linear_program.set_objective_coefficient(v[534], 1); - linear_program.set_objective_coefficient(v[536], 1); - linear_program.set_objective_coefficient(v[538], 1); - linear_program.set_objective_coefficient(v[540], 1); - linear_program.set_objective_coefficient(v[542], 1); - linear_program.set_objective_coefficient(v[544], 1); - linear_program.set_objective_coefficient(v[546], 1); - linear_program.set_objective_coefficient(v[548], 1); - linear_program.set_objective_coefficient(v[550], 1); - linear_program.set_objective_coefficient(v[552], 1); - linear_program.set_objective_coefficient(v[554], 1); - linear_program.set_objective_coefficient(v[556], 1); - linear_program.set_objective_coefficient(v[558], 1); - linear_program.set_objective_coefficient(v[560], 1); - linear_program.set_objective_coefficient(v[562], 1); - linear_program.set_objective_coefficient(v[564], 1); - linear_program.set_objective_coefficient(v[566], 1); - linear_program.set_objective_coefficient(v[568], 1); - linear_program.set_objective_coefficient(v[570], 1); - linear_program.set_objective_coefficient(v[572], 1); - linear_program.set_objective_coefficient(v[574], 1); - linear_program.set_objective_coefficient(v[576], 1); - linear_program.set_objective_coefficient(v[578], 1); - linear_program.set_objective_coefficient(v[580], 1); - linear_program.set_objective_coefficient(v[582], 1); - linear_program.set_objective_coefficient(v[584], 1); - linear_program.set_objective_coefficient(v[586], 1); - linear_program.set_objective_coefficient(v[588], 1); - linear_program.set_objective_coefficient(v[590], 1); - linear_program.set_objective_coefficient(v[592], 1); - linear_program.set_objective_coefficient(v[594], 1); - linear_program.set_objective_coefficient(v[596], 1); - linear_program.set_objective_coefficient(v[598], 1); - linear_program.set_objective_coefficient(v[600], 1); - linear_program.set_objective_coefficient(v[602], 1); - linear_program.set_objective_coefficient(v[604], 1); - linear_program.set_objective_coefficient(v[606], 1); - linear_program.set_objective_coefficient(v[608], 1); - linear_program.set_objective_coefficient(v[610], 1); - linear_program.set_objective_coefficient(v[612], 1); - linear_program.set_objective_coefficient(v[614], 1); - linear_program.set_objective_coefficient(v[616], 1); - linear_program.set_objective_coefficient(v[618], 1); - linear_program.set_objective_coefficient(v[620], 1); - linear_program.set_objective_coefficient(v[622], 1); - linear_program.set_objective_coefficient(v[624], 1); - linear_program.set_objective_coefficient(v[626], 1); - linear_program.set_objective_coefficient(v[628], 1); - linear_program.set_objective_coefficient(v[630], 1); - linear_program.set_objective_coefficient(v[632], 1); - linear_program.set_objective_coefficient(v[634], 1); - linear_program.set_objective_coefficient(v[636], 1); - linear_program.set_objective_coefficient(v[638], 1); - linear_program.set_objective_coefficient(v[640], 1); - linear_program.set_objective_coefficient(v[642], 1); - linear_program.set_objective_coefficient(v[644], 1); - linear_program.set_objective_coefficient(v[646], 1); - linear_program.set_objective_coefficient(v[648], 1); - linear_program.set_objective_coefficient(v[650], 1); - linear_program.set_objective_coefficient(v[652], 1); - linear_program.set_objective_coefficient(v[654], 1); - linear_program.set_objective_coefficient(v[656], 1); - linear_program.set_objective_coefficient(v[658], 1); - linear_program.set_objective_coefficient(v[660], 1); - linear_program.set_objective_coefficient(v[662], 1); - linear_program.set_objective_coefficient(v[664], 1); - linear_program.set_objective_coefficient(v[666], 1); - linear_program.set_objective_coefficient(v[668], 1); - linear_program.set_objective_coefficient(v[670], 1); - linear_program.set_objective_coefficient(v[672], 1); - linear_program.set_objective_coefficient(v[674], 1); - linear_program.set_objective_coefficient(v[676], 1); - linear_program.set_objective_coefficient(v[678], 1); - linear_program.set_objective_coefficient(v[680], 1); - linear_program.set_objective_coefficient(v[682], 1); - linear_program.set_objective_coefficient(v[684], 1); - linear_program.set_objective_coefficient(v[686], 1); - linear_program.set_objective_coefficient(v[688], 1); - linear_program.set_objective_coefficient(v[690], 1); - linear_program.set_objective_coefficient(v[692], 1); - linear_program.set_objective_coefficient(v[694], 1); - linear_program.set_objective_coefficient(v[696], 1); - linear_program.set_objective_coefficient(v[698], 1); - linear_program.set_objective_coefficient(v[700], 1); - linear_program.set_objective_coefficient(v[702], 1); - linear_program.set_objective_coefficient(v[704], 1); - linear_program.set_objective_coefficient(v[706], 1); - linear_program.set_objective_coefficient(v[708], 1); - linear_program.set_objective_coefficient(v[710], 1); - linear_program.set_objective_coefficient(v[712], 1); - linear_program.set_objective_coefficient(v[714], 1); - linear_program.set_objective_coefficient(v[716], 1); - linear_program.set_objective_coefficient(v[718], 1); - linear_program.set_objective_coefficient(v[720], 1); - linear_program.set_objective_coefficient(v[722], 1); - linear_program.set_objective_coefficient(v[724], 1); - linear_program.set_objective_coefficient(v[726], 1); - linear_program.set_objective_coefficient(v[728], 1); - linear_program.set_objective_coefficient(v[730], 1); - linear_program.set_objective_coefficient(v[732], 1); - linear_program.set_objective_coefficient(v[734], 1); - linear_program.set_objective_coefficient(v[736], 1); - linear_program.set_objective_coefficient(v[738], 1); - linear_program.set_objective_coefficient(v[740], 1); - linear_program.set_objective_coefficient(v[742], 1); - linear_program.set_objective_coefficient(v[744], 1); - linear_program.set_objective_coefficient(v[746], 1); - linear_program.set_objective_coefficient(v[748], 1); - linear_program.set_objective_coefficient(v[750], 1); - linear_program.set_objective_coefficient(v[752], 1); - linear_program.set_objective_coefficient(v[754], 1); - linear_program.set_objective_coefficient(v[756], 1); - linear_program.set_objective_coefficient(v[758], 1); - linear_program.set_objective_coefficient(v[760], 1); - linear_program.set_objective_coefficient(v[762], 1); - linear_program.set_objective_coefficient(v[764], 1); - linear_program.set_objective_coefficient(v[766], 1); - linear_program.set_objective_coefficient(v[768], 1); - linear_program.set_objective_coefficient(v[770], 1); - linear_program.set_objective_coefficient(v[772], 1); - linear_program.set_objective_coefficient(v[774], 1); - linear_program.set_objective_coefficient(v[776], 1); - linear_program.set_objective_coefficient(v[778], 1); - linear_program.set_objective_coefficient(v[780], 1); - linear_program.set_objective_coefficient(v[782], 1); - linear_program.set_objective_coefficient(v[784], 1); - linear_program.set_objective_coefficient(v[786], 1); - linear_program.set_objective_coefficient(v[788], 1); - linear_program.set_objective_coefficient(v[790], 1); - linear_program.set_objective_coefficient(v[792], 1); - linear_program.set_objective_coefficient(v[794], 1); - linear_program.set_objective_coefficient(v[796], 1); - linear_program.set_objective_coefficient(v[798], 1); - linear_program.set_objective_coefficient(v[800], 1); - linear_program.set_objective_coefficient(v[802], 1); - linear_program.set_objective_coefficient(v[804], 1); - linear_program.set_objective_coefficient(v[806], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[7], -1).set_coefficient(v[8], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[11], -1).set_coefficient(v[12], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[15], -1).set_coefficient(v[16], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[19], -1).set_coefficient(v[20], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[25], 1).set_coefficient(v[26], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[27], -1).set_coefficient(v[28], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[31], -1).set_coefficient(v[32], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[35], -1).set_coefficient(v[36], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[41], 1).set_coefficient(v[42], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[43], -1).set_coefficient(v[44], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[47], -1).set_coefficient(v[48], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[51], -1).set_coefficient(v[52], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[55], -1).set_coefficient(v[56], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[61], 1).set_coefficient(v[62], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[65], 1).set_coefficient(v[66], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[67], -1).set_coefficient(v[68], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[71], -1).set_coefficient(v[72], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[75], -1).set_coefficient(v[76], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[79], -1).set_coefficient(v[80], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[85], 1).set_coefficient(v[86], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[87], -1).set_coefficient(v[88], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[93], 1).set_coefficient(v[94], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[97], 1).set_coefficient(v[98], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[99], -1).set_coefficient(v[100], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[103], -1).set_coefficient(v[104], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[107], -1).set_coefficient(v[108], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[111], -1).set_coefficient(v[112], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[117], 1).set_coefficient(v[118], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[119], -1).set_coefficient(v[120], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[123], -1).set_coefficient(v[124], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[127], -1).set_coefficient(v[128], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[131], -1).set_coefficient(v[132], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[135], -1).set_coefficient(v[136], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[139], -1).set_coefficient(v[140], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[143], -1).set_coefficient(v[144], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[149], 1).set_coefficient(v[150], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[153], 1).set_coefficient(v[154], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[157], 1).set_coefficient(v[158], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[161], 1).set_coefficient(v[162], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[165], 1).set_coefficient(v[166], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[167], -1).set_coefficient(v[168], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[173], 1).set_coefficient(v[174], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[175], -1).set_coefficient(v[176], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[179], -1).set_coefficient(v[180], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[183], -1).set_coefficient(v[184], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[189], 1).set_coefficient(v[190], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[193], 1).set_coefficient(v[194], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[197], 1).set_coefficient(v[198], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[199], -1).set_coefficient(v[200], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[205], 1).set_coefficient(v[206], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[207], -1).set_coefficient(v[208], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[211], -1).set_coefficient(v[212], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[215], -1).set_coefficient(v[216], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[219], -1).set_coefficient(v[220], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[225], 1).set_coefficient(v[226], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[229], 1).set_coefficient(v[230], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[233], 1).set_coefficient(v[234], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[237], 1).set_coefficient(v[238], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[239], -1).set_coefficient(v[240], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[243], -1).set_coefficient(v[244], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[247], -1).set_coefficient(v[248], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[253], 1).set_coefficient(v[254], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[257], 1).set_coefficient(v[258], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[261], 1).set_coefficient(v[262], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[265], 1).set_coefficient(v[266], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[267], -1).set_coefficient(v[268], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[273], 1).set_coefficient(v[274], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[277], 1).set_coefficient(v[278], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[281], 1).set_coefficient(v[282], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[283], -1).set_coefficient(v[284], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[289], 1).set_coefficient(v[290], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[293], 1).set_coefficient(v[294], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[295], -1).set_coefficient(v[296], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[299], -1).set_coefficient(v[300], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[305], 1).set_coefficient(v[306], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[307], -1).set_coefficient(v[308], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[313], 1).set_coefficient(v[314], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[315], -1).set_coefficient(v[316], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[319], -1).set_coefficient(v[320], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[323], -1).set_coefficient(v[324], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[329], 1).set_coefficient(v[330], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[331], -1).set_coefficient(v[332], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[337], 1).set_coefficient(v[338], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[341], 1).set_coefficient(v[342], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[343], -1).set_coefficient(v[344], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[347], -1).set_coefficient(v[348], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[351], -1).set_coefficient(v[352], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[355], -1).set_coefficient(v[356], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[359], -1).set_coefficient(v[360], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[363], -1).set_coefficient(v[364], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[369], 1).set_coefficient(v[370], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[373], 1).set_coefficient(v[374], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[377], 1).set_coefficient(v[378], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[381], 1).set_coefficient(v[382], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[385], 1).set_coefficient(v[386], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[387], -1).set_coefficient(v[388], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[393], 1).set_coefficient(v[394], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[395], -1).set_coefficient(v[396], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[401], 1).set_coefficient(v[402], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[403], -1).set_coefficient(v[404], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[407], -1).set_coefficient(v[408], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[413], 1).set_coefficient(v[414], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[417], 1).set_coefficient(v[418], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[421], 1).set_coefficient(v[422], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[423], -1).set_coefficient(v[424], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[429], 1).set_coefficient(v[430], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[433], 1).set_coefficient(v[434], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[5], 1).set_coefficient(v[435], -1).set_coefficient(v[436], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[441], 1).set_coefficient(v[442], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[445], 1).set_coefficient(v[446], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[447], -1).set_coefficient(v[448], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[451], -1).set_coefficient(v[452], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[457], 1).set_coefficient(v[458], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[461], 1).set_coefficient(v[462], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[465], 1).set_coefficient(v[466], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[467], -1).set_coefficient(v[468], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[473], 1).set_coefficient(v[474], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[477], 1).set_coefficient(v[478], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[481], 1).set_coefficient(v[482], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[485], 1).set_coefficient(v[486], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[487], -1).set_coefficient(v[488], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[491], -1).set_coefficient(v[492], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[497], 1).set_coefficient(v[498], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[499], -1).set_coefficient(v[500], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[505], 1).set_coefficient(v[506], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[507], -1).set_coefficient(v[508], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[511], -1).set_coefficient(v[512], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[517], 1).set_coefficient(v[518], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[519], -1).set_coefficient(v[520], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[523], -1).set_coefficient(v[524], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[527], -1).set_coefficient(v[528], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[533], 1).set_coefficient(v[534], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[537], 1).set_coefficient(v[538], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[541], 1).set_coefficient(v[542], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[545], 1).set_coefficient(v[546], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[549], 1).set_coefficient(v[550], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[551], -1).set_coefficient(v[552], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[555], -1).set_coefficient(v[556], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[561], 1).set_coefficient(v[562], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[563], -1).set_coefficient(v[564], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[569], 1).set_coefficient(v[570], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[571], -1).set_coefficient(v[572], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[577], 1).set_coefficient(v[578], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[581], 1).set_coefficient(v[582], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[585], 1).set_coefficient(v[586], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[587], -1).set_coefficient(v[588], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[593], 1).set_coefficient(v[594], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[595], -1).set_coefficient(v[596], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[599], -1).set_coefficient(v[600], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[603], -1).set_coefficient(v[604], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[609], 1).set_coefficient(v[610], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[613], 1).set_coefficient(v[614], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[615], -1).set_coefficient(v[616], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[621], 1).set_coefficient(v[622], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[623], -1).set_coefficient(v[624], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[627], -1).set_coefficient(v[628], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[631], -1).set_coefficient(v[632], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[637], 1).set_coefficient(v[638], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[641], 1).set_coefficient(v[642], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[643], -1).set_coefficient(v[644], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[647], -1).set_coefficient(v[648], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[651], -1).set_coefficient(v[652], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[655], -1).set_coefficient(v[656], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[661], 1).set_coefficient(v[662], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[663], -1).set_coefficient(v[664], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[667], -1).set_coefficient(v[668], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[671], -1).set_coefficient(v[672], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[675], -1).set_coefficient(v[676], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[681], 1).set_coefficient(v[682], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[685], 1).set_coefficient(v[686], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[687], -1).set_coefficient(v[688], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[693], 1).set_coefficient(v[694], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[695], -1).set_coefficient(v[696], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[701], 1).set_coefficient(v[702], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[705], 1).set_coefficient(v[706], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[707], -1).set_coefficient(v[708], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[711], -1).set_coefficient(v[712], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[715], -1).set_coefficient(v[716], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[719], -1).set_coefficient(v[720], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[6], 1).set_coefficient(v[725], 1).set_coefficient(v[726], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[729], 1).set_coefficient(v[730], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[731], -1).set_coefficient(v[732], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[735], -1).set_coefficient(v[736], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[739], -1).set_coefficient(v[740], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[745], 1).set_coefficient(v[746], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[747], -1).set_coefficient(v[748], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[751], -1).set_coefficient(v[752], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[755], -1).set_coefficient(v[756], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[759], -1).set_coefficient(v[760], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[765], 1).set_coefficient(v[766], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[769], 1).set_coefficient(v[770], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[773], 1).set_coefficient(v[774], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[775], -1).set_coefficient(v[776], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[779], -1).set_coefficient(v[780], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[785], 1).set_coefficient(v[786], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[787], -1).set_coefficient(v[788], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[791], -1).set_coefficient(v[792], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[795], -1).set_coefficient(v[796], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[801], 1).set_coefficient(v[802], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[805], 1).set_coefficient(v[806], -1); - } - const auto solution = linear_program.solve(); - if (solution) { - return solution->cost; - } else { - return std::nullopt; - } - }); -} diff --git a/lincs/liblincs/linear-programming/test-bug-0003-optimization-still-goes-too-far-during-phase-1.cpp b/lincs/liblincs/linear-programming/test-bug-0003-optimization-still-goes-too-far-during-phase-1.cpp deleted file mode 100644 index 45f03f1d..00000000 --- a/lincs/liblincs/linear-programming/test-bug-0003-optimization-still-goes-too-far-during-phase-1.cpp +++ /dev/null @@ -1,1426 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -TEST_CASE("Bug") { - test([](auto& linear_program) -> std::optional { - { - std::vector::variable_type> v; - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - linear_program.mark_all_variables_created(); - linear_program.set_objective_coefficient(v[8], 1); - linear_program.set_objective_coefficient(v[10], 1); - linear_program.set_objective_coefficient(v[12], 1); - linear_program.set_objective_coefficient(v[14], 1); - linear_program.set_objective_coefficient(v[16], 1); - linear_program.set_objective_coefficient(v[18], 1); - linear_program.set_objective_coefficient(v[20], 1); - linear_program.set_objective_coefficient(v[22], 1); - linear_program.set_objective_coefficient(v[24], 1); - linear_program.set_objective_coefficient(v[26], 1); - linear_program.set_objective_coefficient(v[28], 1); - linear_program.set_objective_coefficient(v[30], 1); - linear_program.set_objective_coefficient(v[32], 1); - linear_program.set_objective_coefficient(v[34], 1); - linear_program.set_objective_coefficient(v[36], 1); - linear_program.set_objective_coefficient(v[38], 1); - linear_program.set_objective_coefficient(v[40], 1); - linear_program.set_objective_coefficient(v[42], 1); - linear_program.set_objective_coefficient(v[44], 1); - linear_program.set_objective_coefficient(v[46], 1); - linear_program.set_objective_coefficient(v[48], 1); - linear_program.set_objective_coefficient(v[50], 1); - linear_program.set_objective_coefficient(v[52], 1); - linear_program.set_objective_coefficient(v[54], 1); - linear_program.set_objective_coefficient(v[56], 1); - linear_program.set_objective_coefficient(v[58], 1); - linear_program.set_objective_coefficient(v[60], 1); - linear_program.set_objective_coefficient(v[62], 1); - linear_program.set_objective_coefficient(v[64], 1); - linear_program.set_objective_coefficient(v[66], 1); - linear_program.set_objective_coefficient(v[68], 1); - linear_program.set_objective_coefficient(v[70], 1); - linear_program.set_objective_coefficient(v[72], 1); - linear_program.set_objective_coefficient(v[74], 1); - linear_program.set_objective_coefficient(v[76], 1); - linear_program.set_objective_coefficient(v[78], 1); - linear_program.set_objective_coefficient(v[80], 1); - linear_program.set_objective_coefficient(v[82], 1); - linear_program.set_objective_coefficient(v[84], 1); - linear_program.set_objective_coefficient(v[86], 1); - linear_program.set_objective_coefficient(v[88], 1); - linear_program.set_objective_coefficient(v[90], 1); - linear_program.set_objective_coefficient(v[92], 1); - linear_program.set_objective_coefficient(v[94], 1); - linear_program.set_objective_coefficient(v[96], 1); - linear_program.set_objective_coefficient(v[98], 1); - linear_program.set_objective_coefficient(v[100], 1); - linear_program.set_objective_coefficient(v[102], 1); - linear_program.set_objective_coefficient(v[104], 1); - linear_program.set_objective_coefficient(v[106], 1); - linear_program.set_objective_coefficient(v[108], 1); - linear_program.set_objective_coefficient(v[110], 1); - linear_program.set_objective_coefficient(v[112], 1); - linear_program.set_objective_coefficient(v[114], 1); - linear_program.set_objective_coefficient(v[116], 1); - linear_program.set_objective_coefficient(v[118], 1); - linear_program.set_objective_coefficient(v[120], 1); - linear_program.set_objective_coefficient(v[122], 1); - linear_program.set_objective_coefficient(v[124], 1); - linear_program.set_objective_coefficient(v[126], 1); - linear_program.set_objective_coefficient(v[128], 1); - linear_program.set_objective_coefficient(v[130], 1); - linear_program.set_objective_coefficient(v[132], 1); - linear_program.set_objective_coefficient(v[134], 1); - linear_program.set_objective_coefficient(v[136], 1); - linear_program.set_objective_coefficient(v[138], 1); - linear_program.set_objective_coefficient(v[140], 1); - linear_program.set_objective_coefficient(v[142], 1); - linear_program.set_objective_coefficient(v[144], 1); - linear_program.set_objective_coefficient(v[146], 1); - linear_program.set_objective_coefficient(v[148], 1); - linear_program.set_objective_coefficient(v[150], 1); - linear_program.set_objective_coefficient(v[152], 1); - linear_program.set_objective_coefficient(v[154], 1); - linear_program.set_objective_coefficient(v[156], 1); - linear_program.set_objective_coefficient(v[158], 1); - linear_program.set_objective_coefficient(v[160], 1); - linear_program.set_objective_coefficient(v[162], 1); - linear_program.set_objective_coefficient(v[164], 1); - linear_program.set_objective_coefficient(v[166], 1); - linear_program.set_objective_coefficient(v[168], 1); - linear_program.set_objective_coefficient(v[170], 1); - linear_program.set_objective_coefficient(v[172], 1); - linear_program.set_objective_coefficient(v[174], 1); - linear_program.set_objective_coefficient(v[176], 1); - linear_program.set_objective_coefficient(v[178], 1); - linear_program.set_objective_coefficient(v[180], 1); - linear_program.set_objective_coefficient(v[182], 1); - linear_program.set_objective_coefficient(v[184], 1); - linear_program.set_objective_coefficient(v[186], 1); - linear_program.set_objective_coefficient(v[188], 1); - linear_program.set_objective_coefficient(v[190], 1); - linear_program.set_objective_coefficient(v[192], 1); - linear_program.set_objective_coefficient(v[194], 1); - linear_program.set_objective_coefficient(v[196], 1); - linear_program.set_objective_coefficient(v[198], 1); - linear_program.set_objective_coefficient(v[200], 1); - linear_program.set_objective_coefficient(v[202], 1); - linear_program.set_objective_coefficient(v[204], 1); - linear_program.set_objective_coefficient(v[206], 1); - linear_program.set_objective_coefficient(v[208], 1); - linear_program.set_objective_coefficient(v[210], 1); - linear_program.set_objective_coefficient(v[212], 1); - linear_program.set_objective_coefficient(v[214], 1); - linear_program.set_objective_coefficient(v[216], 1); - linear_program.set_objective_coefficient(v[218], 1); - linear_program.set_objective_coefficient(v[220], 1); - linear_program.set_objective_coefficient(v[222], 1); - linear_program.set_objective_coefficient(v[224], 1); - linear_program.set_objective_coefficient(v[226], 1); - linear_program.set_objective_coefficient(v[228], 1); - linear_program.set_objective_coefficient(v[230], 1); - linear_program.set_objective_coefficient(v[232], 1); - linear_program.set_objective_coefficient(v[234], 1); - linear_program.set_objective_coefficient(v[236], 1); - linear_program.set_objective_coefficient(v[238], 1); - linear_program.set_objective_coefficient(v[240], 1); - linear_program.set_objective_coefficient(v[242], 1); - linear_program.set_objective_coefficient(v[244], 1); - linear_program.set_objective_coefficient(v[246], 1); - linear_program.set_objective_coefficient(v[248], 1); - linear_program.set_objective_coefficient(v[250], 1); - linear_program.set_objective_coefficient(v[252], 1); - linear_program.set_objective_coefficient(v[254], 1); - linear_program.set_objective_coefficient(v[256], 1); - linear_program.set_objective_coefficient(v[258], 1); - linear_program.set_objective_coefficient(v[260], 1); - linear_program.set_objective_coefficient(v[262], 1); - linear_program.set_objective_coefficient(v[264], 1); - linear_program.set_objective_coefficient(v[266], 1); - linear_program.set_objective_coefficient(v[268], 1); - linear_program.set_objective_coefficient(v[270], 1); - linear_program.set_objective_coefficient(v[272], 1); - linear_program.set_objective_coefficient(v[274], 1); - linear_program.set_objective_coefficient(v[276], 1); - linear_program.set_objective_coefficient(v[278], 1); - linear_program.set_objective_coefficient(v[280], 1); - linear_program.set_objective_coefficient(v[282], 1); - linear_program.set_objective_coefficient(v[284], 1); - linear_program.set_objective_coefficient(v[286], 1); - linear_program.set_objective_coefficient(v[288], 1); - linear_program.set_objective_coefficient(v[290], 1); - linear_program.set_objective_coefficient(v[292], 1); - linear_program.set_objective_coefficient(v[294], 1); - linear_program.set_objective_coefficient(v[296], 1); - linear_program.set_objective_coefficient(v[298], 1); - linear_program.set_objective_coefficient(v[300], 1); - linear_program.set_objective_coefficient(v[302], 1); - linear_program.set_objective_coefficient(v[304], 1); - linear_program.set_objective_coefficient(v[306], 1); - linear_program.set_objective_coefficient(v[308], 1); - linear_program.set_objective_coefficient(v[310], 1); - linear_program.set_objective_coefficient(v[312], 1); - linear_program.set_objective_coefficient(v[314], 1); - linear_program.set_objective_coefficient(v[316], 1); - linear_program.set_objective_coefficient(v[318], 1); - linear_program.set_objective_coefficient(v[320], 1); - linear_program.set_objective_coefficient(v[322], 1); - linear_program.set_objective_coefficient(v[324], 1); - linear_program.set_objective_coefficient(v[326], 1); - linear_program.set_objective_coefficient(v[328], 1); - linear_program.set_objective_coefficient(v[330], 1); - linear_program.set_objective_coefficient(v[332], 1); - linear_program.set_objective_coefficient(v[334], 1); - linear_program.set_objective_coefficient(v[336], 1); - linear_program.set_objective_coefficient(v[338], 1); - linear_program.set_objective_coefficient(v[340], 1); - linear_program.set_objective_coefficient(v[342], 1); - linear_program.set_objective_coefficient(v[344], 1); - linear_program.set_objective_coefficient(v[346], 1); - linear_program.set_objective_coefficient(v[348], 1); - linear_program.set_objective_coefficient(v[350], 1); - linear_program.set_objective_coefficient(v[352], 1); - linear_program.set_objective_coefficient(v[354], 1); - linear_program.set_objective_coefficient(v[356], 1); - linear_program.set_objective_coefficient(v[358], 1); - linear_program.set_objective_coefficient(v[360], 1); - linear_program.set_objective_coefficient(v[362], 1); - linear_program.set_objective_coefficient(v[364], 1); - linear_program.set_objective_coefficient(v[366], 1); - linear_program.set_objective_coefficient(v[368], 1); - linear_program.set_objective_coefficient(v[370], 1); - linear_program.set_objective_coefficient(v[372], 1); - linear_program.set_objective_coefficient(v[374], 1); - linear_program.set_objective_coefficient(v[376], 1); - linear_program.set_objective_coefficient(v[378], 1); - linear_program.set_objective_coefficient(v[380], 1); - linear_program.set_objective_coefficient(v[382], 1); - linear_program.set_objective_coefficient(v[384], 1); - linear_program.set_objective_coefficient(v[386], 1); - linear_program.set_objective_coefficient(v[388], 1); - linear_program.set_objective_coefficient(v[390], 1); - linear_program.set_objective_coefficient(v[392], 1); - linear_program.set_objective_coefficient(v[394], 1); - linear_program.set_objective_coefficient(v[396], 1); - linear_program.set_objective_coefficient(v[398], 1); - linear_program.set_objective_coefficient(v[400], 1); - linear_program.set_objective_coefficient(v[402], 1); - linear_program.set_objective_coefficient(v[404], 1); - linear_program.set_objective_coefficient(v[406], 1); - linear_program.set_objective_coefficient(v[408], 1); - linear_program.set_objective_coefficient(v[410], 1); - linear_program.set_objective_coefficient(v[412], 1); - linear_program.set_objective_coefficient(v[414], 1); - linear_program.set_objective_coefficient(v[416], 1); - linear_program.set_objective_coefficient(v[418], 1); - linear_program.set_objective_coefficient(v[420], 1); - linear_program.set_objective_coefficient(v[422], 1); - linear_program.set_objective_coefficient(v[424], 1); - linear_program.set_objective_coefficient(v[426], 1); - linear_program.set_objective_coefficient(v[428], 1); - linear_program.set_objective_coefficient(v[430], 1); - linear_program.set_objective_coefficient(v[432], 1); - linear_program.set_objective_coefficient(v[434], 1); - linear_program.set_objective_coefficient(v[436], 1); - linear_program.set_objective_coefficient(v[438], 1); - linear_program.set_objective_coefficient(v[440], 1); - linear_program.set_objective_coefficient(v[442], 1); - linear_program.set_objective_coefficient(v[444], 1); - linear_program.set_objective_coefficient(v[446], 1); - linear_program.set_objective_coefficient(v[448], 1); - linear_program.set_objective_coefficient(v[450], 1); - linear_program.set_objective_coefficient(v[452], 1); - linear_program.set_objective_coefficient(v[454], 1); - linear_program.set_objective_coefficient(v[456], 1); - linear_program.set_objective_coefficient(v[458], 1); - linear_program.set_objective_coefficient(v[460], 1); - linear_program.set_objective_coefficient(v[462], 1); - linear_program.set_objective_coefficient(v[464], 1); - linear_program.set_objective_coefficient(v[466], 1); - linear_program.set_objective_coefficient(v[468], 1); - linear_program.set_objective_coefficient(v[470], 1); - linear_program.set_objective_coefficient(v[472], 1); - linear_program.set_objective_coefficient(v[474], 1); - linear_program.set_objective_coefficient(v[476], 1); - linear_program.set_objective_coefficient(v[478], 1); - linear_program.set_objective_coefficient(v[480], 1); - linear_program.set_objective_coefficient(v[482], 1); - linear_program.set_objective_coefficient(v[484], 1); - linear_program.set_objective_coefficient(v[486], 1); - linear_program.set_objective_coefficient(v[488], 1); - linear_program.set_objective_coefficient(v[490], 1); - linear_program.set_objective_coefficient(v[492], 1); - linear_program.set_objective_coefficient(v[494], 1); - linear_program.set_objective_coefficient(v[496], 1); - linear_program.set_objective_coefficient(v[498], 1); - linear_program.set_objective_coefficient(v[500], 1); - linear_program.set_objective_coefficient(v[502], 1); - linear_program.set_objective_coefficient(v[504], 1); - linear_program.set_objective_coefficient(v[506], 1); - linear_program.set_objective_coefficient(v[508], 1); - linear_program.set_objective_coefficient(v[510], 1); - linear_program.set_objective_coefficient(v[512], 1); - linear_program.set_objective_coefficient(v[514], 1); - linear_program.set_objective_coefficient(v[516], 1); - linear_program.set_objective_coefficient(v[518], 1); - linear_program.set_objective_coefficient(v[520], 1); - linear_program.set_objective_coefficient(v[522], 1); - linear_program.set_objective_coefficient(v[524], 1); - linear_program.set_objective_coefficient(v[526], 1); - linear_program.set_objective_coefficient(v[528], 1); - linear_program.set_objective_coefficient(v[530], 1); - linear_program.set_objective_coefficient(v[532], 1); - linear_program.set_objective_coefficient(v[534], 1); - linear_program.set_objective_coefficient(v[536], 1); - linear_program.set_objective_coefficient(v[538], 1); - linear_program.set_objective_coefficient(v[540], 1); - linear_program.set_objective_coefficient(v[542], 1); - linear_program.set_objective_coefficient(v[544], 1); - linear_program.set_objective_coefficient(v[546], 1); - linear_program.set_objective_coefficient(v[548], 1); - linear_program.set_objective_coefficient(v[550], 1); - linear_program.set_objective_coefficient(v[552], 1); - linear_program.set_objective_coefficient(v[554], 1); - linear_program.set_objective_coefficient(v[556], 1); - linear_program.set_objective_coefficient(v[558], 1); - linear_program.set_objective_coefficient(v[560], 1); - linear_program.set_objective_coefficient(v[562], 1); - linear_program.set_objective_coefficient(v[564], 1); - linear_program.set_objective_coefficient(v[566], 1); - linear_program.set_objective_coefficient(v[568], 1); - linear_program.set_objective_coefficient(v[570], 1); - linear_program.set_objective_coefficient(v[572], 1); - linear_program.set_objective_coefficient(v[574], 1); - linear_program.set_objective_coefficient(v[576], 1); - linear_program.set_objective_coefficient(v[578], 1); - linear_program.set_objective_coefficient(v[580], 1); - linear_program.set_objective_coefficient(v[582], 1); - linear_program.set_objective_coefficient(v[584], 1); - linear_program.set_objective_coefficient(v[586], 1); - linear_program.set_objective_coefficient(v[588], 1); - linear_program.set_objective_coefficient(v[590], 1); - linear_program.set_objective_coefficient(v[592], 1); - linear_program.set_objective_coefficient(v[594], 1); - linear_program.set_objective_coefficient(v[596], 1); - linear_program.set_objective_coefficient(v[598], 1); - linear_program.set_objective_coefficient(v[600], 1); - linear_program.set_objective_coefficient(v[602], 1); - linear_program.set_objective_coefficient(v[604], 1); - linear_program.set_objective_coefficient(v[606], 1); - linear_program.set_objective_coefficient(v[608], 1); - linear_program.set_objective_coefficient(v[610], 1); - linear_program.set_objective_coefficient(v[612], 1); - linear_program.set_objective_coefficient(v[614], 1); - linear_program.set_objective_coefficient(v[616], 1); - linear_program.set_objective_coefficient(v[618], 1); - linear_program.set_objective_coefficient(v[620], 1); - linear_program.set_objective_coefficient(v[622], 1); - linear_program.set_objective_coefficient(v[624], 1); - linear_program.set_objective_coefficient(v[626], 1); - linear_program.set_objective_coefficient(v[628], 1); - linear_program.set_objective_coefficient(v[630], 1); - linear_program.set_objective_coefficient(v[632], 1); - linear_program.set_objective_coefficient(v[634], 1); - linear_program.set_objective_coefficient(v[636], 1); - linear_program.set_objective_coefficient(v[638], 1); - linear_program.set_objective_coefficient(v[640], 1); - linear_program.set_objective_coefficient(v[642], 1); - linear_program.set_objective_coefficient(v[644], 1); - linear_program.set_objective_coefficient(v[646], 1); - linear_program.set_objective_coefficient(v[648], 1); - linear_program.set_objective_coefficient(v[650], 1); - linear_program.set_objective_coefficient(v[652], 1); - linear_program.set_objective_coefficient(v[654], 1); - linear_program.set_objective_coefficient(v[656], 1); - linear_program.set_objective_coefficient(v[658], 1); - linear_program.set_objective_coefficient(v[660], 1); - linear_program.set_objective_coefficient(v[662], 1); - linear_program.set_objective_coefficient(v[664], 1); - linear_program.set_objective_coefficient(v[666], 1); - linear_program.set_objective_coefficient(v[668], 1); - linear_program.set_objective_coefficient(v[670], 1); - linear_program.set_objective_coefficient(v[672], 1); - linear_program.set_objective_coefficient(v[674], 1); - linear_program.set_objective_coefficient(v[676], 1); - linear_program.set_objective_coefficient(v[678], 1); - linear_program.set_objective_coefficient(v[680], 1); - linear_program.set_objective_coefficient(v[682], 1); - linear_program.set_objective_coefficient(v[684], 1); - linear_program.set_objective_coefficient(v[686], 1); - linear_program.set_objective_coefficient(v[688], 1); - linear_program.set_objective_coefficient(v[690], 1); - linear_program.set_objective_coefficient(v[692], 1); - linear_program.set_objective_coefficient(v[694], 1); - linear_program.set_objective_coefficient(v[696], 1); - linear_program.set_objective_coefficient(v[698], 1); - linear_program.set_objective_coefficient(v[700], 1); - linear_program.set_objective_coefficient(v[702], 1); - linear_program.set_objective_coefficient(v[704], 1); - linear_program.set_objective_coefficient(v[706], 1); - linear_program.set_objective_coefficient(v[708], 1); - linear_program.set_objective_coefficient(v[710], 1); - linear_program.set_objective_coefficient(v[712], 1); - linear_program.set_objective_coefficient(v[714], 1); - linear_program.set_objective_coefficient(v[716], 1); - linear_program.set_objective_coefficient(v[718], 1); - linear_program.set_objective_coefficient(v[720], 1); - linear_program.set_objective_coefficient(v[722], 1); - linear_program.set_objective_coefficient(v[724], 1); - linear_program.set_objective_coefficient(v[726], 1); - linear_program.set_objective_coefficient(v[728], 1); - linear_program.set_objective_coefficient(v[730], 1); - linear_program.set_objective_coefficient(v[732], 1); - linear_program.set_objective_coefficient(v[734], 1); - linear_program.set_objective_coefficient(v[736], 1); - linear_program.set_objective_coefficient(v[738], 1); - linear_program.set_objective_coefficient(v[740], 1); - linear_program.set_objective_coefficient(v[742], 1); - linear_program.set_objective_coefficient(v[744], 1); - linear_program.set_objective_coefficient(v[746], 1); - linear_program.set_objective_coefficient(v[748], 1); - linear_program.set_objective_coefficient(v[750], 1); - linear_program.set_objective_coefficient(v[752], 1); - linear_program.set_objective_coefficient(v[754], 1); - linear_program.set_objective_coefficient(v[756], 1); - linear_program.set_objective_coefficient(v[758], 1); - linear_program.set_objective_coefficient(v[760], 1); - linear_program.set_objective_coefficient(v[762], 1); - linear_program.set_objective_coefficient(v[764], 1); - linear_program.set_objective_coefficient(v[766], 1); - linear_program.set_objective_coefficient(v[768], 1); - linear_program.set_objective_coefficient(v[770], 1); - linear_program.set_objective_coefficient(v[772], 1); - linear_program.set_objective_coefficient(v[774], 1); - linear_program.set_objective_coefficient(v[776], 1); - linear_program.set_objective_coefficient(v[778], 1); - linear_program.set_objective_coefficient(v[780], 1); - linear_program.set_objective_coefficient(v[782], 1); - linear_program.set_objective_coefficient(v[784], 1); - linear_program.set_objective_coefficient(v[786], 1); - linear_program.set_objective_coefficient(v[788], 1); - linear_program.set_objective_coefficient(v[790], 1); - linear_program.set_objective_coefficient(v[792], 1); - linear_program.set_objective_coefficient(v[794], 1); - linear_program.set_objective_coefficient(v[796], 1); - linear_program.set_objective_coefficient(v[798], 1); - linear_program.set_objective_coefficient(v[800], 1); - linear_program.set_objective_coefficient(v[802], 1); - linear_program.set_objective_coefficient(v[804], 1); - linear_program.set_objective_coefficient(v[806], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[7], -1).set_coefficient(v[8], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[11], -1).set_coefficient(v[12], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[15], -1).set_coefficient(v[16], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[19], -1).set_coefficient(v[20], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[25], 1).set_coefficient(v[26], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[27], -1).set_coefficient(v[28], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[31], -1).set_coefficient(v[32], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[35], -1).set_coefficient(v[36], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[41], 1).set_coefficient(v[42], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[43], -1).set_coefficient(v[44], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[47], -1).set_coefficient(v[48], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[51], -1).set_coefficient(v[52], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[55], -1).set_coefficient(v[56], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[61], 1).set_coefficient(v[62], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[65], 1).set_coefficient(v[66], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[67], -1).set_coefficient(v[68], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[71], -1).set_coefficient(v[72], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[75], -1).set_coefficient(v[76], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[79], -1).set_coefficient(v[80], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[85], 1).set_coefficient(v[86], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[87], -1).set_coefficient(v[88], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[93], 1).set_coefficient(v[94], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[97], 1).set_coefficient(v[98], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[99], -1).set_coefficient(v[100], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[103], -1).set_coefficient(v[104], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[107], -1).set_coefficient(v[108], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[111], -1).set_coefficient(v[112], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[117], 1).set_coefficient(v[118], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[119], -1).set_coefficient(v[120], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[123], -1).set_coefficient(v[124], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[127], -1).set_coefficient(v[128], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[131], -1).set_coefficient(v[132], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[135], -1).set_coefficient(v[136], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[139], -1).set_coefficient(v[140], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[143], -1).set_coefficient(v[144], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[149], 1).set_coefficient(v[150], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[153], 1).set_coefficient(v[154], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[157], 1).set_coefficient(v[158], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[161], 1).set_coefficient(v[162], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[165], 1).set_coefficient(v[166], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[167], -1).set_coefficient(v[168], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[173], 1).set_coefficient(v[174], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[175], -1).set_coefficient(v[176], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[179], -1).set_coefficient(v[180], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[183], -1).set_coefficient(v[184], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[189], 1).set_coefficient(v[190], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[193], 1).set_coefficient(v[194], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[197], 1).set_coefficient(v[198], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[199], -1).set_coefficient(v[200], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[205], 1).set_coefficient(v[206], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[207], -1).set_coefficient(v[208], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[211], -1).set_coefficient(v[212], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[215], -1).set_coefficient(v[216], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[219], -1).set_coefficient(v[220], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[225], 1).set_coefficient(v[226], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[229], 1).set_coefficient(v[230], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[6], 1).set_coefficient(v[233], 1).set_coefficient(v[234], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[237], 1).set_coefficient(v[238], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[239], -1).set_coefficient(v[240], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[243], -1).set_coefficient(v[244], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[247], -1).set_coefficient(v[248], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[253], 1).set_coefficient(v[254], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[257], 1).set_coefficient(v[258], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[261], 1).set_coefficient(v[262], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[265], 1).set_coefficient(v[266], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[267], -1).set_coefficient(v[268], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[273], 1).set_coefficient(v[274], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[277], 1).set_coefficient(v[278], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[281], 1).set_coefficient(v[282], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[283], -1).set_coefficient(v[284], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[289], 1).set_coefficient(v[290], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[293], 1).set_coefficient(v[294], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[295], -1).set_coefficient(v[296], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[299], -1).set_coefficient(v[300], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[305], 1).set_coefficient(v[306], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[307], -1).set_coefficient(v[308], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[313], 1).set_coefficient(v[314], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[315], -1).set_coefficient(v[316], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[319], -1).set_coefficient(v[320], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[323], -1).set_coefficient(v[324], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[329], 1).set_coefficient(v[330], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[331], -1).set_coefficient(v[332], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[337], 1).set_coefficient(v[338], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[341], 1).set_coefficient(v[342], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[343], -1).set_coefficient(v[344], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[347], -1).set_coefficient(v[348], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[351], -1).set_coefficient(v[352], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[355], -1).set_coefficient(v[356], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[359], -1).set_coefficient(v[360], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[363], -1).set_coefficient(v[364], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[369], 1).set_coefficient(v[370], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[373], 1).set_coefficient(v[374], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[377], 1).set_coefficient(v[378], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[381], 1).set_coefficient(v[382], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[385], 1).set_coefficient(v[386], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[387], -1).set_coefficient(v[388], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[393], 1).set_coefficient(v[394], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[395], -1).set_coefficient(v[396], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[401], 1).set_coefficient(v[402], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[403], -1).set_coefficient(v[404], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[407], -1).set_coefficient(v[408], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[413], 1).set_coefficient(v[414], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[417], 1).set_coefficient(v[418], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[421], 1).set_coefficient(v[422], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[423], -1).set_coefficient(v[424], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[429], 1).set_coefficient(v[430], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[433], 1).set_coefficient(v[434], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[435], -1).set_coefficient(v[436], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[441], 1).set_coefficient(v[442], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[445], 1).set_coefficient(v[446], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[447], -1).set_coefficient(v[448], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[451], -1).set_coefficient(v[452], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[457], 1).set_coefficient(v[458], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[461], 1).set_coefficient(v[462], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[465], 1).set_coefficient(v[466], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[467], -1).set_coefficient(v[468], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[473], 1).set_coefficient(v[474], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[477], 1).set_coefficient(v[478], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[481], 1).set_coefficient(v[482], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[485], 1).set_coefficient(v[486], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[487], -1).set_coefficient(v[488], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[491], -1).set_coefficient(v[492], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[497], 1).set_coefficient(v[498], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[499], -1).set_coefficient(v[500], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[505], 1).set_coefficient(v[506], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[507], -1).set_coefficient(v[508], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[511], -1).set_coefficient(v[512], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[517], 1).set_coefficient(v[518], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[519], -1).set_coefficient(v[520], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[523], -1).set_coefficient(v[524], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[527], -1).set_coefficient(v[528], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[533], 1).set_coefficient(v[534], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[537], 1).set_coefficient(v[538], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[541], 1).set_coefficient(v[542], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[545], 1).set_coefficient(v[546], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[549], 1).set_coefficient(v[550], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[551], -1).set_coefficient(v[552], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[555], -1).set_coefficient(v[556], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[561], 1).set_coefficient(v[562], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[563], -1).set_coefficient(v[564], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[569], 1).set_coefficient(v[570], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[571], -1).set_coefficient(v[572], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[577], 1).set_coefficient(v[578], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[581], 1).set_coefficient(v[582], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[585], 1).set_coefficient(v[586], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[587], -1).set_coefficient(v[588], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[593], 1).set_coefficient(v[594], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[595], -1).set_coefficient(v[596], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[599], -1).set_coefficient(v[600], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[603], -1).set_coefficient(v[604], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[609], 1).set_coefficient(v[610], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[613], 1).set_coefficient(v[614], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[5], 1).set_coefficient(v[615], -1).set_coefficient(v[616], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[621], 1).set_coefficient(v[622], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[623], -1).set_coefficient(v[624], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[627], -1).set_coefficient(v[628], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[631], -1).set_coefficient(v[632], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[637], 1).set_coefficient(v[638], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[641], 1).set_coefficient(v[642], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[643], -1).set_coefficient(v[644], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[647], -1).set_coefficient(v[648], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[651], -1).set_coefficient(v[652], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[655], -1).set_coefficient(v[656], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[661], 1).set_coefficient(v[662], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[663], -1).set_coefficient(v[664], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[667], -1).set_coefficient(v[668], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[671], -1).set_coefficient(v[672], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[675], -1).set_coefficient(v[676], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[681], 1).set_coefficient(v[682], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[685], 1).set_coefficient(v[686], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[687], -1).set_coefficient(v[688], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[693], 1).set_coefficient(v[694], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[695], -1).set_coefficient(v[696], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[701], 1).set_coefficient(v[702], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[705], 1).set_coefficient(v[706], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[707], -1).set_coefficient(v[708], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[711], -1).set_coefficient(v[712], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[715], -1).set_coefficient(v[716], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[719], -1).set_coefficient(v[720], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[725], 1).set_coefficient(v[726], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[729], 1).set_coefficient(v[730], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[731], -1).set_coefficient(v[732], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[735], -1).set_coefficient(v[736], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[739], -1).set_coefficient(v[740], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[745], 1).set_coefficient(v[746], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[6], 1).set_coefficient(v[747], -1).set_coefficient(v[748], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[751], -1).set_coefficient(v[752], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[755], -1).set_coefficient(v[756], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[759], -1).set_coefficient(v[760], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[765], 1).set_coefficient(v[766], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[769], 1).set_coefficient(v[770], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[6], 1).set_coefficient(v[773], 1).set_coefficient(v[774], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[775], -1).set_coefficient(v[776], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[6], 1).set_coefficient(v[779], -1).set_coefficient(v[780], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[785], 1).set_coefficient(v[786], -1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[787], -1).set_coefficient(v[788], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[791], -1).set_coefficient(v[792], 1); - linear_program.create_constraint().set_bounds(1, 1).set_coefficient(v[0], 1).set_coefficient(v[1], 1).set_coefficient(v[2], 1).set_coefficient(v[6], 1).set_coefficient(v[795], -1).set_coefficient(v[796], 1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[1], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[801], 1).set_coefficient(v[802], -1); - linear_program.create_constraint().set_bounds(0.999999, 0.999999).set_coefficient(v[2], 1).set_coefficient(v[3], 1).set_coefficient(v[4], 1).set_coefficient(v[5], 1).set_coefficient(v[6], 1).set_coefficient(v[805], 1).set_coefficient(v[806], -1); - } - const auto solution = linear_program.solve(); - if (solution) { - return solution->cost; - } else { - return std::nullopt; - } - }); -} diff --git a/lincs/liblincs/linear-programming/test-bug-0004-small-error-gets-inverted-to-large-error.cpp b/lincs/liblincs/linear-programming/test-bug-0004-small-error-gets-inverted-to-large-error.cpp deleted file mode 100644 index c3313da1..00000000 --- a/lincs/liblincs/linear-programming/test-bug-0004-small-error-gets-inverted-to-large-error.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -TEST_CASE("Bug") { - test([](auto& linear_program) -> std::optional { - { - std::vector::variable_type> v; - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - linear_program.mark_all_variables_created(); - linear_program.set_objective_coefficient(v[0], 1); - linear_program.set_objective_coefficient(v[1], -1); - linear_program.set_objective_coefficient(v[2], -3); - linear_program.create_constraint().set_bounds(0, infinity).set_coefficient(v[0], 1); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 0.29).set_coefficient(v[1], 0.86).set_coefficient(v[2], -1.29); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 0.08).set_coefficient(v[1], -2.05).set_coefficient(v[2], 1.96); - linear_program.create_constraint().set_bounds(1.21, 3.21).set_coefficient(v[0], 1.74).set_coefficient(v[1], 0.54).set_coefficient(v[2], -0.07); - } - const auto solution = linear_program.solve(); - if (solution) { - return solution->cost; - } else { - return std::nullopt; - } - }); -} diff --git a/lincs/liblincs/linear-programming/test-bug-0005-gpu-behaves-differently-from-cpu.cpp b/lincs/liblincs/linear-programming/test-bug-0005-gpu-behaves-differently-from-cpu.cpp deleted file mode 100644 index 19bd605a..00000000 --- a/lincs/liblincs/linear-programming/test-bug-0005-gpu-behaves-differently-from-cpu.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -TEST_CASE("Bug") { - test([](auto& linear_program) -> std::optional { - { - std::vector::variable_type> v; - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - v.push_back(linear_program.create_variable()); - linear_program.mark_all_variables_created(); - linear_program.set_objective_coefficient(v[0], -2.6169455); - linear_program.set_objective_coefficient(v[1], -0.56562924); - linear_program.set_objective_coefficient(v[2], -2.6307747); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 1); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[1], 1); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[2], 1); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 0.3803965).set_coefficient(v[1], -0.9824758).set_coefficient(v[2], 0.4877367); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 0.57658184).set_coefficient(v[1], -0.8118078).set_coefficient(v[2], 0.014208794); - linear_program.create_constraint().set_bounds(-1, 1).set_coefficient(v[0], 0.85147953).set_coefficient(v[1], -0.5650891).set_coefficient(v[2], 0.15271592); - } - const auto solution = linear_program.solve(); - if (solution) { - return solution->cost; - } else { - return std::nullopt; - } - }); -} diff --git a/lincs/liblincs/linear-programming/test.cpp b/lincs/liblincs/linear-programming/test.cpp deleted file mode 100644 index 08b5a9de..00000000 --- a/lincs/liblincs/linear-programming/test.cpp +++ /dev/null @@ -1,660 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "testing.hpp" - - -// @todo(Project management, when we release our in-house LP solvers) Add tests from https://www4.uwsp.edu/math/afelt/slptestset/download.html - -TEST_CASE("Example 1.1 of https://webspace.maths.qmul.ac.uk/felix.fischer/teaching/opt/notes/notes.pdf") { - test([](auto& linear_program){ - const auto x1 = linear_program.create_variable(); - const auto x2 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x1, -1); - linear_program.set_objective_coefficient(x2, -1); - - linear_program.create_constraint().set_coefficient(x1, 1).set_coefficient(x2, 2).set_bounds(-infinity, 6); - linear_program.create_constraint().set_coefficient(x1, 1).set_coefficient(x2, -1).set_bounds(-infinity, 3); - const auto solution = *linear_program.solve(); - - CHECK_NEAR(solution.assignments[x1], 4); - CHECK_NEAR(solution.assignments[x2], 1); - CHECK_NEAR(solution.cost, -5); - - return solution.cost; - }); -} - -TEST_CASE("Simplex orthogonal to objective gradient, origin feasible but not optimal") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - linear_program.set_objective_coefficient(y, -1); - - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, 1).set_bounds(-infinity, +1); - - const auto solution = *linear_program.solve(); - - // Can't check the assignments because they are not unique - CHECK_NEAR(solution.cost, -1); - - return solution.cost; - }); -} - -TEST_CASE("'Small house' linear program") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - // Objective: minimize F(x, y) = -0.1 * x - y - linear_program.set_objective_coefficient(x, -0.1); - linear_program.set_objective_coefficient(y, -1); - - // Constraints: - // -1 <= x <= +1 - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-1, 1); - // -1 <= y <= +1 - linear_program.create_constraint().set_coefficient(y, 1).set_bounds(-1, 1); - // -1 <= x - y - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -1).set_bounds(-1, +infinity); - // x + y <= 1 - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, 1).set_bounds(-infinity, 1); - - // Optimal solution: - // F(0, 1) = -1 - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 0); - CHECK_NEAR(solution.assignments[y], 1); - CHECK_NEAR(solution.cost, -1); - - return solution.cost; - }); -} - -TEST_CASE("Octagon linear program - solution on octagon") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - linear_program.set_objective_coefficient(y, -1); - - // Octagon centered on (0,0) - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, 1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, 2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, -1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -2).set_coefficient(y, 1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -1).set_coefficient(y, 2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -2).set_coefficient(y, -1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -1).set_coefficient(y, -2).set_bounds(-infinity, 3); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 1); - CHECK_NEAR(solution.assignments[y], 1); - CHECK_NEAR(solution.cost, -2); - - return solution.cost; - }); -} - -TEST_CASE("Octagon linear program - solution on origin (Because of implicit positivity constraints on each variable!)") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - linear_program.set_objective_coefficient(y, 1); - - // Octagon centered on (0,0) - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, 1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, 2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, -1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -2).set_coefficient(y, 1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -1).set_coefficient(y, 2).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -2).set_coefficient(y, -1).set_bounds(-infinity, 3); - linear_program.create_constraint().set_coefficient(x, -1).set_coefficient(y, -2).set_bounds(-infinity, 3); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 0); - CHECK_NEAR(solution.assignments[y], 0); - CHECK_NEAR(solution.cost, 0); - - return solution.cost; - }); -} - -TEST_CASE("One unused variable") { - test([](auto& linear_program) { - const auto x0 = linear_program.create_variable(); - const auto x1 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x0, -1); - - linear_program.create_constraint().set_coefficient(x0, 1).set_bounds(-infinity, 1); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x0], 1); - CHECK_NEAR(solution.assignments[x1], 0); // Not unique but all current solvers happen to return this value - CHECK_NEAR(solution.cost, -1); - - return solution.cost; - }); -} - -TEST_CASE("Two unused variables") { - test([](auto& linear_program) { - const auto x0 = linear_program.create_variable(); - const auto x1 = linear_program.create_variable(); - const auto x2 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x2, -1); - - linear_program.create_constraint().set_coefficient(x2, 1).set_bounds(-infinity, 1); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x0], 0); // Not unique but all current solvers happen to return this value - CHECK_NEAR(solution.assignments[x1], 0); // Idem - CHECK_NEAR(solution.assignments[x2], 1); - CHECK_NEAR(solution.cost, -1); - - return solution.cost; - }); -} - -TEST_CASE("Equality constraint with origin feasible") { - test([](auto& linear_program) { - const auto x1 = linear_program.create_variable(); - const auto x2 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x1, -1); - linear_program.set_objective_coefficient(x2, -1); - - linear_program.create_constraint().set_coefficient(x1, 1).set_coefficient(x2, -2).set_bounds(0, 0); - linear_program.create_constraint().set_coefficient(x1, 1).set_coefficient(x2, 1).set_bounds(-infinity, 3); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x1], 2); - CHECK_NEAR(solution.assignments[x2], 1); - CHECK_NEAR(solution.cost, -3); - - return solution.cost; - }); -} - -TEST_CASE("Section 8 of https://webspace.maths.qmul.ac.uk/felix.fischer/teaching/opt/notes/notes.pdf") { - test([](auto& linear_program) { - const auto x1 = linear_program.create_variable(); - const auto x2 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x1, 6); - linear_program.set_objective_coefficient(x2, 3); - - linear_program.create_constraint().set_coefficient(x1, 1).set_coefficient(x2, 1).set_bounds(1, infinity); - linear_program.create_constraint().set_coefficient(x1, 2).set_coefficient(x2, -1).set_bounds(1, infinity); - linear_program.create_constraint().set_coefficient(x2, 3).set_bounds(-infinity, 2); - - const auto solution = *linear_program.solve(); - - CHECK_NEAR(solution.assignments[x1], 2./3); - CHECK_NEAR(solution.assignments[x2], 1./3); - CHECK_NEAR(solution.cost, 5); - - return solution.cost; - }); - - // Small variations because the example has several equal constants in different places, so we need to make sure we don't mix them up - for (unsigned seed = 0; seed != 1'000; ++seed) { - CAPTURE(seed); - - test([seed](auto& linear_program) { - std::mt19937 mt(seed); - std::uniform_real_distribution make_small_variation(-0.01, 0.01); - - const auto x1 = linear_program.create_variable(); - const auto x2 = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x1, 6 + make_small_variation(mt)); - linear_program.set_objective_coefficient(x2, 3 + make_small_variation(mt)); - - linear_program.create_constraint().set_coefficient(x1, 1 + make_small_variation(mt)).set_coefficient(x2, 1 + make_small_variation(mt)).set_bounds(1 + make_small_variation(mt), infinity); - linear_program.create_constraint().set_coefficient(x1, 2 + make_small_variation(mt)).set_coefficient(x2, -1 + make_small_variation(mt)).set_bounds(1 + make_small_variation(mt), infinity); - linear_program.create_constraint().set_coefficient(x2, 3 + make_small_variation(mt)).set_bounds(-infinity, 2 + make_small_variation(mt)); - - const auto solution = *linear_program.solve(); - - return solution.cost; - }); - } -} - -TEST_CASE("Origin optimal") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-1, 1); - - const auto solution = *linear_program.solve(); - - CHECK_NEAR(solution.assignments[x], 0); - CHECK_NEAR(solution.cost, 0); - - return solution.cost; - }); -} - -TEST_CASE("Origin not feasible") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(1, +infinity); - - const auto solution = *linear_program.solve(); - - CHECK_NEAR(solution.assignments[x], 1); - CHECK_NEAR(solution.cost, 1); - - return solution.cost; - }); -} - -TEST_CASE("Simplex orthogonal to objective gradient, origin not feasible - 1") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - linear_program.set_objective_coefficient(y, 1); - - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, 1).set_bounds(1, +infinity); - - const auto solution = *linear_program.solve(); - - // Can't check the assignments because they are not unique - CHECK_NEAR(solution.cost, 1); - - return solution.cost; - }); -} - -TEST_CASE("Simplex orthogonal to objective gradient, origin not feasible - 2") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - linear_program.set_objective_coefficient(y, 1); - - linear_program.create_constraint().set_coefficient(x, -1).set_coefficient(y, -1).set_bounds(-infinity, -1); - - const auto solution = *linear_program.solve(); - - // Can't check the assignments because they are not unique - CHECK_NEAR(solution.cost, 1); - - return solution.cost; - }); -} - -TEST_CASE("Triangle far from origin linear program - 1") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, 1); - linear_program.set_objective_coefficient(y, 2); - - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -1).set_bounds(1, infinity); - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-infinity, 2); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 1); - CHECK_NEAR(solution.assignments[y], 0); - CHECK_NEAR(solution.cost, 1); - - return solution.cost; - }); -} - -TEST_CASE("Triangle far from origin linear program - 2") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -2); - linear_program.set_objective_coefficient(y, -1); - - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -1).set_bounds(1, infinity); - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-infinity, 2); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 2); - CHECK_NEAR(solution.assignments[y], 1); - CHECK_NEAR(solution.cost, -5); - - return solution.cost; - }); -} - -TEST_CASE("Triangle far from origin linear program - 3") { - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - linear_program.set_objective_coefficient(y, 1); - - linear_program.create_constraint().set_coefficient(x, 1).set_coefficient(y, -1).set_bounds(1, infinity); - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-infinity, 2); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.assignments[x], 2); - CHECK_NEAR(solution.assignments[y], 0); - CHECK_NEAR(solution.cost, -2); - - return solution.cost; - }); -} - -TEST_CASE("Wikipedia example 1") { - // https://en.wikipedia.org/wiki/Simplex_algorithm#Example - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - const auto z = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -2); - linear_program.set_objective_coefficient(y, -3); - linear_program.set_objective_coefficient(z, -4); - - linear_program.create_constraint().set_coefficient(x, 3).set_coefficient(y, 2).set_coefficient(z, 1).set_bounds(-infinity, 10); - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, 5).set_coefficient(z, 3).set_bounds(-infinity, 15); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.cost, -20); - const float recomputed_cost = -2 * solution.assignments[x] -3 * solution.assignments[y] - 4 * solution.assignments[z]; - CHECK_NEAR(recomputed_cost, solution.cost); - - return solution.cost; - }); -} - -TEST_CASE("Wikipedia example 2 - equality constraints, origin not feasible") { - // https://en.wikipedia.org/wiki/Simplex_algorithm#Example_2 - test([](auto& linear_program) { - const auto x = linear_program.create_variable(); - const auto y = linear_program.create_variable(); - const auto z = linear_program.create_variable(); - - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -2); - linear_program.set_objective_coefficient(y, -3); - linear_program.set_objective_coefficient(z, -4); - - linear_program.create_constraint().set_coefficient(x, 3).set_coefficient(y, 2).set_coefficient(z, 1).set_bounds(10, 10); - linear_program.create_constraint().set_coefficient(x, 2).set_coefficient(y, 5).set_coefficient(z, 3).set_bounds(15, 15); - - const auto solution = *linear_program.solve(); - CHECK_NEAR(solution.cost, -130./7.); - const float recomputed_cost = -2 * solution.assignments[x] -3 * solution.assignments[y] - 4 * solution.assignments[z]; - CHECK_NEAR(recomputed_cost, solution.cost); - - return solution.cost; - }); -} - -TEST_CASE("Random linear programs with optimal solutions reached in one Simplex phase") { - for (unsigned seed = 0; seed != 10'000; ++seed) { - CAPTURE(seed); - - test([seed](auto& linear_program) { - std::mt19937 mt(seed); - - std::uniform_int_distribution make_variables_count(2, 10); - const unsigned variables_count = make_variables_count(mt); - std::uniform_real_distribution make_objective_coefficient(-3, 3); - std::uniform_int_distribution make_constraints_count(0, 2 * variables_count); - const unsigned constraints_count = make_constraints_count(mt); - std::uniform_real_distribution make_constraint_coefficient(-1, 1); - - std::vector variables; - for (unsigned i = 0; i != variables_count; ++i) { - variables.push_back(linear_program.create_variable()); - } - - linear_program.mark_all_variables_created(); - - // Give a coefficient to each variable - // @todo(Project management, when we release our in-house LP solvers) Let some variables not appear in the objective - std::vector objective_coefficients; - objective_coefficients.resize(variables_count); - for (unsigned i = 0; i != variables_count; ++i) { - const float coefficient = make_objective_coefficient(mt); - objective_coefficients[i] = coefficient; - linear_program.set_objective_coefficient(variables[i], coefficient); - } - - // Box all variables to ensure the problem is bounded - for (const auto& v : variables) { - auto c = linear_program.create_constraint(); - c.set_bounds(-1, 1); - c.set_coefficient(v, 1); - } - - for (unsigned i = 0; i != constraints_count; ++i) { - auto c = linear_program.create_constraint(); - c.set_bounds(-1, 1); - // @todo(Project management, when we release our in-house LP solvers) Let some variables not appear in some constraints - for (const auto& v : variables) { - c.set_coefficient(v, make_constraint_coefficient(mt)); - } - } - - const auto solution = *linear_program.solve(); - CHECK(solution.cost != -infinity); - CHECK(!std::isnan(solution.cost)); - - float expected_cost = 0; - for (unsigned i = 0; i != variables_count; ++i) { - expected_cost += objective_coefficients[i] * solution.assignments[variables[i]]; - } - CHECK_NEAR(solution.cost, expected_cost); - - return solution.cost; - }); - } -} - -TEST_CASE("Random linear programs requiring two Simplex phases") { - for (unsigned seed = 0; seed != 10'000; ++seed) { - CAPTURE(seed); - - test([seed](auto& linear_program) -> std::optional { - std::mt19937 mt(seed); - - std::uniform_int_distribution make_variables_count(2, 10); - const unsigned variables_count = make_variables_count(mt); - std::uniform_real_distribution make_objective_coefficient(-3, 3); - std::uniform_int_distribution make_constraints_count(1, 2 * variables_count); - const unsigned constraints_count = make_constraints_count(mt); - std::uniform_real_distribution make_constraint_coefficient(-1, 1); - - std::vector variables; - for (unsigned i = 0; i != variables_count; ++i) { - variables.push_back(linear_program.create_variable()); - } - - linear_program.mark_all_variables_created(); - - // Give a coefficient to each variable - // @todo(Project management, when we release our in-house LP solvers) Let some variables not appear in the objective - std::vector objective_coefficients; - objective_coefficients.resize(variables_count); - for (unsigned i = 0; i != variables_count; ++i) { - const float coefficient = make_objective_coefficient(mt); - objective_coefficients[i] = coefficient; - linear_program.set_objective_coefficient(variables[i], coefficient); - } - - // Box all variables to ensure the problem is bounded - for (const auto& v : variables) { - auto c = linear_program.create_constraint(); - c.set_bounds(-infinity, 1); - c.set_coefficient(v, 1); - } - - for (unsigned i = 0; i != constraints_count; ++i) { - auto c = linear_program.create_constraint(); - c.set_bounds(1, 10); - // @todo(Project management, when we release our in-house LP solvers) Let some variables not appear in some constraints - for (const auto& v : variables) { - c.set_coefficient(v, make_constraint_coefficient(mt)); - } - } - - const auto solution = linear_program.solve(); - if (solution) { - float expected_cost = 0; - for (unsigned i = 0; i != variables_count; ++i) { - expected_cost += objective_coefficients[i] * solution->assignments[variables[i]]; - } - CHECK_NEAR(solution->cost, expected_cost); - return solution->cost; - } else { - return std::nullopt; - } - }); - } -} - -TEST_CASE("Unbounded (single phase)") { - test([](auto& linear_program) -> std::optional { - const auto x = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(0, infinity); - - const auto solution = linear_program.solve(); - CHECK_FALSE(solution); - return std::nullopt; - }); -} - -TEST_CASE("Unbounded (two phases)") { - test([](auto& linear_program) -> std::optional { - const auto x = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(1, infinity); - - const auto solution = linear_program.solve(); - CHECK_FALSE(solution); - return std::nullopt; - }); -} - -TEST_CASE("Infeasible") { - test([](auto& linear_program) -> std::optional { - const auto x = linear_program.create_variable(); - linear_program.mark_all_variables_created(); - - linear_program.set_objective_coefficient(x, -1); - - linear_program.create_constraint().set_coefficient(x, 1).set_bounds(-2, -1); - - const auto solution = linear_program.solve(); - CHECK_FALSE(solution); - return std::nullopt; - }); -} - -TEST_CASE("More random linear programs with optimal solutions") { - for (unsigned variables_count = 2; variables_count != 10; ++variables_count) { - CAPTURE(variables_count); - - for (unsigned seed = 0; seed != 100; ++seed) { - CAPTURE(seed); - - test([variables_count, seed](auto& linear_program) { - std::vector::variable_type> variables; - for (unsigned i = 0; i != variables_count; ++i) { - variables.push_back(linear_program.create_variable()); - } - linear_program.mark_all_variables_created(); - for (const auto& v : variables) { - linear_program.create_constraint().set_coefficient(v, 1).set_bounds(0, 1000); - } - - std::mt19937 mt(seed); - - std::uniform_real_distribution make_objective_coefficient(-3, 3); - for (const auto& v : variables) { - linear_program.set_objective_coefficient(v, make_objective_coefficient(mt)); - } - - std::uniform_int_distribution make_constraints_count(0, 2 * variables_count); - std::uniform_int_distribution make_constraint_variables_count(2, variables_count); - const unsigned constraints_count = make_constraints_count(mt); - for (unsigned constraint_index = 0; constraint_index != constraints_count; ++constraint_index) { - std::vector variable_indices(variables_count, 0); - std::iota(variable_indices.begin(), variable_indices.end(), 0); - std::shuffle(variable_indices.begin(), variable_indices.end(), mt); - variable_indices.resize(make_constraint_variables_count(mt)); - - auto constraint = linear_program.create_constraint(); - float value_at_one = 0; - for (const auto& variable_index : variable_indices) { - const float coefficient = make_objective_coefficient(mt); - constraint.set_coefficient(variables[variable_index], coefficient); - value_at_one += coefficient; - } - // Make sure the Simplex contains point (1, 1, ..., 1) - constraint.set_bounds(value_at_one - 1, value_at_one + 1); - } - - const auto solution = linear_program.solve(); - CHECK(solution); - return solution->cost; - }); - } - } -} - -// @todo(Project management, when we release our in-house LP solvers) Test consistency on all kinds of linear programs (unbounded, infeasible, others?) diff --git a/lincs/liblincs/linear-programming/testing.hpp b/lincs/liblincs/linear-programming/testing.hpp deleted file mode 100644 index 8ccb99ae..00000000 --- a/lincs/liblincs/linear-programming/testing.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2024 Vincent Jacques - -#ifndef LINCS__LINEAR_PROGRAMMING__TESTING_HPP -#define LINCS__LINEAR_PROGRAMMING__TESTING_HPP - -#include -#include - -#include "alglib.hpp" -#include "glop.hpp" - -#include "../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -constexpr float infinity = std::numeric_limits::infinity(); - -// @todo(Feature, later) Understand why we need such a high tolerance; try to reduce it -const float rel_diff_epsilon = 1e-2; - -inline float relative_difference(float a, float b) { - assert(!std::isnan(a) && !std::isnan(b)); - assert(std::abs(a) != infinity && std::abs(b) != infinity); - - if (std::abs(a) < rel_diff_epsilon && std::abs(b) < rel_diff_epsilon) { - return 0; - } else { - return std::abs(a - b) / std::max(std::abs(a), std::abs(b)); - } -} - -#define CHECK_NEAR(a, b) CHECK(relative_difference(a, b) < rel_diff_epsilon) - - -typedef std::tuple< - lincs::GlopLinearProgram, - lincs::AlglibLinearProgram -> LinearPrograms; - -template -void check_all_equal_impl(const std::tuple...>& costs) { - static_assert(0 < Index); - static_assert(Index <= sizeof...(Float)); - if constexpr (Index < sizeof...(Float)) { - if (std::get<0>(costs)) { - if (std::get(costs)) { - CHECK_NEAR(*std::get<0>(costs), *std::get(costs)); - } else { - CHECK(false); - } - } else { - CHECK_FALSE(std::get(costs)); - } - check_all_equal_impl(costs); - } -} - -template -void check_all_equal(const std::tuple...>& costs) { - check_all_equal_impl<1>(costs); -} - -template -void check_all_equal_impl(const std::tuple& costs) { - static_assert(0 < Index); - static_assert(Index <= sizeof...(Float)); - if constexpr (Index < sizeof...(Float)) { - CHECK_NEAR(std::get<0>(costs), std::get(costs)); - check_all_equal_impl(costs); - } -} - -template -void check_all_equal(const std::tuple& costs) { - check_all_equal_impl<1>(costs); -} - -template -void test(F&& f) { - LinearPrograms linear_programs; - const auto costs = std::apply([&f](auto&... linear_program) { return std::make_tuple(f(linear_program)...); }, linear_programs); - check_all_equal(costs); -} - -#endif // LINCS__LINEAR_PROGRAMMING__TESTING_HPP diff --git a/lincs/liblincs/randomness-utils.cpp b/lincs/liblincs/randomness-utils.cpp deleted file mode 100644 index 197a1918..00000000 --- a/lincs/liblincs/randomness-utils.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "randomness-utils.hpp" - -#include "vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -TEST_CASE("ProbabilityWeightedGenerator") { - std::map value_probabilities = { - {"a", 0.1}, - {"b", 0.2}, - {"c", 0.3}, - {"d", 0.4}, - }; - - auto generator = ProbabilityWeightedGenerator(value_probabilities); - - std::mt19937 mt(42); - std::map counts; - for (unsigned i = 0; i < 10000; ++i) { - const std::string value = generator(mt); - counts[value] += 1; - } - - CHECK(counts.size() == 4); - CHECK(counts["a"] == 1016); - CHECK(counts["b"] == 1958); - CHECK(counts["c"] == 3002); - CHECK(counts["d"] == 4024); -} - -TEST_CASE("Equivalent 'ProbabilityWeightedGenerator's with copied generators generate equivalent values") { - std::mt19937 mt1(42); - std::mt19937 mt2(mt1); - - auto generator1 = ProbabilityWeightedGenerator({ - {0, 0.1}, - {1, 0.2}, - {2, 0.3}, - {3, 0.4}, - }); - - auto generator2 = ProbabilityWeightedGenerator({ - {'3', 0.4}, - {'2', 0.3}, - {'1', 0.2}, - {'0', 0.1}, - }); - - CHECK(generator1(mt1) == 3); - CHECK(generator1(mt1) == 1); - CHECK(generator1(mt1) == 3); - CHECK(generator1(mt1) == 2); - CHECK(generator1(mt1) == 2); - CHECK(generator1(mt1) == 0); - CHECK(generator1(mt1) == 2); - CHECK(generator1(mt1) == 2); - CHECK(generator1(mt1) == 1); - CHECK(generator1(mt1) == 3); - - CHECK(generator2(mt2) == '3'); - CHECK(generator2(mt2) == '1'); - CHECK(generator2(mt2) == '3'); - CHECK(generator2(mt2) == '2'); - CHECK(generator2(mt2) == '2'); - CHECK(generator2(mt2) == '0'); - CHECK(generator2(mt2) == '2'); - CHECK(generator2(mt2) == '2'); - CHECK(generator2(mt2) == '1'); - CHECK(generator2(mt2) == '3'); -} diff --git a/lincs/liblincs/randomness-utils.hpp b/lincs/liblincs/randomness-utils.hpp deleted file mode 100644 index 78439d3b..00000000 --- a/lincs/liblincs/randomness-utils.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__RANDOMNESS_UTILS_HPP -#define LINCS__RANDOMNESS_UTILS_HPP - -#include -#include -#include -#include -#include - - -/* -Pick random values from a finite set with given probabilities -(a discrete distribution with arbitrary values). -*/ -template -class ProbabilityWeightedGenerator { - ProbabilityWeightedGenerator(const std::vector& values_, const std::vector& probabilities) : - values(values_), - distribution(probabilities.begin(), probabilities.end()) - {} - - // I tried using ranges and all but I failed - std::vector map_keys(const std::map& value_probabilities) { - std::vector keys; - for (const auto& [k, v] : value_probabilities) { - keys.push_back(k); - } - return keys; - } - - std::vector map_values(const std::map& value_probabilities) { - std::vector values; - for (const auto& [k, v] : value_probabilities) { - values.push_back(v); - } - return values; - } - - public: - ProbabilityWeightedGenerator(const std::map& value_probabilities) : - ProbabilityWeightedGenerator(map_keys(value_probabilities), map_values(value_probabilities)) - { - assert(!value_probabilities.empty()); - } - - template - T operator()(Generator& gen) const { - const unsigned index = distribution(gen); - assert(index < values.size()); - return values[index]; - } - - private: - std::vector values; - mutable std::discrete_distribution distribution; -}; - -template -void shuffle(std::mt19937& random_generator, T m) { - for (unsigned i = 0; i != m.s0(); ++i) { - std::swap(m[i], m[std::uniform_int_distribution(0, m.s0() - 1)(random_generator)]); - } -} - -#endif // LINCS__RANDOMNESS_UTILS_HPP diff --git a/lincs/liblincs/sat/eval-max-sat.cpp b/lincs/liblincs/sat/eval-max-sat.cpp deleted file mode 100644 index 9ad3f995..00000000 --- a/lincs/liblincs/sat/eval-max-sat.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#define EVALMAXSAT_IMPLEMENT -#include "eval-max-sat.hpp" - -#include "../chrones.hpp" - - -namespace lincs { - -std::optional> EvalmaxsatMaxSatProblem::solve() { - CHRONE(); - - if (solver.solve()) { - std::vector solution(variables.back() + 1); - for (const int v : variables) { - solution[v] = solver.getValue(v); - } - return solution; - } else { - return std::nullopt; - } -} - -} // namespace lincs diff --git a/lincs/liblincs/sat/eval-max-sat.hpp b/lincs/liblincs/sat/eval-max-sat.hpp deleted file mode 100644 index 2a8c35bf..00000000 --- a/lincs/liblincs/sat/eval-max-sat.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__SAT__EVALMAXSAT_HPP -#define LINCS__SAT__EVALMAXSAT_HPP - -#include -#include - -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#pragma GCC diagnostic ignored "-Wmisleading-indentation" -#pragma GCC diagnostic ignored "-Wparentheses" -#pragma GCC diagnostic ignored "-Wreorder" -#pragma GCC diagnostic ignored "-Wreturn-type" -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include "../vendored/eval-max-sat/EvalMaxSAT.h" -#pragma GCC diagnostic pop // No associated push => restore command-line options -#undef LOG - - -namespace lincs { - -class EvalmaxsatMaxSatProblem { - public: - EvalmaxsatMaxSatProblem( - unsigned nb_minimize_threads = 0, - unsigned timeout_fast_minimize = 60, // Seconds. Documented as "Magic number" in EvalMaxSAT source code. - unsigned coef_minimize_time = 2 // Documented as "Magic number" in EvalMaxSAT source code. - ) : solver(nb_minimize_threads) { - solver.setTimeOutFast(timeout_fast_minimize); - solver.setCoefMinimize(coef_minimize_time); - } - - public: - typedef int variable_type; - variable_type create_variable() { - int v = solver.newVar(); - variables.push_back(v); - return v; - } - - void mark_all_variables_created() {} - - public: - void add_clause(std::vector clause) { - solver.addClause(clause); - } - - typedef unsigned weight_type; - void add_weighted_clause(std::vector clause, weight_type weight) { - solver.addWeightedClause(clause, weight); - } - - std::optional> solve(); - - private: - EvalMaxSAT solver; - std::vector variables; -}; - -} // namespace lincs - -#endif // LINCS__SAT__EVALMAXSAT_HPP diff --git a/lincs/liblincs/sat/minisat.cpp b/lincs/liblincs/sat/minisat.cpp deleted file mode 100644 index fe60ab8f..00000000 --- a/lincs/liblincs/sat/minisat.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "minisat.hpp" - -#include "../chrones.hpp" - - -namespace lincs { - -std::optional> MinisatSatProblem::solve() { - CHRONE(); - - Minisat::vec dummy; - const auto ret = solver.solveLimited(dummy); - - if (ret == Minisat::l_True) { - std::vector solution(solver.nVars() + 1); - for (int i = 0; i < solver.nVars(); ++i) { - solution[i + 1] = solver.model[i] == Minisat::l_True; - } - - return solution; - } else { - return std::nullopt; - } -} - -} // namespace lincs diff --git a/lincs/liblincs/sat/minisat.hpp b/lincs/liblincs/sat/minisat.hpp deleted file mode 100644 index 75aedce1..00000000 --- a/lincs/liblincs/sat/minisat.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#ifndef LINCS__SAT__MINISAT_HPP -#define LINCS__SAT__MINISAT_HPP - -#include -#include - -#include "../vendored/minisat/simp/SimpSolver.h" - - -namespace lincs { - -class MinisatSatProblem { - public: - typedef int variable_type; - variable_type create_variable() { - return solver.newVar() + 1; - } - - void mark_all_variables_created() {} - - private: - auto make_literal(variable_type v) { - if (v > 0) { - return Minisat::mkLit(v - 1); - } else { - assert(v < 0); - return ~Minisat::mkLit(-v - 1); - } - } - - public: - void add_clause(std::vector clause_) { - Minisat::vec clause; - for (auto variable : clause_) { - clause.push(make_literal(variable)); - } - solver.addClause(clause); - } - - typedef void weight_type; - - std::optional> solve(); - - private: - Minisat::SimpSolver solver; -}; - -} // namespace lincs - -#endif // LINCS__SAT__MINISAT_HPP diff --git a/lincs/liblincs/sat/test.cpp b/lincs/liblincs/sat/test.cpp deleted file mode 100644 index 43c2c332..00000000 --- a/lincs/liblincs/sat/test.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include "eval-max-sat.hpp" -#include "minisat.hpp" - -#include "../vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -template -void test_sat_problem() { - { - SatProblem problem; - - auto x1 = problem.create_variable(); - auto x2 = problem.create_variable(); - auto x3 = problem.create_variable(); - - problem.mark_all_variables_created(); - - problem.add_clause({x1, -x3}); - problem.add_clause({x2, x3, -x1}); - - std::optional> solution = problem.solve(); - - CHECK(((*solution)[x1] || !(*solution)[x3])); - CHECK(((*solution)[x2] || (*solution)[x3] || !(*solution)[x1])); - } - { - SatProblem problem; - - auto x1 = problem.create_variable(); - - problem.mark_all_variables_created(); - - problem.add_clause({x1}); - problem.add_clause({-x1}); - - std::optional> solution = problem.solve(); - - CHECK(!solution); - } -} - -template -void test_max_sat_problem() { - MaxSatProblem problem; - - auto x1 = problem.create_variable(); - auto x2 = problem.create_variable(); - auto x3 = problem.create_variable(); - - problem.add_clause({-x1, -x2, -x3}); // a - - problem.add_weighted_clause({x1, x2}, 1); // b - problem.add_weighted_clause({x3}, 1); // c - problem.add_weighted_clause({x1, -x3}, 1); // d - problem.add_weighted_clause({x2, -x3}, 1); // e - - // x1 x2 x3 a b c d e score - // 0 0 0 1 0 0 1 1 2 - // 0 0 1 1 0 1 0 0 1 - // 0 1 0 1 1 0 1 1 3 - // 0 1 1 1 1 1 0 1 3 - // 1 0 0 1 1 0 1 1 3 - // 1 0 1 1 1 1 1 0 3 - // 1 1 0 1 1 0 1 1 3 - // 1 1 1 0 1 1 1 1 4 - - auto solution = problem.solve(); - - CHECK((!(*solution)[x1] || !(*solution)[x2] || !(*solution)[x3])); - - int score = 0; - if ((*solution)[x1] || (*solution)[x2]) ++score; - if ((*solution)[x3]) ++score; - if ((*solution)[x1] || !(*solution)[x3]) ++score; - if ((*solution)[x2] || !(*solution)[x3]) ++score; - CHECK(score == 3); -} - -// Some SAT solvers: -// - minisat -// - glucose -// - cadical -// - lingeling -// - cryptominisat -// - picosat -// - riss -// - kissat -// - minisatp - -// Some max-SAT solvers: -// - EvalMaxSAT -// - open-wbo -// - maxhs -// - cryptominisat -// - maxwalksat -// - maxsatz - -TEST_CASE("Minisat SAT problem") { - test_sat_problem(); -} - -TEST_CASE("EvalMaxSAT SAT problem") { - test_sat_problem(); -} - -TEST_CASE("EvalMaxSAT max-SAT problem") { - test_max_sat_problem(); -} diff --git a/lincs/liblincs/test-cuda-floating-points.cu b/lincs/liblincs/test-cuda-floating-points.cu deleted file mode 100644 index 98b28c59..00000000 --- a/lincs/liblincs/test-cuda-floating-points.cu +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2023-2024 Vincent Jacques - -#include -#include -#include - -#include "vendored/lov-e.hpp" - -#include "vendored/doctest.h" // Keep last because it defines really common names like CHECK that we don't want injected into other headers - - -namespace { - -bool env_is_true(const char* name) { - const char* value = std::getenv(name); - return value && std::string(value) == "true"; -} - -const bool forbid_gpu = env_is_true("LINCS_DEV_FORBID_GPU"); - -} // namespace - -namespace { - -typedef GridFactory1D<128> grid; - -__global__ void kernel( - const ArrayView2D operands, - const ArrayView2D results -) { - assert(results.s0() == operands.s0()); - assert(results.s1() == 4); - - unsigned index = grid::x(); - assert(index < operands.s0() + grid::blockDim().x); - if (index < operands.s0()) { - results[0][index] = operands[0][index] + operands[1][index]; - results[1][index] = operands[0][index] - operands[1][index]; - results[2][index] = operands[0][index] * operands[1][index]; - results[3][index] = operands[0][index] / operands[1][index]; - } -} - -TEST_CASE("floating point operations on random doubles behave bit-to-bit-the-same on the GPU and on the CPU" * doctest::skip(forbid_gpu)) { - const unsigned count = 1'000'000; - for (unsigned random_seed = 0; random_seed != 25; ++random_seed) { - std::mt19937 gen(random_seed); - std::uniform_real_distribution dist(0, 1); - - Array2D operands_on_host(2, count, uninitialized); - for (unsigned i = 0; i < count; ++i) { - operands_on_host[0][i] = dist(gen); - operands_on_host[1][i] = dist(gen); - } - Array2D operands_on_device = operands_on_host.clone_to(); - - Array2D host_results(4, count, uninitialized); - for (unsigned index = 0; index < count; ++index) { - host_results[0][index] = operands_on_host[0][index] + operands_on_host[1][index]; - host_results[1][index] = operands_on_host[0][index] - operands_on_host[1][index]; - host_results[2][index] = operands_on_host[0][index] * operands_on_host[1][index]; - host_results[3][index] = operands_on_host[0][index] / operands_on_host[1][index]; - } - - Array2D device_results(4, count, uninitialized); - Grid grid = grid::make(count); - kernel<<>>(operands_on_device, ref(device_results)); - Array2D device_results_on_host = device_results.clone_to(); - - for (unsigned index = 0; index < count; ++index) { - CHECK(device_results_on_host[0][index] == host_results[0][index]); - CHECK(device_results_on_host[1][index] == host_results[1][index]); - CHECK(device_results_on_host[2][index] == host_results[2][index]); - CHECK(device_results_on_host[3][index] == host_results[3][index]); - } - } -} - -} // namespace - - -namespace { - -__host__ __device__ -double compute(double a, double b, double c, double d) { - return (c * a - b * d) / a; -} - -__global__ void kernel( - const ArrayView1D inputs, - const ArrayView1D outputs -) { - assert(inputs.s0() == 4); - - outputs[0] = compute(inputs[0], inputs[1], inputs[2], inputs[3]); -} - -TEST_CASE("Specific operations on specific values behave differently on the GPU and on the CPU" * doctest::skip(forbid_gpu)) { - Array1D inputs_on_host(4, uninitialized); - inputs_on_host[0] = 0.6636555388921431; - inputs_on_host[1] = 2.3023796233172344; - inputs_on_host[2] = -5.234825899201804; - inputs_on_host[3] = 0.004927249084663451; - Array1D inputs_on_device = inputs_on_host.clone_to(); - - const double expected_result = -5.251919703482374; - const double unexpected_result = -5.251919703482373; - assert(expected_result != unexpected_result); - - Array1D host_outputs(1, uninitialized); - host_outputs[0] = compute(inputs_on_host[0], inputs_on_host[1], inputs_on_host[2], inputs_on_host[3]); - CHECK(host_outputs[0] == expected_result); - - Array1D device_outputs(1, uninitialized); - kernel<<<1, 1>>>(inputs_on_device, ref(device_outputs)); - Array1D device_outputs_on_host = device_outputs.clone_to(); - CHECK(device_outputs_on_host[0] != expected_result); - CHECK(device_outputs_on_host[0] == unexpected_result); -} - -} diff --git a/lincs/liblincs/vendored/alglib/alglibinternal.cpp b/lincs/liblincs/vendored/alglib/alglibinternal.cpp deleted file mode 120000 index 85381e4f..00000000 --- a/lincs/liblincs/vendored/alglib/alglibinternal.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/alglibinternal.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/alglibinternal.h b/lincs/liblincs/vendored/alglib/alglibinternal.h deleted file mode 120000 index 7426f99d..00000000 --- a/lincs/liblincs/vendored/alglib/alglibinternal.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/alglibinternal.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/alglibmisc.cpp b/lincs/liblincs/vendored/alglib/alglibmisc.cpp deleted file mode 120000 index 65ab1732..00000000 --- a/lincs/liblincs/vendored/alglib/alglibmisc.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/alglibmisc.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/alglibmisc.h b/lincs/liblincs/vendored/alglib/alglibmisc.h deleted file mode 120000 index b3a0c411..00000000 --- a/lincs/liblincs/vendored/alglib/alglibmisc.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/alglibmisc.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/ap.cpp b/lincs/liblincs/vendored/alglib/ap.cpp deleted file mode 120000 index 90cb19dc..00000000 --- a/lincs/liblincs/vendored/alglib/ap.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/ap.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/ap.h b/lincs/liblincs/vendored/alglib/ap.h deleted file mode 120000 index cda2f331..00000000 --- a/lincs/liblincs/vendored/alglib/ap.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/ap.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/dataanalysis.cpp b/lincs/liblincs/vendored/alglib/dataanalysis.cpp deleted file mode 120000 index 93d03ff2..00000000 --- a/lincs/liblincs/vendored/alglib/dataanalysis.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/dataanalysis.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/dataanalysis.h b/lincs/liblincs/vendored/alglib/dataanalysis.h deleted file mode 120000 index f6ddc94b..00000000 --- a/lincs/liblincs/vendored/alglib/dataanalysis.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/dataanalysis.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/diffequations.cpp b/lincs/liblincs/vendored/alglib/diffequations.cpp deleted file mode 120000 index 51d22185..00000000 --- a/lincs/liblincs/vendored/alglib/diffequations.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/diffequations.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/diffequations.h b/lincs/liblincs/vendored/alglib/diffequations.h deleted file mode 120000 index ea72bff8..00000000 --- a/lincs/liblincs/vendored/alglib/diffequations.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/diffequations.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/fasttransforms.cpp b/lincs/liblincs/vendored/alglib/fasttransforms.cpp deleted file mode 120000 index 709988e0..00000000 --- a/lincs/liblincs/vendored/alglib/fasttransforms.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/fasttransforms.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/fasttransforms.h b/lincs/liblincs/vendored/alglib/fasttransforms.h deleted file mode 120000 index 9437dccf..00000000 --- a/lincs/liblincs/vendored/alglib/fasttransforms.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/fasttransforms.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/integration.cpp b/lincs/liblincs/vendored/alglib/integration.cpp deleted file mode 120000 index 872b42fa..00000000 --- a/lincs/liblincs/vendored/alglib/integration.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/integration.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/integration.h b/lincs/liblincs/vendored/alglib/integration.h deleted file mode 120000 index 144eb8f0..00000000 --- a/lincs/liblincs/vendored/alglib/integration.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/integration.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/interpolation.cpp b/lincs/liblincs/vendored/alglib/interpolation.cpp deleted file mode 120000 index 9435ecd8..00000000 --- a/lincs/liblincs/vendored/alglib/interpolation.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/interpolation.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/interpolation.h b/lincs/liblincs/vendored/alglib/interpolation.h deleted file mode 120000 index 19f8a4f0..00000000 --- a/lincs/liblincs/vendored/alglib/interpolation.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/interpolation.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_avx2.cpp b/lincs/liblincs/vendored/alglib/kernels_avx2.cpp deleted file mode 120000 index b22f57b8..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_avx2.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_avx2.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_avx2.h b/lincs/liblincs/vendored/alglib/kernels_avx2.h deleted file mode 120000 index 709f1207..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_avx2.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_avx2.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_fma.cpp b/lincs/liblincs/vendored/alglib/kernels_fma.cpp deleted file mode 120000 index f3ac37d9..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_fma.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_fma.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_fma.h b/lincs/liblincs/vendored/alglib/kernels_fma.h deleted file mode 120000 index 18bf4724..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_fma.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_fma.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_sse2.cpp b/lincs/liblincs/vendored/alglib/kernels_sse2.cpp deleted file mode 120000 index bc31535c..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_sse2.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_sse2.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/kernels_sse2.h b/lincs/liblincs/vendored/alglib/kernels_sse2.h deleted file mode 120000 index 5174408d..00000000 --- a/lincs/liblincs/vendored/alglib/kernels_sse2.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/kernels_sse2.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/linalg.cpp b/lincs/liblincs/vendored/alglib/linalg.cpp deleted file mode 120000 index 5ad599b3..00000000 --- a/lincs/liblincs/vendored/alglib/linalg.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/linalg.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/linalg.h b/lincs/liblincs/vendored/alglib/linalg.h deleted file mode 120000 index ab4eb333..00000000 --- a/lincs/liblincs/vendored/alglib/linalg.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/linalg.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/optimization.cpp b/lincs/liblincs/vendored/alglib/optimization.cpp deleted file mode 120000 index f9e83761..00000000 --- a/lincs/liblincs/vendored/alglib/optimization.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/optimization.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/optimization.h b/lincs/liblincs/vendored/alglib/optimization.h deleted file mode 120000 index 4abd1a16..00000000 --- a/lincs/liblincs/vendored/alglib/optimization.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/optimization.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/solvers.cpp b/lincs/liblincs/vendored/alglib/solvers.cpp deleted file mode 120000 index 61b18d36..00000000 --- a/lincs/liblincs/vendored/alglib/solvers.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/solvers.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/solvers.h b/lincs/liblincs/vendored/alglib/solvers.h deleted file mode 120000 index 8c657499..00000000 --- a/lincs/liblincs/vendored/alglib/solvers.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/solvers.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/specialfunctions.cpp b/lincs/liblincs/vendored/alglib/specialfunctions.cpp deleted file mode 120000 index 3a222cc4..00000000 --- a/lincs/liblincs/vendored/alglib/specialfunctions.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/specialfunctions.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/specialfunctions.h b/lincs/liblincs/vendored/alglib/specialfunctions.h deleted file mode 120000 index 7ca0c517..00000000 --- a/lincs/liblincs/vendored/alglib/specialfunctions.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/specialfunctions.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/statistics.cpp b/lincs/liblincs/vendored/alglib/statistics.cpp deleted file mode 120000 index 9e0edfc9..00000000 --- a/lincs/liblincs/vendored/alglib/statistics.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/statistics.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/statistics.h b/lincs/liblincs/vendored/alglib/statistics.h deleted file mode 120000 index ed9927d4..00000000 --- a/lincs/liblincs/vendored/alglib/statistics.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/statistics.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/alglib/stdafx.h b/lincs/liblincs/vendored/alglib/stdafx.h deleted file mode 120000 index 883aa010..00000000 --- a/lincs/liblincs/vendored/alglib/stdafx.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/alglib-cpp/src/stdafx.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/EvalMaxSAT.h b/lincs/liblincs/vendored/eval-max-sat/EvalMaxSAT.h deleted file mode 120000 index 055b962e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/EvalMaxSAT.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/EvalMaxSAT.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/MaLib/Chrono.h b/lincs/liblincs/vendored/eval-max-sat/MaLib/Chrono.h deleted file mode 120000 index 9552367b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/MaLib/Chrono.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/MaLib/src/Chrono.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/MaLib/View.h b/lincs/liblincs/vendored/eval-max-sat/MaLib/View.h deleted file mode 120000 index 22b19599..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/MaLib/View.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/MaLib/src/View.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/MaLib/communicationlist.h b/lincs/liblincs/vendored/eval-max-sat/MaLib/communicationlist.h deleted file mode 120000 index e8526d6c..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/MaLib/communicationlist.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/MaLib/src/communicationlist.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/analyze.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/analyze.cpp deleted file mode 120000 index d88f0a41..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/analyze.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/analyze.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/arena.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/arena.cpp deleted file mode 120000 index f99192f0..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/arena.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/arena.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/arena.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/arena.hpp deleted file mode 120000 index 7e8767a4..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/arena.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/arena.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/assume.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/assume.cpp deleted file mode 120000 index 493ee25b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/assume.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/assume.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/averages.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/averages.cpp deleted file mode 120000 index 04b2d263..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/averages.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/averages.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/averages.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/averages.hpp deleted file mode 120000 index 6da7426c..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/averages.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/averages.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/backtrack.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/backtrack.cpp deleted file mode 120000 index eb5d6d96..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/backtrack.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/backtrack.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/backward.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/backward.cpp deleted file mode 120000 index 8f10c4ce..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/backward.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/backward.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/bins.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/bins.cpp deleted file mode 120000 index de393f62..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/bins.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/bins.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/bins.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/bins.hpp deleted file mode 120000 index 7ab0b759..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/bins.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/bins.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/block.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/block.cpp deleted file mode 120000 index 50a5aa7a..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/block.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/block.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/block.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/block.hpp deleted file mode 120000 index db3f73a2..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/block.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/block.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/cadical.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/cadical.hpp deleted file mode 120000 index 333d20da..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/cadical.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/cadical.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/checker.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/checker.cpp deleted file mode 120000 index 28eb902b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/checker.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/checker.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/checker.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/checker.hpp deleted file mode 120000 index a749e98a..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/checker.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/checker.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/clause.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/clause.cpp deleted file mode 120000 index 8cd14a54..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/clause.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/clause.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/clause.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/clause.hpp deleted file mode 120000 index 5a8de630..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/clause.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/clause.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/collect.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/collect.cpp deleted file mode 120000 index 8366d37b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/collect.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/collect.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/compact.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/compact.cpp deleted file mode 120000 index 2c53a945..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/compact.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/compact.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/condition.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/condition.cpp deleted file mode 120000 index 1b36bfc9..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/condition.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/condition.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/config.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/config.cpp deleted file mode 120000 index bdf3deee..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/config.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/config.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/config.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/config.hpp deleted file mode 120000 index dd8677b8..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/config.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/config.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/constrain.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/constrain.cpp deleted file mode 120000 index 53f4f8c2..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/constrain.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/constrain.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/contract.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/contract.cpp deleted file mode 120000 index af1e3aa4..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/contract.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/contract.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/contract.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/contract.hpp deleted file mode 120000 index 7e541f7f..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/contract.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/contract.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/cover.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/cover.cpp deleted file mode 120000 index c1557e2b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/cover.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/cover.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/cover.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/cover.hpp deleted file mode 120000 index 8a362017..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/cover.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/cover.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/decide.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/decide.cpp deleted file mode 120000 index 3962854c..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/decide.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/decide.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/decompose.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/decompose.cpp deleted file mode 120000 index c90355d2..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/decompose.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/decompose.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/deduplicate.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/deduplicate.cpp deleted file mode 120000 index b32bf63e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/deduplicate.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/deduplicate.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/elim.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/elim.cpp deleted file mode 120000 index d65ec86f..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/elim.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/elim.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/elim.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/elim.hpp deleted file mode 120000 index 8e7e0d75..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/elim.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/elim.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/ema.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/ema.cpp deleted file mode 120000 index 05aee232..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/ema.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/ema.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/ema.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/ema.hpp deleted file mode 120000 index 30c96285..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/ema.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/ema.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/extend.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/extend.cpp deleted file mode 120000 index cf535cd8..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/extend.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/extend.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/external.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/external.cpp deleted file mode 120000 index 80c891ca..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/external.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/external.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/external.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/external.hpp deleted file mode 120000 index 35baaffe..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/external.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/external.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/flags.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/flags.cpp deleted file mode 120000 index 66525d55..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/flags.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/flags.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/flags.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/flags.hpp deleted file mode 120000 index 20bdb6e0..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/flags.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/flags.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/format.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/format.cpp deleted file mode 120000 index afd0039e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/format.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/format.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/format.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/format.hpp deleted file mode 120000 index 40a80ae1..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/format.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/format.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/gates.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/gates.cpp deleted file mode 120000 index 12a5a6d8..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/gates.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/gates.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/heap.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/heap.hpp deleted file mode 120000 index 267626c5..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/heap.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/heap.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.cpp deleted file mode 120000 index cdccb09d..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/instantiate.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.hpp deleted file mode 120000 index 5fe0ecbe..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/instantiate.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/instantiate.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/internal.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/internal.cpp deleted file mode 120000 index 4c2501e0..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/internal.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/internal.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/internal.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/internal.hpp deleted file mode 120000 index a7475a1b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/internal.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/internal.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/inttypes.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/inttypes.hpp deleted file mode 120000 index 8387d713..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/inttypes.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/inttypes.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/ipasir.h b/lincs/liblincs/vendored/eval-max-sat/cadical/ipasir.h deleted file mode 120000 index 0d446b1a..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/ipasir.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/ipasir.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/level.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/level.hpp deleted file mode 120000 index 240a6b6e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/level.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/level.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/limit.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/limit.cpp deleted file mode 120000 index 57dfeb00..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/limit.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/limit.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/limit.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/limit.hpp deleted file mode 120000 index 74a6506e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/limit.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/limit.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/logging.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/logging.cpp deleted file mode 120000 index b4b16f06..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/logging.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/logging.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/logging.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/logging.hpp deleted file mode 120000 index 88ba9839..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/logging.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/logging.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/lookahead.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/lookahead.cpp deleted file mode 120000 index a862ae18..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/lookahead.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/lookahead.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/lucky.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/lucky.cpp deleted file mode 120000 index 3436ac64..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/lucky.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/lucky.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/message.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/message.cpp deleted file mode 120000 index 1551ff56..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/message.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/message.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/message.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/message.hpp deleted file mode 120000 index 03d86c5e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/message.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/message.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/minimize.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/minimize.cpp deleted file mode 120000 index 06a1dbda..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/minimize.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/minimize.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/observer.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/observer.hpp deleted file mode 120000 index bad504b6..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/observer.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/observer.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/occs.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/occs.cpp deleted file mode 120000 index 02674ddc..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/occs.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/occs.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/occs.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/occs.hpp deleted file mode 120000 index 6a6e58e9..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/occs.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/occs.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/options.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/options.cpp deleted file mode 120000 index b50dbf40..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/options.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/options.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/options.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/options.hpp deleted file mode 120000 index dccb389d..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/options.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/options.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/parse.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/parse.hpp deleted file mode 120000 index 60feee89..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/parse.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/parse.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/phases.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/phases.cpp deleted file mode 120000 index 7ae07251..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/phases.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/phases.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/phases.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/phases.hpp deleted file mode 120000 index f05b800d..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/phases.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/phases.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/probe.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/probe.cpp deleted file mode 120000 index d2113653..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/probe.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/probe.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/profile.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/profile.cpp deleted file mode 120000 index 9f5a4a47..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/profile.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/profile.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/profile.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/profile.hpp deleted file mode 120000 index 38c5cc64..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/profile.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/profile.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/propagate.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/propagate.cpp deleted file mode 120000 index 8864c08f..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/propagate.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/propagate.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/queue.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/queue.cpp deleted file mode 120000 index 6b11fdf0..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/queue.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/queue.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/queue.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/queue.hpp deleted file mode 120000 index ab35c579..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/queue.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/queue.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/radix.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/radix.hpp deleted file mode 120000 index df9c55bc..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/radix.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/radix.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/random.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/random.cpp deleted file mode 120000 index 9ca381bf..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/random.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/random.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/random.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/random.hpp deleted file mode 120000 index f5b8a92b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/random.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/random.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/range.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/range.hpp deleted file mode 120000 index 23af9a2f..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/range.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/range.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/reduce.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/reduce.cpp deleted file mode 120000 index d15c416b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/reduce.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/reduce.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/reluctant.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/reluctant.hpp deleted file mode 120000 index c96b3083..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/reluctant.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/reluctant.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/rephase.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/rephase.cpp deleted file mode 120000 index af14a97e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/rephase.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/rephase.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/report.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/report.cpp deleted file mode 120000 index ef2a0a74..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/report.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/report.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/resources.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/resources.cpp deleted file mode 120000 index d19175ec..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/resources.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/resources.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/resources.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/resources.hpp deleted file mode 120000 index b3aa9f21..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/resources.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/resources.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/restart.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/restart.cpp deleted file mode 120000 index d5a8693d..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/restart.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/restart.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/restore.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/restore.cpp deleted file mode 120000 index a5a5ca83..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/restore.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/restore.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/score.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/score.cpp deleted file mode 120000 index fbca2595..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/score.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/score.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/score.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/score.hpp deleted file mode 120000 index e972e120..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/score.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/score.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/shrink.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/shrink.cpp deleted file mode 120000 index 324524b2..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/shrink.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/shrink.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/signal.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/signal.hpp deleted file mode 120000 index b0291c6a..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/signal.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/signal.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/solution.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/solution.cpp deleted file mode 120000 index 59633f98..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/solution.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/solver.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/solver.cpp deleted file mode 120000 index d3e61a61..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/solver.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/solver.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/stats.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/stats.cpp deleted file mode 120000 index 8e229503..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/stats.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/stats.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/stats.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/stats.hpp deleted file mode 120000 index b959eb7e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/stats.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/stats.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/subsume.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/subsume.cpp deleted file mode 120000 index f8c60578..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/subsume.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/subsume.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/ternary.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/ternary.cpp deleted file mode 120000 index 841ae7b3..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/ternary.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/ternary.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/tracer.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/tracer.hpp deleted file mode 120000 index 484e3a6e..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/tracer.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/tracer.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/transred.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/transred.cpp deleted file mode 120000 index 6ade6c45..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/transred.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/transred.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/util.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/util.cpp deleted file mode 120000 index bb6ac53a..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/util.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/util.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/util.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/util.hpp deleted file mode 120000 index f501ad3b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/util.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/util.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/var.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/var.cpp deleted file mode 120000 index a7377164..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/var.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/var.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/var.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/var.hpp deleted file mode 120000 index 48d2b8d3..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/var.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/var.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/version.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/version.cpp deleted file mode 120000 index b74a93da..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/version.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/version.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/version.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/version.hpp deleted file mode 120000 index a845132c..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/version.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/version.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.cpp deleted file mode 120000 index ac8e6e36..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/vivify.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.hpp deleted file mode 120000 index 0752fbba..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/vivify.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/vivify.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/walk.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/walk.cpp deleted file mode 120000 index e9b71227..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/walk.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/walk.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/watch.cpp b/lincs/liblincs/vendored/eval-max-sat/cadical/watch.cpp deleted file mode 120000 index f437aa90..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/watch.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/watch.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadical/watch.hpp b/lincs/liblincs/vendored/eval-max-sat/cadical/watch.hpp deleted file mode 120000 index 061cb275..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadical/watch.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/eval-max-sat/lib/cadical/src/watch.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cadicalinterface.h b/lincs/liblincs/vendored/eval-max-sat/cadicalinterface.h deleted file mode 120000 index 7232001b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cadicalinterface.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/cadicalinterface.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/card_oe.h b/lincs/liblincs/vendored/eval-max-sat/card_oe.h deleted file mode 120000 index 51b63016..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/card_oe.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/card_oe.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cardincremental.cpp b/lincs/liblincs/vendored/eval-max-sat/cardincremental.cpp deleted file mode 120000 index cf9cea4b..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cardincremental.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/cardincremental.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/cardincremental.h b/lincs/liblincs/vendored/eval-max-sat/cardincremental.h deleted file mode 120000 index 78fad12f..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/cardincremental.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/cardincremental.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/lazyvariable.cpp b/lincs/liblincs/vendored/eval-max-sat/lazyvariable.cpp deleted file mode 120000 index c57b5d8d..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/lazyvariable.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/lazyvariable.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/lazyvariable.h b/lincs/liblincs/vendored/eval-max-sat/lazyvariable.h deleted file mode 120000 index 9d9da603..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/lazyvariable.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/lazyvariable.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/mcqd.h b/lincs/liblincs/vendored/eval-max-sat/mcqd.h deleted file mode 120000 index 33cfd3c7..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/mcqd.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/mcqd.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/virtualcard.cpp b/lincs/liblincs/vendored/eval-max-sat/virtualcard.cpp deleted file mode 120000 index 9f5db028..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/virtualcard.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/virtualcard.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/virtualcard.h b/lincs/liblincs/vendored/eval-max-sat/virtualcard.h deleted file mode 120000 index a118b790..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/virtualcard.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/virtualcard.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/virtualmaxsat.h b/lincs/liblincs/vendored/eval-max-sat/virtualmaxsat.h deleted file mode 120000 index 96dfcaca..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/virtualmaxsat.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/virtualmaxsat.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/virtualsat.cpp b/lincs/liblincs/vendored/eval-max-sat/virtualsat.cpp deleted file mode 120000 index 3cc484d8..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/virtualsat.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/virtualsat.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/eval-max-sat/virtualsat.h b/lincs/liblincs/vendored/eval-max-sat/virtualsat.h deleted file mode 120000 index 3c3b30c5..00000000 --- a/lincs/liblincs/vendored/eval-max-sat/virtualsat.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/eval-max-sat/lib/EvalMaxSAT/src/virtualsat.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/lov-e.hpp b/lincs/liblincs/vendored/lov-e.hpp deleted file mode 120000 index 98293ab1..00000000 --- a/lincs/liblincs/vendored/lov-e.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../vendored/lov-e-cuda/lov-e.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/magic_enum.hpp b/lincs/liblincs/vendored/magic_enum.hpp deleted file mode 120000 index 90481b36..00000000 --- a/lincs/liblincs/vendored/magic_enum.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../vendored/magic-enum/include/magic_enum.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/core/Solver.cc b/lincs/liblincs/vendored/minisat/core/Solver.cc deleted file mode 120000 index 5641ba46..00000000 --- a/lincs/liblincs/vendored/minisat/core/Solver.cc +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/core/Solver.cc \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/core/Solver.h b/lincs/liblincs/vendored/minisat/core/Solver.h deleted file mode 120000 index f3e0c5fd..00000000 --- a/lincs/liblincs/vendored/minisat/core/Solver.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/core/Solver.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/core/SolverTypes.h b/lincs/liblincs/vendored/minisat/core/SolverTypes.h deleted file mode 120000 index cd7e1357..00000000 --- a/lincs/liblincs/vendored/minisat/core/SolverTypes.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/core/SolverTypes.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Alg.h b/lincs/liblincs/vendored/minisat/mtl/Alg.h deleted file mode 120000 index 539f1a0a..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Alg.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Alg.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Alloc.h b/lincs/liblincs/vendored/minisat/mtl/Alloc.h deleted file mode 120000 index 5b85cc87..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Alloc.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Alloc.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Heap.h b/lincs/liblincs/vendored/minisat/mtl/Heap.h deleted file mode 120000 index 73e77e0f..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Heap.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Heap.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/IntMap.h b/lincs/liblincs/vendored/minisat/mtl/IntMap.h deleted file mode 120000 index b57e10e7..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/IntMap.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/IntMap.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/IntTypes.h b/lincs/liblincs/vendored/minisat/mtl/IntTypes.h deleted file mode 120000 index e79c3f06..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/IntTypes.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/IntTypes.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Map.h b/lincs/liblincs/vendored/minisat/mtl/Map.h deleted file mode 120000 index 1a3bcaad..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Map.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Map.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Queue.h b/lincs/liblincs/vendored/minisat/mtl/Queue.h deleted file mode 120000 index 2157540c..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Queue.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Queue.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Sort.h b/lincs/liblincs/vendored/minisat/mtl/Sort.h deleted file mode 120000 index dd3794a9..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Sort.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Sort.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/Vec.h b/lincs/liblincs/vendored/minisat/mtl/Vec.h deleted file mode 120000 index a36df2a3..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/Vec.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/Vec.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/mtl/XAlloc.h b/lincs/liblincs/vendored/minisat/mtl/XAlloc.h deleted file mode 120000 index 8b697ee9..00000000 --- a/lincs/liblincs/vendored/minisat/mtl/XAlloc.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/mtl/XAlloc.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/simp/SimpSolver.cc b/lincs/liblincs/vendored/minisat/simp/SimpSolver.cc deleted file mode 120000 index 8c4f3645..00000000 --- a/lincs/liblincs/vendored/minisat/simp/SimpSolver.cc +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/simp/SimpSolver.cc \ No newline at end of file diff --git a/lincs/liblincs/vendored/minisat/simp/SimpSolver.h b/lincs/liblincs/vendored/minisat/simp/SimpSolver.h deleted file mode 120000 index 26843153..00000000 --- a/lincs/liblincs/vendored/minisat/simp/SimpSolver.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/minisat/minisat/simp/SimpSolver.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/rapidcsv.h b/lincs/liblincs/vendored/rapidcsv.h deleted file mode 120000 index c942e9ac..00000000 --- a/lincs/liblincs/vendored/rapidcsv.h +++ /dev/null @@ -1 +0,0 @@ -../../../vendored/rapidcsv/src/rapidcsv.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/adapters/std_string_adapter.hpp b/lincs/liblincs/vendored/valijson/adapters/std_string_adapter.hpp deleted file mode 120000 index cdbf2abc..00000000 --- a/lincs/liblincs/vendored/valijson/adapters/std_string_adapter.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/adapters/std_string_adapter.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/adapters/yaml_cpp_adapter.hpp b/lincs/liblincs/vendored/valijson/adapters/yaml_cpp_adapter.hpp deleted file mode 120000 index c75eccd1..00000000 --- a/lincs/liblincs/vendored/valijson/adapters/yaml_cpp_adapter.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/adapters/yaml_cpp_adapter.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/compat/optional.hpp b/lincs/liblincs/vendored/valijson/compat/optional.hpp deleted file mode 120000 index 7fc5e287..00000000 --- a/lincs/liblincs/vendored/valijson/compat/optional.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/compat/optional.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/constraint_builder.hpp b/lincs/liblincs/vendored/valijson/constraint_builder.hpp deleted file mode 120000 index 34ad230e..00000000 --- a/lincs/liblincs/vendored/valijson/constraint_builder.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/constraint_builder.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/constraints/basic_constraint.hpp b/lincs/liblincs/vendored/valijson/constraints/basic_constraint.hpp deleted file mode 120000 index 2bf5b28d..00000000 --- a/lincs/liblincs/vendored/valijson/constraints/basic_constraint.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/constraints/basic_constraint.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/constraints/concrete_constraints.hpp b/lincs/liblincs/vendored/valijson/constraints/concrete_constraints.hpp deleted file mode 120000 index 8cd3b41c..00000000 --- a/lincs/liblincs/vendored/valijson/constraints/concrete_constraints.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/constraints/concrete_constraints.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/constraints/constraint.hpp b/lincs/liblincs/vendored/valijson/constraints/constraint.hpp deleted file mode 120000 index 6f9e1092..00000000 --- a/lincs/liblincs/vendored/valijson/constraints/constraint.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/constraints/constraint.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/constraints/constraint_visitor.hpp b/lincs/liblincs/vendored/valijson/constraints/constraint_visitor.hpp deleted file mode 120000 index 7b391c83..00000000 --- a/lincs/liblincs/vendored/valijson/constraints/constraint_visitor.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/constraints/constraint_visitor.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/exceptions.hpp b/lincs/liblincs/vendored/valijson/exceptions.hpp deleted file mode 120000 index 271d8371..00000000 --- a/lincs/liblincs/vendored/valijson/exceptions.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/exceptions.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/adapter.hpp b/lincs/liblincs/vendored/valijson/internal/adapter.hpp deleted file mode 120000 index 2f637fc2..00000000 --- a/lincs/liblincs/vendored/valijson/internal/adapter.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/adapter.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/basic_adapter.hpp b/lincs/liblincs/vendored/valijson/internal/basic_adapter.hpp deleted file mode 120000 index 1ac192ad..00000000 --- a/lincs/liblincs/vendored/valijson/internal/basic_adapter.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/basic_adapter.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/custom_allocator.hpp b/lincs/liblincs/vendored/valijson/internal/custom_allocator.hpp deleted file mode 120000 index 6208f0e1..00000000 --- a/lincs/liblincs/vendored/valijson/internal/custom_allocator.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/custom_allocator.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/debug.hpp b/lincs/liblincs/vendored/valijson/internal/debug.hpp deleted file mode 120000 index f7f3a500..00000000 --- a/lincs/liblincs/vendored/valijson/internal/debug.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/debug.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/frozen_value.hpp b/lincs/liblincs/vendored/valijson/internal/frozen_value.hpp deleted file mode 120000 index 56e3e7ac..00000000 --- a/lincs/liblincs/vendored/valijson/internal/frozen_value.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/frozen_value.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/json_pointer.hpp b/lincs/liblincs/vendored/valijson/internal/json_pointer.hpp deleted file mode 120000 index 1d93186f..00000000 --- a/lincs/liblincs/vendored/valijson/internal/json_pointer.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/json_pointer.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/json_reference.hpp b/lincs/liblincs/vendored/valijson/internal/json_reference.hpp deleted file mode 120000 index 6a41bac0..00000000 --- a/lincs/liblincs/vendored/valijson/internal/json_reference.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/json_reference.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/optional.hpp b/lincs/liblincs/vendored/valijson/internal/optional.hpp deleted file mode 120000 index 27e94e91..00000000 --- a/lincs/liblincs/vendored/valijson/internal/optional.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/optional.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/optional_bundled.hpp b/lincs/liblincs/vendored/valijson/internal/optional_bundled.hpp deleted file mode 120000 index 5b6e51f8..00000000 --- a/lincs/liblincs/vendored/valijson/internal/optional_bundled.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/optional_bundled.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/internal/uri.hpp b/lincs/liblincs/vendored/valijson/internal/uri.hpp deleted file mode 120000 index 40d9606c..00000000 --- a/lincs/liblincs/vendored/valijson/internal/uri.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/internal/uri.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/schema.hpp b/lincs/liblincs/vendored/valijson/schema.hpp deleted file mode 120000 index 09af795d..00000000 --- a/lincs/liblincs/vendored/valijson/schema.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/schema.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/schema_parser.hpp b/lincs/liblincs/vendored/valijson/schema_parser.hpp deleted file mode 120000 index 9db0b83f..00000000 --- a/lincs/liblincs/vendored/valijson/schema_parser.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/schema_parser.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/subschema.hpp b/lincs/liblincs/vendored/valijson/subschema.hpp deleted file mode 120000 index 8a9a0f99..00000000 --- a/lincs/liblincs/vendored/valijson/subschema.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/subschema.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/utils/file_utils.hpp b/lincs/liblincs/vendored/valijson/utils/file_utils.hpp deleted file mode 120000 index c9049875..00000000 --- a/lincs/liblincs/vendored/valijson/utils/file_utils.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/utils/file_utils.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/utils/utf8_utils.hpp b/lincs/liblincs/vendored/valijson/utils/utf8_utils.hpp deleted file mode 120000 index 2c30af07..00000000 --- a/lincs/liblincs/vendored/valijson/utils/utf8_utils.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/valijson/include/valijson/utils/utf8_utils.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/validation_results.hpp b/lincs/liblincs/vendored/valijson/validation_results.hpp deleted file mode 120000 index 38fbf72d..00000000 --- a/lincs/liblincs/vendored/valijson/validation_results.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/validation_results.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/validation_visitor.hpp b/lincs/liblincs/vendored/valijson/validation_visitor.hpp deleted file mode 120000 index 59357f67..00000000 --- a/lincs/liblincs/vendored/valijson/validation_visitor.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/validation_visitor.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/valijson/validator.hpp b/lincs/liblincs/vendored/valijson/validator.hpp deleted file mode 120000 index 946f17d2..00000000 --- a/lincs/liblincs/vendored/valijson/validator.hpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/valijson/include/valijson/validator.hpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/anchor.h b/lincs/liblincs/vendored/yaml-cpp/anchor.h deleted file mode 120000 index 85ee5de1..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/anchor.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/anchor.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/binary.cpp b/lincs/liblincs/vendored/yaml-cpp/binary.cpp deleted file mode 120000 index 5a44a2e6..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/binary.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/binary.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/binary.h b/lincs/liblincs/vendored/yaml-cpp/binary.h deleted file mode 120000 index 866e5fab..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/binary.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/binary.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/collectionstack.h b/lincs/liblincs/vendored/yaml-cpp/collectionstack.h deleted file mode 120000 index ad855b90..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/collectionstack.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/collectionstack.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/convert.cpp b/lincs/liblincs/vendored/yaml-cpp/convert.cpp deleted file mode 120000 index dbb0dfff..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/convert.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/convert.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/depthguard.cpp b/lincs/liblincs/vendored/yaml-cpp/depthguard.cpp deleted file mode 120000 index 35a0b5b2..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/depthguard.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/depthguard.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/depthguard.h b/lincs/liblincs/vendored/yaml-cpp/depthguard.h deleted file mode 120000 index 5a63fe95..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/depthguard.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/depthguard.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/directives.cpp b/lincs/liblincs/vendored/yaml-cpp/directives.cpp deleted file mode 120000 index d75f36aa..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/directives.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/directives.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/directives.h b/lincs/liblincs/vendored/yaml-cpp/directives.h deleted file mode 120000 index 04a6fa70..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/directives.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/directives.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/dll.h b/lincs/liblincs/vendored/yaml-cpp/dll.h deleted file mode 120000 index d6c703db..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/dll.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/dll.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emit.cpp b/lincs/liblincs/vendored/yaml-cpp/emit.cpp deleted file mode 120000 index 225bc594..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emit.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emit.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitfromevents.cpp b/lincs/liblincs/vendored/yaml-cpp/emitfromevents.cpp deleted file mode 120000 index 8b53e553..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitfromevents.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitfromevents.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitfromevents.h b/lincs/liblincs/vendored/yaml-cpp/emitfromevents.h deleted file mode 120000 index 5905e0ae..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitfromevents.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/emitfromevents.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitter.cpp b/lincs/liblincs/vendored/yaml-cpp/emitter.cpp deleted file mode 120000 index 3734c54d..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitter.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitter.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitter.h b/lincs/liblincs/vendored/yaml-cpp/emitter.h deleted file mode 120000 index cc9bcc0f..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitter.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/emitter.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterdef.h b/lincs/liblincs/vendored/yaml-cpp/emitterdef.h deleted file mode 120000 index da3e8b4a..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterdef.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/emitterdef.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emittermanip.h b/lincs/liblincs/vendored/yaml-cpp/emittermanip.h deleted file mode 120000 index 003e05dc..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emittermanip.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/emittermanip.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterstate.cpp b/lincs/liblincs/vendored/yaml-cpp/emitterstate.cpp deleted file mode 120000 index e1f3147c..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterstate.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitterstate.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterstate.h b/lincs/liblincs/vendored/yaml-cpp/emitterstate.h deleted file mode 120000 index 28d549b2..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterstate.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitterstate.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterstyle.h b/lincs/liblincs/vendored/yaml-cpp/emitterstyle.h deleted file mode 120000 index cd9160b1..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterstyle.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/emitterstyle.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterutils.cpp b/lincs/liblincs/vendored/yaml-cpp/emitterutils.cpp deleted file mode 120000 index bb59448c..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterutils.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitterutils.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/emitterutils.h b/lincs/liblincs/vendored/yaml-cpp/emitterutils.h deleted file mode 120000 index aa60f570..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/emitterutils.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/emitterutils.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/eventhandler.h b/lincs/liblincs/vendored/yaml-cpp/eventhandler.h deleted file mode 120000 index 9ccf7941..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/eventhandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/eventhandler.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/exceptions.cpp b/lincs/liblincs/vendored/yaml-cpp/exceptions.cpp deleted file mode 120000 index c65bd88f..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/exceptions.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/exceptions.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/exceptions.h b/lincs/liblincs/vendored/yaml-cpp/exceptions.h deleted file mode 120000 index f098640c..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/exceptions.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/exceptions.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/exp.cpp b/lincs/liblincs/vendored/yaml-cpp/exp.cpp deleted file mode 120000 index 9e748cb4..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/exp.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/exp.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/exp.h b/lincs/liblincs/vendored/yaml-cpp/exp.h deleted file mode 120000 index ae26cc79..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/exp.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/exp.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/indentation.h b/lincs/liblincs/vendored/yaml-cpp/indentation.h deleted file mode 120000 index 8e05c06d..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/indentation.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/indentation.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/mark.h b/lincs/liblincs/vendored/yaml-cpp/mark.h deleted file mode 120000 index 03fc9d45..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/mark.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/mark.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/memory.cpp b/lincs/liblincs/vendored/yaml-cpp/memory.cpp deleted file mode 120000 index 4e12d083..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/memory.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/memory.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node.cpp b/lincs/liblincs/vendored/yaml-cpp/node.cpp deleted file mode 120000 index f1f3611b..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/node.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/convert.h b/lincs/liblincs/vendored/yaml-cpp/node/convert.h deleted file mode 120000 index 7457ef04..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/convert.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/convert.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/impl.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/impl.h deleted file mode 120000 index e0b35627..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/impl.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/impl.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator.h deleted file mode 120000 index 39a20b6b..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/iterator.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator_fwd.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator_fwd.h deleted file mode 120000 index 8c227042..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/iterator_fwd.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/iterator_fwd.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/memory.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/memory.h deleted file mode 120000 index a5dc748a..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/memory.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/memory.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/node.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/node.h deleted file mode 120000 index d79e1b58..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/node.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/node.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_data.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/node_data.h deleted file mode 120000 index 749eebd7..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_data.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/node_data.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_iterator.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/node_iterator.h deleted file mode 120000 index d5530bfc..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_iterator.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/node_iterator.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_ref.h b/lincs/liblincs/vendored/yaml-cpp/node/detail/node_ref.h deleted file mode 120000 index df09d096..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/detail/node_ref.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../vendored/yaml-cpp/include/yaml-cpp/node/detail/node_ref.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/emit.h b/lincs/liblincs/vendored/yaml-cpp/node/emit.h deleted file mode 120000 index 3c27f445..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/emit.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/emit.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/impl.h b/lincs/liblincs/vendored/yaml-cpp/node/impl.h deleted file mode 120000 index d34fe54f..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/impl.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/impl.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/iterator.h b/lincs/liblincs/vendored/yaml-cpp/node/iterator.h deleted file mode 120000 index 0fd89dc0..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/iterator.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/iterator.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/node.h b/lincs/liblincs/vendored/yaml-cpp/node/node.h deleted file mode 120000 index f8bd2ac9..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/node.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/node.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/parse.h b/lincs/liblincs/vendored/yaml-cpp/node/parse.h deleted file mode 120000 index c7767a90..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/parse.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/parse.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/ptr.h b/lincs/liblincs/vendored/yaml-cpp/node/ptr.h deleted file mode 120000 index c174e722..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/ptr.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/ptr.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node/type.h b/lincs/liblincs/vendored/yaml-cpp/node/type.h deleted file mode 120000 index 918c82dd..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node/type.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../vendored/yaml-cpp/include/yaml-cpp/node/type.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/node_data.cpp b/lincs/liblincs/vendored/yaml-cpp/node_data.cpp deleted file mode 120000 index 8c7b4098..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/node_data.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/node_data.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/nodebuilder.cpp b/lincs/liblincs/vendored/yaml-cpp/nodebuilder.cpp deleted file mode 120000 index 08682ee9..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/nodebuilder.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/nodebuilder.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/nodebuilder.h b/lincs/liblincs/vendored/yaml-cpp/nodebuilder.h deleted file mode 120000 index edd63987..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/nodebuilder.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/nodebuilder.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/nodeevents.cpp b/lincs/liblincs/vendored/yaml-cpp/nodeevents.cpp deleted file mode 120000 index 6ce79eb3..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/nodeevents.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/nodeevents.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/nodeevents.h b/lincs/liblincs/vendored/yaml-cpp/nodeevents.h deleted file mode 120000 index 954bb292..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/nodeevents.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/nodeevents.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/noexcept.h b/lincs/liblincs/vendored/yaml-cpp/noexcept.h deleted file mode 120000 index feeaf1d3..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/noexcept.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/noexcept.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/null.cpp b/lincs/liblincs/vendored/yaml-cpp/null.cpp deleted file mode 120000 index 9e41363c..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/null.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/null.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/null.h b/lincs/liblincs/vendored/yaml-cpp/null.h deleted file mode 120000 index ebfe21e0..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/null.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/null.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.cpp b/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.cpp deleted file mode 120000 index 9459bd43..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/ostream_wrapper.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.h b/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.h deleted file mode 120000 index 6799fac3..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/ostream_wrapper.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/ostream_wrapper.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/parse.cpp b/lincs/liblincs/vendored/yaml-cpp/parse.cpp deleted file mode 120000 index 88e7eed7..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/parse.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/parse.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/parser.cpp b/lincs/liblincs/vendored/yaml-cpp/parser.cpp deleted file mode 120000 index 157cbe73..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/parser.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/parser.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/parser.h b/lincs/liblincs/vendored/yaml-cpp/parser.h deleted file mode 120000 index d2df4af8..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/parser.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/parser.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/ptr_vector.h b/lincs/liblincs/vendored/yaml-cpp/ptr_vector.h deleted file mode 120000 index 382564f7..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/ptr_vector.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/ptr_vector.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/regex_yaml.cpp b/lincs/liblincs/vendored/yaml-cpp/regex_yaml.cpp deleted file mode 120000 index 286eeea2..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/regex_yaml.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/regex_yaml.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/regex_yaml.h b/lincs/liblincs/vendored/yaml-cpp/regex_yaml.h deleted file mode 120000 index 333015c0..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/regex_yaml.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/regex_yaml.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/regeximpl.h b/lincs/liblincs/vendored/yaml-cpp/regeximpl.h deleted file mode 120000 index 756405b8..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/regeximpl.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/regeximpl.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scanner.cpp b/lincs/liblincs/vendored/yaml-cpp/scanner.cpp deleted file mode 120000 index ef9820b0..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scanner.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scanner.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scanner.h b/lincs/liblincs/vendored/yaml-cpp/scanner.h deleted file mode 120000 index 714d059e..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scanner.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scanner.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scanscalar.cpp b/lincs/liblincs/vendored/yaml-cpp/scanscalar.cpp deleted file mode 120000 index c0fdf764..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scanscalar.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scanscalar.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scanscalar.h b/lincs/liblincs/vendored/yaml-cpp/scanscalar.h deleted file mode 120000 index f9535eea..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scanscalar.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scanscalar.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scantag.cpp b/lincs/liblincs/vendored/yaml-cpp/scantag.cpp deleted file mode 120000 index 7da69fc7..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scantag.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scantag.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scantag.h b/lincs/liblincs/vendored/yaml-cpp/scantag.h deleted file mode 120000 index ec268068..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scantag.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scantag.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/scantoken.cpp b/lincs/liblincs/vendored/yaml-cpp/scantoken.cpp deleted file mode 120000 index f1069d4e..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/scantoken.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/scantoken.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/setting.h b/lincs/liblincs/vendored/yaml-cpp/setting.h deleted file mode 120000 index a9db2df5..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/setting.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/setting.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/simplekey.cpp b/lincs/liblincs/vendored/yaml-cpp/simplekey.cpp deleted file mode 120000 index cb69524a..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/simplekey.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/simplekey.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/singledocparser.cpp b/lincs/liblincs/vendored/yaml-cpp/singledocparser.cpp deleted file mode 120000 index 31c751c2..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/singledocparser.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/singledocparser.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/singledocparser.h b/lincs/liblincs/vendored/yaml-cpp/singledocparser.h deleted file mode 120000 index 444d8102..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/singledocparser.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/singledocparser.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/stlemitter.h b/lincs/liblincs/vendored/yaml-cpp/stlemitter.h deleted file mode 120000 index 42389c1e..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/stlemitter.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/stlemitter.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/stream.cpp b/lincs/liblincs/vendored/yaml-cpp/stream.cpp deleted file mode 120000 index b46fb775..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/stream.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/stream.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/stream.h b/lincs/liblincs/vendored/yaml-cpp/stream.h deleted file mode 120000 index fe19b0d0..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/stream.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/stream.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/streamcharsource.h b/lincs/liblincs/vendored/yaml-cpp/streamcharsource.h deleted file mode 120000 index 90bcdbdd..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/streamcharsource.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/streamcharsource.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/stringsource.h b/lincs/liblincs/vendored/yaml-cpp/stringsource.h deleted file mode 120000 index 5ecac094..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/stringsource.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/stringsource.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/tag.cpp b/lincs/liblincs/vendored/yaml-cpp/tag.cpp deleted file mode 120000 index f2d930ff..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/tag.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/tag.cpp \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/tag.h b/lincs/liblincs/vendored/yaml-cpp/tag.h deleted file mode 120000 index 03327f82..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/tag.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/tag.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/token.h b/lincs/liblincs/vendored/yaml-cpp/token.h deleted file mode 120000 index d3daff38..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/token.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/src/token.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/traits.h b/lincs/liblincs/vendored/yaml-cpp/traits.h deleted file mode 120000 index fc063aa5..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/traits.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/traits.h \ No newline at end of file diff --git a/lincs/liblincs/vendored/yaml-cpp/yaml.h b/lincs/liblincs/vendored/yaml-cpp/yaml.h deleted file mode 120000 index 058365a3..00000000 --- a/lincs/liblincs/vendored/yaml-cpp/yaml.h +++ /dev/null @@ -1 +0,0 @@ -../../../../vendored/yaml-cpp/include/yaml-cpp/yaml.h \ No newline at end of file diff --git a/lincs/liblincs_module_tests.py b/lincs/liblincs_module_tests.py deleted file mode 100644 index fcc8e827..00000000 --- a/lincs/liblincs_module_tests.py +++ /dev/null @@ -1,2258 +0,0 @@ -# Copyright 2023-2024 Vincent Jacques - -import copy -import io -import pickle -import textwrap -import unittest -import os - -from . import DataValidationException, LearningFailureException -from .classification import * - - -forbid_gpu = os.environ.get("LINCS_DEV_FORBID_GPU", "false") == "true" - -class ProblemTestCase(unittest.TestCase): - def test_init_simplest(self): - problem = Problem( - criteria=[ - Criterion(name="Criterion name", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - ordered_categories=[ - Category("Bad"), - Category("Good"), - ], - ) - self.assertEqual(len(problem.criteria), 1) - self.assertEqual(problem.criteria[0].name, "Criterion name") - self.assertEqual(problem.criteria[0].value_type, Criterion.ValueType.real) - self.assertTrue(problem.criteria[0].is_real) - self.assertFalse(problem.criteria[0].is_integer) - self.assertFalse(problem.criteria[0].is_enumerated) - self.assertEqual(problem.criteria[0].real_values.preference_direction, Criterion.PreferenceDirection.increasing) - self.assertEqual(problem.criteria[0].real_values.min_value, 0) - self.assertEqual(problem.criteria[0].real_values.max_value, 1) - self.assertEqual(len(problem.ordered_categories), 2) - self.assertEqual(problem.ordered_categories[0].name, "Bad") - self.assertEqual(problem.ordered_categories[1].name, "Good") - - def test_init_not_enough_categories(self): - criterion = Criterion("Criterion name", Criterion.RealValues(preference_direction=Criterion.PreferenceDirection.increasing, min_value=0, max_value=1)) - with self.assertRaises(DataValidationException) as cm: - Problem([criterion], []) - self.assertEqual(cm.exception.args[0], "A problem must have at least 2 categories") - with self.assertRaises(DataValidationException) as cm: - Problem([criterion], [Category("Single")]) - self.assertEqual(cm.exception.args[0], "A problem must have at least 2 categories") - - def test_init_no_criterion(self): - with self.assertRaises(DataValidationException) as cm: - Problem([], [Category("Bad"), Category("Good")]) - self.assertEqual(cm.exception.args[0], "A problem must have at least one criterion") - - def test_init_wrong_types(self): - with self.assertRaises(TypeError): - Problem() - with self.assertRaises(TypeError): - Problem([]) - with self.assertRaises(TypeError): - Problem([0], []) - with self.assertRaises(TypeError): - Problem([], [0]) - with self.assertRaises(TypeError): - Problem([], [], 0) - - def test_iso_antitone(self): - self.assertEqual(Criterion.PreferenceDirection.isotone, Criterion.PreferenceDirection.increasing) - self.assertEqual(Criterion.PreferenceDirection.antitone, Criterion.PreferenceDirection.decreasing) - - def test_real_criterion(self): - criterion = Criterion("Criterion name", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0.25, 2.75)) - self.assertEqual(criterion.name, "Criterion name") - self.assertEqual(criterion.value_type, Criterion.ValueType.real) - self.assertTrue(criterion.is_real) - self.assertFalse(criterion.is_integer) - self.assertFalse(criterion.is_enumerated) - self.assertEqual(criterion.real_values.preference_direction, Criterion.PreferenceDirection.increasing) - self.assertEqual(criterion.real_values.min_value, 0.25) - self.assertEqual(criterion.real_values.max_value, 2.75) - with self.assertRaises(RuntimeError): - criterion.integer_values - with self.assertRaises(RuntimeError): - criterion.enumerated_values - - def test_integer_criterion(self): - criterion = Criterion("Criterion name", Criterion.IntegerValues(Criterion.PreferenceDirection.increasing, 0, 20)) - self.assertEqual(criterion.name, "Criterion name") - self.assertEqual(criterion.value_type, Criterion.ValueType.integer) - self.assertFalse(criterion.is_real) - self.assertTrue(criterion.is_integer) - self.assertFalse(criterion.is_enumerated) - self.assertEqual(criterion.integer_values.preference_direction, Criterion.PreferenceDirection.increasing) - self.assertEqual(criterion.integer_values.min_value, 0) - self.assertEqual(criterion.integer_values.max_value, 20) - - def test_enumerated_criterion(self): - criterion = Criterion("Criterion name", Criterion.EnumeratedValues(["a a", "b", "c"])) - self.assertEqual(criterion.name, "Criterion name") - self.assertEqual(criterion.value_type, Criterion.ValueType.enumerated) - self.assertFalse(criterion.is_real) - self.assertFalse(criterion.is_integer) - self.assertTrue(criterion.is_enumerated) - self.assertEqual(list(criterion.enumerated_values.ordered_values), ["a a", "b", "c"]) - self.assertEqual(criterion.enumerated_values.get_value_rank("a a"), 0) - self.assertEqual(criterion.enumerated_values.get_value_rank("b"), 1) - self.assertEqual(criterion.enumerated_values.get_value_rank("c"), 2) - - def test_single_peaked_real_criteria(self): - criterion = Criterion("Criterion name", Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 0.25, 2.75)) - self.assertEqual(criterion.name, "Criterion name") - self.assertEqual(criterion.value_type, Criterion.ValueType.real) - self.assertTrue(criterion.is_real) - self.assertFalse(criterion.is_integer) - self.assertFalse(criterion.is_enumerated) - self.assertTrue(criterion.real_values.is_single_peaked) - self.assertFalse(criterion.real_values.is_increasing) - self.assertFalse(criterion.real_values.is_decreasing) - self.assertEqual(criterion.real_values.preference_direction, Criterion.PreferenceDirection.single_peaked) - self.assertEqual(criterion.real_values.min_value, 0.25) - self.assertEqual(criterion.real_values.max_value, 2.75) - - def test_single_peaked_integer_criteria(self): - criterion = Criterion("Criterion name", Criterion.IntegerValues(Criterion.PreferenceDirection.single_peaked, 25, 75)) - self.assertEqual(criterion.name, "Criterion name") - self.assertEqual(criterion.value_type, Criterion.ValueType.integer) - self.assertFalse(criterion.is_real) - self.assertTrue(criterion.is_integer) - self.assertFalse(criterion.is_enumerated) - self.assertTrue(criterion.integer_values.is_single_peaked) - self.assertFalse(criterion.integer_values.is_increasing) - self.assertFalse(criterion.integer_values.is_decreasing) - self.assertEqual(criterion.integer_values.preference_direction, Criterion.PreferenceDirection.single_peaked) - self.assertEqual(criterion.integer_values.min_value, 25) - self.assertEqual(criterion.integer_values.max_value, 75) - - def test_pickle_and_deep_copy(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - Criterion(name="Single-peaked criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 0, 1)), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - pickled_problem = pickle.dumps(problem) - self.assertIsInstance(pickled_problem, bytes) - unpickled_problem = pickle.loads(pickled_problem) - copied_problem = copy.deepcopy(problem) - - for p in (problem, unpickled_problem, copied_problem): - self.assertEqual(len(p.criteria), 4) - self.assertEqual(p.criteria[0].name, "Real criterion") - self.assertEqual(p.criteria[0].value_type, Criterion.ValueType.real) - self.assertTrue(p.criteria[0].is_real) - self.assertFalse(p.criteria[0].is_integer) - self.assertFalse(p.criteria[0].is_enumerated) - self.assertEqual(p.criteria[0].real_values.preference_direction, Criterion.PreferenceDirection.increasing) - self.assertEqual(p.criteria[0].real_values.min_value, 5) - self.assertEqual(p.criteria[0].real_values.max_value, 10) - self.assertEqual(p.criteria[1].name, "Integer criterion") - self.assertEqual(p.criteria[1].value_type, Criterion.ValueType.integer) - self.assertFalse(p.criteria[1].is_real) - self.assertTrue(p.criteria[1].is_integer) - self.assertFalse(p.criteria[1].is_enumerated) - self.assertEqual(p.criteria[1].integer_values.preference_direction, Criterion.PreferenceDirection.decreasing) - self.assertEqual(p.criteria[1].integer_values.min_value, 15) - self.assertEqual(p.criteria[1].integer_values.max_value, 100) - self.assertEqual(p.criteria[2].name, "Enumerated criterion") - self.assertEqual(p.criteria[2].value_type, Criterion.ValueType.enumerated) - self.assertFalse(p.criteria[2].is_real) - self.assertFalse(p.criteria[2].is_integer) - self.assertTrue(p.criteria[2].is_enumerated) - self.assertEqual(list(p.criteria[2].enumerated_values.ordered_values), ["a", "b", "c"]) - self.assertEqual(p.criteria[2].enumerated_values.get_value_rank("a"), 0) - self.assertEqual(p.criteria[2].enumerated_values.get_value_rank("b"), 1) - self.assertEqual(p.criteria[2].enumerated_values.get_value_rank("c"), 2) - self.assertEqual(p.criteria[3].name, "Single-peaked criterion") - self.assertEqual(p.criteria[3].value_type, Criterion.ValueType.real) - self.assertTrue(p.criteria[3].is_real) - self.assertFalse(p.criteria[3].is_integer) - self.assertFalse(p.criteria[3].is_enumerated) - self.assertEqual(p.criteria[3].real_values.preference_direction, Criterion.PreferenceDirection.single_peaked) - self.assertEqual(p.criteria[3].real_values.min_value, 0) - self.assertEqual(p.criteria[3].real_values.max_value, 1) - self.assertEqual(len(p.ordered_categories), 3) - self.assertEqual(p.ordered_categories[0].name, "Bad") - self.assertEqual(p.ordered_categories[1].name, "Medium") - self.assertEqual(p.ordered_categories[2].name, "Good") - - for p in (unpickled_problem, copied_problem): - self.assertIsNot(p, problem) - self.assertIsNot(p.criteria, problem.criteria) - self.assertIsNot(p.criteria[0], problem.criteria[0]) - self.assertIsNot(p.criteria[1], problem.criteria[1]) - self.assertIsNot(p.criteria[2], problem.criteria[2]) - self.assertIsNot(p.criteria[3], problem.criteria[3]) - self.assertIsNot(p.ordered_categories, problem.ordered_categories) - self.assertIsNot(p.ordered_categories[0], problem.ordered_categories[0]) - self.assertIsNot(p.ordered_categories[1], problem.ordered_categories[1]) - self.assertIsNot(p.ordered_categories[2], problem.ordered_categories[2]) - - -class ModelTestCase(unittest.TestCase): - def test_init_wrong_types(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ) - with self.assertRaises(TypeError): - Model() - with self.assertRaises(TypeError): - Model(problem) - with self.assertRaises(TypeError): - Model(problem, 0) - with self.assertRaises(TypeError): - Model(0, []) - with self.assertRaises(TypeError): - Model(problem, [0]) - - def test_init_simplest(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ) - model = Model( - problem=problem, - accepted_values=[AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - sufficient_coalitions=[SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(len(model.accepted_values), 1) - self.assertEqual(model.accepted_values[0].value_type, Criterion.ValueType.real) - self.assertTrue(model.accepted_values[0].is_real) - self.assertFalse(model.accepted_values[0].is_integer) - self.assertFalse(model.accepted_values[0].is_enumerated) - self.assertEqual(model.accepted_values[0].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[0].is_thresholds) - self.assertEqual(len(model.accepted_values[0].real_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[0].real_thresholds.thresholds[0], 0.5) - self.assertEqual(len(model.sufficient_coalitions), 1) - self.assertEqual(model.sufficient_coalitions[0].kind, SufficientCoalitions.Kind.weights) - self.assertTrue(model.sufficient_coalitions[0].is_weights) - self.assertFalse(model.sufficient_coalitions[0].is_roots) - self.assertEqual(len(model.sufficient_coalitions[0].weights.criterion_weights), 1) - self.assertEqual(model.sufficient_coalitions[0].weights.criterion_weights[0], 0.75) - - def test_bad_accesses(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ) - with self.assertRaises(RuntimeError): - problem.criteria[0].integer_values - model = Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - with self.assertRaises(RuntimeError): - model.accepted_values[0].integer_thresholds - with self.assertRaises(RuntimeError): - model.sufficient_coalitions[0].roots - - def test_init_size_mismatch(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(cm.exception.args[0], "The number of accepted values descriptors in the model must be equal to the number of criteria in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [ - AcceptedValues(AcceptedValues.RealThresholds([0.5])), - AcceptedValues(AcceptedValues.RealThresholds([0.5])), - ], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(cm.exception.args[0], "The number of accepted values descriptors in the model must be equal to the number of criteria in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(cm.exception.args[0], "The number of real thresholds in an accepted values descriptor must be one less than the number of categories in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5, 0.6]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(cm.exception.args[0], "The number of real thresholds in an accepted values descriptor must be one less than the number of categories in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [], - ) - self.assertEqual(cm.exception.args[0], "The number of sufficient coalitions in the model must be one less than the number of categories in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [ - SufficientCoalitions(SufficientCoalitions.Weights([0.75])), - SufficientCoalitions(SufficientCoalitions.Weights([0.75])), - ], - ) - self.assertEqual(cm.exception.args[0], "The number of sufficient coalitions in the model must be one less than the number of categories in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [SufficientCoalitions(SufficientCoalitions.Weights([]))], - ) - self.assertEqual(cm.exception.args[0], "The number of criterion weights in a sufficient coalitions descriptor must be equal to the number of criteria in the problem") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75, 0.75]))], - ) - self.assertEqual(cm.exception.args[0], "The number of criterion weights in a sufficient coalitions descriptor must be equal to the number of criteria in the problem") - - def test_init_type_mismatch(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], [ - Category("Category 1"), - Category("Category 2"), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [ - AcceptedValues(AcceptedValues.IntegerThresholds([50])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Roots(problem, [[0]])), - ], - ) - self.assertEqual(cm.exception.args[0], "The value type of an accepted values descriptor must be the same as the value type of the corresponding criterion") - - def test_init_roots(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - Criterion("Criterion 2", Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 0, 100)), - Criterion("Criterion 3", Criterion.EnumeratedValues(["c", "b", "a"])), - ], [ - Category("Category 1"), - Category("Category 2"), - ], - ) - model = Model( - problem, - [ - AcceptedValues(AcceptedValues.RealThresholds([0.5])), - AcceptedValues(AcceptedValues.IntegerThresholds([50])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b"])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Roots(problem, [[0, 1], [0, 2]])), - ], - ) - self.assertEqual(len(model.accepted_values), 3) - self.assertEqual(model.accepted_values[0].value_type, Criterion.ValueType.real) - self.assertTrue(model.accepted_values[0].is_real) - self.assertFalse(model.accepted_values[0].is_integer) - self.assertFalse(model.accepted_values[0].is_enumerated) - self.assertEqual(model.accepted_values[0].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[0].is_thresholds) - self.assertEqual(len(model.accepted_values[0].real_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[0].real_thresholds.thresholds[0], 0.5) - self.assertEqual(model.accepted_values[1].value_type, Criterion.ValueType.integer) - self.assertFalse(model.accepted_values[1].is_real) - self.assertTrue(model.accepted_values[1].is_integer) - self.assertFalse(model.accepted_values[1].is_enumerated) - self.assertEqual(model.accepted_values[1].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[1].is_thresholds) - self.assertEqual(len(model.accepted_values[1].integer_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[1].integer_thresholds.thresholds[0], 50) - self.assertEqual(model.accepted_values[2].value_type, Criterion.ValueType.enumerated) - self.assertFalse(model.accepted_values[2].is_real) - self.assertFalse(model.accepted_values[2].is_integer) - self.assertTrue(model.accepted_values[2].is_enumerated) - self.assertEqual(model.accepted_values[2].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[2].is_thresholds) - self.assertEqual(len(model.accepted_values[2].enumerated_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[2].enumerated_thresholds.thresholds[0], "b") - self.assertEqual(len(model.sufficient_coalitions), 1) - self.assertEqual(model.sufficient_coalitions[0].kind, SufficientCoalitions.Kind.roots) - self.assertFalse(model.sufficient_coalitions[0].is_weights) - self.assertTrue(model.sufficient_coalitions[0].is_roots) - self.assertEqual(model.sufficient_coalitions[0].roots.upset_roots[0][0], 0) - self.assertEqual(model.sufficient_coalitions[0].roots.upset_roots[0][1], 1) - self.assertEqual(model.sufficient_coalitions[0].roots.upset_roots[1][0], 0) - self.assertEqual(model.sufficient_coalitions[0].roots.upset_roots[1][1], 2) - - def test_init_size_mismatch_2(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], [ - Category("Category 1"), - Category("Category 2"), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, - [AcceptedValues(AcceptedValues.RealThresholds([0.5]))], - [SufficientCoalitions(SufficientCoalitions.Roots(problem, [[3]]))], - ) - self.assertEqual(cm.exception.args[0], "An element index in a root in a sufficient coalitions descriptor must be less than the number of criteria in the problem") - - def test_init_integer(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.IntegerValues(Criterion.PreferenceDirection.increasing, 0, 10)), - ], - [ - Category("Category 1"), - Category("Category 2"), - ], - ) - model = Model( - problem, - [AcceptedValues(AcceptedValues.IntegerThresholds([5]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(len(model.accepted_values), 1) - self.assertEqual(model.accepted_values[0].value_type, Criterion.ValueType.integer) - self.assertFalse(model.accepted_values[0].is_real) - self.assertTrue(model.accepted_values[0].is_integer) - self.assertFalse(model.accepted_values[0].is_enumerated) - self.assertEqual(model.accepted_values[0].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[0].is_thresholds) - self.assertEqual(len(model.accepted_values[0].integer_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[0].integer_thresholds.thresholds[0], 5) - - def test_init_enumerated(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.EnumeratedValues(["low", "mid", "high"])), - ], - [ - Category("Category 1"), - Category("Category 2"), - ], - ) - model = Model( - problem, - [AcceptedValues(AcceptedValues.EnumeratedThresholds(["mid"]))], - [SufficientCoalitions(SufficientCoalitions.Weights([0.75]))], - ) - self.assertEqual(len(model.accepted_values), 1) - self.assertEqual(model.accepted_values[0].value_type, Criterion.ValueType.enumerated) - self.assertFalse(model.accepted_values[0].is_real) - self.assertFalse(model.accepted_values[0].is_integer) - self.assertTrue(model.accepted_values[0].is_enumerated) - self.assertEqual(model.accepted_values[0].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(model.accepted_values[0].is_thresholds) - self.assertEqual(len(model.accepted_values[0].enumerated_thresholds.thresholds), 1) - self.assertEqual(model.accepted_values[0].enumerated_thresholds.thresholds[0], "mid") - - def test_init_single_peaked(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.IntegerValues(Criterion.PreferenceDirection.single_peaked, 0, 10)), - Criterion("Criterion 2", Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 0, 100)), - ], - [ - Category("Category 1"), - Category("Category 2"), - Category("Category 3"), - ], - ) - model = Model( - problem, - [ - AcceptedValues(AcceptedValues.IntegerIntervals([(2, 8), (4, 6)])), - AcceptedValues(AcceptedValues.RealIntervals([(20, 80), (40, 60)])), - ], - [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5])), - ], - ) - self.assertEqual(len(model.accepted_values), 2) - self.assertEqual(model.accepted_values[0].value_type, Criterion.ValueType.integer) - self.assertFalse(model.accepted_values[0].is_real) - self.assertTrue(model.accepted_values[0].is_integer) - self.assertFalse(model.accepted_values[0].is_enumerated) - self.assertEqual(model.accepted_values[0].kind, AcceptedValues.Kind.intervals) - self.assertTrue(model.accepted_values[0].is_intervals) - self.assertEqual(len(model.accepted_values[0].integer_intervals.intervals), 2) - self.assertEqual(model.accepted_values[0].integer_intervals.intervals[0], (2, 8)) - self.assertEqual(model.accepted_values[0].integer_intervals.intervals[1], (4, 6)) - self.assertEqual(model.accepted_values[1].value_type, Criterion.ValueType.real) - self.assertTrue(model.accepted_values[1].is_real) - self.assertFalse(model.accepted_values[1].is_integer) - self.assertFalse(model.accepted_values[1].is_enumerated) - self.assertEqual(model.accepted_values[1].kind, AcceptedValues.Kind.intervals) - self.assertTrue(model.accepted_values[1].is_intervals) - self.assertEqual(len(model.accepted_values[1].real_intervals.intervals), 2) - self.assertEqual(model.accepted_values[1].real_intervals.intervals[0], (20, 80)) - self.assertEqual(model.accepted_values[1].real_intervals.intervals[1], (40, 60)) - - def test_pickle_and_deep_copy(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - Criterion(name="Single-peaked criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.single_peaked, 0, 8)), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - model = Model( - problem=problem, - accepted_values=[ - AcceptedValues(AcceptedValues.RealThresholds([7, 9])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - AcceptedValues(AcceptedValues.RealIntervals([(1, 7), (3, 5)])), - ], - sufficient_coalitions=[ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Roots(problem, [[0, 1], [0, 2], [0, 3]])), - ], - ) - pickled_model = pickle.dumps(model) - self.assertIsInstance(pickled_model, bytes) - unpickled_model = pickle.loads(pickled_model) - copied_model = copy.deepcopy(model) - - for m in (model, unpickled_model, copied_model): - self.assertEqual(len(m.accepted_values), 4) - self.assertEqual(m.accepted_values[0].value_type, Criterion.ValueType.real) - self.assertTrue(m.accepted_values[0].is_real) - self.assertFalse(m.accepted_values[0].is_integer) - self.assertFalse(m.accepted_values[0].is_enumerated) - self.assertEqual(m.accepted_values[0].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(m.accepted_values[0].is_thresholds) - self.assertFalse(m.accepted_values[0].is_intervals) - self.assertEqual(len(m.accepted_values[0].real_thresholds.thresholds), 2) - self.assertEqual(m.accepted_values[0].real_thresholds.thresholds[0], 7) - self.assertEqual(m.accepted_values[0].real_thresholds.thresholds[1], 9) - self.assertEqual(m.accepted_values[1].value_type, Criterion.ValueType.integer) - self.assertFalse(m.accepted_values[1].is_real) - self.assertTrue(m.accepted_values[1].is_integer) - self.assertFalse(m.accepted_values[1].is_enumerated) - self.assertEqual(m.accepted_values[1].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(m.accepted_values[1].is_thresholds) - self.assertFalse(m.accepted_values[1].is_intervals) - self.assertEqual(len(m.accepted_values[1].integer_thresholds.thresholds), 2) - self.assertEqual(m.accepted_values[1].integer_thresholds.thresholds[0], 50) - self.assertEqual(m.accepted_values[1].integer_thresholds.thresholds[1], 25) - self.assertEqual(m.accepted_values[2].value_type, Criterion.ValueType.enumerated) - self.assertFalse(m.accepted_values[2].is_real) - self.assertFalse(m.accepted_values[2].is_integer) - self.assertTrue(m.accepted_values[2].is_enumerated) - self.assertEqual(m.accepted_values[2].kind, AcceptedValues.Kind.thresholds) - self.assertTrue(m.accepted_values[2].is_thresholds) - self.assertFalse(m.accepted_values[2].is_intervals) - self.assertEqual(len(m.accepted_values[2].enumerated_thresholds.thresholds), 2) - self.assertEqual(m.accepted_values[2].enumerated_thresholds.thresholds[0], "b") - self.assertEqual(m.accepted_values[2].enumerated_thresholds.thresholds[1], "c") - self.assertEqual(m.accepted_values[3].value_type, Criterion.ValueType.real) - self.assertTrue(m.accepted_values[3].is_real) - self.assertFalse(m.accepted_values[3].is_integer) - self.assertFalse(m.accepted_values[3].is_enumerated) - self.assertEqual(m.accepted_values[3].kind, AcceptedValues.Kind.intervals) - self.assertFalse(m.accepted_values[3].is_thresholds) - self.assertTrue(m.accepted_values[3].is_intervals) - self.assertEqual(len(m.accepted_values[3].real_intervals.intervals), 2) - self.assertEqual(m.accepted_values[3].real_intervals.intervals[0], (1, 7)) - self.assertEqual(m.accepted_values[3].real_intervals.intervals[1], (3, 5)) - self.assertEqual(len(m.sufficient_coalitions), 2) - self.assertEqual(m.sufficient_coalitions[0].kind, SufficientCoalitions.Kind.weights) - self.assertTrue(m.sufficient_coalitions[0].is_weights) - self.assertFalse(m.sufficient_coalitions[0].is_roots) - self.assertEqual(len(m.sufficient_coalitions[0].weights.criterion_weights), 4) - self.assertEqual(m.sufficient_coalitions[0].weights.criterion_weights[0], 0.5) - self.assertEqual(m.sufficient_coalitions[0].weights.criterion_weights[1], 0.5) - self.assertEqual(m.sufficient_coalitions[0].weights.criterion_weights[2], 0.5) - self.assertEqual(m.sufficient_coalitions[0].weights.criterion_weights[3], 0.5) - self.assertEqual(m.sufficient_coalitions[1].kind, SufficientCoalitions.Kind.roots) - self.assertFalse(m.sufficient_coalitions[1].is_weights) - self.assertTrue(m.sufficient_coalitions[1].is_roots) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[0][0], 0) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[0][1], 1) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[1][0], 0) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[1][1], 2) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[2][0], 0) - self.assertEqual(m.sufficient_coalitions[1].roots.upset_roots[2][1], 3) - - for m in (unpickled_model, copied_model): - self.assertIsNot(m, model) - self.assertIsNot(m.accepted_values, model.accepted_values) - self.assertIsNot(m.accepted_values[0], model.accepted_values[0]) - self.assertIsNot(m.accepted_values[1], model.accepted_values[1]) - self.assertIsNot(m.accepted_values[2], model.accepted_values[2]) - self.assertIsNot(m.sufficient_coalitions, model.sufficient_coalitions) - self.assertIsNot(m.sufficient_coalitions[0], model.sufficient_coalitions[0]) - self.assertIsNot(m.sufficient_coalitions[1], model.sufficient_coalitions[1]) - - def test_pickle_empty_roots(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - r = pickle.loads(pickle.dumps(SufficientCoalitions.Roots(problem, []))) - self.assertEqual(r.upset_roots, []) - - def test_init_unordered_profiles(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([9., 7.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "The real thresholds in an accepted values descriptor must be in preference order") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([25, 50])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "The integer thresholds in an accepted values descriptor must be in preference order") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "a"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "The enumerated thresholds in an accepted values descriptor must be in preference order") - - def test_init_profiles_outside_range(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([3., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding real criterion") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 11.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding real criterion") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 10])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding integer criterion") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([110, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "Each threshold in an accepted values descriptor must be between the min and max values for the corresponding integer criterion") - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "d"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - self.assertEqual(cm.exception.args[0], "Each threshold in an accepted values descriptor must be in the enumerated values for the corresponding criterion") - - def test_init_accepted_values_not_imbricated(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Model( - problem, [ - AcceptedValues(AcceptedValues.RealThresholds([7., 9.])), - AcceptedValues(AcceptedValues.IntegerThresholds([50, 25])), - AcceptedValues(AcceptedValues.EnumeratedThresholds(["b", "c"])), - ], [ - SufficientCoalitions(SufficientCoalitions.Weights([0.5, 0.5, 0.5])), - SufficientCoalitions(SufficientCoalitions.Weights([1, 1, 1])), - ], - ) - self.assertEqual(cm.exception.args[0], "Sufficient coalitions must be imbricated") - - -class AlternativesTestCase(unittest.TestCase): - def test_init_wrong_types(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], - [Category("Bad"), Category("Good")], - ) - with self.assertRaises(TypeError): - Alternatives() - with self.assertRaises(TypeError): - Alternatives(problem) - with self.assertRaises(TypeError): - Alternatives(problem, 0) - with self.assertRaises(TypeError): - Alternatives(0, []) - with self.assertRaises(TypeError): - Alternatives(problem, [0]) - - def test_init_three_criteria_two_categories(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 10)), - Criterion("Criterion 2", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 10)), - Criterion("Criterion 3", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 10)), - ], [ - Category("Category 1"), - Category("Category 2"), - ], - ) - alternatives = Alternatives( - problem, - [ - Alternative("First alternative", [Performance(Performance.Real(5.)), Performance(Performance.Real(5.)), Performance(Performance.Real(5))], 0), - Alternative("Second alternative", [Performance(Performance.Real(1.)), Performance(Performance.Real(2.)), Performance(Performance.Real(3.))], None), - Alternative("Third alternative", [Performance(Performance.Real(2.)), Performance(Performance.Real(4.)), Performance(Performance.Real(6.))]), - ], - ) - self.assertEqual(len(alternatives.alternatives), 3) - - self.assertEqual(alternatives.alternatives[0].name, "First alternative") - self.assertEqual(alternatives.alternatives[0].profile[0].real.value, 5.) - self.assertEqual(alternatives.alternatives[0].profile[1].real.value, 5.) - self.assertEqual(alternatives.alternatives[0].profile[2].real.value, 5.) - self.assertEqual(alternatives.alternatives[0].category_index, 0) - - self.assertEqual(alternatives.alternatives[1].name, "Second alternative") - self.assertEqual(alternatives.alternatives[1].profile[0].real.value, 1.) - self.assertEqual(alternatives.alternatives[1].profile[1].real.value, 2.) - self.assertEqual(alternatives.alternatives[1].profile[2].real.value, 3.) - self.assertIsNone(alternatives.alternatives[1].category_index) - - self.assertEqual(alternatives.alternatives[2].name, "Third alternative") - self.assertEqual(alternatives.alternatives[2].profile[0].real.value, 2.) - self.assertEqual(alternatives.alternatives[2].profile[1].real.value, 4.) - self.assertEqual(alternatives.alternatives[2].profile[2].real.value, 6.) - self.assertIsNone(alternatives.alternatives[2].category_index) - - def test_init_size_mismatch(self): - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.increasing, 0, 1)), - ], [ - Category("Category 1"), - Category("Category 2"), - ], - ) - with self.assertRaises(DataValidationException) as cm: - Alternatives( - problem, - [ - Alternative("First alternative", [], 0), - ], - ) - self.assertEqual(cm.exception.args[0], "The profile of an alternative must have as many performances as there are criteria in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives( - problem, - [ - Alternative("First alternative", [Performance(Performance.Real(5.)), Performance(Performance.Real(5.))], 0), - ], - ) - self.assertEqual(cm.exception.args[0], "The profile of an alternative must have as many performances as there are criteria in the problem") - - def test_init_type_mismatch(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0)]) - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Integer(8)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The type of the performance of an alternative must match the type of the real-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Real(25)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The type of the performance of an alternative must match the type of the integer-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(25)), Performance(Performance.Integer(42))], 0)]) - self.assertEqual(cm.exception.args[0], "The type of the performance of an alternative must match the type of the enumerated criterion in the problem") - - def test_pickle_and_deep_copy(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - alternatives = Alternatives( - problem, - [ - Alternative("First alternative", [Performance(Performance.Real(8.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0), - Alternative("Second alternative", [Performance(Performance.Real(6.)), Performance(Performance.Integer(50)), Performance(Performance.Enumerated("b"))], None), - ], - ) - pickled_alternatives = pickle.dumps(alternatives) - self.assertIsInstance(pickled_alternatives, bytes) - unpickled_alternatives = pickle.loads(pickled_alternatives) - copied_alternatives = copy.deepcopy(alternatives) - - for a in (alternatives, unpickled_alternatives, copied_alternatives): - self.assertEqual(len(a.alternatives), 2) - self.assertEqual(a.alternatives[0].name, "First alternative") - self.assertEqual(a.alternatives[0].profile[0].real.value, 8.) - self.assertEqual(a.alternatives[0].profile[1].integer.value, 25) - self.assertEqual(a.alternatives[0].profile[2].enumerated.value, "a") - self.assertEqual(a.alternatives[0].category_index, 0) - self.assertEqual(a.alternatives[1].name, "Second alternative") - self.assertEqual(a.alternatives[1].profile[0].real.value, 6.) - self.assertEqual(a.alternatives[1].profile[1].integer.value, 50) - self.assertEqual(a.alternatives[1].profile[2].enumerated.value, "b") - self.assertIsNone(a.alternatives[1].category_index) - - for a in (unpickled_alternatives, copied_alternatives): - self.assertIsNot(a, alternatives) - self.assertIsNot(a.alternatives, alternatives.alternatives) - self.assertIsNot(a.alternatives[0], alternatives.alternatives[0]) - self.assertIsNot(a.alternatives[1], alternatives.alternatives[1]) - - def test_init_out_of_range(self): - problem = Problem( - criteria=[ - Criterion(name="Real criterion", values=Criterion.RealValues(Criterion.PreferenceDirection.increasing, 5, 10)), - Criterion(name="Integer criterion", values=Criterion.IntegerValues(Criterion.PreferenceDirection.decreasing, 15, 100)), - Criterion(name="Enumerated criterion", values=Criterion.EnumeratedValues(["a", "b", "c"])), - ], - ordered_categories=[ - Category("Bad"), - Category("Medium"), - Category("Good"), - ], - ) - - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0)]) - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(3.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The performance of an alternative must be between the min and max values for the real-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(11.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The performance of an alternative must be between the min and max values for the real-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(10)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The performance of an alternative must be between the min and max values for the integer-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(110)), Performance(Performance.Enumerated("a"))], 0)]) - self.assertEqual(cm.exception.args[0], "The performance of an alternative must be between the min and max values for the integer-valued criterion in the problem") - with self.assertRaises(DataValidationException) as cm: - Alternatives(problem, [Alternative("Name", [Performance(Performance.Real(8.)), Performance(Performance.Integer(25)), Performance(Performance.Enumerated("d"))], 0)]) - self.assertEqual(cm.exception.args[0], "The performance of an alternative must be int the enumerated values for a criterion in the problem") - - -class LearningTestCase(unittest.TestCase): - def test_access_preprocessed_learning_set(self): - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing, Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - - self.assertEqual(preprocessed_learning_set.criteria_count, 5) - - self.assertEqual(preprocessed_learning_set.categories_count, 3) - - self.assertEqual(preprocessed_learning_set.boundaries_count, 2) - - self.assertEqual(preprocessed_learning_set.alternatives_count, 200) - - self.assertEqual(len(preprocessed_learning_set.values_counts), 5) - self.assertEqual(preprocessed_learning_set.values_counts[0], 202) - self.assertEqual(list(preprocessed_learning_set.values_counts), [202, 202, 202, 202, 202]) - - self.assertEqual(len(preprocessed_learning_set.performance_ranks), 5) - self.assertEqual(len(preprocessed_learning_set.performance_ranks[0]), 200) - self.assertEqual(preprocessed_learning_set.performance_ranks[0][0], 24) - - self.assertEqual(len(preprocessed_learning_set.assignments), 200) - self.assertEqual(preprocessed_learning_set.assignments[0], 0) - - self.assertEqual(list(preprocessed_learning_set.single_peaked), [False, True, False, False, True]) - - def test_access_wpb_models_being_learned(self): - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing, Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(PreprocessedLearningSet(problem, learning_set), 9, 44) - - self.assertEqual(models_being_learned.models_count, 9) - - self.assertEqual(len(models_being_learned.random_generators), 9) - self.assertEqual(models_being_learned.random_generators[0](), 3585619732) - - self.assertEqual(models_being_learned.iteration_index, 0) - - self.assertEqual(len(models_being_learned.model_indexes), 9) - self.assertEqual(models_being_learned.model_indexes[0], 0) - - self.assertEqual(len(models_being_learned.accuracies), 9) - self.assertEqual(models_being_learned.accuracies[0], 0) - - self.assertEqual(len(models_being_learned.low_profile_ranks), 9) - self.assertEqual(len(models_being_learned.low_profile_ranks[0]), 2) - self.assertEqual(len(models_being_learned.low_profile_ranks[0][0]), 5) - self.assertIsInstance(models_being_learned.low_profile_ranks[0][0][0], int) - - self.assertEqual(len(models_being_learned.high_profile_rank_indexes), 5) - self.assertEqual(models_being_learned.high_profile_rank_indexes[1], 0) - self.assertEqual(models_being_learned.high_profile_rank_indexes[4], 1) - - self.assertEqual(len(models_being_learned.high_profile_ranks), 9) - self.assertEqual(len(models_being_learned.high_profile_ranks[0]), 2) - self.assertEqual(len(models_being_learned.high_profile_ranks[0][0]), 2) - self.assertIsInstance(models_being_learned.high_profile_ranks[0][0][0], int) - - self.assertEqual(len(models_being_learned.weights), 9) - self.assertEqual(len(models_being_learned.weights[0]), 5) - self.assertIsInstance(models_being_learned.weights[0][0], float) - - def test_basic_mrsort_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - self.assertEqual(models_being_learned.iteration_index, 8) - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 29) - self.assertEqual(result.unchanged, 971) - - def test_learn_with_deleted_strategies(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - best_accuracies = [] - - class MyObserver(LearnMrsortByWeightsProfilesBreed.Observer): - def __init__(self, models_being_learned): - super().__init__() - self.models_being_learned = models_being_learned - - def after_iteration(self): - # nonlocal best_accuracies - best_accuracies.append(self.models_being_learned.get_best_accuracy()) - - def before_return(self): - best_accuracies.append(self.models_being_learned.get_best_accuracy()) - - # This test is about a bug where strategy objects were garbage-collected before - # the learning was 'perform'ed, causing a crash. - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - observer = MyObserver(models_being_learned) - observers = [observer] - learning = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - observers, - ) - - del preprocessed_learning_set - del models_being_learned - del profiles_initialization_strategy - del weights_optimization_strategy - del profiles_improvement_strategy - del breeding_strategy - del termination_strategy - del observer - del observers - - learning.perform() - - self.assertEqual(best_accuracies, [182, 192, 192, 193, 193, 194, 196, 199, 200]) - - def test_iterations_restricted_mrsort_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 1000, 43) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAfterIterations(models_being_learned, 1) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - self.assertGreater(classify_alternatives(problem, learned_model, learning_set).changed, 0) - - def test_terminate_when_any(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - class MyTerminationStrategy(LearnMrsortByWeightsProfilesBreed.TerminationStrategy): - def __init__(self): - super().__init__() - self.called_count = 0 - - def terminate(self): - self.called_count += 1 - return self.called_count == 6 - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - my_termination_strategy = MyTerminationStrategy() - termination_strategy = TerminateWhenAny([my_termination_strategy, TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives))]) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - self.assertEqual(my_termination_strategy.called_count, 6) - self.assertEqual(classify_alternatives(problem, learned_model, learning_set).changed, 6) - - def test_python_strategies(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - class MyProfileInitializationStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesInitializationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - self.called_count = 0 - - def initialize_profiles(self, begin, end): - self.called_count += 1 - return self.strategy.initialize_profiles(begin, end) - - class MyWeightsOptimizationStrategy(LearnMrsortByWeightsProfilesBreed.WeightsOptimizationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - self.called_count = 0 - - def optimize_weights(self, begin, end): - self.called_count += 1 - return self.strategy.optimize_weights(begin, end) - - class MyProfilesImprovementStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesImprovementStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - self.called_count = 0 - - def improve_profiles(self, begin, end): - self.called_count += 1 - return self.strategy.improve_profiles(begin, end) - - class MyBreedingStrategy(LearnMrsortByWeightsProfilesBreed.BreedingStrategy): - def __init__(self, models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count): - super().__init__() - self.strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count) - self.called_count = 0 - - def breed(self): - self.called_count += 1 - return self.strategy.breed() - - class MyTerminationStrategy(LearnMrsortByWeightsProfilesBreed.TerminationStrategy): - def __init__(self, models_being_learned): - super().__init__() - self.models_being_learned = models_being_learned - self.accuracies = [] - - def terminate(self): - self.accuracies.append(models_being_learned.get_best_accuracy()) - return len(self.accuracies) == 2 - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = MyProfileInitializationStrategy(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = MyWeightsOptimizationStrategy(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = MyProfilesImprovementStrategy(preprocessed_learning_set, models_being_learned) - breeding_strategy = MyBreedingStrategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = MyTerminationStrategy(models_being_learned) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - self.assertEqual(profiles_initialization_strategy.called_count, 2) - self.assertEqual(weights_optimization_strategy.called_count, 4) - self.assertEqual(profiles_improvement_strategy.called_count, 2) - self.assertEqual(breeding_strategy.called_count, 1) - self.assertEqual(termination_strategy.accuracies, [182, 192]) - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 8) - self.assertEqual(result.unchanged, 192) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 68) - self.assertEqual(result.unchanged, 932) - - def test_silly_strategies(self): - class SillyProfilesInitializationStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesInitializationStrategy): - def __init__(self, log, preprocessed_learning_set, models_being_learned): - super().__init__() - self.log = log - self.preprocessed_learning_set = preprocessed_learning_set - self.models_being_learned = models_being_learned - - def initialize_profiles(self, model_indexes_begin, model_indexes_end): - self.log.append(("initialize_profiles", model_indexes_begin, model_indexes_end)) - for model_index_index in range(model_indexes_begin, model_indexes_end): - model_index = models_being_learned.model_indexes[model_index_index] - for boundary_index in range(self.preprocessed_learning_set.boundaries_count): - for criterion_index in range(self.preprocessed_learning_set.criteria_count): - self.models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] = 0 - - class SillyWeightsOptimizationStrategy(LearnMrsortByWeightsProfilesBreed.WeightsOptimizationStrategy): - def __init__(self, log, preprocessed_learning_set, models_being_learned): - super().__init__() - self.log = log - self.preprocessed_learning_set = preprocessed_learning_set - self.models_being_learned = models_being_learned - - def optimize_weights(self, model_indexes_begin, model_indexes_end): - self.log.append(("optimize_weights", model_indexes_begin, model_indexes_end)) - for model_index_index in range(model_indexes_begin, model_indexes_end): - model_index = models_being_learned.model_indexes[model_index_index] - for criterion_index in range(self.preprocessed_learning_set.criteria_count): - self.models_being_learned.weights[model_index][criterion_index] = 1.1 / self.preprocessed_learning_set.criteria_count - - class SillyProfilesImprovementStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesImprovementStrategy): - def __init__(self, log, preprocessed_learning_set, models_being_learned): - super().__init__() - self.log = log - self.preprocessed_learning_set = preprocessed_learning_set - self.models_being_learned = models_being_learned - - def improve_profiles(self, model_indexes_begin, model_indexes_end): - self.log.append(("improve_profiles", model_indexes_begin, model_indexes_end)) - for model_index_index in range(model_indexes_begin, model_indexes_end): - model_index = models_being_learned.model_indexes[model_index_index] - for boundary_index in range(self.preprocessed_learning_set.boundaries_count): - for criterion_index in range(self.preprocessed_learning_set.criteria_count): - rank = (boundary_index + 1) * (self.preprocessed_learning_set.values_counts[criterion_index] // (self.preprocessed_learning_set.boundaries_count + 1)) - self.models_being_learned.low_profile_ranks[model_index][boundary_index][criterion_index] = rank - - class SillyBreedingStrategy(LearnMrsortByWeightsProfilesBreed.BreedingStrategy): - def __init__(self, log): - super().__init__() - self.log = log - - def breed(self): - self.log.append(("breed",)) - - class SillyTerminationStrategy(LearnMrsortByWeightsProfilesBreed.TerminationStrategy): - def __init__(self, log, models_being_learned): - super().__init__() - self.log = log - self.models_being_learned = models_being_learned - - def terminate(self): - self.log.append(("terminate",)) - return self.models_being_learned.iteration_index == 3 - - problem = Problem( - [ - Criterion("Criterion 1", Criterion.RealValues(Criterion.PreferenceDirection.decreasing, 0, 10)), - Criterion("Criterion 2", Criterion.IntegerValues(Criterion.PreferenceDirection.increasing, 0, 100)), - Criterion("Criterion 3", Criterion.EnumeratedValues(["F", "E", "D", "C", "B", "A"])), - ], - [Category("Bad"), Category("Medium"), Category("Good")], - ) - learning_set = generate_alternatives(problem, generate_mrsort_model(problem, random_seed=42), alternatives_count=1000, random_seed=43) - - log = [] - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, models_count=9, random_seed=43) - profiles_initialization_strategy = SillyProfilesInitializationStrategy(log, preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = SillyWeightsOptimizationStrategy(log, preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = SillyProfilesImprovementStrategy(log, preprocessed_learning_set, models_being_learned) - breeding_strategy = SillyBreedingStrategy(log) - termination_strategy = SillyTerminationStrategy(log, models_being_learned) - - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - self.assertEqual(log, [ - ("initialize_profiles", 0, 9), - ("optimize_weights", 0, 9), - ("improve_profiles", 0, 9), - ("optimize_weights", 0, 9), - ("terminate",), - ("breed",), - ("improve_profiles", 0, 9), - ("optimize_weights", 0, 9), - ("terminate",), - ("breed",), - ("improve_profiles", 0, 9), - ("optimize_weights", 0, 9), - ("terminate",), - ("breed",), - ("improve_profiles", 0, 9), - ("optimize_weights", 0, 9), - ("terminate",), - ]) - - self.assertAlmostEqual(learned_model.accepted_values[0].real_thresholds.thresholds[0], 6.9493637) - self.assertAlmostEqual(learned_model.accepted_values[0].real_thresholds.thresholds[1], 3.2469211) - self.assertEqual(learned_model.accepted_values[1].integer_thresholds.thresholds[0], 33) - self.assertEqual(learned_model.accepted_values[1].integer_thresholds.thresholds[1], 66) - self.assertEqual(learned_model.accepted_values[2].enumerated_thresholds.thresholds[0], "D") - self.assertEqual(learned_model.accepted_values[2].enumerated_thresholds.thresholds[1], "B") - self.assertAlmostEqual(learned_model.sufficient_coalitions[0].weights.criterion_weights[0], 1.1 / 3) - self.assertAlmostEqual(learned_model.sufficient_coalitions[0].weights.criterion_weights[1], 1.1 / 3) - self.assertAlmostEqual(learned_model.sufficient_coalitions[0].weights.criterion_weights[2], 1.1 / 3) - self.assertAlmostEqual(learned_model.sufficient_coalitions[1].weights.criterion_weights[0], 1.1 / 3) - self.assertAlmostEqual(learned_model.sufficient_coalitions[1].weights.criterion_weights[1], 1.1 / 3) - self.assertAlmostEqual(learned_model.sufficient_coalitions[1].weights.criterion_weights[2], 1.1 / 3) - - def test_profiles_initialization_strategy_that_does_not_support_single_peaked_criteria(self): - class MyProfileInitializationStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesInitializationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - - def initialize_profiles(self, begin, end): - return self.strategy.initialize_profiles(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = MyProfileInitializationStrategy(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - - with self.assertRaises(LearningFailureException) as cm: - learning.perform() - self.assertEqual(cm.exception.args[0], "This profiles initialization strategy doesn't support single-peaked criteria.") - - def test_profiles_initialization_strategy_that_does_support_single_peaked_criteria(self): - class MyProfileInitializationStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesInitializationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__(supports_single_peaked_criteria=True) - self.strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - - def initialize_profiles(self, begin, end): - return self.strategy.initialize_profiles(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = MyProfileInitializationStrategy(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - def test_weights_optimization_strategy_that_does_not_support_single_peaked_criteria(self): - class MyWeightsOptimizationStrategy(LearnMrsortByWeightsProfilesBreed.WeightsOptimizationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - - def optimize_weights(self, begin, end): - return self.strategy.optimize_weights(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = MyWeightsOptimizationStrategy(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - - with self.assertRaises(LearningFailureException) as cm: - learning.perform() - self.assertEqual(cm.exception.args[0], "This weights optimization strategy doesn't support single-peaked criteria.") - - def test_weights_optimization_strategy_that_does_support_single_peaked_criteria(self): - class MyWeightsOptimizationStrategy(LearnMrsortByWeightsProfilesBreed.WeightsOptimizationStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__(True) - self.strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - - def optimize_weights(self, begin, end): - return self.strategy.optimize_weights(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = MyWeightsOptimizationStrategy(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - def test_profiles_improvement_strategy_that_does_not_support_single_peaked_criteria(self): - class MyProfilesImprovementStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesImprovementStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__() - self.strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - - def improve_profiles(self, begin, end): - return self.strategy.improve_profiles(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = MyProfilesImprovementStrategy(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - - with self.assertRaises(LearningFailureException) as cm: - learning.perform() - self.assertEqual(cm.exception.args[0], "This profiles improvement strategy doesn't support single-peaked criteria.") - - def test_profiles_improvement_strategy_that_does_support_single_peaked_criteria(self): - class MyProfilesImprovementStrategy(LearnMrsortByWeightsProfilesBreed.ProfilesImprovementStrategy): - def __init__(self, preprocessed_learning_set, models_being_learned): - super().__init__(True) - self.strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - - def improve_profiles(self, begin, end): - return self.strategy.improve_profiles(begin, end) - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = MyProfilesImprovementStrategy(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - def test_breeding_strategy_that_does_not_support_single_peaked_criteria(self): - class MyBreedingStrategy(LearnMrsortByWeightsProfilesBreed.BreedingStrategy): - def __init__(self, models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count): - super().__init__() - self.strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count) - - def breed(self): - return self.strategy.breed() - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = MyBreedingStrategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - - with self.assertRaises(LearningFailureException) as cm: - learning.perform() - self.assertEqual(cm.exception.args[0], "This breeding strategy doesn't support single-peaked criteria.") - - def test_breeding_strategy_that_does_support_single_peaked_criteria(self): - class MyBreedingStrategy(LearnMrsortByWeightsProfilesBreed.BreedingStrategy): - def __init__(self, models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count): - super().__init__(True) - self.strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count) - - def breed(self): - return self.strategy.breed() - - def make_learning(problem, learning_set): - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = MyBreedingStrategy(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - return LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ) - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.increasing]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - problem = generate_problem(5, 3, 41, allowed_preference_directions=[Criterion.PreferenceDirection.single_peaked]) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - learning = make_learning(problem, learning_set) - learning.perform() - - def test_observers(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - class MyObserver(LearnMrsortByWeightsProfilesBreed.Observer): - def __init__(self, models_being_learned): - super().__init__() - self.models_being_learned = models_being_learned - self.best_accuracies = [] - self.final_accuracy = None - - def after_iteration(self): - self.best_accuracies.append(self.models_being_learned.get_best_accuracy()) - - def before_return(self): - self.final_accuracy = self.models_being_learned.get_best_accuracy() - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - observer = MyObserver(models_being_learned) - LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - [observer], - ).perform() - - self.assertEqual(observer.best_accuracies, [182, 192, 192, 193, 193, 194, 196, 199]) - self.assertEqual(observer.final_accuracy, 200) - - def test_alglib_mrsort_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingAlglib(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 21) - self.assertEqual(result.unchanged, 979) - - @unittest.skipIf(forbid_gpu, "Can't use GPU") - def test_gpu_mrsort_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, 9, 44) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnGpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, 4) - termination_strategy = TerminateAtAccuracy(models_being_learned, len(learning_set.alternatives)) - learned_model = LearnMrsortByWeightsProfilesBreed( - preprocessed_learning_set, - models_being_learned, - profiles_initialization_strategy, - weights_optimization_strategy, - profiles_improvement_strategy, - breeding_strategy, - termination_strategy, - ).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 29) - self.assertEqual(result.unchanged, 971) - - def test_sat_by_coalitions_using_minisat_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - learned_model = LearnUcncsBySatByCoalitionsUsingMinisat(problem, learning_set).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 26) - self.assertEqual(result.unchanged, 974) - - def test_sat_by_separation_using_minisat_learning(self): - problem = generate_problem(5, 2, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - learned_model = LearnUcncsBySatBySeparationUsingMinisat(problem, learning_set).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 28) - self.assertEqual(result.unchanged, 972) - - def test_max_sat_by_coalitions_using_evalmaxsat_learning(self): - problem = generate_problem(5, 3, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - learned_model = LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat(problem, learning_set).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 32) - self.assertEqual(result.unchanged, 968) - - def test_max_sat_by_separation_using_evalmaxsat_learning(self): - problem = generate_problem(5, 2, 41) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 200, 43) - - learned_model = LearnUcncsByMaxSatBySeparationUsingEvalmaxsat(problem, learning_set).perform() - - result = classify_alternatives(problem, learned_model, learning_set) - self.assertEqual(result.changed, 0) - self.assertEqual(result.unchanged, 200) - - testing_set = generate_alternatives(problem, model, 1000, 44) - result = classify_alternatives(problem, learned_model, testing_set) - self.assertEqual(result.changed, 25) - self.assertEqual(result.unchanged, 975) - - def test_learning_failure_exception(self): - problem = generate_problem(2, 2, 42) - model = generate_mrsort_model(problem, 42) - learning_set = generate_alternatives(problem, model, 100, 42) - misclassify_alternatives(problem, learning_set, 10, 42 + 27) - - learning = LearnUcncsBySatByCoalitionsUsingMinisat(problem, learning_set) - - with self.assertRaises(LearningFailureException): - learned_model = learning.perform() - - def test_bug_found_by_laurent_cabaret_in_real_life_data(self): - # Previously, in (max-)SAT learning methods, when the SAT solver returned a solution where no value was accepted - # for a given criterion, we used the maximum value for that criterion (as configured in the problem) as the threshold. - # This was incorrect, and would in rare occasions cause the resulting model to classify alternatives in a higher - # category that expected. To solve this issue, we had to allow "unreachable thresholds", materialized by None in - # Python, and null in YAML. That change broke the public interface of the library, so it required releasing a - # major version. - - problem = Problem.load(io.StringIO(textwrap.dedent("""\ - kind: classification-problem - format_version: 1 - criteria: - - name: a - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 1 - - name: b - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 1 - - name: c - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 1 # Setting to 2 improves accuracy. Why? - - name: d - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 1 # Setting to 2 improves accuracy. Why? - - name: e - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 4 # Setting to 5 improves accuracy. Why? - - name: f - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 15 # Setting to 16 improves accuracy. Why? - - name: g - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 15 - - name: h - value_type: integer - preference_direction: increasing - min_value: 0 - max_value: 10 - ordered_categories: - - name: 4 - - name: 3 - - name: 2 - - name: 1 - """))) - - learning_set = Alternatives.load(problem, io.StringIO(textwrap.dedent("""\ - name,a,b,c,d,e,f,g,h,category - 01,1,1,1,1,4,12,10,7,1 - 02,1,1,1,1,0,15,9,9,1 - 03,1,1,1,1,4,13,8,7,1 - 04,1,1,1,1,4,12,6,5,1 - 05,1,1,1,1,1,15,10,5,1 - 06,1,1,1,1,4,12,1,5,1 - 07,1,1,1,1,4,13,12,10,1 - 08,1,1,1,1,4,14,14,10,1 - 09,1,1,1,1,0,15,14,10,1 - 10,1,1,1,1,4,6,5,6,1 - 11,0,1,1,1,3,15,4,5,2 - 12,1,1,1,1,4,8,12,10,1 - 13,0,1,1,1,4,4,6,7,3 - 14,1,1,1,1,3,15,14,10,1 - 15,1,0,1,1,4,12,2,0,3 - 16,1,1,1,1,4,12,13,4,1 - 17,1,1,1,1,0,15,14,7,1 - 18,1,1,1,1,4,7,11,7,1 - 19,1,1,1,1,4,10,5,5,1 - 20,0,1,1,1,4,2,15,7,3 - 21,1,1,1,1,4,12,7,7,1 - 22,1,1,1,1,0,15,7,7,1 - 23,1,1,1,1,4,12,5,8,1 - 24,1,0,1,1,2,15,3,1,3 - 25,1,0,1,1,4,12,2,2,3 - 26,0,1,1,1,4,12,9,9,2 - 27,0,1,1,1,4,12,12,10,2 - 28,1,1,1,1,3,15,10,9,1 - 29,0,1,1,1,4,12,11,9,2 - 30,0,1,1,1,4,3,4,7,3 - 31,1,1,1,1,0,15,13,5,1 - 32,0,1,1,1,4,12,11,4,2 - 33,1,1,1,1,3,15,5,8,1 - 34,0,1,1,1,4,11,7,7,2 - 35,1,0,1,1,2,15,2,5,3 - 36,1,1,1,1,4,11,7,7,1 - 37,0,1,0,0,4,5,6,5,4 - 38,1,1,1,1,4,6,13,8,1 - 39,0,0,0,1,2,15,4,7,4 - 40,1,0,1,1,2,15,2,1,3 - 41,1,1,1,1,4,12,7,8,1 - 42,0,1,1,1,4,1,4,4,3 - 43,1,0,1,1,4,9,10,9,2 - 44,1,0,1,1,4,12,2,7,3 - 45,0,1,1,1,4,0,7,5,3 - 46,0,1,1,1,3,15,11,3,2 - 47,1,1,1,1,4,7,8,4,1 - 48,1,0,1,1,4,11,4,1,3 - 49,1,0,1,1,4,12,0,0,3 - 50,1,0,1,1,3,15,4,1,3 - """))) - - preprocessed_learning_set = PreprocessedLearningSet(problem, learning_set) - models_being_learned = LearnMrsortByWeightsProfilesBreed.ModelsBeingLearned(preprocessed_learning_set, models_count=9, random_seed=43) - profiles_initialization_strategy = InitializeProfilesForProbabilisticMaximalDiscriminationPowerPerCriterion(preprocessed_learning_set, models_being_learned) - weights_optimization_strategy = OptimizeWeightsUsingGlop(preprocessed_learning_set, models_being_learned) - profiles_improvement_strategy = ImproveProfilesWithAccuracyHeuristicOnCpu(preprocessed_learning_set, models_being_learned) - breeding_strategy = ReinitializeLeastAccurate(models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, count=4) - termination_strategy = TerminateAtAccuracy(models_being_learned, target_accuracy=len(learning_set.alternatives)) - model = LearnMrsortByWeightsProfilesBreed(preprocessed_learning_set, models_being_learned, profiles_initialization_strategy, weights_optimization_strategy, profiles_improvement_strategy, breeding_strategy, termination_strategy).perform() - model_dump = io.StringIO() - model.dump(problem, model_dump) - self.assertEqual(model_dump.getvalue(), textwrap.dedent("""\ - kind: ncs-classification-model - format_version: 1 - accepted_values: - - kind: thresholds - thresholds: [0, 1, 1] - - kind: thresholds - thresholds: [0, 1, 1] - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [3, 3, 4] - - kind: thresholds - thresholds: [5, 5, 14] - - kind: thresholds - thresholds: [3, 9, 9] - - kind: thresholds - thresholds: [0, 1, 5] - sufficient_coalitions: - - &coalitions - kind: weights - criterion_weights: [0.166666836, 0.333332658, 0.166666836, 0.166666836, 0.166666836, 0.166666836, 0.166665822, 0] - - *coalitions - - *coalitions - """)) - learning_set_copy = copy.deepcopy(learning_set) - classification_result = classify_alternatives(problem, model, learning_set_copy) - self.assertEqual(classification_result.unchanged, 50) - - model = LearnUcncsBySatBySeparationUsingMinisat(problem, learning_set).perform() - model_dump = io.StringIO() - model.dump(problem, model_dump) - self.assertEqual(model_dump.getvalue(), textwrap.dedent("""\ - kind: ncs-classification-model - format_version: 1 - accepted_values: - - kind: thresholds - thresholds: [0, 0, 1] - - kind: thresholds - thresholds: [0, 1, 1] - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [1, null, null] - - kind: thresholds - thresholds: [0, 3, 3] - - kind: thresholds - thresholds: [0, 6, 6] - - kind: thresholds - thresholds: [5, 5, 5] - - kind: thresholds - thresholds: [0, 8, 10] - sufficient_coalitions: - - &coalitions - kind: roots - upset_roots: - - [0, 1, 2, 4, 5] - - [0, 1, 2, 5, 6] - - [0, 2, 4, 5, 6, 7] - - *coalitions - - *coalitions - """)) - learning_set_copy = copy.deepcopy(learning_set) - classification_result = classify_alternatives(problem, model, learning_set_copy) - self.assertEqual(classification_result.unchanged, 50) - - model = LearnUcncsBySatByCoalitionsUsingMinisat(problem, learning_set).perform() - model_dump = io.StringIO() - model.dump(problem, model_dump) - self.assertEqual(model_dump.getvalue(), textwrap.dedent("""\ - kind: ncs-classification-model - format_version: 1 - accepted_values: - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [0, 1, 1] - - kind: thresholds - thresholds: [1, null, null] - - kind: thresholds - thresholds: [1, 1, null] - - kind: thresholds - thresholds: [3, 3, null] - - kind: thresholds - thresholds: [6, 9, null] - - kind: thresholds - thresholds: [0, 4, 13] - - kind: thresholds - thresholds: [0, 8, null] - sufficient_coalitions: - - &coalitions - kind: roots - upset_roots: - - [0, 1] - - [1, 2, 6] - - [1, 4, 5, 6] - - [1, 2, 4, 5, 7] - - [1, 3, 4, 6, 7] - - [0, 3, 4, 5, 6, 7] - - *coalitions - - *coalitions - """)) - learning_set_copy = copy.deepcopy(learning_set) - classification_result = classify_alternatives(problem, model, learning_set_copy) - self.assertEqual(classification_result.unchanged, 50) - - model = LearnUcncsByMaxSatBySeparationUsingEvalmaxsat(problem, learning_set).perform() - model_dump = io.StringIO() - model.dump(problem, model_dump) - self.assertEqual(model_dump.getvalue(), textwrap.dedent("""\ - kind: ncs-classification-model - format_version: 1 - accepted_values: - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [0, 1, 1] - - kind: thresholds - thresholds: [1, 1, null] - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [0, 3, 4] - - kind: thresholds - thresholds: [0, 6, 10] - - kind: thresholds - thresholds: [0, 3, 8] - - kind: thresholds - thresholds: [0, 3, 4] - sufficient_coalitions: - - &coalitions - kind: roots - upset_roots: - - [0, 1, 3, 4, 7] - - [0, 1, 3, 5, 7] - - [0, 2, 3, 4, 5, 6, 7] - - [1, 2, 3, 4, 5, 6, 7] - - *coalitions - - *coalitions - """)) - learning_set_copy = copy.deepcopy(learning_set) - classification_result = classify_alternatives(problem, model, learning_set_copy) - self.assertEqual(classification_result.unchanged, 50) - - model = LearnUcncsByMaxSatByCoalitionsUsingEvalmaxsat(problem, learning_set).perform() - model_dump = io.StringIO() - model.dump(problem, model_dump) - self.assertEqual(model_dump.getvalue(), textwrap.dedent("""\ - kind: ncs-classification-model - format_version: 1 - accepted_values: - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [1, 1, 1] - - kind: thresholds - thresholds: [1, null, null] - - kind: thresholds - thresholds: [null, null, null] - - kind: thresholds - thresholds: [3, null, null] - - kind: thresholds - thresholds: [11, 11, null] - - kind: thresholds - thresholds: [7, null, null] - - kind: thresholds - thresholds: [8, 8, null] - sufficient_coalitions: - - &coalitions - kind: roots - upset_roots: - - [0, 1] - - [1, 2, 4] - - [1, 3, 4] - - [1, 5] - - [2, 5] - - [3, 5] - - [4, 5] - - [6] - - [7] - - *coalitions - - *coalitions - """)) - learning_set_copy = copy.deepcopy(learning_set) - classification_result = classify_alternatives(problem, model, learning_set_copy) - self.assertEqual(classification_result.unchanged, 50) diff --git a/lincs/visualization.py b/lincs/visualization.py deleted file mode 100644 index 32fdc29e..00000000 --- a/lincs/visualization.py +++ /dev/null @@ -1,285 +0,0 @@ -# Copyright 2023-2024 Vincent Jacques - -import sys -from typing import Iterable -import unittest - -import matplotlib.pyplot - -from .classification import Problem, Model, Alternative - - -single_peaked_not_supported_message = "Single-peaked criteria are not yet supported by the visualization. See https://github.com/MICS-Lab/lincs/discussions/21 and maybe contribute your ideas?" - - -def visualize_classification_model(problem: Problem, model: Model, alternatives: Iterable[Alternative], axes: matplotlib.pyplot.Axes): - """ - Create a visual representation of a classification model and classified alternatives, using Matplotlib. - """ - - criteria_count = len(problem.criteria) - assert criteria_count >= 1 - categories_count = len(problem.ordered_categories) - assert categories_count >= 2 - boundaries_count = categories_count - 1 - - vertical_margin = 0.05 - horizontal_margin = 0.1 - - if criteria_count == 1: - xs = [0.5] - else: - xs = [horizontal_margin + criterion_index * (1 - 2 * horizontal_margin) / (criteria_count - 1) for criterion_index in range(criteria_count)] - - if criteria_count <= 2: - criterion_index_for_alternatives = 0 - else: - criterion_index_for_alternatives = 1 - - axes.set_xlim(0, 1) - axes.set_xticks(xs, [criterion.name for criterion in problem.criteria]) - - axes.set_ylim(-vertical_margin, 1 + vertical_margin) - axes.set_yticks([0, 1], ["worst", "best"]) - - boundary_profiles = [[] for _ in problem.ordered_categories[1:]] - for criterion, accepted_values in zip(problem.criteria, model.accepted_values): - if criterion.is_real: - if accepted_values.is_thresholds: - for boundary_index in range(boundaries_count): - boundary_profiles[boundary_index].append(accepted_values.real_thresholds.thresholds[boundary_index]) - else: - assert accepted_values.is_intervals - print(single_peaked_not_supported_message, file=sys.stderr) - exit(1) - elif criterion.is_integer: - if accepted_values.is_thresholds: - for boundary_index in range(boundaries_count): - boundary_profiles[boundary_index].append(accepted_values.integer_thresholds.thresholds[boundary_index]) - else: - assert accepted_values.is_intervals - print(single_peaked_not_supported_message, file=sys.stderr) - exit(1) - else: - assert criterion.is_enumerated - assert accepted_values.is_thresholds - for boundary_index in range(boundaries_count): - boundary_profiles[boundary_index].append(criterion.enumerated_values.get_value_rank(accepted_values.enumerated_thresholds.thresholds[boundary_index])) - - def extend(ys): - return [ys[0]] + ys + [ys[-1]] - ys = [ - extend(normalize_profile(problem.criteria, boundary_profile)) - for boundary_profile in boundary_profiles - ] - ys.append(extend([1] * len(xs))) - unstacked_ys = [ys[0]] - for ys1, ys2 in zip(ys[1:], ys[:-1]): - unstacked_ys.append([y1 - y2 for y1, y2 in zip(ys1, ys2)]) - collections = axes.stackplot([0] + xs + [1], unstacked_ys, alpha=0.4) - colors = [collection.get_facecolor()[0] for collection in collections] - - for (x, criterion) in zip(xs, problem.criteria): - criterion_axis = axes.secondary_yaxis(x) - if criterion.is_real: - values = criterion.real_values - ticks = [0, 0.25, 0.5, 0.75, 1] - labels = [f"{values.min_value + tick * (values.max_value - values.min_value):.1f}" for tick in ticks] - if values.is_increasing: - criterion_axis.set_yticks(ticks, labels) - else: - assert values.is_decreasing - criterion_axis.set_yticks(ticks, reversed(labels)) - elif criterion.is_integer: - values = criterion.integer_values - labels = list(make_integer_labels(values.min_value, values.max_value)) - ticks = [(label - values.min_value) / (values.max_value - values.min_value) for label in labels] - if values.is_increasing: - criterion_axis.set_yticks(ticks, labels) - else: - assert values.is_decreasing - criterion_axis.set_yticks(ticks, reversed(labels)) - else: - assert criterion.is_enumerated - values = criterion.enumerated_values - ticks_count = len(values.ordered_values) - ticks = [n / (ticks_count - 1) for n in range(ticks_count)] - criterion_axis.set_yticks(ticks, values.ordered_values) - - for (category_index, category) in enumerate(problem.ordered_categories): - if category_index == 0: - low_y = 0 - else: - low_y = normalize_value(problem.criteria[0], boundary_profiles[category_index - 1][0]) - if category_index == len(problem.ordered_categories) - 1: - high_y = 1 - else: - high_y = normalize_value(problem.criteria[0], boundary_profiles[category_index][0]) - y = (low_y + high_y) / 2 - color = colors[category_index] - axes.text( - 0, y, - category.name, - color=color, - alpha=1, - fontweight="bold", verticalalignment="center" - ) - - for alternative in alternatives: - if alternative.category_index is None: - color = "black" - else: - color = colors[alternative.category_index] - axes.plot( - xs, normalize_profile(problem.criteria, make_numeric_profile(problem.criteria, alternative.profile)), - "o--", - label=alternative.name, - color=color, - alpha=1, - ) - axes.text( - xs[criterion_index_for_alternatives], - normalize_value( - problem.criteria[criterion_index_for_alternatives], - make_numeric_value( - problem.criteria[criterion_index_for_alternatives], - alternative.profile[criterion_index_for_alternatives], - ), - ), - alternative.name, - color=color, alpha=1) - - -def make_integer_labels(min_value, max_value): - intervals_count = max_value - min_value - assert intervals_count >= 1 - if intervals_count == 1: - yield min_value - yield max_value - elif intervals_count == 2: - yield min_value - yield min_value + 1 - yield max_value - elif intervals_count % 2 == 0: - yield min_value - yield min_value + intervals_count // 4 - yield (min_value + max_value) // 2 - yield max_value - intervals_count // 4 - yield max_value - else: - yield min_value - yield min_value + intervals_count // 3 - yield max_value - intervals_count // 3 - yield max_value - - -class MakeIntegerLabelsTests(unittest.TestCase): - def _test(self, min_value, max_value, expected): - self.assertEqual(list(make_integer_labels(min_value, max_value)), expected) - - def test_all(self): - for n in range(100): - l = list(make_integer_labels(10, n + 11)) - self.assertLessEqual(len(l), 5) - self.assertEqual(l[0], 10) - self.assertEqual(l[-1], n + 11) - if len(l) % 2 == 1: - self.assertEqual(l[len(l) // 2], (10 + n + 11) // 2) - self.assertEqual(l, sorted(l)) - - def test_0_1(self): - self._test(0, 1, [0, 1]) - - def test_0_2(self): - self._test(0, 2, [0, 1, 2]) - - def test_0_3(self): - self._test(0, 3, [0, 1, 2, 3]) - - def test_0_4(self): - self._test(0, 4, [0, 1, 2, 3, 4]) - - def test_10_14(self): - self._test(10, 14, [10, 11, 12, 13, 14]) - - def test_0_5(self): - self._test(0, 5, [0, 1, 4, 5]) - - def test_0_6(self): - self._test(0, 6, [0, 1, 3, 5, 6]) - - def test_0_7(self): - self._test(0, 7, [0, 2, 5, 7]) - - def test_0_70(self): - self._test(0, 70, [0, 17, 35, 53, 70]) - - def test_0_8(self): - self._test(0, 8, [0, 2, 4, 6, 8]) - - def test_0_8(self): - self._test(0, 80, [0, 20, 40, 60, 80]) - - def test_bug_1(self): - self._test(-4949, 9942, [-4949, 14, 4979, 9942]) - - def test_0_9000(self): - self._test(0, 9000, [0, 2250, 4500, 6750, 9000]) - - def test_0_9001(self): - self._test(0, 9001, [0, 3000, 6001, 9001]) - - def test_0_9002(self): - self._test(0, 9002, [0, 2250, 4501, 6752, 9002]) - - def test_0_9003(self): - self._test(0, 9003, [0, 3001, 6002, 9003]) - - def test_0_9004(self): - self._test(0, 9004, [0, 2251, 4502, 6753, 9004]) - - -def make_numeric_profile(criteria, profile): - return [ - make_numeric_value(criterion, y) - for (criterion, y) in zip(criteria, profile) - ] - - -def make_numeric_value(criterion, y): - if criterion.is_real: - return y.real.value - elif criterion.is_integer: - return y.integer.value - else: - assert criterion.is_enumerated - return criterion.enumerated_values.get_value_rank(y.enumerated.value) - - -def normalize_profile(criteria, ys): - return [ - normalize_value(criterion, y) - for (criterion, y) in zip(criteria, ys) - ] - - -def normalize_value(criterion, y): - is_increasing = None - if criterion.is_real: - values = criterion.real_values - is_increasing = values.is_increasing - y = (y - values.min_value) / (values.max_value - values.min_value) - elif criterion.is_integer: - values = criterion.integer_values - is_increasing = values.is_increasing - y = (y - values.min_value) / (values.max_value - values.min_value) - else: - assert criterion.is_enumerated - values = criterion.enumerated_values - is_increasing = True - y = y / (len(values.ordered_values) - 1) - - if is_increasing: - return y - else: - return 1 - y diff --git a/setup.py b/setup.py index 31f6b996..47997e92 100644 --- a/setup.py +++ b/setup.py @@ -229,7 +229,6 @@ def make_liblincs_extension(): extra_compile_args["vendored-c++"] = ["-std=c++17", "-Werror=switch", "-w", "-DQUIET", "-DNBUILD", "-DNCONTRACTS"] extra_link_args += ["-fopenmp"] libraries += [ - "ortools", f"python{sys.version_info.major}.{sys.version_info.minor}", ] if os.environ.get("LINCS_DEV_COVERAGE", "false") == "true":