cbrkit 0.26.4__tar.gz → 0.26.5__tar.gz
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.
- {cbrkit-0.26.4 → cbrkit-0.26.5}/PKG-INFO +1 -1
- {cbrkit-0.26.4 → cbrkit-0.26.5}/pyproject.toml +1 -1
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/eval/common.py +1 -1
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/eval/retrieval.py +2 -4
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/helpers.py +26 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/astar.py +8 -44
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/common.py +42 -5
- {cbrkit-0.26.4 → cbrkit-0.26.5}/README.md +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/__main__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/adapt/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/adapt/attribute_value.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/adapt/generic.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/adapt/numbers.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/adapt/strings.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/api.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/cli.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/constants.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/cycle.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/dumpers.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/eval/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/loaders.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/model/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/model/graph.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/model/result.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/py.typed +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/retrieval/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/retrieval/apply.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/retrieval/build.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/retrieval/rerank.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/reuse/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/reuse/apply.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/reuse/build.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/aggregator.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/attribute_value.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/collections.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/embed.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/generic.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/alignment.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/brute_force.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/dfs.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/greedy.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/lap.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/precompute.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/qap.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/graphs/vf2.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/numbers.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/strings.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/taxonomy.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/sim/wrappers.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/apply.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/build.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/model.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/prompts.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/__init__.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/anthropic.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/cohere.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/google.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/instructor.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/model.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/ollama.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/openai.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/synthesis/providers/wrappers.py +0 -0
- {cbrkit-0.26.4 → cbrkit-0.26.5}/src/cbrkit/typing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: cbrkit
|
|
3
|
-
Version: 0.26.
|
|
3
|
+
Version: 0.26.5
|
|
4
4
|
Summary: Customizable Case-Based Reasoning (CBR) toolkit for Python with a built-in API and CLI
|
|
5
5
|
Keywords: cbr,case-based reasoning,api,similarity,nlp,retrieval,cli,tool,library
|
|
6
6
|
Author: Mirko Lenz
|
|
@@ -244,7 +244,7 @@ def kendall_tau(
|
|
|
244
244
|
qrel_relevant = {k for k, v in qrels[key].items() if v >= relevance_level}
|
|
245
245
|
sorted_qrel_relevant = sorted(qrel_relevant, key=lambda x: qrels[key][x])
|
|
246
246
|
|
|
247
|
-
sorted_run = sorted(run.keys(), key=lambda x: run[key][x], reverse=True)
|
|
247
|
+
sorted_run = sorted(run[key].keys(), key=lambda x: run[key][x], reverse=True)
|
|
248
248
|
run_k = sorted_run[: k if k > 0 else len(sorted_run)]
|
|
249
249
|
|
|
250
250
|
max_idx = min(len(run_k), len(sorted_qrel_relevant))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
2
|
from typing import Any, Literal
|
|
3
3
|
|
|
4
|
-
from ..helpers import
|
|
4
|
+
from ..helpers import normalize_and_scale, round, unpack_float
|
|
5
5
|
from ..retrieval import Result, ResultStep
|
|
6
6
|
from ..typing import EvalMetricFunc, Float, QueryCaseMatrix
|
|
7
7
|
from .common import DEFAULT_METRICS, compute
|
|
@@ -65,12 +65,10 @@ def retrieval_step_to_qrels[Q, C, S: Float](
|
|
|
65
65
|
min_sim = 0.0
|
|
66
66
|
max_sim = 1.0
|
|
67
67
|
|
|
68
|
-
qrel_factor = max_qrel - min_qrel
|
|
69
|
-
|
|
70
68
|
return {
|
|
71
69
|
query: {
|
|
72
70
|
case: round(
|
|
73
|
-
|
|
71
|
+
normalize_and_scale(sim, min_sim, max_sim, min_qrel, max_qrel),
|
|
74
72
|
round_mode,
|
|
75
73
|
)
|
|
76
74
|
for case, sim in entry.items()
|
|
@@ -71,6 +71,8 @@ __all__ = [
|
|
|
71
71
|
"load_callables_map",
|
|
72
72
|
"load_callables",
|
|
73
73
|
"load_object",
|
|
74
|
+
"normalize",
|
|
75
|
+
"normalize_and_scale",
|
|
74
76
|
"log_batch",
|
|
75
77
|
"mp_count",
|
|
76
78
|
"mp_map",
|
|
@@ -605,6 +607,30 @@ def scale(value: float, lower: float, upper: float) -> float:
|
|
|
605
607
|
return value * (upper - lower) + lower
|
|
606
608
|
|
|
607
609
|
|
|
610
|
+
def normalize(value: float, value_min: float, value_max: float) -> float:
|
|
611
|
+
"""Normalize a value from [value_min, value_max] to [0, 1]."""
|
|
612
|
+
if value_max == value_min:
|
|
613
|
+
# Handle edge case where all values are identical
|
|
614
|
+
return 0.0
|
|
615
|
+
|
|
616
|
+
return (value - value_min) / (value_max - value_min)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
def normalize_and_scale(
|
|
620
|
+
value: float,
|
|
621
|
+
value_min: float,
|
|
622
|
+
value_max: float,
|
|
623
|
+
target_min: float,
|
|
624
|
+
target_max: float,
|
|
625
|
+
) -> float:
|
|
626
|
+
"""Normalize a value from [value_min, value_max] to [target_min, target_max]."""
|
|
627
|
+
# First normalize to [0, 1]
|
|
628
|
+
normalized = normalize(value, value_min, value_max)
|
|
629
|
+
|
|
630
|
+
# Then scale to target range
|
|
631
|
+
return scale(normalized, target_min, target_max)
|
|
632
|
+
|
|
633
|
+
|
|
608
634
|
def load_object(import_name: str) -> Any:
|
|
609
635
|
"""Import an object based on a string.
|
|
610
636
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import heapq
|
|
2
|
-
from collections.abc import
|
|
2
|
+
from collections.abc import Mapping
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Protocol
|
|
5
5
|
|
|
6
6
|
from ...helpers import (
|
|
7
7
|
get_logger,
|
|
@@ -13,11 +13,7 @@ from ...model.graph import (
|
|
|
13
13
|
Node,
|
|
14
14
|
)
|
|
15
15
|
from ...typing import SimFunc
|
|
16
|
-
from .common import
|
|
17
|
-
GraphSim,
|
|
18
|
-
SearchGraphSimFunc,
|
|
19
|
-
SearchState,
|
|
20
|
-
)
|
|
16
|
+
from .common import GraphSim, SearchGraphSimFunc, SearchState, next_elem, sorted_iter
|
|
21
17
|
|
|
22
18
|
__all__ = [
|
|
23
19
|
"HeuristicFunc",
|
|
@@ -34,33 +30,6 @@ __all__ = [
|
|
|
34
30
|
logger = get_logger(__name__)
|
|
35
31
|
|
|
36
32
|
|
|
37
|
-
def next_elem[K](elements: Collection[K]) -> K:
|
|
38
|
-
"""Select the next element from a set deterministically.
|
|
39
|
-
|
|
40
|
-
If elements are sortable, returns the smallest one.
|
|
41
|
-
Otherwise, returns the first element from iteration.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
elements: Set of elements to choose from
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
A single element from the set
|
|
48
|
-
|
|
49
|
-
Raises:
|
|
50
|
-
ValueError: If the set is empty
|
|
51
|
-
"""
|
|
52
|
-
if not elements:
|
|
53
|
-
raise ValueError("Cannot select from empty set")
|
|
54
|
-
|
|
55
|
-
if len(elements) == 1:
|
|
56
|
-
return next(iter(elements))
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
return min(cast(Collection[Any], elements))
|
|
60
|
-
except TypeError:
|
|
61
|
-
return next(iter(elements))
|
|
62
|
-
|
|
63
|
-
|
|
64
33
|
@dataclass(slots=True, frozen=True, order=True)
|
|
65
34
|
class PriorityState[K]:
|
|
66
35
|
priority: float
|
|
@@ -207,7 +176,7 @@ class select2[K, N, E, G](SelectionFunc[K, N, E, G]):
|
|
|
207
176
|
|
|
208
177
|
edge_candidates = {
|
|
209
178
|
key
|
|
210
|
-
for key in s.open_y_edges
|
|
179
|
+
for key in sorted_iter(s.open_y_edges)
|
|
211
180
|
if y.edges[key].source.key not in s.open_y_nodes
|
|
212
181
|
and y.edges[key].target.key not in s.open_y_nodes
|
|
213
182
|
}
|
|
@@ -290,15 +259,10 @@ class select3[K, N, E, G](SelectionFunc[K, N, E, G]):
|
|
|
290
259
|
}
|
|
291
260
|
|
|
292
261
|
# select the one with the lowest key
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
)
|
|
298
|
-
except TypeError:
|
|
299
|
-
best_selection = next(iter(best_selections))
|
|
300
|
-
|
|
301
|
-
selection_key, selection_type = best_selection
|
|
262
|
+
selection_key, selection_type = next_elem(
|
|
263
|
+
best_selections,
|
|
264
|
+
key=lambda item: item[0],
|
|
265
|
+
)
|
|
302
266
|
|
|
303
267
|
if selection_type == "edge":
|
|
304
268
|
edge = y.edges[selection_key]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from collections.abc import Mapping, Sequence
|
|
3
|
+
from collections.abc import Callable, Collection, Iterable, Mapping, Sequence
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from typing import Any, Protocol, cast
|
|
6
6
|
|
|
@@ -247,6 +247,44 @@ class SearchState[K]:
|
|
|
247
247
|
open_x_edges: frozenset[K]
|
|
248
248
|
|
|
249
249
|
|
|
250
|
+
def sorted_iter[K](iterable: Iterable[K]) -> Iterable[K]:
|
|
251
|
+
"""Sort an iterable if possible, otherwise return it unchanged."""
|
|
252
|
+
try:
|
|
253
|
+
return sorted(cast(Iterable[Any], iterable))
|
|
254
|
+
except TypeError:
|
|
255
|
+
return iterable
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def next_elem[K](
|
|
259
|
+
elements: Collection[K],
|
|
260
|
+
key: Callable[[K], Any] | None = None,
|
|
261
|
+
) -> K:
|
|
262
|
+
"""Select the next element from a set deterministically.
|
|
263
|
+
|
|
264
|
+
If elements are sortable, returns the smallest one.
|
|
265
|
+
Otherwise, returns the first element from iteration.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
elements: Set of elements to choose from
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
A single element from the set
|
|
272
|
+
|
|
273
|
+
Raises:
|
|
274
|
+
ValueError: If the set is empty
|
|
275
|
+
"""
|
|
276
|
+
if not elements:
|
|
277
|
+
raise ValueError("Cannot select from empty set")
|
|
278
|
+
|
|
279
|
+
if len(elements) == 1:
|
|
280
|
+
return next(iter(elements))
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
return min(cast(Iterable[Any], elements), key=key)
|
|
284
|
+
except TypeError:
|
|
285
|
+
return next(iter(elements))
|
|
286
|
+
|
|
287
|
+
|
|
250
288
|
class SearchStateInit[K, N, E, G](Protocol):
|
|
251
289
|
def __call__(
|
|
252
290
|
self,
|
|
@@ -413,7 +451,7 @@ class SearchGraphSimFunc[K, N, E, G](BaseGraphSimFunc[K, N, E, G]):
|
|
|
413
451
|
state.open_x_nodes - {x_key},
|
|
414
452
|
state.open_x_edges,
|
|
415
453
|
)
|
|
416
|
-
for x_key in state.open_x_nodes
|
|
454
|
+
for x_key in sorted_iter(state.open_x_nodes)
|
|
417
455
|
if self.legal_node_mapping(x, y, state, x_key, y_key)
|
|
418
456
|
]
|
|
419
457
|
|
|
@@ -447,7 +485,7 @@ class SearchGraphSimFunc[K, N, E, G](BaseGraphSimFunc[K, N, E, G]):
|
|
|
447
485
|
state.open_x_nodes,
|
|
448
486
|
state.open_x_edges - {x_key},
|
|
449
487
|
)
|
|
450
|
-
for x_key in state.open_x_edges
|
|
488
|
+
for x_key in sorted_iter(state.open_x_edges)
|
|
451
489
|
if self.legal_edge_mapping(x, y, state, x_key, y_key)
|
|
452
490
|
]
|
|
453
491
|
|
|
@@ -473,10 +511,9 @@ class SearchGraphSimFunc[K, N, E, G](BaseGraphSimFunc[K, N, E, G]):
|
|
|
473
511
|
y_key: K,
|
|
474
512
|
) -> list[SearchState[K]]:
|
|
475
513
|
"""Expand a given edge and map its source/target node if not already mapped"""
|
|
476
|
-
|
|
477
514
|
next_states: list[SearchState[K]] = []
|
|
478
515
|
|
|
479
|
-
for x_key in state.open_x_edges:
|
|
516
|
+
for x_key in sorted_iter(state.open_x_edges):
|
|
480
517
|
next_state = state
|
|
481
518
|
x_source_key = x.edges[x_key].source.key
|
|
482
519
|
x_target_key = x.edges[x_key].target.key
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|