desdeo 2.1.1__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,8 @@ import json
4
4
  from typing import Annotated
5
5
 
6
6
  from fastapi import APIRouter, Depends
7
- from sqlmodel import Session, select
7
+ from sqlmodel import select
8
8
 
9
- from desdeo.api.db import get_session
10
9
  from desdeo.api.models import (
11
10
  ForestProblemMetaData,
12
11
  NIMBUSFinalState,
@@ -14,33 +13,33 @@ from desdeo.api.models import (
14
13
  NIMBUSSaveState,
15
14
  ProblemMetaDataDB,
16
15
  StateDB,
17
- User,
18
16
  UtopiaRequest,
19
17
  UtopiaResponse,
20
18
  )
21
- from desdeo.api.routers.user_authentication import get_current_user
19
+ from desdeo.api.routers.utils import SessionContext, get_session_context
22
20
 
23
21
  router = APIRouter(prefix="/utopia")
24
22
 
25
23
 
26
24
  @router.post("/")
27
- def get_utopia_data(
25
+ def get_utopia_data( # noqa: C901
28
26
  request: UtopiaRequest,
29
- user: Annotated[User, Depends(get_current_user)],
30
- session: Annotated[Session, Depends(get_session)],
27
+ context: Annotated[SessionContext, Depends(get_session_context)],
31
28
  ) -> UtopiaResponse:
32
29
  """Request and receive the Utopia map corresponding to the decision variables sent.
33
30
 
34
31
  Args:
35
32
  request (UtopiaRequest): the set of decision variables and problem for which the utopia forest map is requested
36
- for.
37
- user (Annotated[User, Depend(get_current_user)]) the current user
38
- session (Annotated[Session, Depends(get_session)]) the current database session
33
+ for.
34
+ context (Annotated[SessionContext, Depends(get_session_context)]): the current session context
35
+
39
36
  Raises:
40
37
  HTTPException:
41
38
  Returns:
42
39
  UtopiaResponse: the map for the forest, to be rendered in frontend
43
40
  """
41
+ session = context.db_session
42
+
44
43
  empty_response = UtopiaResponse(is_utopia=False, map_name="", map_json={}, options={}, description="", years=[])
45
44
 
46
45
  state = session.exec(select(StateDB).where(StateDB.id == request.solution.state_id)).first()
@@ -105,9 +104,9 @@ def get_utopia_data(
105
104
  # The dict keys get converted to ints to strings when it's loaded from database
106
105
  try:
107
106
  treatments = forest_metadata.schedule_dict[key][str(decision_variables[key].index(1))]
108
- except ValueError as e:
107
+ except ValueError:
109
108
  # if the optimization didn't choose any decision alternative, it's safe to assume
110
- # that nothing is being done at that forest stand
109
+ # that nothing is being done at that forest stand
111
110
  treatments = forest_metadata.schedule_dict[key]["0"]
112
111
  # print(e)
113
112
  treatments_dict[key] = {forest_metadata.years[0]: 0, forest_metadata.years[1]: 0, forest_metadata.years[2]: 0}
@@ -110,6 +110,7 @@ def test_refresh(client: TestClient):
110
110
  response_refresh = client.post("/refresh")
111
111
 
112
112
  assert "access_token" in response_refresh.json()
113
+ assert "access_token" in response_refresh.cookies
113
114
 
114
115
  assert response_good.json()["access_token"] != response_refresh.json()["access_token"]
115
116
 
@@ -649,7 +650,7 @@ def test_nimbus_save_and_delete_save(client: TestClient):
649
650
  assert len(solve_result.saved_solutions) > 0
650
651
 
651
652
  # 4. Delete save
652
- request: NIMBUSDeleteSaveRequest = NIMBUSDeleteSaveRequest(state_id=2, solution_index=1)
653
+ request: NIMBUSDeleteSaveRequest = NIMBUSDeleteSaveRequest(state_id=2, solution_index=1, problem_id=1)
653
654
  response = post_json(client, "/method/nimbus/delete_save", request.model_dump(), access_token)
654
655
  delete_save_result: NIMBUSDeleteSaveResponse = NIMBUSDeleteSaveResponse.model_validate(json.loads(response.content))
655
656
 
@@ -930,9 +931,9 @@ def test_preferred_solver(client: TestClient):
930
931
  response = post_json(client, "/method/nimbus/initialize", request.model_dump(), access_token)
931
932
  model = NIMBUSInitializationResponse.model_validate(response.json())
932
933
  except Exception as e:
933
- print(e)
934
- print("^ This outcome is expected since pyomo_cbc doesn't support nonlinear problems.")
935
- print(" As that solver is what we set it to be in the start, we can verify that they actually get used.")
934
+ print(e) # noqa: T201
935
+ print("^ This outcome is expected since pyomo_cbc doesn't support nonlinear problems.") # noqa: T201
936
+ print(" As that solver is what we set it to be in the start, we can verify that they actually get used.") # noqa: T201
936
937
 
937
938
 
938
939
  def test_get_available_solvers(client: TestClient):
@@ -1027,7 +1028,7 @@ def test_gdm_score_bands(client: TestClient):
1027
1028
  response = post_json(client=client, endpoint="/gdm/add_to_group", json=req, access_token=access_token)
1028
1029
  assert response.status_code == 200
1029
1030
 
1030
- access_token = login(client=client, username="dm", password="dm")
1031
+ access_token = login(client=client, username="dm", password="dm") # noqa: S106
1031
1032
 
1032
1033
  # Now we have a group, so let's get on with making stuff with gdm score bands.
1033
1034
  req = GDMScoreBandsInitializationRequest(
desdeo/emo/__init__.py CHANGED
@@ -42,6 +42,7 @@ from .options.generator import (
42
42
  RandomGeneratorOptions,
43
43
  RandomIntegerGeneratorOptions,
44
44
  RandomMixedIntegerGeneratorOptions,
45
+ SeededHybridGeneratorOptions,
45
46
  )
46
47
  from .options.mutation import (
47
48
  BinaryFlipMutationOptions,
@@ -131,6 +132,7 @@ generator = SimpleNamespace(
131
132
  RandomGeneratorOptions=RandomGeneratorOptions,
132
133
  RandomIntegerGeneratorOptions=RandomIntegerGeneratorOptions,
133
134
  RandomMixedIntegerGeneratorOptions=RandomMixedIntegerGeneratorOptions,
135
+ SeededHybridGeneratorOptions=SeededHybridGeneratorOptions,
134
136
  )
135
137
 
136
138
  templates = SimpleNamespace(
@@ -1 +1 @@
1
-
1
+ """Exports of the 'operators' module."""
@@ -383,7 +383,7 @@ class ArchiveGenerator(BaseGenerator):
383
383
  publisher: Publisher,
384
384
  verbosity: int,
385
385
  solutions: pl.DataFrame,
386
- **kwargs, # just to dump seed
386
+ **kwargs: dict, # just to dump seed
387
387
  ):
388
388
  """Initialize the ArchiveGenerator class.
389
389
 
@@ -395,10 +395,11 @@ class ArchiveGenerator(BaseGenerator):
395
395
  verbosity (int): The verbosity level of the generator. A verbosity of 2 is needed if you want to maintain
396
396
  an external archive. Otherwise, a verbosity of 1 is sufficient.
397
397
  solutions (pl.DataFrame): The decision variable vectors to use as the initial population.
398
+ kwargs (dict): Other keyword arguments to pass, e.g., a random seed.
398
399
  """
399
400
  super().__init__(problem, verbosity=verbosity, publisher=publisher)
400
401
  if not isinstance(solutions, pl.DataFrame):
401
- raise ValueError("The solutions must be a polars DataFrame.")
402
+ raise TypeError("The solutions must be a polars DataFrame.")
402
403
  if solutions.shape[0] == 0:
403
404
  raise ValueError("The solutions DataFrame is empty.")
404
405
  self.solutions = solutions
@@ -457,3 +458,153 @@ class ArchiveGenerator(BaseGenerator):
457
458
 
458
459
  def update(self, message) -> None:
459
460
  """Update the generator based on the message."""
461
+
462
+
463
+ class SeededHybridGenerator(BaseGenerator):
464
+ """Generates an initial population using a mix of seeded, perturbed, and random solutions."""
465
+
466
+ def __init__(
467
+ self,
468
+ problem,
469
+ evaluator,
470
+ publisher,
471
+ verbosity,
472
+ seed: int,
473
+ n_points: int,
474
+ seed_solution: pl.DataFrame,
475
+ perturb_fraction: float = 0.2,
476
+ sigma: float = 0.02,
477
+ flip_prob: float = 0.1,
478
+ ):
479
+ """Initialize the seeded hybrid generator.
480
+
481
+ The generator always includes the provided seed solution in the initial
482
+ population, fills a fraction of the population with small perturbations
483
+ around the seed, and fills the remainder with randomly generated solutions.
484
+
485
+ Args:
486
+ problem (Problem): The optimization problem.
487
+ evaluator (EMOEvaluator): Evaluator used to compute objectives and constraints.
488
+ publisher (Publisher): Publisher used for emitting generator messages.
489
+ verbosity (int): Verbosity level of the generator.
490
+ seed (int): Seed used for random number generation.
491
+ n_points (int): Total size of the initial population.
492
+ seed_solution (pl.DataFrame): A single-row DataFrame containing a seed
493
+ decision variable vector.
494
+ perturb_fraction (float, optional): Fraction of the population generated
495
+ by perturbing the seed solution. Defaults to 0.2.
496
+ sigma (float, optional): Relative perturbation scale with respect to
497
+ variable ranges. Defaults to 0.02.
498
+ flip_prob (float, optional): Probability of flipping a binary variable
499
+ when perturbing the seed. Defaults to 0.1.
500
+
501
+ Raises:
502
+ TypeError: If ``seed_solution`` is not a polars DataFrame.
503
+ ValueError: If ``seed_solution`` does not contain exactly one row.
504
+ ValueError: If ``seed_solution`` columns do not match problem variables.
505
+ ValueError: If ``n_points`` is not positive.
506
+ ValueError: If ``perturb_fraction`` is outside ``[0, 1]``.
507
+ ValueError: If ``sigma`` is negative.
508
+ ValueError: If ``flip_prob`` is outside ``[0, 1]``.
509
+ """
510
+ super().__init__(problem, verbosity=verbosity, publisher=publisher)
511
+
512
+ if not isinstance(seed_solution, pl.DataFrame):
513
+ raise TypeError("seed_solution must be a polars DataFrame.")
514
+ if seed_solution.shape[0] != 1:
515
+ raise ValueError("seed_solution must have exactly one row.")
516
+ if set(seed_solution.columns) != set(self.variable_symbols):
517
+ raise ValueError("seed_solution columns must match problem variables.")
518
+
519
+ if n_points <= 0:
520
+ raise ValueError("n_points must be > 0.")
521
+ if not (0.0 <= perturb_fraction <= 1.0):
522
+ raise ValueError("perturb_fraction must be in [0, 1].")
523
+ if sigma < 0:
524
+ raise ValueError("sigma must be >= 0.")
525
+ if not (0.0 <= flip_prob <= 1.0):
526
+ raise ValueError("flip_prob must be in [0, 1].")
527
+
528
+ self.n_points = n_points
529
+ self.seed_solution = seed_solution
530
+ self.perturb_fraction = perturb_fraction
531
+ self.sigma = sigma
532
+ self.flip_prob = flip_prob
533
+
534
+ self.evaluator = evaluator
535
+ self.seed = seed
536
+ self.rng = np.random.default_rng(self.seed)
537
+
538
+ self.population = None
539
+ self.out = None
540
+
541
+ def _random_population(self, n: int) -> pl.DataFrame:
542
+ tmp = {}
543
+ for var in self.problem.variables:
544
+ if var.variable_type in [VariableTypeEnum.binary, VariableTypeEnum.integer]:
545
+ vals = self.rng.integers(var.lowerbound, var.upperbound, size=n, endpoint=True).astype(float)
546
+ else:
547
+ vals = self.rng.uniform(var.lowerbound, var.upperbound, size=n).astype(float)
548
+ tmp[var.symbol] = vals
549
+ return pl.DataFrame(tmp)
550
+
551
+ def _perturb_seed(self, n: int) -> pl.DataFrame:
552
+ # includes the exact seed as first row
553
+ seed_row = self.seed_solution.select(self.variable_symbols).to_dict(as_series=False)
554
+ seed_vals = {k: float(v[0]) for k, v in seed_row.items()}
555
+
556
+ rows = [seed_vals] # ensure seed present
557
+ if n <= 1:
558
+ return pl.DataFrame(rows)
559
+
560
+ for _ in range(n - 1):
561
+ x = {}
562
+ for var in self.problem.variables:
563
+ lb, ub = float(var.lowerbound), float(var.upperbound)
564
+ r = ub - lb
565
+
566
+ v0 = seed_vals[var.symbol]
567
+
568
+ if var.variable_type == VariableTypeEnum.binary:
569
+ v = 1.0 - v0 if self.rng.random() < self.flip_prob else v0
570
+ elif var.variable_type == VariableTypeEnum.integer:
571
+ # scales integer nose
572
+ step = max(1, round(self.sigma * r)) if r >= 1 else 0
573
+ dv = self.rng.integers(-step, step + 1) if step > 0 else 0
574
+ v = float(int(np.clip(round(v0 + dv), lb, ub)))
575
+ else:
576
+ # continuous noise is proportional to range
577
+ dv = self.rng.normal(0.0, self.sigma * r if r > 0 else 0.0)
578
+ v = float(np.clip(v0 + dv, lb, ub))
579
+
580
+ x[var.symbol] = v
581
+ rows.append(x)
582
+
583
+ return pl.DataFrame(rows)
584
+
585
+ def do(self) -> tuple[pl.DataFrame, pl.DataFrame]:
586
+ """Generate a population.
587
+
588
+ Returns:
589
+ tuple[pl.DataFrame, pl.DataFrame]: the population.
590
+ """
591
+ if self.population is not None and self.out is not None:
592
+ self.notify()
593
+ return self.population, self.out
594
+
595
+ n_pert = max(1, round(self.perturb_fraction * self.n_points))
596
+ n_pert = min(n_pert, self.n_points)
597
+ n_rand = self.n_points - n_pert
598
+
599
+ pert = self._perturb_seed(n_pert)
600
+ rand = self._random_population(n_rand) if n_rand > 0 else pl.DataFrame({s: [] for s in self.variable_symbols})
601
+
602
+ self.population = pl.concat([pert, rand], how="vertical")
603
+
604
+ self.out = self.evaluator.evaluate(self.population)
605
+ self.notify()
606
+
607
+ return self.population, self.out
608
+
609
+ def update(self, message) -> None:
610
+ """Update the generator based on the message."""
@@ -1,3 +1,5 @@
1
+ """Exports of the 'options' module."""
2
+
1
3
  from .crossover import (
2
4
  BlendAlphaCrossoverOptions,
3
5
  BoundedExponentialCrossoverOptions,
@@ -17,6 +19,7 @@ from .generator import (
17
19
  RandomGeneratorOptions,
18
20
  RandomIntegerGeneratorOptions,
19
21
  RandomMixedIntegerGeneratorOptions,
22
+ SeededHybridGeneratorOptions,
20
23
  generator_constructor,
21
24
  )
22
25
  from .mutation import (
@@ -105,4 +108,5 @@ __all__ = [ # noqa: RUF022
105
108
  "selection_constructor",
106
109
  "RepairOptions",
107
110
  "repair_constructor",
111
+ "SeededHybridGeneratorOptions",
108
112
  ]
@@ -16,6 +16,7 @@ from desdeo.emo.operators.generator import (
16
16
  RandomGenerator,
17
17
  RandomIntegerGenerator,
18
18
  RandomMixedIntegerGenerator,
19
+ SeededHybridGenerator,
19
20
  )
20
21
 
21
22
  if TYPE_CHECKING:
@@ -85,6 +86,27 @@ class ArchiveGeneratorOptions(BaseModel):
85
86
  outputs: pl.DataFrame
86
87
  """The corresponding outputs of the initial solutions."""
87
88
 
89
+
90
+ class SeededHybridGeneratorOptions(BaseGeneratorOptions):
91
+ """Options for the seeded hybrid generator."""
92
+
93
+ name: Literal["SeededHybridGenerator"] = Field(default="SeededHybridGenerator", frozen=True)
94
+ model_config = {"arbitrary_types_allowed": True, "use_attribute_docstrings": True}
95
+
96
+ seed_solution: pl.DataFrame
97
+ """A dataframe with a single row representing the solution seed. The columns
98
+ must math the symbols of the variables in the problem being solved.
99
+ """
100
+ perturb_fraction: float = Field(default=0.2, ge=0.0, le=1.0)
101
+ """The desired fraction of perturbed vs random solutions in the generated population."""
102
+
103
+ sigma: float = Field(default=0.02, ge=0.0)
104
+ """The relative perturbation scale with respect to variable ranges."""
105
+
106
+ flip_prob: float = Field(default=0.1, ge=0.0, le=1.0)
107
+ """The flipping probability when perturbing binary variables."""
108
+
109
+
88
110
  GeneratorOptions = (
89
111
  LHSGeneratorOptions
90
112
  | RandomBinaryGeneratorOptions
@@ -92,6 +114,7 @@ GeneratorOptions = (
92
114
  | RandomIntegerGeneratorOptions
93
115
  | RandomMixedIntegerGeneratorOptions
94
116
  | ArchiveGeneratorOptions
117
+ | SeededHybridGeneratorOptions
95
118
  )
96
119
 
97
120
 
@@ -123,6 +146,7 @@ def generator_constructor(
123
146
  "RandomIntegerGenerator": RandomIntegerGenerator,
124
147
  "RandomMixedIntegerGenerator": RandomMixedIntegerGenerator,
125
148
  "ArchiveGenerator": ArchiveGenerator,
149
+ "SeededHybridGenerator": SeededHybridGenerator,
126
150
  }
127
151
  options: dict = options.model_dump()
128
152
  name = options.pop("name")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: desdeo
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: DESDEO is a modular and open source framework for interactive multiobjective optimization.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -40,7 +40,12 @@ Project-URL: Homepage, https://github.com/industrial-optimization-group/DESDEO
40
40
  Project-URL: Repository, https://github.com/industrial-optimization-group/DESDEO
41
41
  Description-Content-Type: text/markdown
42
42
 
43
- [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY) [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/) ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=master&label=Tests)
43
+ ![Latest release](https://img.shields.io/github/v/release/industrial-optimization-group/DESDEO?label=Latest%20release)
44
+ [![PyPI version](https://img.shields.io/pypi/v/desdeo?label=PyPI)](https://pypi.org/project/desdeo/)
45
+ [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/)
46
+ ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=master&label=Tests)
47
+ [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY)
48
+
44
49
 
45
50
  # DESDEO: the open-source software framework for interactive multiobjective optimization
46
51
  ## Introduction
@@ -73,13 +78,17 @@ decision-support using the framework. __The
73
78
  web-API is currently under heavy development, and is subject to changes.__
74
79
  3. The __web-GUI__ (WIP), which implements a web-based interface for utilizing
75
80
  the interactive methods and tools for modeling and solving multiobjective
76
- optimization problems. __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
81
+ optimization problems.
82
+
83
+ > __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
77
84
 
78
85
  For developing and experimenting with interactive multiobjective optimization
79
86
  methods on a "grass root" level, the __core-logic__ provides the necessary
80
- tools. For deploying interactive methods, the __web-API__ and the __web_GUI__
87
+ tools. For deploying interactive methods, the __web-API__ and the __web-GUI__
81
88
  play a central role.
82
89
 
90
+ > Users interested in using or developing the web-API and/or web-GUI are highly encouraged to express such intentions on our [Discord server](https://discord.gg/uGCEgQTJyY)!.
91
+
83
92
  DESDEO is an open-source project and everybody is welcome to contribute!
84
93
 
85
94
  ## Core-logic: key features
@@ -111,11 +120,12 @@ issue](https://github.com/industrial-optimization-group/DESDEO/issues/245).
111
120
 
112
121
  ## Web-GUI: key features
113
122
 
114
- DESDEO's web-GUI is currently in a planning stage. Once its active development
115
- starts, an issue will be created for documenting its development, as is
116
- currently the case with the web-API.
123
+ DESDEO's web-GUI is currently under active development. Once it stabilized, its
124
+ key features will be listed here. In the meantime, the interested user can
125
+ follow (and contribute!) the development progress of the web-API in [this
126
+ issue](https://github.com/industrial-optimization-group/DESDEO/issues/251).
117
127
 
118
- ## Installation instructions
128
+ ## Installation instructions (core-logic)
119
129
 
120
130
  DESDEO is available on PyPI to be installed via pip:
121
131
 
@@ -174,12 +184,12 @@ this repository's master branch is considered to be _DESDEO 2.0_.
174
184
 
175
185
  ## Funding
176
186
 
177
- Currently, DESDEO's development is partly funded by two projects granted by the
187
+ Currently, DESDEO's development has been funded by projects granted by the
178
188
  [Research Council of Finland](https://www.aka.fi/en/). The most recent ones
179
189
  include:
180
190
 
181
191
  - DESIDES (project 355346)
182
192
  - UTOPIA (project 352784)
183
193
  - DAEMON (project 322221)
184
-
194
+ - DESDEO (project 287496)
185
195
 
@@ -22,7 +22,7 @@ desdeo/api/models/gdm/gdm_score_bands.py,sha256=C2RMO8Q-kkaIlljBstqjkjY6kSzKLsA9
22
22
  desdeo/api/models/gdm/gnimbus.py,sha256=W0WulzY4qWi510lnBnTUrN-VFfkn4cES5pL1iHi_HwI,4709
23
23
  desdeo/api/models/generic.py,sha256=TxCtdNoR0lx5j2IBvItxhGiiSQz77orZRl1VmdHdQbQ,4345
24
24
  desdeo/api/models/generic_states.py,sha256=vBEwE7l2s1U7fr-xOaePfsRBrL0CMaZRIVF7Y1_mJiY,12848
25
- desdeo/api/models/nimbus.py,sha256=FCTApf4y0X4JiAZexerV_7c-uHnMe3PgWQsiBPsLpH8,6095
25
+ desdeo/api/models/nimbus.py,sha256=w5Ba1i_5NRFYLsOhZnEjXiAFFY-tHQa-apOewMAuUbY,6172
26
26
  desdeo/api/models/preference.py,sha256=BnsRR_JBEdJsz0C3aOpOtQ5FZU5cO4ZlzGAPTEe_nI8,4719
27
27
  desdeo/api/models/problem.py,sha256=wO5j4Ytjmo1FE-KSL3elO0oB-7UnCY_7lJLjublmA7Q,26474
28
28
  desdeo/api/models/reference_point_method.py,sha256=afEX6CKrgvrCh7yYBfEGTcKiB1cNDVEsJ6-KVB-T4-w,678
@@ -35,7 +35,7 @@ desdeo/api/routers/_NAUTILUS.py,sha256=rNrbWUjPGvslIpxybMi44vNCUMeewsVwNKcUwvBPw
35
35
  desdeo/api/routers/_NAUTILUS_navigator.py,sha256=64i9Fsa-P69K39S_3iGfN5BHlNRgeC6Ha2g6__MsECw,9802
36
36
  desdeo/api/routers/_NIMBUS.py,sha256=20IfUuKYc6SAmyLutmDPbPwJulnq-PyLLUYhFFqKz3o,28806
37
37
  desdeo/api/routers/__init__.py,sha256=hJXYK27BbnIR_ShlYnHJOzHid0ZXABkDL3rB1SVuUgI,111
38
- desdeo/api/routers/emo.py,sha256=_SGo7ZdyCJgPHYKTI2mwumz7IbH4OgidZwXHbfANPbo,18950
38
+ desdeo/api/routers/emo.py,sha256=2PAnNN_GrwqMf-VemFY0rUkMGz7ARwLaurL4eLY5vjo,17766
39
39
  desdeo/api/routers/enautilus.py,sha256=-wUH4PJl_-Ko0ivOCTcGPfxPDA2iUn3jJc9IESYZ-Y4,9157
40
40
  desdeo/api/routers/gdm/gdm_aggregate.py,sha256=QrT3FOCvJXGhDhlg22rqe3JeyRY3nHqJzTAGKAQR9oI,8956
41
41
  desdeo/api/routers/gdm/gdm_base.py,sha256=5nEab8qPoIeRcyI3DybS4OncdE1bViGDI7oBZifoSsA,14164
@@ -43,44 +43,44 @@ desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_manager.py,sha256=NLiZdRJ
43
43
  desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_routers.py,sha256=GYxjL3cpCgrqk-oRmC0wX61b9PB0mc0mE_0mVdpLZH4,15026
44
44
  desdeo/api/routers/gdm/gnimbus/gnimbus_manager.py,sha256=Nqk06HYVO6lM-g1hoihB_J6_Iw2oKAsF28xeTxRtj_4,26854
45
45
  desdeo/api/routers/gdm/gnimbus/gnimbus_routers.py,sha256=vObjUUemINEp5Brk1CPDCOYp4Hzrz2XbNYu_rPw9LNo,22913
46
- desdeo/api/routers/generic.py,sha256=zHV_2jJ7oukoCjGLvt-A6P6W9g79UlUFlPk9YCSI7xY,8943
47
- desdeo/api/routers/nimbus.py,sha256=iHq4QXDy33dt0VIz1iVQpiezWcax_KSZwNR9OmdTZYw,27031
48
- desdeo/api/routers/problem.py,sha256=U5WET-vc9qhRA1mXCqePFHlDefi0BW7IbsW6vr_dCMg,10598
49
- desdeo/api/routers/reference_point_method.py,sha256=atmIXNFt5WyVMptbeOf_EuN2jFLb6LT2uja8YjQEQow,2931
50
- desdeo/api/routers/session.py,sha256=96fNmBp5UGfKXPdnOuGtZkcm7rrkQoBXPoO_m0VQgTA,3046
46
+ desdeo/api/routers/generic.py,sha256=MhCizImj9ukVqUEbd3K1dr-4Da41eApQzJ0R_uM85W8,7569
47
+ desdeo/api/routers/nimbus.py,sha256=Ex6igiEKO6-mYuoxhrK_B2q1aXjbYKCgadN_n1YeCwE,21216
48
+ desdeo/api/routers/problem.py,sha256=OvhNkKwSpGY3oyhTetiBaFreHx87dtOXZPSqSb96Bqw,10606
49
+ desdeo/api/routers/reference_point_method.py,sha256=pugEPSERTlGzwP66aGgYRFHnakP9bxUc7usD17VoTfw,2771
50
+ desdeo/api/routers/session.py,sha256=H6G1PtK5KIVpEvhpz0-RdIma5TN-S7Bedv_zu7E7WHs,3164
51
51
  desdeo/api/routers/test.py,sha256=gvULBP3DvCaMwnnNQDaXSCxrav0IR5awQrsAoEn3dh0,434
52
- desdeo/api/routers/user_authentication.py,sha256=BSh8pEfmEml8mpGHs34pgNCj1gSAesY5nA9UmCc0Pn8,16958
53
- desdeo/api/routers/utils.py,sha256=ZTtOqDEo15sqq9zqyTneZmtmvL1U7n6jxR85IaEL_6w,7672
54
- desdeo/api/routers/utopia.py,sha256=RKDAbqLALTIEMwMDFelxV9cka5QwkzXRMP0krzwSQE4,8455
52
+ desdeo/api/routers/user_authentication.py,sha256=LGcL-0SfT_BZveqIA4_u59LxUF7Ol7lQE5CSvHHPLLg,17730
53
+ desdeo/api/routers/utils.py,sha256=O3fi4Yj0fYM92uUmUUgA8tqG5omF9SvxGSiBTO3gWbI,7745
54
+ desdeo/api/routers/utopia.py,sha256=MWxoKNd5ah6X6W46BAQJNJt8tXFnrjy_vR52IQDJ6gs,8352
55
55
  desdeo/api/schema.py,sha256=nIxVGlsUt5cvpk3FdeppfwBWVdB7OJDvb_jzjVwMm-I,2623
56
56
  desdeo/api/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  desdeo/api/tests/conftest.py,sha256=gcjhWYcvBW1VpyAWCf-VyDW_VXbhYdeC18-lvsc5Y1U,4887
58
58
  desdeo/api/tests/test_enautilus.py,sha256=Sc0ycVe_ckPmQI_SxiJUaIOQEtHohwBpb28btB9NeMA,15267
59
59
  desdeo/api/tests/test_models.py,sha256=yNvemg43TmcAVHglB-CyhApCbOT1-DFYkQdH7q2efx8,37393
60
- desdeo/api/tests/test_routes.py,sha256=4iaW6LjNIOzebTLV1e68q01JS7lO5iYgcjDsRZHetLU,40829
60
+ desdeo/api/tests/test_routes.py,sha256=ytYbO3yVzWe4NclQRLh1mcCelQJNdEBo0PjdnBInxRo,40953
61
61
  desdeo/api/utils/_database.py,sha256=qJAdjCWmZpT8x7Sdnet9rWakXaFmBzQW0yNTZfSzsJE,7966
62
62
  desdeo/api/utils/_logger.py,sha256=Zo163Zi9ZJc8hJEeMDzI7pGSeiJtRf79wRSidtK0ZXI,668
63
63
  desdeo/api/utils/database.py,sha256=iQPHsa5HvJ0hSAi4980-tRV6PTbz9S54JIFeCIzHwaM,1162
64
64
  desdeo/api/utils/emo_database.py,sha256=XKmS-O3bnK9q6OQ6klxVkhWbKnY0fku9dJe5X-RRLQ8,1316
65
65
  desdeo/core.py,sha256=MruvDrZQhBarLi7x1UBPyaQ7WA_nZ5Gb6BPfSfCxBjI,1258
66
- desdeo/emo/__init__.py,sha256=_M8RIOfDI8udx_uVLQ0nmXGiasiAsVMClaRm9DIJrvc,5221
66
+ desdeo/emo/__init__.py,sha256=BDCx_9gmglohRZdoQWFXrvWG_Pvpc-98y433404MV7k,5318
67
67
  desdeo/emo/hooks/archivers.py,sha256=PZxAsuISikrnlESU0NlFdeZiOblvbNWxivrfmAaT1nI,7055
68
68
  desdeo/emo/methods/EAs.py,sha256=2Wd-_QzCSWMX7coxFxo1gEVmL0PfmpuWT2XLlPQgj4g,23003
69
69
  desdeo/emo/methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  desdeo/emo/methods/bases.py,sha256=d506vIEwOhRtEXZ1Ali7Y0WB2_ASfHfSGm_Tv4KPDGg,341
71
71
  desdeo/emo/methods/templates.py,sha256=KjUcnVs_-PGde_9GH6f9cpWdw3-3JNRoQenvdYBkWg4,5068
72
- desdeo/emo/operators/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
72
+ desdeo/emo/operators/__init__.py,sha256=EZ6wdIr2Wbs3e_oKgwYKIYqxGnGVXjojXFAI8tP3W-A,41
73
73
  desdeo/emo/operators/crossover.py,sha256=6kXxtQxscpLHistgJzVMtg8mrI27YL9jcEZMD0vob68,49488
74
74
  desdeo/emo/operators/evaluator.py,sha256=0WZbw48k9fY8AgIA7F7SgIJXThyNj4qKVwk3uv8-mGk,4074
75
- desdeo/emo/operators/generator.py,sha256=MEKgzjSvdR8snKtoTZwvEEf0t2X0ayzsbmLn0Zma5zk,19070
75
+ desdeo/emo/operators/generator.py,sha256=kfN0VX6VcEA5nA5YHwm2svynXUw8lv0CJkCqX6vXW4A,25415
76
76
  desdeo/emo/operators/mutation.py,sha256=SSn2h9CKm2B34A0tNTTuJnCRCVLVyYKiDCRmSi8cqEs,47817
77
77
  desdeo/emo/operators/scalar_selection.py,sha256=-li-AsjTtSDv6S-Q6epjKJ9ocsotgTZV3f_q_c-Z-wA,8774
78
78
  desdeo/emo/operators/selection.py,sha256=sE1PJqkBh_Z6cdg4zNbDvXRLHxHhqBcvB0s4P4GmRG0,77468
79
79
  desdeo/emo/operators/termination.py,sha256=zaAAmQZB-X6L5x8YRWLg7Yt11XxshQfHaBirlXCOKPw,11263
80
- desdeo/emo/options/__init__.py,sha256=bGoKZTdq-FCC4yV5iDzBH-yNpdjQ9kn-WcD0jeNVik8,3172
80
+ desdeo/emo/options/__init__.py,sha256=IyDE-6a8W7Mi7Rj-aKdAkagZwbsSFZxxH2rh9g5_IiY,3282
81
81
  desdeo/emo/options/algorithms.py,sha256=k88OHAxbsXKUjY1GcX8N6MbLxuQLlmFB2ttAELVqI5w,16756
82
82
  desdeo/emo/options/crossover.py,sha256=ahvuuRPQ0XStI3IUrZX0qKEH13CFsdxA7g8Nk8atwOY,6365
83
- desdeo/emo/options/generator.py,sha256=MaAyGWQfAxhoCtRSBXFYjiexMWxOuEyXyIlOxcYSUIE,4234
83
+ desdeo/emo/options/generator.py,sha256=dg1JIvr801S_D_ZBjoXGkjps43P0ILsmcGWI_3cHkuA,5252
84
84
  desdeo/emo/options/mutation.py,sha256=htBOSULDJ8TlUv5KoXwu1wb-9eTP-g_-d1ahR84bZlY,8854
85
85
  desdeo/emo/options/repair.py,sha256=azC-_IpQQWD8SUEFpe6NKSwp8a8DZkBv0YcQw-TZBoA,2178
86
86
  desdeo/emo/options/scalar_selection.py,sha256=9r9oEgTrf7-jfVyf16iuNAfwdaSV3S4N-ix5d2o6Snk,2462
@@ -174,7 +174,7 @@ desdeo/utopia_stuff/utopia_db_init.py,sha256=BlvJNxZE5Pgtr_aEUNBuCjPONi19FT4-73k
174
174
  desdeo/utopia_stuff/utopia_problem.py,sha256=ZIoYDqvlspfcK0IFBZ3XgBB5qCB0BSSYRU5KmOwWZEM,15190
175
175
  desdeo/utopia_stuff/utopia_problem_old.py,sha256=G-Qtrmg7Uip2M0QEEXKbIHlCBcM4WfWDvM1Rut5LzMU,16201
176
176
  desdeo/utopia_stuff/utopia_reference_solutions.py,sha256=uU1FTOATg9Mx19ENidoSJF0hAzWvud4zCzR54qW_GO4,2536
177
- desdeo-2.1.1.dist-info/METADATA,sha256=hqstpdAnUsV4Ad6PyM8baCwlbR3Wy2tQsiciPLJt6ao,8710
178
- desdeo-2.1.1.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
179
- desdeo-2.1.1.dist-info/licenses/LICENSE,sha256=OWc9n9JaYCMc9dTTdOUv042049jOjm1cmQyJ0nkRbJk,1129
180
- desdeo-2.1.1.dist-info/RECORD,,
177
+ desdeo-2.2.0.dist-info/METADATA,sha256=D2rhb3RWPTFobyc-rdqWff4K9ARDSCwxauaHBCt9j60,9261
178
+ desdeo-2.2.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
179
+ desdeo-2.2.0.dist-info/licenses/LICENSE,sha256=OWc9n9JaYCMc9dTTdOUv042049jOjm1cmQyJ0nkRbJk,1129
180
+ desdeo-2.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.3.0
2
+ Generator: poetry-core 2.3.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any