bead 0.1.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.
- bead/__init__.py +11 -0
- bead/__main__.py +11 -0
- bead/active_learning/__init__.py +15 -0
- bead/active_learning/config.py +231 -0
- bead/active_learning/loop.py +566 -0
- bead/active_learning/models/__init__.py +24 -0
- bead/active_learning/models/base.py +852 -0
- bead/active_learning/models/binary.py +910 -0
- bead/active_learning/models/categorical.py +943 -0
- bead/active_learning/models/cloze.py +862 -0
- bead/active_learning/models/forced_choice.py +956 -0
- bead/active_learning/models/free_text.py +773 -0
- bead/active_learning/models/lora.py +365 -0
- bead/active_learning/models/magnitude.py +835 -0
- bead/active_learning/models/multi_select.py +795 -0
- bead/active_learning/models/ordinal_scale.py +811 -0
- bead/active_learning/models/peft_adapter.py +155 -0
- bead/active_learning/models/random_effects.py +639 -0
- bead/active_learning/selection.py +354 -0
- bead/active_learning/strategies.py +391 -0
- bead/active_learning/trainers/__init__.py +26 -0
- bead/active_learning/trainers/base.py +210 -0
- bead/active_learning/trainers/data_collator.py +172 -0
- bead/active_learning/trainers/dataset_utils.py +261 -0
- bead/active_learning/trainers/huggingface.py +304 -0
- bead/active_learning/trainers/lightning.py +324 -0
- bead/active_learning/trainers/metrics.py +424 -0
- bead/active_learning/trainers/mixed_effects.py +551 -0
- bead/active_learning/trainers/model_wrapper.py +509 -0
- bead/active_learning/trainers/registry.py +104 -0
- bead/adapters/__init__.py +11 -0
- bead/adapters/huggingface.py +61 -0
- bead/behavioral/__init__.py +116 -0
- bead/behavioral/analytics.py +646 -0
- bead/behavioral/extraction.py +343 -0
- bead/behavioral/merging.py +343 -0
- bead/cli/__init__.py +11 -0
- bead/cli/active_learning.py +513 -0
- bead/cli/active_learning_commands.py +779 -0
- bead/cli/completion.py +359 -0
- bead/cli/config.py +624 -0
- bead/cli/constraint_builders.py +286 -0
- bead/cli/deployment.py +859 -0
- bead/cli/deployment_trials.py +493 -0
- bead/cli/deployment_ui.py +332 -0
- bead/cli/display.py +378 -0
- bead/cli/items.py +960 -0
- bead/cli/items_factories.py +776 -0
- bead/cli/list_constraints.py +714 -0
- bead/cli/lists.py +490 -0
- bead/cli/main.py +430 -0
- bead/cli/models.py +877 -0
- bead/cli/resource_loaders.py +621 -0
- bead/cli/resources.py +1036 -0
- bead/cli/shell.py +356 -0
- bead/cli/simulate.py +840 -0
- bead/cli/templates.py +1158 -0
- bead/cli/training.py +1080 -0
- bead/cli/utils.py +614 -0
- bead/cli/workflow.py +1273 -0
- bead/config/__init__.py +68 -0
- bead/config/active_learning.py +1009 -0
- bead/config/config.py +192 -0
- bead/config/defaults.py +118 -0
- bead/config/deployment.py +217 -0
- bead/config/env.py +147 -0
- bead/config/item.py +45 -0
- bead/config/list.py +193 -0
- bead/config/loader.py +149 -0
- bead/config/logging.py +42 -0
- bead/config/model.py +49 -0
- bead/config/paths.py +46 -0
- bead/config/profiles.py +320 -0
- bead/config/resources.py +47 -0
- bead/config/serialization.py +210 -0
- bead/config/simulation.py +206 -0
- bead/config/template.py +238 -0
- bead/config/validation.py +267 -0
- bead/data/__init__.py +65 -0
- bead/data/base.py +87 -0
- bead/data/identifiers.py +97 -0
- bead/data/language_codes.py +61 -0
- bead/data/metadata.py +270 -0
- bead/data/range.py +123 -0
- bead/data/repository.py +358 -0
- bead/data/serialization.py +249 -0
- bead/data/timestamps.py +89 -0
- bead/data/validation.py +349 -0
- bead/data_collection/__init__.py +11 -0
- bead/data_collection/jatos.py +223 -0
- bead/data_collection/merger.py +154 -0
- bead/data_collection/prolific.py +198 -0
- bead/deployment/__init__.py +5 -0
- bead/deployment/distribution.py +402 -0
- bead/deployment/jatos/__init__.py +1 -0
- bead/deployment/jatos/api.py +200 -0
- bead/deployment/jatos/exporter.py +210 -0
- bead/deployment/jspsych/__init__.py +9 -0
- bead/deployment/jspsych/biome.json +44 -0
- bead/deployment/jspsych/config.py +411 -0
- bead/deployment/jspsych/generator.py +598 -0
- bead/deployment/jspsych/package.json +51 -0
- bead/deployment/jspsych/pnpm-lock.yaml +2141 -0
- bead/deployment/jspsych/randomizer.py +299 -0
- bead/deployment/jspsych/src/lib/list-distributor.test.ts +327 -0
- bead/deployment/jspsych/src/lib/list-distributor.ts +1282 -0
- bead/deployment/jspsych/src/lib/randomizer.test.ts +232 -0
- bead/deployment/jspsych/src/lib/randomizer.ts +367 -0
- bead/deployment/jspsych/src/plugins/cloze-dropdown.ts +252 -0
- bead/deployment/jspsych/src/plugins/forced-choice.ts +265 -0
- bead/deployment/jspsych/src/plugins/plugins.test.ts +141 -0
- bead/deployment/jspsych/src/plugins/rating.ts +248 -0
- bead/deployment/jspsych/src/slopit/index.ts +9 -0
- bead/deployment/jspsych/src/types/jatos.d.ts +256 -0
- bead/deployment/jspsych/src/types/jspsych.d.ts +228 -0
- bead/deployment/jspsych/templates/experiment.css +1 -0
- bead/deployment/jspsych/templates/experiment.js.template +289 -0
- bead/deployment/jspsych/templates/index.html +51 -0
- bead/deployment/jspsych/templates/randomizer.js +241 -0
- bead/deployment/jspsych/templates/randomizer.js.template +313 -0
- bead/deployment/jspsych/trials.py +723 -0
- bead/deployment/jspsych/tsconfig.json +23 -0
- bead/deployment/jspsych/tsup.config.ts +30 -0
- bead/deployment/jspsych/ui/__init__.py +1 -0
- bead/deployment/jspsych/ui/components.py +383 -0
- bead/deployment/jspsych/ui/styles.py +411 -0
- bead/dsl/__init__.py +80 -0
- bead/dsl/ast.py +168 -0
- bead/dsl/context.py +178 -0
- bead/dsl/errors.py +71 -0
- bead/dsl/evaluator.py +570 -0
- bead/dsl/grammar.lark +81 -0
- bead/dsl/parser.py +231 -0
- bead/dsl/stdlib.py +929 -0
- bead/evaluation/__init__.py +13 -0
- bead/evaluation/convergence.py +485 -0
- bead/evaluation/interannotator.py +398 -0
- bead/items/__init__.py +40 -0
- bead/items/adapters/__init__.py +70 -0
- bead/items/adapters/anthropic.py +224 -0
- bead/items/adapters/api_utils.py +167 -0
- bead/items/adapters/base.py +216 -0
- bead/items/adapters/google.py +259 -0
- bead/items/adapters/huggingface.py +1074 -0
- bead/items/adapters/openai.py +323 -0
- bead/items/adapters/registry.py +202 -0
- bead/items/adapters/sentence_transformers.py +224 -0
- bead/items/adapters/togetherai.py +309 -0
- bead/items/binary.py +515 -0
- bead/items/cache.py +558 -0
- bead/items/categorical.py +593 -0
- bead/items/cloze.py +757 -0
- bead/items/constructor.py +784 -0
- bead/items/forced_choice.py +413 -0
- bead/items/free_text.py +681 -0
- bead/items/generation.py +432 -0
- bead/items/item.py +396 -0
- bead/items/item_template.py +787 -0
- bead/items/magnitude.py +573 -0
- bead/items/multi_select.py +621 -0
- bead/items/ordinal_scale.py +569 -0
- bead/items/scoring.py +448 -0
- bead/items/validation.py +723 -0
- bead/lists/__init__.py +30 -0
- bead/lists/balancer.py +263 -0
- bead/lists/constraints.py +1067 -0
- bead/lists/experiment_list.py +286 -0
- bead/lists/list_collection.py +378 -0
- bead/lists/partitioner.py +1141 -0
- bead/lists/stratification.py +254 -0
- bead/participants/__init__.py +73 -0
- bead/participants/collection.py +699 -0
- bead/participants/merging.py +312 -0
- bead/participants/metadata_spec.py +491 -0
- bead/participants/models.py +276 -0
- bead/resources/__init__.py +29 -0
- bead/resources/adapters/__init__.py +19 -0
- bead/resources/adapters/base.py +104 -0
- bead/resources/adapters/cache.py +128 -0
- bead/resources/adapters/glazing.py +508 -0
- bead/resources/adapters/registry.py +117 -0
- bead/resources/adapters/unimorph.py +796 -0
- bead/resources/classification.py +856 -0
- bead/resources/constraint_builders.py +329 -0
- bead/resources/constraints.py +165 -0
- bead/resources/lexical_item.py +223 -0
- bead/resources/lexicon.py +744 -0
- bead/resources/loaders.py +209 -0
- bead/resources/template.py +441 -0
- bead/resources/template_collection.py +707 -0
- bead/resources/template_generation.py +349 -0
- bead/simulation/__init__.py +29 -0
- bead/simulation/annotators/__init__.py +15 -0
- bead/simulation/annotators/base.py +175 -0
- bead/simulation/annotators/distance_based.py +135 -0
- bead/simulation/annotators/lm_based.py +114 -0
- bead/simulation/annotators/oracle.py +182 -0
- bead/simulation/annotators/random.py +181 -0
- bead/simulation/dsl_extension/__init__.py +3 -0
- bead/simulation/noise_models/__init__.py +13 -0
- bead/simulation/noise_models/base.py +42 -0
- bead/simulation/noise_models/random_noise.py +82 -0
- bead/simulation/noise_models/systematic.py +132 -0
- bead/simulation/noise_models/temperature.py +86 -0
- bead/simulation/runner.py +144 -0
- bead/simulation/strategies/__init__.py +23 -0
- bead/simulation/strategies/base.py +123 -0
- bead/simulation/strategies/binary.py +103 -0
- bead/simulation/strategies/categorical.py +123 -0
- bead/simulation/strategies/cloze.py +224 -0
- bead/simulation/strategies/forced_choice.py +127 -0
- bead/simulation/strategies/free_text.py +105 -0
- bead/simulation/strategies/magnitude.py +116 -0
- bead/simulation/strategies/multi_select.py +129 -0
- bead/simulation/strategies/ordinal_scale.py +131 -0
- bead/templates/__init__.py +27 -0
- bead/templates/adapters/__init__.py +17 -0
- bead/templates/adapters/base.py +128 -0
- bead/templates/adapters/cache.py +178 -0
- bead/templates/adapters/huggingface.py +312 -0
- bead/templates/combinatorics.py +103 -0
- bead/templates/filler.py +605 -0
- bead/templates/renderers.py +177 -0
- bead/templates/resolver.py +178 -0
- bead/templates/strategies.py +1806 -0
- bead/templates/streaming.py +195 -0
- bead-0.1.0.dist-info/METADATA +212 -0
- bead-0.1.0.dist-info/RECORD +231 -0
- bead-0.1.0.dist-info/WHEEL +4 -0
- bead-0.1.0.dist-info/entry_points.txt +2 -0
- bead-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Template rendering system with plugin support.
|
|
2
|
+
|
|
3
|
+
This module provides the base template rendering interface and a simple
|
|
4
|
+
default implementation. Language-specific or custom rendering logic should
|
|
5
|
+
be implemented as external plugins.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from collections.abc import Mapping
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from bead.resources.lexical_item import LexicalItem
|
|
16
|
+
from bead.resources.template import Slot
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TemplateRenderer(ABC):
|
|
20
|
+
"""Base class for template renderers.
|
|
21
|
+
|
|
22
|
+
Custom renderers should subclass this and implement the render() method.
|
|
23
|
+
This allows for language-specific or experiment-specific rendering logic
|
|
24
|
+
to be implemented as external plugins.
|
|
25
|
+
|
|
26
|
+
Examples
|
|
27
|
+
--------
|
|
28
|
+
>>> from bead.templates.renderers import TemplateRenderer
|
|
29
|
+
>>> class CustomRenderer(TemplateRenderer):
|
|
30
|
+
... def render(self, template_string, slot_fillers, template_slots):
|
|
31
|
+
... # Custom rendering logic here
|
|
32
|
+
... return rendered_text
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def render(
|
|
37
|
+
self,
|
|
38
|
+
template_string: str,
|
|
39
|
+
slot_fillers: Mapping[str, LexicalItem],
|
|
40
|
+
template_slots: Mapping[str, Slot],
|
|
41
|
+
) -> str:
|
|
42
|
+
"""Render template with slot fillers.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
template_string : str
|
|
47
|
+
Template string with {slot_name} placeholders.
|
|
48
|
+
slot_fillers : Mapping[str, LexicalItem]
|
|
49
|
+
Mapping from slot names to lexical items that fill them.
|
|
50
|
+
template_slots : Mapping[str, Slot]
|
|
51
|
+
Mapping from slot names to slot definitions. Provides access
|
|
52
|
+
to slot constraints and metadata for context-aware rendering.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
str
|
|
57
|
+
Rendered text with placeholders replaced.
|
|
58
|
+
|
|
59
|
+
Examples
|
|
60
|
+
--------
|
|
61
|
+
>>> renderer = DefaultRenderer()
|
|
62
|
+
>>> from bead.resources.lexical_item import LexicalItem
|
|
63
|
+
>>> from bead.resources.template import Slot
|
|
64
|
+
>>> fillers = {
|
|
65
|
+
... "subj": LexicalItem(lemma="cat", language_code="eng"),
|
|
66
|
+
... "verb": LexicalItem(lemma="run", form="runs", language_code="eng")
|
|
67
|
+
... }
|
|
68
|
+
>>> slots = {
|
|
69
|
+
... "subj": Slot(name="subj"),
|
|
70
|
+
... "verb": Slot(name="verb")
|
|
71
|
+
... }
|
|
72
|
+
>>> renderer.render("{subj} {verb}", fillers, slots)
|
|
73
|
+
'cat runs'
|
|
74
|
+
"""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class DefaultRenderer(TemplateRenderer):
|
|
79
|
+
"""Default renderer using simple slot substitution.
|
|
80
|
+
|
|
81
|
+
Uses item.form if available, otherwise item.lemma.
|
|
82
|
+
This is a language-agnostic implementation suitable for most use cases.
|
|
83
|
+
|
|
84
|
+
Examples
|
|
85
|
+
--------
|
|
86
|
+
>>> from bead.templates.renderers import DefaultRenderer
|
|
87
|
+
>>> from bead.resources.lexical_item import LexicalItem
|
|
88
|
+
>>> from bead.resources.template import Slot
|
|
89
|
+
>>> renderer = DefaultRenderer()
|
|
90
|
+
>>>
|
|
91
|
+
>>> # Example 1: Basic rendering with lemmas
|
|
92
|
+
>>> fillers = {
|
|
93
|
+
... "det": LexicalItem(lemma="the", language_code="eng"),
|
|
94
|
+
... "noun": LexicalItem(lemma="cat", language_code="eng"),
|
|
95
|
+
... "verb": LexicalItem(lemma="run", language_code="eng")
|
|
96
|
+
... }
|
|
97
|
+
>>> slots = {name: Slot(name=name) for name in fillers.keys()}
|
|
98
|
+
>>> renderer.render("{det} {noun} {verb}", fillers, slots)
|
|
99
|
+
'the cat run'
|
|
100
|
+
>>>
|
|
101
|
+
>>> # Example 2: Rendering with forms (inflected)
|
|
102
|
+
>>> fillers_with_forms = {
|
|
103
|
+
... "det": LexicalItem(lemma="the", language_code="eng"),
|
|
104
|
+
... "noun": LexicalItem(lemma="cat", form="cats", language_code="eng"),
|
|
105
|
+
... "verb": LexicalItem(lemma="run", form="runs", language_code="eng")
|
|
106
|
+
... }
|
|
107
|
+
>>> renderer.render("{det} {noun} {verb}", fillers_with_forms, slots)
|
|
108
|
+
'the cats runs'
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def render(
|
|
112
|
+
self,
|
|
113
|
+
template_string: str,
|
|
114
|
+
slot_fillers: Mapping[str, LexicalItem],
|
|
115
|
+
template_slots: Mapping[str, Slot],
|
|
116
|
+
) -> str:
|
|
117
|
+
"""Render template with simple slot substitution.
|
|
118
|
+
|
|
119
|
+
Uses item.form if available, otherwise item.lemma. This provides
|
|
120
|
+
a straightforward rendering suitable for most templates without
|
|
121
|
+
special language-specific handling.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
template_string : str
|
|
126
|
+
Template string with {slot_name} placeholders.
|
|
127
|
+
slot_fillers : Mapping[str, LexicalItem]
|
|
128
|
+
Mapping from slot names to lexical items.
|
|
129
|
+
template_slots : Mapping[str, Slot]
|
|
130
|
+
Mapping from slot names to slot definitions (unused in default
|
|
131
|
+
implementation, but provided for subclasses).
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
str
|
|
136
|
+
Rendered text with placeholders replaced by item forms or lemmas.
|
|
137
|
+
|
|
138
|
+
Notes
|
|
139
|
+
-----
|
|
140
|
+
This renderer prioritizes item.form over item.lemma to support
|
|
141
|
+
morphological inflection. If item.form is None, it falls back to
|
|
142
|
+
item.lemma.
|
|
143
|
+
|
|
144
|
+
The template_slots parameter is not used in the default implementation
|
|
145
|
+
but is available for subclasses that need slot metadata for rendering.
|
|
146
|
+
|
|
147
|
+
Examples
|
|
148
|
+
--------
|
|
149
|
+
>>> renderer = DefaultRenderer()
|
|
150
|
+
>>> from bead.resources.lexical_item import LexicalItem
|
|
151
|
+
>>> from bead.resources.template import Slot
|
|
152
|
+
>>>
|
|
153
|
+
>>> # Form takes precedence over lemma
|
|
154
|
+
>>> fillers = {
|
|
155
|
+
... "verb": LexicalItem(lemma="walk", form="walked", language_code="eng")
|
|
156
|
+
... }
|
|
157
|
+
>>> slots = {"verb": Slot(name="verb")}
|
|
158
|
+
>>> renderer.render("{verb}", fillers, slots)
|
|
159
|
+
'walked'
|
|
160
|
+
>>>
|
|
161
|
+
>>> # Falls back to lemma when form is None
|
|
162
|
+
>>> fillers_no_form = {
|
|
163
|
+
... "verb": LexicalItem(lemma="walk", form=None, language_code="eng")
|
|
164
|
+
... }
|
|
165
|
+
>>> renderer.render("{verb}", fillers_no_form, slots)
|
|
166
|
+
'walk'
|
|
167
|
+
"""
|
|
168
|
+
result = template_string
|
|
169
|
+
|
|
170
|
+
for slot_name, item in slot_fillers.items():
|
|
171
|
+
placeholder = f"{{{slot_name}}}"
|
|
172
|
+
if placeholder in result:
|
|
173
|
+
# Use form if available, otherwise lemma
|
|
174
|
+
surface = item.form if item.form is not None else item.lemma
|
|
175
|
+
result = result.replace(placeholder, surface)
|
|
176
|
+
|
|
177
|
+
return result
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Constraint resolution for template slot filling.
|
|
2
|
+
|
|
3
|
+
This module provides the ConstraintResolver class for evaluating constraints
|
|
4
|
+
against lexical items to determine which items satisfy template slot requirements.
|
|
5
|
+
The resolver is now a thin wrapper around DSLEvaluator.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
from bead.dsl.evaluator import DSLEvaluator
|
|
13
|
+
from bead.resources.constraints import Constraint
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from bead.resources.constraints import ContextValue
|
|
17
|
+
from bead.resources.lexical_item import LexicalItem
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConstraintResolver:
|
|
21
|
+
"""Simplified resolver that wraps DSLEvaluator.
|
|
22
|
+
|
|
23
|
+
The ConstraintResolver evaluates DSL constraint expressions against
|
|
24
|
+
lexical items and filled slots. It provides two main methods:
|
|
25
|
+
- evaluate_slot_constraints: for single-slot constraints
|
|
26
|
+
- evaluate_template_constraints: for multi-slot constraints
|
|
27
|
+
|
|
28
|
+
All constraint logic is delegated to the DSL evaluator.
|
|
29
|
+
|
|
30
|
+
Examples
|
|
31
|
+
--------
|
|
32
|
+
>>> from bead.resources.models import LexicalItem
|
|
33
|
+
>>> from bead.resources.constraints import Constraint
|
|
34
|
+
>>> resolver = ConstraintResolver()
|
|
35
|
+
>>> item = LexicalItem(lemma="walk", pos="VERB")
|
|
36
|
+
>>> constraints = [
|
|
37
|
+
... Constraint(expression="self.pos == 'VERB'")
|
|
38
|
+
... ]
|
|
39
|
+
>>> resolver.evaluate_slot_constraints(item, constraints)
|
|
40
|
+
True
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
"""Initialize resolver with DSL evaluator."""
|
|
45
|
+
self.dsl_evaluator = DSLEvaluator()
|
|
46
|
+
|
|
47
|
+
def evaluate_slot_constraints(
|
|
48
|
+
self,
|
|
49
|
+
item: LexicalItem,
|
|
50
|
+
constraints: list[Constraint],
|
|
51
|
+
context: dict[str, ContextValue] | None = None,
|
|
52
|
+
) -> bool:
|
|
53
|
+
"""Evaluate single-slot constraints.
|
|
54
|
+
|
|
55
|
+
Single-slot constraints are evaluated with 'self' referring to
|
|
56
|
+
the lexical item being checked. The item is available as 'self'
|
|
57
|
+
in the DSL expression context.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
item : LexicalItem
|
|
62
|
+
Lexical item to evaluate constraints against.
|
|
63
|
+
constraints : list[Constraint]
|
|
64
|
+
Single-slot constraints from Slot.constraints.
|
|
65
|
+
context : dict[str, ContextValue] | None
|
|
66
|
+
Additional context variables (optional).
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
bool
|
|
71
|
+
True if all constraints are satisfied, False otherwise.
|
|
72
|
+
|
|
73
|
+
Examples
|
|
74
|
+
--------
|
|
75
|
+
>>> from bead.resources.models import LexicalItem
|
|
76
|
+
>>> from bead.resources.constraints import Constraint
|
|
77
|
+
>>> resolver = ConstraintResolver()
|
|
78
|
+
>>> item = LexicalItem(lemma="walk", pos="VERB")
|
|
79
|
+
>>> constraints = [
|
|
80
|
+
... Constraint(
|
|
81
|
+
... expression="self.lemma in motion_verbs",
|
|
82
|
+
... context={"motion_verbs": {"walk", "run", "jump"}}
|
|
83
|
+
... )
|
|
84
|
+
... ]
|
|
85
|
+
>>> resolver.evaluate_slot_constraints(item, constraints)
|
|
86
|
+
True
|
|
87
|
+
"""
|
|
88
|
+
for constraint in constraints:
|
|
89
|
+
# build evaluation context
|
|
90
|
+
eval_context: dict[str, Any] = {
|
|
91
|
+
"self": item,
|
|
92
|
+
**constraint.context,
|
|
93
|
+
}
|
|
94
|
+
if context:
|
|
95
|
+
eval_context.update(context)
|
|
96
|
+
|
|
97
|
+
# evaluate constraint
|
|
98
|
+
result = self.dsl_evaluator.evaluate(constraint.expression, eval_context)
|
|
99
|
+
if not result:
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
def evaluate_template_constraints(
|
|
105
|
+
self,
|
|
106
|
+
filled_slots: dict[str, LexicalItem],
|
|
107
|
+
constraints: list[Constraint],
|
|
108
|
+
context: dict[str, ContextValue] | None = None,
|
|
109
|
+
) -> bool:
|
|
110
|
+
"""Evaluate multi-slot constraints.
|
|
111
|
+
|
|
112
|
+
Multi-slot constraints are evaluated with slot names as variables.
|
|
113
|
+
For example, a constraint like "subject.features.number == verb.features.number"
|
|
114
|
+
would have access to both the 'subject' and 'verb' slot fillers.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
filled_slots : dict[str, LexicalItem]
|
|
119
|
+
Dictionary mapping slot names to their filled items.
|
|
120
|
+
constraints : list[Constraint]
|
|
121
|
+
Multi-slot constraints from Template.constraints.
|
|
122
|
+
context : dict[str, ContextValue] | None
|
|
123
|
+
Additional context variables (optional).
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
bool
|
|
128
|
+
True if all constraints are satisfied, False otherwise.
|
|
129
|
+
|
|
130
|
+
Examples
|
|
131
|
+
--------
|
|
132
|
+
>>> from bead.resources.models import LexicalItem
|
|
133
|
+
>>> from bead.resources.constraints import Constraint
|
|
134
|
+
>>> resolver = ConstraintResolver()
|
|
135
|
+
>>> subject = LexicalItem(
|
|
136
|
+
... lemma="dog",
|
|
137
|
+
... pos="NOUN",
|
|
138
|
+
... features={"number": "singular"}
|
|
139
|
+
... )
|
|
140
|
+
>>> verb = LexicalItem(
|
|
141
|
+
... lemma="runs",
|
|
142
|
+
... pos="VERB",
|
|
143
|
+
... features={"number": "singular"}
|
|
144
|
+
... )
|
|
145
|
+
>>> filled = {"subject": subject, "verb": verb}
|
|
146
|
+
>>> constraints = [
|
|
147
|
+
... Constraint(
|
|
148
|
+
... expression="subject.features.number == verb.features.number"
|
|
149
|
+
... )
|
|
150
|
+
... ]
|
|
151
|
+
>>> resolver.evaluate_template_constraints(filled, constraints)
|
|
152
|
+
True
|
|
153
|
+
"""
|
|
154
|
+
for constraint in constraints:
|
|
155
|
+
# build evaluation context with slot fillers
|
|
156
|
+
eval_context: dict[str, Any] = {
|
|
157
|
+
**filled_slots,
|
|
158
|
+
**constraint.context,
|
|
159
|
+
}
|
|
160
|
+
if context:
|
|
161
|
+
eval_context.update(context)
|
|
162
|
+
|
|
163
|
+
# evaluate constraint
|
|
164
|
+
result = self.dsl_evaluator.evaluate(constraint.expression, eval_context)
|
|
165
|
+
if not result:
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
return True
|
|
169
|
+
|
|
170
|
+
def clear_cache(self) -> None:
|
|
171
|
+
"""Clear DSL evaluator's compiled expression cache.
|
|
172
|
+
|
|
173
|
+
Examples
|
|
174
|
+
--------
|
|
175
|
+
>>> resolver = ConstraintResolver()
|
|
176
|
+
>>> resolver.clear_cache()
|
|
177
|
+
"""
|
|
178
|
+
self.dsl_evaluator.clear_cache()
|