|
1 | 1 | from IPython.display import HTML, display |
2 | 2 | from utils import argmax, argmin |
3 | 3 | from games import TicTacToe, alphabeta_player, random_player, Fig52Extended, infinity |
| 4 | +from logic import parse_definite_clause, standardize_variables, unify, subst |
4 | 5 |
|
5 | 6 | _canvas = """ |
6 | 7 | <script type="text/javascript" src="./js/canvas.js"></script> |
@@ -526,3 +527,126 @@ def draw_graph(self): |
526 | 527 | self.text_n(alpha, x - self.l/2, y - self.l/10) |
527 | 528 | self.text_n(beta, x + self.l, y - self.l/10) |
528 | 529 | self.update() |
| 530 | + |
| 531 | + |
| 532 | +class Canvas_fol_bc_ask(Canvas): |
| 533 | + """fol_bc_ask() on HTML canvas |
| 534 | + """ |
| 535 | + def __init__(self, varname, kb, query, width=800, height=600, cid=None): |
| 536 | + Canvas.__init__(self, varname, width, height, cid) |
| 537 | + self.kb = kb |
| 538 | + self.query = query |
| 539 | + self.l = 1/20 |
| 540 | + self.b = 3*self.l |
| 541 | + bc_out = list(self.fol_bc_ask()) |
| 542 | + if len(bc_out) is 0: |
| 543 | + self.valid = False |
| 544 | + else: |
| 545 | + self.valid = True |
| 546 | + graph = bc_out[0][0][0] |
| 547 | + s = bc_out[0][1] |
| 548 | + while True: |
| 549 | + new_graph = subst(s, graph) |
| 550 | + if graph == new_graph: |
| 551 | + break |
| 552 | + graph = new_graph |
| 553 | + self.make_table(graph) |
| 554 | + self.context = None |
| 555 | + self.draw_table() |
| 556 | + |
| 557 | + def fol_bc_ask(self): |
| 558 | + KB = self.kb |
| 559 | + query = self.query |
| 560 | + def fol_bc_or(KB, goal, theta): |
| 561 | + for rule in KB.fetch_rules_for_goal(goal): |
| 562 | + lhs, rhs = parse_definite_clause(standardize_variables(rule)) |
| 563 | + for theta1 in fol_bc_and(KB, lhs, unify(rhs, goal, theta)): |
| 564 | + yield ([(goal, theta1[0])], theta1[1]) |
| 565 | + |
| 566 | + def fol_bc_and(KB, goals, theta): |
| 567 | + if theta is None: |
| 568 | + pass |
| 569 | + elif not goals: |
| 570 | + yield ([], theta) |
| 571 | + else: |
| 572 | + first, rest = goals[0], goals[1:] |
| 573 | + for theta1 in fol_bc_or(KB, subst(theta, first), theta): |
| 574 | + for theta2 in fol_bc_and(KB, rest, theta1[1]): |
| 575 | + yield (theta1[0] + theta2[0], theta2[1]) |
| 576 | + |
| 577 | + return fol_bc_or(KB, query, {}) |
| 578 | + |
| 579 | + def make_table(self, graph): |
| 580 | + table = [] |
| 581 | + pos = {} |
| 582 | + links = set() |
| 583 | + edges = set() |
| 584 | + |
| 585 | + def dfs(node, depth): |
| 586 | + if len(table) <= depth: |
| 587 | + table.append([]) |
| 588 | + pos = len(table[depth]) |
| 589 | + table[depth].append(node[0]) |
| 590 | + for child in node[1]: |
| 591 | + child_id = dfs(child, depth + 1) |
| 592 | + links.add(((depth, pos), child_id)) |
| 593 | + return (depth, pos) |
| 594 | + |
| 595 | + dfs(graph, 0) |
| 596 | + y_off = 0.85/len(table) |
| 597 | + for i, row in enumerate(table): |
| 598 | + x_off = 0.95/len(row) |
| 599 | + for j, node in enumerate(row): |
| 600 | + pos[(i, j)] = (0.025 + j*x_off + (x_off - self.b)/2, 0.025 + i*y_off + (y_off - self.l)/2) |
| 601 | + for p, c in links: |
| 602 | + x1, y1 = pos[p] |
| 603 | + x2, y2 = pos[c] |
| 604 | + edges.add((x1 + self.b/2, y1 + self.l, x2 + self.b/2, y2)) |
| 605 | + |
| 606 | + self.table = table |
| 607 | + self.pos = pos |
| 608 | + self.edges = edges |
| 609 | + |
| 610 | + def mouse_click(self, x, y): |
| 611 | + x, y = x/self.width, y/self.height |
| 612 | + for node in self.pos: |
| 613 | + xs, ys = self.pos[node] |
| 614 | + xe, ye = xs + self.b, ys + self.l |
| 615 | + if xs <= x <= xe and ys <= y <= ye: |
| 616 | + self.context = node |
| 617 | + break |
| 618 | + self.draw_table() |
| 619 | + |
| 620 | + def draw_table(self): |
| 621 | + self.clear() |
| 622 | + self.strokeWidth(3) |
| 623 | + self.stroke(0, 0, 0) |
| 624 | + self.font("12px Arial") |
| 625 | + if self.valid: |
| 626 | + # draw nodes |
| 627 | + for i, j in self.pos: |
| 628 | + x, y = self.pos[(i, j)] |
| 629 | + self.fill(200, 200, 200) |
| 630 | + self.rect_n(x, y, self.b, self.l) |
| 631 | + self.line_n(x, y, x + self.b, y) |
| 632 | + self.line_n(x, y, x, y + self.l) |
| 633 | + self.line_n(x + self.b, y, x + self.b, y + self.l) |
| 634 | + self.line_n(x, y + self.l, x + self.b, y + self.l) |
| 635 | + self.fill(0, 0, 0) |
| 636 | + self.text_n(self.table[i][j], x + 0.01, y + self.l - 0.01) |
| 637 | + #draw edges |
| 638 | + for x1, y1, x2, y2 in self.edges: |
| 639 | + self.line_n(x1, y1, x2, y2) |
| 640 | + else: |
| 641 | + self.fill(255, 0, 0) |
| 642 | + self.rect_n(0, 0, 1, 1) |
| 643 | + # text area |
| 644 | + self.fill(255, 255, 255) |
| 645 | + self.rect_n(0, 0.9, 1, 0.1) |
| 646 | + self.strokeWidth(5) |
| 647 | + self.stroke(0, 0, 0) |
| 648 | + self.line_n(0, 0.9, 1, 0.9) |
| 649 | + self.font("22px Arial") |
| 650 | + self.fill(0, 0, 0) |
| 651 | + self.text_n(self.table[self.context[0]][self.context[1]] if self.context else "Click for text", 0.025, 0.975) |
| 652 | + self.update() |
0 commit comments