Files changed (1) hide show
  1. app.py +84 -0
app.py CHANGED
@@ -299,6 +299,90 @@ class BasicAgent:
299
  return m.group(1).strip()
300
 
301
  return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
  def _answer_from_op_table(self, question: str, table_text: str):
304
  parsed = self._parse_op_table_from_text(table_text)
 
299
  return m.group(1).strip()
300
 
301
  return None
302
+
303
+ def _parse_op_table_from_text(self, text: str):
304
+ """
305
+ Parse a Markdown table like:
306
+ |*|a|b|c|
307
+ |---|---|---|---|
308
+ |a|a|b|c|
309
+ |b|b|c|a|
310
+ |c|c|a|b|
311
+ Returns (S, T) where S is a list of symbols, and
312
+ T is a dict-of-dicts T[row][col] = result.
313
+ """
314
+ if not text:
315
+ return None
316
+
317
+ lines = [ln.strip() for ln in text.splitlines() if "|" in ln]
318
+ if not lines:
319
+ return None
320
+
321
+ # find header line (the one starting with |*|)
322
+ header = None
323
+ for ln in lines:
324
+ cells = [c.strip() for c in ln.strip("|").split("|")]
325
+ if cells and cells[0] in {"*", "∗"}:
326
+ header = cells
327
+ break
328
+ if not header:
329
+ return None
330
+
331
+ symbols = header[1:]
332
+ if not symbols:
333
+ return None
334
+
335
+ # build table from subsequent lines that look like rows
336
+ T = {r: {} for r in symbols}
337
+ for ln in lines:
338
+ cells = [c.strip() for c in ln.strip("|").split("|")]
339
+ if not cells or cells[0] not in symbols:
340
+ continue
341
+ row = cells[0]
342
+ vals = cells[1:]
343
+ if len(vals) != len(symbols):
344
+ continue
345
+ for col, val in zip(symbols, vals):
346
+ T[row][col] = val
347
+
348
+ # sanity: ensure all rows present
349
+ if any(r not in T or len(T[r]) != len(symbols) for r in symbols):
350
+ return None
351
+
352
+ return symbols, T
353
+
354
+ def _find_identity(self, S, T):
355
+ # two-sided identity e satisfies e*x = x and x*e = x for all x
356
+ for e in S:
357
+ if all(T[e][x] == x for x in S) and all(T[x][e] == x for x in S):
358
+ return e
359
+ return None
360
+
361
+ def _is_commutative(self, S, T):
362
+ for x in S:
363
+ for y in S:
364
+ if T[x][y] != T[y][x]:
365
+ return False
366
+ return True
367
+
368
+ def _is_associative(self, S, T):
369
+ for x in S:
370
+ for y in S:
371
+ for z in S:
372
+ if T[T[x][y]][z] != T[x][T[y][z]]:
373
+ return False
374
+ return True
375
+
376
+ def _inverse_of(self, x, S, T, e):
377
+ if e is None:
378
+ return None
379
+ for y in S:
380
+ if T[x][y] == e and T[y][x] == e:
381
+ return y
382
+ return None
383
+
384
+ def _idempotents(self, S, T):
385
+ return [x for x in S if T[x][x] == x]
386
 
387
  def _answer_from_op_table(self, question: str, table_text: str):
388
  parsed = self._parse_op_table_from_text(table_text)