boolean-algebra-engine 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.
api/__init__.py ADDED
File without changes
api/routes.py ADDED
@@ -0,0 +1,386 @@
1
+ """
2
+ api/routes.py — REST API wrapping the boolean algebra engine.
3
+
4
+ Endpoints:
5
+ POST /evaluate expression → truth table
6
+ POST /simplify expression → minimal form
7
+ POST /equivalent two expressions → same truth table?
8
+ POST /satisfiable expression → any row outputs 1?
9
+ POST /check-rules list of expressions → contradictions, conflicts
10
+ POST /nl/ask plain English → verified boolean result
11
+ POST /nl/check-rules list of plain English rules → analysis
12
+ GET /health liveness check
13
+
14
+ Run:
15
+ uvicorn api.routes:app --host 0.0.0.0 --port 8080 --reload
16
+
17
+ Environment variables:
18
+ ANTHROPIC_API_KEY — for nl/* endpoints with anthropic provider
19
+ OPENAI_API_KEY — for nl/* endpoints with openai provider
20
+ REDIS_URL — optional, enables caching (default: redis://localhost:6379)
21
+ API_KEY — optional, enables auth (Pro/Team tiers)
22
+ """
23
+ from __future__ import annotations
24
+
25
+ import hashlib
26
+ import json
27
+ import os
28
+ import time
29
+ from typing import Optional
30
+
31
+ from fastapi import FastAPI, HTTPException, Request, Response
32
+ from fastapi.middleware.cors import CORSMiddleware
33
+ from pydantic import BaseModel
34
+
35
+ from core.evaluator import evaluate as _evaluate
36
+ from core.synthesizer import synthesize as _synthesize
37
+ from core.parser import validate, infix_to_prefix
38
+ from core.evaluator import _evaluate_prefix
39
+
40
+ app = FastAPI(
41
+ title="Boolean Algebra Engine",
42
+ description="Deterministic boolean logic verification API.",
43
+ version="0.1.0",
44
+ )
45
+
46
+ app.add_middleware(
47
+ CORSMiddleware,
48
+ allow_origins=["*"],
49
+ allow_methods=["*"],
50
+ allow_headers=["*"],
51
+ )
52
+
53
+
54
+ # ---------------------------------------------------------------------------
55
+ # Redis cache — optional, degrades gracefully if not available
56
+ # ---------------------------------------------------------------------------
57
+
58
+ _redis = None
59
+
60
+ def _get_redis():
61
+ global _redis
62
+ if _redis is not None:
63
+ return _redis
64
+ try:
65
+ import redis
66
+ r = redis.from_url(os.environ.get("REDIS_URL", "redis://localhost:6379"))
67
+ r.ping()
68
+ _redis = r
69
+ except Exception:
70
+ _redis = None
71
+ return _redis
72
+
73
+
74
+ def _cache_get(key: str) -> dict | None:
75
+ r = _get_redis()
76
+ if not r:
77
+ return None
78
+ try:
79
+ val = r.get(key)
80
+ return json.loads(val) if val else None
81
+ except Exception:
82
+ return None
83
+
84
+
85
+ def _cache_set(key: str, value: dict, ttl: int = 86400):
86
+ r = _get_redis()
87
+ if not r:
88
+ return
89
+ try:
90
+ r.setex(key, ttl, json.dumps(value))
91
+ except Exception:
92
+ pass
93
+
94
+
95
+ def _cache_key(*parts) -> str:
96
+ raw = ":".join(str(p) for p in parts)
97
+ return "bae:" + hashlib.sha256(raw.encode()).hexdigest()[:16]
98
+
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # Auth — optional, enabled when API_KEY env var is set
102
+ # ---------------------------------------------------------------------------
103
+
104
+ def _check_auth(request: Request):
105
+ required = os.environ.get("API_KEY")
106
+ if not required:
107
+ return
108
+ provided = request.headers.get("X-API-Key")
109
+ if provided != required:
110
+ raise HTTPException(status_code=401, detail="Invalid or missing X-API-Key")
111
+
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # Request / response models
115
+ # ---------------------------------------------------------------------------
116
+
117
+ class EvaluateRequest(BaseModel):
118
+ expression: str
119
+
120
+ class SimplifyRequest(BaseModel):
121
+ expression: str
122
+
123
+ class EquivalentRequest(BaseModel):
124
+ expression1: str
125
+ expression2: str
126
+
127
+ class SatisfiableRequest(BaseModel):
128
+ expression: str
129
+
130
+ class CheckRulesRequest(BaseModel):
131
+ rules: list[str]
132
+
133
+ class NLAskRequest(BaseModel):
134
+ sentence: str
135
+ provider: str = "anthropic"
136
+ api_key: Optional[str] = None
137
+ model: Optional[str] = None
138
+ base_url: Optional[str] = None
139
+
140
+ class NLCheckRulesRequest(BaseModel):
141
+ rules: list[str]
142
+ provider: str = "anthropic"
143
+ api_key: Optional[str] = None
144
+ model: Optional[str] = None
145
+ base_url: Optional[str] = None
146
+
147
+
148
+ # ---------------------------------------------------------------------------
149
+ # Helper — build provider from request fields
150
+ # ---------------------------------------------------------------------------
151
+
152
+ def _build_provider(provider: str, api_key: Optional[str], model: Optional[str], base_url: Optional[str]):
153
+ from nl.nl import AnthropicProvider, OpenAIProvider, OllamaProvider, OpenAICompatProvider
154
+ if provider == "anthropic":
155
+ return AnthropicProvider(api_key=api_key, model=model or "claude-sonnet-4-6")
156
+ if provider == "openai":
157
+ return OpenAIProvider(api_key=api_key, model=model or "gpt-4o")
158
+ if provider == "ollama":
159
+ return OllamaProvider(model=model or "llama3", base_url=base_url or "http://localhost:11434")
160
+ if provider == "compat":
161
+ if not base_url or not model:
162
+ raise HTTPException(status_code=400, detail="base_url and model required for compat provider")
163
+ return OpenAICompatProvider(api_key=api_key or "", base_url=base_url, model=model)
164
+ raise HTTPException(status_code=400, detail=f"Unknown provider '{provider}'. Choose: anthropic, openai, ollama, compat")
165
+
166
+
167
+ # ---------------------------------------------------------------------------
168
+ # Endpoints
169
+ # ---------------------------------------------------------------------------
170
+
171
+ @app.get("/health")
172
+ def health():
173
+ redis_ok = _get_redis() is not None
174
+ return {"status": "ok", "version": "0.1.0", "redis": redis_ok}
175
+
176
+
177
+ @app.post("/evaluate")
178
+ def evaluate(req: EvaluateRequest, request: Request, response: Response):
179
+ _check_auth(request)
180
+
181
+ cache_key = _cache_key("evaluate", req.expression)
182
+ cached = _cache_get(cache_key)
183
+ if cached:
184
+ response.headers["X-Cache"] = "HIT"
185
+ return cached
186
+
187
+ error = validate(req.expression)
188
+ if error:
189
+ raise HTTPException(status_code=422, detail={"error": "invalid_expression", "message": error, "expression": req.expression})
190
+
191
+ t0 = time.perf_counter()
192
+ table, metrics = _evaluate(req.expression)
193
+ elapsed = round((time.perf_counter() - t0) * 1000, 4)
194
+
195
+ result = {
196
+ "expression": table.expression,
197
+ "variables": table.variables,
198
+ "rows": [{**row.inputs, "output": row.output} for row in table.rows],
199
+ "satisfiable": table.satisfiable,
200
+ "tautology": table.tautology,
201
+ "minterms": table.minterms,
202
+ "maxterms": table.maxterms,
203
+ "eval_time_ms": elapsed,
204
+ "rows_evaluated": metrics.rows_evaluated,
205
+ }
206
+
207
+ _cache_set(cache_key, result, ttl=86400)
208
+ response.headers["X-Cache"] = "MISS"
209
+ response.headers["X-Eval-Time-Ms"] = str(elapsed)
210
+ return result
211
+
212
+
213
+ @app.post("/simplify")
214
+ def simplify(req: SimplifyRequest, request: Request, response: Response):
215
+ _check_auth(request)
216
+
217
+ cache_key = _cache_key("simplify", req.expression)
218
+ cached = _cache_get(cache_key)
219
+ if cached:
220
+ response.headers["X-Cache"] = "HIT"
221
+ return cached
222
+
223
+ error = validate(req.expression)
224
+ if error:
225
+ raise HTTPException(status_code=422, detail={"error": "invalid_expression", "message": error, "expression": req.expression})
226
+
227
+ table, _ = _evaluate(req.expression)
228
+ minimal, metrics = _synthesize(table)
229
+
230
+ result = {
231
+ "original": req.expression,
232
+ "minimal": minimal,
233
+ "changed": minimal != req.expression,
234
+ "prime_implicant_count": metrics.prime_implicant_count,
235
+ "synth_time_ms": metrics.synth_time_ms,
236
+ }
237
+
238
+ _cache_set(cache_key, result, ttl=86400)
239
+ response.headers["X-Cache"] = "MISS"
240
+ return result
241
+
242
+
243
+ @app.post("/equivalent")
244
+ def equivalent(req: EquivalentRequest, request: Request, response: Response):
245
+ _check_auth(request)
246
+
247
+ cache_key = _cache_key("equivalent", req.expression1, req.expression2)
248
+ cached = _cache_get(cache_key)
249
+ if cached:
250
+ response.headers["X-Cache"] = "HIT"
251
+ return cached
252
+
253
+ for expr in [req.expression1, req.expression2]:
254
+ error = validate(expr)
255
+ if error:
256
+ raise HTTPException(status_code=422, detail={"error": "invalid_expression", "message": error, "expression": expr})
257
+
258
+ from core.parser import get_variables
259
+ vars1 = set(get_variables(req.expression1))
260
+ vars2 = set(get_variables(req.expression2))
261
+ all_vars = sorted(vars1 | vars2)
262
+ n = len(all_vars)
263
+
264
+ p1 = infix_to_prefix(req.expression1)
265
+ p2 = infix_to_prefix(req.expression2)
266
+
267
+ differing = []
268
+ for i in range(2 ** n):
269
+ values = {var: (i >> (n - 1 - j)) & 1 for j, var in enumerate(all_vars)}
270
+ v1 = {k: v for k, v in values.items() if k in vars1}
271
+ v2 = {k: v for k, v in values.items() if k in vars2}
272
+ out1 = _evaluate_prefix(p1, v1)
273
+ out2 = _evaluate_prefix(p2, v2)
274
+ if out1 != out2:
275
+ differing.append({**values, req.expression1: out1, req.expression2: out2})
276
+
277
+ result: dict = {
278
+ "equivalent": len(differing) == 0,
279
+ "expression1": req.expression1,
280
+ "expression2": req.expression2,
281
+ }
282
+ if differing:
283
+ result["differing_rows"] = differing[:10]
284
+ result["total_differing"] = len(differing)
285
+
286
+ _cache_set(cache_key, result, ttl=86400)
287
+ response.headers["X-Cache"] = "MISS"
288
+ return result
289
+
290
+
291
+ @app.post("/satisfiable")
292
+ def satisfiable(req: SatisfiableRequest, request: Request, response: Response):
293
+ _check_auth(request)
294
+
295
+ cache_key = _cache_key("satisfiable", req.expression)
296
+ cached = _cache_get(cache_key)
297
+ if cached:
298
+ response.headers["X-Cache"] = "HIT"
299
+ return cached
300
+
301
+ error = validate(req.expression)
302
+ if error:
303
+ raise HTTPException(status_code=422, detail={"error": "invalid_expression", "message": error, "expression": req.expression})
304
+
305
+ table, _ = _evaluate(req.expression)
306
+ result: dict = {"satisfiable": table.satisfiable, "expression": req.expression}
307
+ if table.satisfiable:
308
+ first = table.rows[table.minterms[0]]
309
+ result["example"] = {**first.inputs, "output": first.output}
310
+
311
+ _cache_set(cache_key, result, ttl=86400)
312
+ response.headers["X-Cache"] = "MISS"
313
+ return result
314
+
315
+
316
+ @app.post("/check-rules")
317
+ def check_rules(req: CheckRulesRequest, request: Request, response: Response):
318
+ _check_auth(request)
319
+
320
+ cache_key = _cache_key("check-rules", *sorted(req.rules))
321
+ cached = _cache_get(cache_key)
322
+ if cached:
323
+ response.headers["X-Cache"] = "HIT"
324
+ return cached
325
+
326
+ from mcp_server.server import check_prompt_logic
327
+ result = check_prompt_logic(req.rules)
328
+
329
+ _cache_set(cache_key, result, ttl=3600)
330
+ response.headers["X-Cache"] = "MISS"
331
+ return result
332
+
333
+
334
+ @app.post("/nl/ask")
335
+ def nl_ask(req: NLAskRequest, request: Request, response: Response):
336
+ _check_auth(request)
337
+
338
+ cache_key = _cache_key("nl-ask", req.sentence, req.provider, req.model or "")
339
+ cached = _cache_get(cache_key)
340
+ if cached:
341
+ response.headers["X-Cache"] = "HIT"
342
+ return cached
343
+
344
+ try:
345
+ from nl.nl import ask
346
+ prov = _build_provider(req.provider, req.api_key, req.model, req.base_url)
347
+ result = ask(req.sentence, provider=prov)
348
+ except ValueError as e:
349
+ raise HTTPException(status_code=422, detail={"error": "parse_failed", "message": str(e)})
350
+ except Exception as e:
351
+ raise HTTPException(status_code=500, detail={"error": "internal", "message": str(e)})
352
+
353
+ data = {
354
+ "input": result.input_sentence,
355
+ "expression": result.expression,
356
+ "variables": result.variables,
357
+ "minimal": result.minimal,
358
+ "satisfiable": result.satisfiable,
359
+ "tautology": result.tautology,
360
+ "contradiction": result.contradiction,
361
+ "minterms": result.minterms,
362
+ "maxterms": result.maxterms,
363
+ "explanation": result.explanation,
364
+ "rows": result.rows,
365
+ }
366
+
367
+ _cache_set(cache_key, data, ttl=3600)
368
+ response.headers["X-Cache"] = "MISS"
369
+ return data
370
+
371
+
372
+ @app.post("/nl/check-rules")
373
+ def nl_check_rules(req: NLCheckRulesRequest, request: Request, response: Response):
374
+ _check_auth(request)
375
+
376
+ try:
377
+ from nl.nl import check_rules as _check_rules
378
+ prov = _build_provider(req.provider, req.api_key, req.model, req.base_url)
379
+ result = _check_rules(req.rules, provider=prov)
380
+ except ValueError as e:
381
+ raise HTTPException(status_code=422, detail={"error": "parse_failed", "message": str(e)})
382
+ except Exception as e:
383
+ raise HTTPException(status_code=500, detail={"error": "internal", "message": str(e)})
384
+
385
+ response.headers["X-Cache"] = "MISS"
386
+ return result
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: boolean-algebra-engine
3
+ Version: 0.1.0
4
+ Summary: Boolean algebra engine — evaluate expressions, generate truth tables, synthesize minimal forms
5
+ Author-email: Aditya Shrivastava <adityars.work@gmail.com>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/Shrivastava-Aditya/boolean-algebra-engine-python
8
+ Project-URL: Repository, https://github.com/Shrivastava-Aditya/boolean-algebra-engine-python
9
+ Project-URL: Issues, https://github.com/Shrivastava-Aditya/boolean-algebra-engine-python/issues
10
+ Keywords: boolean,algebra,logic,truth-table,quine-mccluskey,digital-logic
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Education
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Provides-Extra: cli
25
+ Requires-Dist: typer>=0.12.0; extra == "cli"
26
+ Requires-Dist: rich>=13.0.0; extra == "cli"
27
+ Provides-Extra: mcp
28
+ Requires-Dist: mcp[cli]>=1.0.0; extra == "mcp"
29
+ Provides-Extra: nl-anthropic
30
+ Requires-Dist: anthropic>=0.50.0; extra == "nl-anthropic"
31
+ Provides-Extra: nl-openai
32
+ Requires-Dist: openai>=1.0.0; extra == "nl-openai"
33
+ Provides-Extra: nl
34
+ Requires-Dist: anthropic>=0.50.0; extra == "nl"
35
+ Provides-Extra: api
36
+ Requires-Dist: fastapi>=0.100.0; extra == "api"
37
+ Requires-Dist: uvicorn>=0.20.0; extra == "api"
38
+ Provides-Extra: api-cache
39
+ Requires-Dist: fastapi>=0.100.0; extra == "api-cache"
40
+ Requires-Dist: uvicorn>=0.20.0; extra == "api-cache"
41
+ Requires-Dist: redis>=5.0.0; extra == "api-cache"
42
+ Provides-Extra: dev
43
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
44
+ Requires-Dist: httpx>=0.24.0; extra == "dev"
45
+ Dynamic: license-file
46
+
47
+ # boolean-algebra-engine-python
48
+
49
+ A deterministic boolean algebra engine — evaluates expressions, generates truth tables, synthesises minimal forms, and verifies logical consistency.
50
+
51
+ Forked from [boolean-algebra-java](https://github.com/Shrivastava-Aditya/boolean-algebra-java) — original Java implementation written during placement season.
52
+
53
+ ---
54
+
55
+ ## What it does
56
+
57
+ **Forward:** expression → full truth table, exhaustive 2^n evaluation, exact.
58
+
59
+ **Inverse:** truth table → minimal boolean expression via Quine-McCluskey.
60
+
61
+ **Verification:** satisfiability, contradiction, tautology, equivalence, pairwise conflict detection across rule sets.
62
+
63
+ ---
64
+
65
+ ## Operators
66
+
67
+ | Symbol | Operation | Precedence |
68
+ |--------|-----------|------------|
69
+ | `!` | NOT | 4 (highest) |
70
+ | `.` | AND | 3 |
71
+ | `^` | XOR | 2 |
72
+ | `+` | OR | 1 (lowest) |
73
+
74
+ Variables: uppercase `A`–`Z`. Parentheses override precedence.
75
+
76
+ ---
77
+
78
+ ## Architecture
79
+
80
+ ```
81
+ ┌──────────────────────────────────────────────────────┐
82
+ │ Interface Layer │
83
+ │ CLI/REPL MCP Server REST API Streamlit UI │
84
+ └───────────────────────┬──────────────────────────────┘
85
+
86
+ ┌───────────────────────┴──────────────────────────────┐
87
+ │ NL Layer │
88
+ │ plain English → expression → plain English │
89
+ │ Anthropic · OpenAI · Ollama · OpenAI-compat │
90
+ └───────────────────────┬──────────────────────────────┘
91
+
92
+ ┌───────────────────────┴──────────────────────────────┐
93
+ │ Core Engine │
94
+ │ parser (shunting-yard) → evaluator (prefix stack) │
95
+ │ → synthesizer (Quine-McCluskey)│
96
+ └───────────────────────┬──────────────────────────────┘
97
+
98
+ ┌───────────────────────┴──────────────────────────────┐
99
+ │ Acceleration Layer (planned) │
100
+ │ numpy · CUDA · Redis │
101
+ └──────────────────────────────────────────────────────┘
102
+ ```
103
+
104
+ `core/` has zero external dependencies. Every layer above is a thin wrapper. Independently deployable, independently testable.
105
+
106
+ ---
107
+
108
+ ## Project structure
109
+
110
+ ```
111
+ core/
112
+ models.py TruthTable, TruthTableRow, PerformanceMetrics
113
+ parser.py Shunting-yard — infix → prefix, validation, variable extraction
114
+ evaluator.py Prefix stack evaluator — exhaustive 2^n row enumeration
115
+ synthesizer.py Quine-McCluskey — truth table → minimal SOP expression
116
+
117
+ mcp_server/
118
+ server.py 5 tools for agent integration (evaluate, simplify,
119
+ equivalent, satisfiable, check_prompt_logic)
120
+
121
+ api/
122
+ routes.py FastAPI — 7 endpoints, Redis cache, optional auth
123
+
124
+ nl/
125
+ nl.py Provider abstraction — Anthropic, OpenAI, Ollama, OpenAI-compat
126
+
127
+ cli/
128
+ main.py typer + rich — REPL and one-shot, all output formats
129
+
130
+ ui/
131
+ app.py Streamlit — Expression, Rule Auditor, Plain English modes
132
+
133
+ tests/ 90 tests — unit, integration, edge cases, round-trips
134
+
135
+ benchmark.py LLM hallucination benchmark — engine as oracle
136
+ visualisations.ipynb Colab notebook — complexity vs variables, conflict graph
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Quickstart
142
+
143
+ ```bash
144
+ git clone https://github.com/Shrivastava-Aditya/boolean-algebra-engine-python
145
+ cd boolean-algebra-engine-python
146
+ pip install -e ".[dev]"
147
+ python3 -m pytest tests/
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Core usage
153
+
154
+ ```python
155
+ from core.evaluator import evaluate
156
+ from core.synthesizer import synthesize
157
+
158
+ table, _ = evaluate("A.(B+C)")
159
+ print(table.variables) # ['A', 'B', 'C']
160
+ print(table.minterms) # [5, 6, 7]
161
+ print(table.satisfiable) # True
162
+
163
+ minimal, _ = synthesize(table)
164
+ print(minimal) # A.C+A.B
165
+ ```
166
+
167
+ ---
168
+
169
+ ## check_prompt_logic
170
+
171
+ ```python
172
+ from mcp_server.server import check_prompt_logic
173
+
174
+ result = check_prompt_logic([
175
+ "A.B", # approve: good credit AND income verified
176
+ "C", # approve: collateral exists
177
+ "!A", # reject: bad credit
178
+ "!B.!C", # reject: no income AND no collateral
179
+ ])
180
+ print(result["summary"])
181
+ # {'total': 4, 'contradictions': 0, 'conflicting_pairs': 3}
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Benchmark
187
+
188
+ Measures LLM hallucination rate on boolean logic. Engine is the oracle — ground truth by exhaustive enumeration, no human labelers.
189
+
190
+ ```bash
191
+ ollama pull tinyllama
192
+ python3 benchmark.py
193
+ ```
194
+
195
+ First result: tinyllama (1B) · 3 variables · 10 cases · **40% hallucination rate**.
196
+
197
+ See `FAILURES.md` for real-world severity analysis of each failure.
198
+
199
+ ---
200
+
201
+ ## Branches
202
+
203
+ | Branch | What |
204
+ |---|---|
205
+ | `master` | Project — engine, interfaces, tests |
206
+ | `product-readme` | Product brief — what it proves, what it's for |
207
+ | `benchmark` | Benchmark methodology, multi-model results (in progress) |
208
+
209
+ ---
210
+
211
+ ## Related
212
+
213
+ - [boolean-algebra-java](https://github.com/Shrivastava-Aditya/boolean-algebra-java) — original Java version
@@ -0,0 +1,19 @@
1
+ api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ api/routes.py,sha256=MUtb2if-jYhXOT2C5GD5mC6EgACawNTANtCPS57UnYc,12646
3
+ boolean_algebra_engine-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
4
+ cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ cli/main.py,sha256=yU6Syy61qvtFgVGQADOUhjPFqjRO-D3IRqJE9n4berM,16055
6
+ core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ core/evaluator.py,sha256=BqLvyb2JkF7WPmwPZYP1bzqbzLr7G8QJAAxELAypfNU,2655
8
+ core/models.py,sha256=FTepIO8GFxzyRNScprYqUOzuYd10Ta1iTcdHjwMywTo,3255
9
+ core/parser.py,sha256=cDJdlUhTliSZZw6VxlgKe7O_D9YEACsWGXfRviIGp-s,2364
10
+ core/synthesizer.py,sha256=o044C3G9Az1ZCgLFaU-0g68CJvNtZMWW-cBRF-Ye6Ok,5648
11
+ mcp_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ mcp_server/server.py,sha256=-3tyFeAndsCwNY-0pNnhA4xm_DBcAoIQPBBwwx5tNF4,8417
13
+ nl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ nl/nl.py,sha256=YdJo4rMMbTFPFNgyIXDNMn0zLICzt0av1bkx8NiilTU,14742
15
+ boolean_algebra_engine-0.1.0.dist-info/METADATA,sha256=Anwq8pP8wjvFHQ11riofLqaEeSBIyZBuV01VauXsbZU,7890
16
+ boolean_algebra_engine-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
17
+ boolean_algebra_engine-0.1.0.dist-info/entry_points.txt,sha256=-iwEp4864Mi7hNnYR1L1p5NxXEhSqJNn3X2mt_92nlk,42
18
+ boolean_algebra_engine-0.1.0.dist-info/top_level.txt,sha256=CDi0ytQMStd1Hy9rROqsiRPzWUS3mN5P8-Jr7ztlVFI,27
19
+ boolean_algebra_engine-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ boolcalc = cli.main:app