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.
Files changed (231) hide show
  1. bead/__init__.py +11 -0
  2. bead/__main__.py +11 -0
  3. bead/active_learning/__init__.py +15 -0
  4. bead/active_learning/config.py +231 -0
  5. bead/active_learning/loop.py +566 -0
  6. bead/active_learning/models/__init__.py +24 -0
  7. bead/active_learning/models/base.py +852 -0
  8. bead/active_learning/models/binary.py +910 -0
  9. bead/active_learning/models/categorical.py +943 -0
  10. bead/active_learning/models/cloze.py +862 -0
  11. bead/active_learning/models/forced_choice.py +956 -0
  12. bead/active_learning/models/free_text.py +773 -0
  13. bead/active_learning/models/lora.py +365 -0
  14. bead/active_learning/models/magnitude.py +835 -0
  15. bead/active_learning/models/multi_select.py +795 -0
  16. bead/active_learning/models/ordinal_scale.py +811 -0
  17. bead/active_learning/models/peft_adapter.py +155 -0
  18. bead/active_learning/models/random_effects.py +639 -0
  19. bead/active_learning/selection.py +354 -0
  20. bead/active_learning/strategies.py +391 -0
  21. bead/active_learning/trainers/__init__.py +26 -0
  22. bead/active_learning/trainers/base.py +210 -0
  23. bead/active_learning/trainers/data_collator.py +172 -0
  24. bead/active_learning/trainers/dataset_utils.py +261 -0
  25. bead/active_learning/trainers/huggingface.py +304 -0
  26. bead/active_learning/trainers/lightning.py +324 -0
  27. bead/active_learning/trainers/metrics.py +424 -0
  28. bead/active_learning/trainers/mixed_effects.py +551 -0
  29. bead/active_learning/trainers/model_wrapper.py +509 -0
  30. bead/active_learning/trainers/registry.py +104 -0
  31. bead/adapters/__init__.py +11 -0
  32. bead/adapters/huggingface.py +61 -0
  33. bead/behavioral/__init__.py +116 -0
  34. bead/behavioral/analytics.py +646 -0
  35. bead/behavioral/extraction.py +343 -0
  36. bead/behavioral/merging.py +343 -0
  37. bead/cli/__init__.py +11 -0
  38. bead/cli/active_learning.py +513 -0
  39. bead/cli/active_learning_commands.py +779 -0
  40. bead/cli/completion.py +359 -0
  41. bead/cli/config.py +624 -0
  42. bead/cli/constraint_builders.py +286 -0
  43. bead/cli/deployment.py +859 -0
  44. bead/cli/deployment_trials.py +493 -0
  45. bead/cli/deployment_ui.py +332 -0
  46. bead/cli/display.py +378 -0
  47. bead/cli/items.py +960 -0
  48. bead/cli/items_factories.py +776 -0
  49. bead/cli/list_constraints.py +714 -0
  50. bead/cli/lists.py +490 -0
  51. bead/cli/main.py +430 -0
  52. bead/cli/models.py +877 -0
  53. bead/cli/resource_loaders.py +621 -0
  54. bead/cli/resources.py +1036 -0
  55. bead/cli/shell.py +356 -0
  56. bead/cli/simulate.py +840 -0
  57. bead/cli/templates.py +1158 -0
  58. bead/cli/training.py +1080 -0
  59. bead/cli/utils.py +614 -0
  60. bead/cli/workflow.py +1273 -0
  61. bead/config/__init__.py +68 -0
  62. bead/config/active_learning.py +1009 -0
  63. bead/config/config.py +192 -0
  64. bead/config/defaults.py +118 -0
  65. bead/config/deployment.py +217 -0
  66. bead/config/env.py +147 -0
  67. bead/config/item.py +45 -0
  68. bead/config/list.py +193 -0
  69. bead/config/loader.py +149 -0
  70. bead/config/logging.py +42 -0
  71. bead/config/model.py +49 -0
  72. bead/config/paths.py +46 -0
  73. bead/config/profiles.py +320 -0
  74. bead/config/resources.py +47 -0
  75. bead/config/serialization.py +210 -0
  76. bead/config/simulation.py +206 -0
  77. bead/config/template.py +238 -0
  78. bead/config/validation.py +267 -0
  79. bead/data/__init__.py +65 -0
  80. bead/data/base.py +87 -0
  81. bead/data/identifiers.py +97 -0
  82. bead/data/language_codes.py +61 -0
  83. bead/data/metadata.py +270 -0
  84. bead/data/range.py +123 -0
  85. bead/data/repository.py +358 -0
  86. bead/data/serialization.py +249 -0
  87. bead/data/timestamps.py +89 -0
  88. bead/data/validation.py +349 -0
  89. bead/data_collection/__init__.py +11 -0
  90. bead/data_collection/jatos.py +223 -0
  91. bead/data_collection/merger.py +154 -0
  92. bead/data_collection/prolific.py +198 -0
  93. bead/deployment/__init__.py +5 -0
  94. bead/deployment/distribution.py +402 -0
  95. bead/deployment/jatos/__init__.py +1 -0
  96. bead/deployment/jatos/api.py +200 -0
  97. bead/deployment/jatos/exporter.py +210 -0
  98. bead/deployment/jspsych/__init__.py +9 -0
  99. bead/deployment/jspsych/biome.json +44 -0
  100. bead/deployment/jspsych/config.py +411 -0
  101. bead/deployment/jspsych/generator.py +598 -0
  102. bead/deployment/jspsych/package.json +51 -0
  103. bead/deployment/jspsych/pnpm-lock.yaml +2141 -0
  104. bead/deployment/jspsych/randomizer.py +299 -0
  105. bead/deployment/jspsych/src/lib/list-distributor.test.ts +327 -0
  106. bead/deployment/jspsych/src/lib/list-distributor.ts +1282 -0
  107. bead/deployment/jspsych/src/lib/randomizer.test.ts +232 -0
  108. bead/deployment/jspsych/src/lib/randomizer.ts +367 -0
  109. bead/deployment/jspsych/src/plugins/cloze-dropdown.ts +252 -0
  110. bead/deployment/jspsych/src/plugins/forced-choice.ts +265 -0
  111. bead/deployment/jspsych/src/plugins/plugins.test.ts +141 -0
  112. bead/deployment/jspsych/src/plugins/rating.ts +248 -0
  113. bead/deployment/jspsych/src/slopit/index.ts +9 -0
  114. bead/deployment/jspsych/src/types/jatos.d.ts +256 -0
  115. bead/deployment/jspsych/src/types/jspsych.d.ts +228 -0
  116. bead/deployment/jspsych/templates/experiment.css +1 -0
  117. bead/deployment/jspsych/templates/experiment.js.template +289 -0
  118. bead/deployment/jspsych/templates/index.html +51 -0
  119. bead/deployment/jspsych/templates/randomizer.js +241 -0
  120. bead/deployment/jspsych/templates/randomizer.js.template +313 -0
  121. bead/deployment/jspsych/trials.py +723 -0
  122. bead/deployment/jspsych/tsconfig.json +23 -0
  123. bead/deployment/jspsych/tsup.config.ts +30 -0
  124. bead/deployment/jspsych/ui/__init__.py +1 -0
  125. bead/deployment/jspsych/ui/components.py +383 -0
  126. bead/deployment/jspsych/ui/styles.py +411 -0
  127. bead/dsl/__init__.py +80 -0
  128. bead/dsl/ast.py +168 -0
  129. bead/dsl/context.py +178 -0
  130. bead/dsl/errors.py +71 -0
  131. bead/dsl/evaluator.py +570 -0
  132. bead/dsl/grammar.lark +81 -0
  133. bead/dsl/parser.py +231 -0
  134. bead/dsl/stdlib.py +929 -0
  135. bead/evaluation/__init__.py +13 -0
  136. bead/evaluation/convergence.py +485 -0
  137. bead/evaluation/interannotator.py +398 -0
  138. bead/items/__init__.py +40 -0
  139. bead/items/adapters/__init__.py +70 -0
  140. bead/items/adapters/anthropic.py +224 -0
  141. bead/items/adapters/api_utils.py +167 -0
  142. bead/items/adapters/base.py +216 -0
  143. bead/items/adapters/google.py +259 -0
  144. bead/items/adapters/huggingface.py +1074 -0
  145. bead/items/adapters/openai.py +323 -0
  146. bead/items/adapters/registry.py +202 -0
  147. bead/items/adapters/sentence_transformers.py +224 -0
  148. bead/items/adapters/togetherai.py +309 -0
  149. bead/items/binary.py +515 -0
  150. bead/items/cache.py +558 -0
  151. bead/items/categorical.py +593 -0
  152. bead/items/cloze.py +757 -0
  153. bead/items/constructor.py +784 -0
  154. bead/items/forced_choice.py +413 -0
  155. bead/items/free_text.py +681 -0
  156. bead/items/generation.py +432 -0
  157. bead/items/item.py +396 -0
  158. bead/items/item_template.py +787 -0
  159. bead/items/magnitude.py +573 -0
  160. bead/items/multi_select.py +621 -0
  161. bead/items/ordinal_scale.py +569 -0
  162. bead/items/scoring.py +448 -0
  163. bead/items/validation.py +723 -0
  164. bead/lists/__init__.py +30 -0
  165. bead/lists/balancer.py +263 -0
  166. bead/lists/constraints.py +1067 -0
  167. bead/lists/experiment_list.py +286 -0
  168. bead/lists/list_collection.py +378 -0
  169. bead/lists/partitioner.py +1141 -0
  170. bead/lists/stratification.py +254 -0
  171. bead/participants/__init__.py +73 -0
  172. bead/participants/collection.py +699 -0
  173. bead/participants/merging.py +312 -0
  174. bead/participants/metadata_spec.py +491 -0
  175. bead/participants/models.py +276 -0
  176. bead/resources/__init__.py +29 -0
  177. bead/resources/adapters/__init__.py +19 -0
  178. bead/resources/adapters/base.py +104 -0
  179. bead/resources/adapters/cache.py +128 -0
  180. bead/resources/adapters/glazing.py +508 -0
  181. bead/resources/adapters/registry.py +117 -0
  182. bead/resources/adapters/unimorph.py +796 -0
  183. bead/resources/classification.py +856 -0
  184. bead/resources/constraint_builders.py +329 -0
  185. bead/resources/constraints.py +165 -0
  186. bead/resources/lexical_item.py +223 -0
  187. bead/resources/lexicon.py +744 -0
  188. bead/resources/loaders.py +209 -0
  189. bead/resources/template.py +441 -0
  190. bead/resources/template_collection.py +707 -0
  191. bead/resources/template_generation.py +349 -0
  192. bead/simulation/__init__.py +29 -0
  193. bead/simulation/annotators/__init__.py +15 -0
  194. bead/simulation/annotators/base.py +175 -0
  195. bead/simulation/annotators/distance_based.py +135 -0
  196. bead/simulation/annotators/lm_based.py +114 -0
  197. bead/simulation/annotators/oracle.py +182 -0
  198. bead/simulation/annotators/random.py +181 -0
  199. bead/simulation/dsl_extension/__init__.py +3 -0
  200. bead/simulation/noise_models/__init__.py +13 -0
  201. bead/simulation/noise_models/base.py +42 -0
  202. bead/simulation/noise_models/random_noise.py +82 -0
  203. bead/simulation/noise_models/systematic.py +132 -0
  204. bead/simulation/noise_models/temperature.py +86 -0
  205. bead/simulation/runner.py +144 -0
  206. bead/simulation/strategies/__init__.py +23 -0
  207. bead/simulation/strategies/base.py +123 -0
  208. bead/simulation/strategies/binary.py +103 -0
  209. bead/simulation/strategies/categorical.py +123 -0
  210. bead/simulation/strategies/cloze.py +224 -0
  211. bead/simulation/strategies/forced_choice.py +127 -0
  212. bead/simulation/strategies/free_text.py +105 -0
  213. bead/simulation/strategies/magnitude.py +116 -0
  214. bead/simulation/strategies/multi_select.py +129 -0
  215. bead/simulation/strategies/ordinal_scale.py +131 -0
  216. bead/templates/__init__.py +27 -0
  217. bead/templates/adapters/__init__.py +17 -0
  218. bead/templates/adapters/base.py +128 -0
  219. bead/templates/adapters/cache.py +178 -0
  220. bead/templates/adapters/huggingface.py +312 -0
  221. bead/templates/combinatorics.py +103 -0
  222. bead/templates/filler.py +605 -0
  223. bead/templates/renderers.py +177 -0
  224. bead/templates/resolver.py +178 -0
  225. bead/templates/strategies.py +1806 -0
  226. bead/templates/streaming.py +195 -0
  227. bead-0.1.0.dist-info/METADATA +212 -0
  228. bead-0.1.0.dist-info/RECORD +231 -0
  229. bead-0.1.0.dist-info/WHEEL +4 -0
  230. bead-0.1.0.dist-info/entry_points.txt +2 -0
  231. bead-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,286 @@
1
+ """Constraint builder commands for bead CLI.
2
+
3
+ This module provides commands for creating constraints for template slot filling
4
+ using three types: extensional (value whitelists), intensional (feature-based
5
+ expressions), and relational (cross-slot constraints).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+
12
+ import click
13
+ from rich.console import Console
14
+
15
+ from bead.cli.utils import print_error, print_info, print_success
16
+ from bead.resources.constraints import Constraint
17
+
18
+ console = Console()
19
+
20
+
21
+ @click.command()
22
+ @click.argument("output_file", type=click.Path(path_type=Path))
23
+ @click.option(
24
+ "--type",
25
+ "constraint_type",
26
+ type=click.Choice(["extensional", "intensional", "relational"]),
27
+ required=True,
28
+ help="Type of constraint to create",
29
+ )
30
+ @click.option(
31
+ "--slot",
32
+ help="Slot name for single-slot constraints (extensional, intensional)",
33
+ )
34
+ @click.option(
35
+ "--expression",
36
+ help="DSL expression for intensional constraints (e.g., \"self.pos == 'VERB'\")",
37
+ )
38
+ @click.option(
39
+ "--relation",
40
+ help='DSL expression for relational constraints (e.g., "a.number == b.number")',
41
+ )
42
+ @click.option(
43
+ "--values-file",
44
+ type=click.Path(exists=True, path_type=Path),
45
+ help="File with values for extensional constraints (one value per line)",
46
+ )
47
+ @click.option(
48
+ "--values",
49
+ help="Comma-separated values for extensional constraints",
50
+ )
51
+ @click.option(
52
+ "--context-var-name",
53
+ default="allowed_values",
54
+ help="Context variable name for extensional constraints (default: allowed_values)",
55
+ )
56
+ @click.option(
57
+ "--description",
58
+ help="Human-readable description of the constraint",
59
+ )
60
+ @click.option(
61
+ "--prop-name",
62
+ default="lemma",
63
+ help="Property to check for extensional constraints (default: lemma)",
64
+ )
65
+ @click.pass_context
66
+ def create_constraint(
67
+ ctx: click.Context,
68
+ output_file: Path,
69
+ constraint_type: str,
70
+ slot: str | None,
71
+ expression: str | None,
72
+ relation: str | None,
73
+ values_file: Path | None,
74
+ values: str | None,
75
+ context_var_name: str,
76
+ description: str | None,
77
+ prop_name: str,
78
+ ) -> None:
79
+ r"""Create a constraint for template slot filling.
80
+
81
+ Supports three types of constraints:
82
+
83
+ \b
84
+ 1. EXTENSIONAL: Whitelist of allowed values
85
+ $ bead resources create-constraint constraints.jsonl \
86
+ --type extensional \
87
+ --slot verb \
88
+ --values "walk,run,jump" \
89
+ --description "Motion verbs"
90
+
91
+ \b
92
+ 2. INTENSIONAL: Feature-based DSL expression
93
+ $ bead resources create-constraint constraints.jsonl \
94
+ --type intensional \
95
+ --slot verb \
96
+ --expression "self.pos == 'VERB' and self.features.tense == 'past'" \
97
+ --description "Past tense verbs"
98
+
99
+ \b
100
+ 3. RELATIONAL: Cross-slot agreement
101
+ $ bead resources create-constraint constraints.jsonl \
102
+ --type relational \
103
+ --relation "subject.features.number == verb.features.number" \
104
+ --description "Subject-verb agreement"
105
+
106
+ Parameters
107
+ ----------
108
+ ctx : click.Context
109
+ Click context object.
110
+ output_file : Path
111
+ Path to output constraints file (JSONL).
112
+ constraint_type : str
113
+ Type of constraint (extensional, intensional, relational).
114
+ slot : str | None
115
+ Slot name for single-slot constraints.
116
+ expression : str | None
117
+ DSL expression for intensional constraints.
118
+ relation : str | None
119
+ DSL expression for relational constraints.
120
+ values_file : Path | None
121
+ File with values for extensional constraints.
122
+ values : str | None
123
+ Comma-separated values for extensional constraints.
124
+ context_var_name : str
125
+ Context variable name for extensional constraints.
126
+ description : str | None
127
+ Description of the constraint.
128
+ prop_name : str
129
+ Property to check for extensional constraints.
130
+
131
+ Examples
132
+ --------
133
+ # Extensional constraint from file
134
+ $ bead resources create-constraint constraints.jsonl \\
135
+ --type extensional \\
136
+ --slot verb \\
137
+ --values-file motion_verbs.txt \\
138
+ --description "Motion verbs only"
139
+
140
+ # Extensional constraint from values
141
+ $ bead resources create-constraint constraints.jsonl \\
142
+ --type extensional \\
143
+ --slot noun \\
144
+ --values "cat,dog,bird" \\
145
+ --prop-name lemma
146
+
147
+ # Intensional constraint
148
+ $ bead resources create-constraint constraints.jsonl \\
149
+ --type intensional \\
150
+ --slot verb \\
151
+ --expression "self.pos == 'VERB' and self.features.number == 'singular'"
152
+
153
+ # Relational constraint
154
+ $ bead resources create-constraint constraints.jsonl \\
155
+ --type relational \\
156
+ --relation "det.lemma != 'a' or noun.features.number == 'singular'" \\
157
+ --description "Article-noun agreement"
158
+ """
159
+ try:
160
+ constraint: Constraint | None = None
161
+
162
+ if constraint_type == "extensional":
163
+ # Validate required parameters
164
+ if not values_file and not values:
165
+ print_error("Extensional constraints require --values-file or --values")
166
+ ctx.exit(1)
167
+
168
+ if not slot:
169
+ print_error("Extensional constraints require --slot")
170
+ ctx.exit(1)
171
+
172
+ # Load values
173
+ value_set: set[str]
174
+ if values_file:
175
+ print_info(f"Loading values from {values_file}")
176
+ with open(values_file, encoding="utf-8") as f:
177
+ value_set = {line.strip() for line in f if line.strip()}
178
+ else:
179
+ assert values is not None
180
+ value_set = {v.strip() for v in values.split(",") if v.strip()}
181
+
182
+ if not value_set:
183
+ print_error("No values provided")
184
+ ctx.exit(1)
185
+
186
+ # Create constraint
187
+ # Expression uses 'self' for single-slot constraints
188
+ expr = f"self.{prop_name} in {context_var_name}"
189
+ constraint = Constraint(
190
+ expression=expr,
191
+ context={context_var_name: value_set},
192
+ description=description
193
+ or f"Allowed {prop_name} values for {slot}: {len(value_set)} values",
194
+ )
195
+ print_success(
196
+ f"Created extensional constraint for '{slot}' "
197
+ f"with {len(value_set)} values"
198
+ )
199
+
200
+ elif constraint_type == "intensional":
201
+ # Validate required parameters
202
+ if not expression:
203
+ print_error("Intensional constraints require --expression")
204
+ ctx.exit(1)
205
+
206
+ if not slot:
207
+ print_info(
208
+ "No --slot specified; constraint will apply to template level"
209
+ )
210
+
211
+ # Validate expression starts with 'self.' for slot-level constraints
212
+ if slot and not expression.startswith("self."):
213
+ print_error(
214
+ f"Intensional expression for slot '{slot}' must start with 'self.' "
215
+ f"to refer to the slot filler.\n\n"
216
+ f"Example: self.pos == 'VERB' and self.features.tense == 'past'"
217
+ )
218
+ ctx.exit(1)
219
+
220
+ # Create constraint
221
+ constraint = Constraint(
222
+ expression=expression,
223
+ description=description or f"Intensional constraint: {expression}",
224
+ )
225
+ print_success(
226
+ f"Created intensional constraint{' for slot ' + slot if slot else ''}"
227
+ )
228
+
229
+ elif constraint_type == "relational":
230
+ # Validate required parameters
231
+ if not relation:
232
+ print_error("Relational constraints require --relation")
233
+ ctx.exit(1)
234
+
235
+ # Validate expression does NOT start with 'self.' (multi-slot)
236
+ if relation.startswith("self."):
237
+ print_error(
238
+ "Relational constraints are multi-slot; do not use 'self.'.\n\n"
239
+ "Use slot names as variables instead.\n\n"
240
+ "Example: subject.features.number == verb.features.number"
241
+ )
242
+ ctx.exit(1)
243
+
244
+ # Create constraint
245
+ constraint = Constraint(
246
+ expression=relation,
247
+ description=description or f"Relational constraint: {relation}",
248
+ )
249
+ print_success("Created relational constraint")
250
+
251
+ else:
252
+ print_error(f"Unknown constraint type: {constraint_type}")
253
+ ctx.exit(1)
254
+
255
+ # Save constraint to JSONL
256
+ assert constraint is not None
257
+ output_file.parent.mkdir(parents=True, exist_ok=True)
258
+
259
+ # Append to file if it exists, create new file otherwise
260
+ mode = "a" if output_file.exists() else "w"
261
+ with open(output_file, mode, encoding="utf-8") as f:
262
+ f.write(constraint.model_dump_json() + "\n")
263
+
264
+ print_info(f"Constraint written to: {output_file}")
265
+
266
+ # Show example usage
267
+ if constraint_type == "extensional":
268
+ console.print("\n[cyan]Usage in template:[/cyan]")
269
+ console.print(
270
+ f" Add to Slot(name='{slot}', constraints=[...loaded from file...])"
271
+ )
272
+ elif constraint_type == "intensional":
273
+ console.print("\n[cyan]Usage in template:[/cyan]")
274
+ if slot:
275
+ console.print(
276
+ f" Add to Slot(name='{slot}', constraints=[...from file...])"
277
+ )
278
+ else:
279
+ console.print(" Add to Template.constraints=[...loaded from file...]")
280
+ elif constraint_type == "relational":
281
+ console.print("\n[cyan]Usage in template:[/cyan]")
282
+ console.print(" Add to Template.constraints=[...loaded from file...]")
283
+
284
+ except Exception as e:
285
+ print_error(f"Failed to create constraint: {e}")
286
+ ctx.exit(1)