478 in |
474 in |
479 tac (instantiate' [] [SOME (cterm_of thy ACG), SOME (cterm_of thy mfuns)] st) |
475 tac (instantiate' [] [SOME (cterm_of thy ACG), SOME (cterm_of thy mfuns)] st) |
480 end |
476 end |
481 |
477 |
482 |
478 |
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 (* Faster implementation of transitive closures *) |
|
494 |
|
495 (* sedge: Only relevant edges. Qtrees have separate value for 0 *) |
|
496 datatype sedge = LESS | LEQ | BOTH |
|
497 |
|
498 |
|
499 |
|
500 datatype key = KHere | K0 of key | K1 of key |
|
501 |
|
502 datatype 'a stree = |
|
503 sLeaf of 'a |
|
504 | sBranch of ('a * 'a stree * 'a stree) |
|
505 |
|
506 (* |
|
507 fun lookup (sLeaf x) KHere = x |
|
508 | lookup (sBranch x s t) KHere = x |
|
509 | lookup (sBranch x s t) (K0 k) = lookup s k |
|
510 | lookup (sBranch x s t) (K1 k) = lookup t k |
|
511 | lookup _ _ = raise Match |
|
512 *) |
|
513 |
|
514 datatype 'a qtree = |
|
515 QEmpty |
|
516 | QNode of 'a |
|
517 | QQuad of ('a qtree * 'a qtree * 'a qtree * 'a qtree) |
|
518 |
|
519 fun qlookup z QEmpty k l = z |
|
520 | qlookup z (QNode S) k l = S |
|
521 | qlookup z (QQuad (a, b, c, d)) (K0 k) (K0 l) = qlookup z a k l |
|
522 | qlookup z (QQuad (a, b, c, d)) (K0 k) (K1 l) = qlookup z b k l |
|
523 | qlookup z (QQuad (a, b, c, d)) (K1 k) (K0 l) = qlookup z c k l |
|
524 | qlookup z (QQuad (a, b, c, d)) (K1 k) (K1 l) = qlookup z d k l |
|
525 | qlookup _ _ _ _ = raise Match |
|
526 |
|
527 |
|
528 |
|
529 (* Size-change graphs *) |
|
530 |
|
531 type |
|
532 scg = sedge qtree |
|
533 |
|
534 |
|
535 (* addition of single edges *) |
|
536 fun add_sedge BOTH _ = BOTH |
|
537 | add_sedge LESS LESS = LESS |
|
538 | add_sedge LESS _ = BOTH |
|
539 | add_sedge LEQ LEQ = LEQ |
|
540 | add_sedge LEQ _ = BOTH |
|
541 |
|
542 fun mult_sedge LESS _ = LESS |
|
543 | mult_sedge _ LESS = LESS |
|
544 | mult_sedge LEQ x = x |
|
545 | mult_sedge BOTH _ = BOTH |
|
546 |
|
547 fun subsumes_edge LESS LESS = true |
|
548 | subsumes_edge LEQ _ = true |
|
549 | subsumes_edge _ _ = false |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 (* subsumes_SCG G H := G contains strictly less estimations than H *) |
|
555 fun subsumes_SCG (QEmpty : scg) (H : scg) = true |
|
556 | subsumes_SCG (QQuad (a, b, c, d)) (QQuad (e,f,g,h)) = |
|
557 (subsumes_SCG a e) andalso (subsumes_SCG b f) |
|
558 andalso (subsumes_SCG c g) andalso (subsumes_SCG d h) |
|
559 | subsumes_SCG (QNode e) (QNode e') = subsumes_edge e e' |
|
560 | subsumes_SCG _ QEmpty = false |
|
561 | subsumes_SCG _ _ = raise Match |
|
562 |
|
563 |
|
564 (* managing lists of SCGs. *) |
|
565 |
|
566 (* |
|
567 Graphs are partially ordered. A list of graphs has the invariant that no G,H with G <= H. |
|
568 To maintain this when adding a new graph G, check |
|
569 (1) G <= H for some H in l => Do nothing |
|
570 (2) has to be added. Then, all H <= G can be removed. |
|
571 |
|
572 We can check (2) first, removing all smaller graphs. |
|
573 If we could remove at least one, just add G in the end (Invariant!). |
|
574 Otherwise, check again, if G needs to be added at all. |
|
575 |
|
576 OTOH, doing (1) first is probably better, because it does not produce garbage unless needed. |
|
577 |
|
578 The definition is tail-recursive. Order is not preserved (unneccessary). |
|
579 *) |
|
580 |
|
581 |
|
582 |
|
583 fun add_scg' G Hs = (* returns a flag indicating if the graph was really added *) |
|
584 if exists (fn H => subsumes_SCG H G) Hs then (false, Hs) (* redundant addition *) |
|
585 else (true, G :: remove (uncurry subsumes_SCG) G Hs) (* remove all new redundancy and add G *) |
|
586 (* NB: This does the second checks twice :-( *) |
|
587 |
|
588 (* Simpler version *) |
|
589 fun add_scg' G Hs = (not (member (op =) Hs G), insert (op =) G Hs) |
|
590 |
|
591 |
|
592 val add_scg = snd oo add_scg' (* without flag *) |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 (* quadtrees *) |
|
599 |
|
600 fun keylen 0 = 0 |
|
601 | keylen n = (keylen (n div 2)) + 1 |
|
602 |
|
603 fun mk_key 0 _ = KHere |
|
604 | mk_key l m = if m mod 2 = 0 |
|
605 then K0 (mk_key (l - 1) (m div 2)) |
|
606 else K1 (mk_key (l - 1) (m div 2)) |
|
607 |
|
608 |
|
609 fun qupdate f KHere KHere n = f n |
|
610 | qupdate f (K0 k) (K0 k') (QQuad (a, b, c, d)) = QQuad (qupdate f k k' a, b, c, d) |
|
611 | qupdate f (K0 k) (K1 k') (QQuad (a, b, c, d)) = QQuad (a, qupdate f k k' b, c, d) |
|
612 | qupdate f (K1 k) (K0 k') (QQuad (a, b, c, d)) = QQuad (a, b, qupdate f k k' c, d) |
|
613 | qupdate f (K1 k) (K1 k') (QQuad (a, b, c, d)) = QQuad (a, b, c, qupdate f k k' d) |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 (* quadtree composition *) |
|
623 |
|
624 fun qadd A QEmpty q = q |
|
625 | qadd A q QEmpty = q |
|
626 | qadd A (QNode s) (QNode t) = QNode (A s t) |
|
627 | qadd A (QQuad (a, b, c, d)) (QQuad (e, f, g, h)) = |
|
628 QQuad (qadd A a e, qadd A b f, qadd A c g, qadd A d h) |
|
629 | qadd _ _ _ = raise Match |
|
630 |
|
631 |
|
632 fun qmult A m QEmpty H = QEmpty |
|
633 | qmult A m G QEmpty = QEmpty |
|
634 | qmult A m (QNode x) (QNode y) = QNode (m x y) |
|
635 | qmult A m (QQuad (a, b, c, d)) (QQuad (e, f, g, h)) = |
|
636 QQuad ((qadd A (qmult A m a e) (qmult A m b g)), |
|
637 (qadd A (qmult A m a f) (qmult A m b h)), |
|
638 (qadd A (qmult A m c e) (qmult A m d g)), |
|
639 (qadd A (qmult A m c f) (qmult A m d h))) |
|
640 | qmult _ _ _ _ = raise Match |
|
641 |
|
642 |
|
643 val (mult_scg : scg -> scg -> scg) = qmult add_sedge mult_sedge |
|
644 |
|
645 (* Misc notes: |
|
646 |
|
647 - When building the tcl: Check on addition and raise FAIL if the property is not true... (pract) |
|
648 |
|
649 - Can we reduce subsumption checking by some integer fingerprints? |
|
650 |
|
651 Number of edges: LESS(G) LEQ(G) |
|
652 G <= H ==> E(G) <= E(H) |
|
653 |
|
654 |
|
655 |
|
656 How to check: |
|
657 |
|
658 For each pair of adjacent edges: n -> m -> q |
|
659 compute all product SCGS and check if they are subsumed by something in the tcl. |
|
660 |
|
661 all midnode m: all fromnode n: all tonode q: alledges (n,m) e: alledges (m,q) e': subsumes (e*e') (edgs m,q) |
|
662 |
|
663 This is still quite a lot of checking... But: no garbage, just inspection. Can probably be done in logic. |
|
664 |
|
665 *) |
|
666 |
|
667 |
|
668 |
|
669 (* Operations on lists: These preserve the invariants *) |
|
670 fun SCGs_mult Gs Hs = fold (fn (G,H) => add_scg (mult_scg G H)) (product Gs Hs) [] |
|
671 val SCGs_plus = fold add_scg |
|
672 |
|
673 |
|
674 fun add_scgs Gs Hs = fold_rev (fn G => fn (Xs,As) => |
|
675 let val (b, Xs') = add_scg' G Xs |
|
676 in (Xs', if b then G::As else As) end) |
|
677 Gs (Hs,[]) |
|
678 |
|
679 (* Transitive Closure for lists of SCGs *) |
|
680 fun SCGs_tcl Gs = |
|
681 let |
|
682 fun aux S [] = S |
|
683 | aux S (H::HS) = |
|
684 let val (S', Ns) = add_scgs (map (mult_scg H) Gs) S |
|
685 in aux S' (SCGs_plus Ns HS) end |
|
686 in |
|
687 aux Gs Gs |
|
688 end |
|
689 |
|
690 |
|
691 |
|
692 (* Kleene algorithm: DP version, with imperative array... *) |
|
693 |
|
694 |
|
695 |
|
696 |
|
697 (* Terrible imperative stuff: *) |
|
698 type matrix = scg list array array |
|
699 |
|
700 fun mupdate i j f M = |
|
701 let |
|
702 val row = Array.sub (M, i) |
|
703 val x = Array.sub (row, j) |
|
704 in |
|
705 Array.update (row, j, f x) |
|
706 end |
|
707 |
|
708 fun mget i j M = Array.sub(Array.sub(M,i),j) |
|
709 |
|
710 fun print_scg (x : scg) = Output.warning (PolyML.makestring x); |
|
711 |
|
712 |
|
713 fun kleene add mult tcl M = |
|
714 let |
|
715 val n = Array.length M |
|
716 |
|
717 fun update Mkk i j k = |
|
718 let |
|
719 val Mik = mget i k M |
|
720 val Mkj = mget k j M |
|
721 in |
|
722 mupdate i j (fn X => X |> add (mult Mik (mult Mkk Mkj)) |
|
723 |> add (mult Mik Mkj)) |
|
724 M |
|
725 end |
|
726 |
|
727 fun step k () = |
|
728 let |
|
729 val _ = mupdate k k tcl M |
|
730 val Mkk = mget k k M |
|
731 |
|
732 val no_k = filter_out (fn i => i = k) (0 upto (n - 1)) |
|
733 val _ = fold (fn i => fold (fn j => K (update Mkk i j k)) no_k) no_k () |
|
734 |
|
735 val _ = fold (fn i => K (update Mkk i k k)) no_k () |
|
736 |
|
737 val _ = fold (fn j => K (update Mkk k j k)) no_k () |
|
738 in |
|
739 () |
|
740 end |
|
741 in |
|
742 fold step (0 upto (n - 1)) () |
|
743 end |
|
744 |
|
745 val (SCGs_kleene : matrix -> unit) = kleene SCGs_plus SCGs_mult SCGs_tcl |
|
746 |
|
747 |
|
748 fun andop x y = x andalso y |
|
749 fun orop x y = x orelse y |
|
750 |
|
751 fun array2 n x = Array.tabulate (n, (fn i => Array.array (n, x))) |
|
752 |
|
753 (*val bool_kleene = kleene orop andop I |
|
754 |
|
755 |
|
756 fun test_bool () = |
|
757 let |
|
758 val M = array2 2 false |
|
759 val _ = mupdate 0 1 (K true) M |
|
760 val _ = mupdate 1 0 (K true) M |
|
761 val _ = bool_kleene M |
|
762 in |
|
763 M |
|
764 end |
|
765 *) |
|
766 |
|
767 (* Standard 2-2-Size-change graphs *) |
|
768 |
|
769 val swap = QQuad(QEmpty, QNode LEQ, |
|
770 QNode LEQ, QEmpty) |
|
771 |
|
772 val swapRTop = QQuad(QNode LESS, QNode LEQ, |
|
773 QNode LEQ, QEmpty) |
|
774 |
|
775 val BTopRBot = QQuad(QNode LEQ, QEmpty, |
|
776 QEmpty, QNode LESS) |
|
777 |
|
778 val RTopBBot = QQuad(QNode LESS, QEmpty, |
|
779 QEmpty, QNode LEQ) |
|
780 |
|
781 val R2Straight = QQuad(QNode LESS, QEmpty, |
|
782 QEmpty, QNode LESS) |
|
783 |
|
784 val R3StraightUp = QQuad(QNode LESS, QEmpty, |
|
785 QNode LESS, QNode LESS) |
|
786 |
|
787 val R3StraightDn = QQuad(QNode LESS, QNode LESS, |
|
788 QEmpty, QNode LESS) |
|
789 |
|
790 |
|
791 |
|
792 |
|
793 val diag = QQuad(QEmpty, QNode LEQ, |
|
794 QEmpty, QEmpty) |
|
795 |
|
796 val straight = QQuad(QNode LEQ, QEmpty, |
|
797 QEmpty, QEmpty) |
|
798 |
|
799 |
|
800 |
|
801 val R467913 = ([R2Straight, R3StraightDn, R3StraightDn] @ replicate 11 R2Straight @ [R3StraightUp, R3StraightUp]) |
|
802 |> map single |
|
803 |
|
804 val swapPos = [(0,8),(0,9),(0,10),(3,4),(3,5),(11,12)] |
|
805 |
|
806 val BRPos = (map (pair 5) (0 :: (3 upto 7))) |
|
807 @ (map (pair 8) [8,9,11,12,13]) |
|
808 @ (map (pair 12) [8,9,11,12,13]) |
|
809 |
|
810 val RBPos = map (pair 10) (3 upto 10) |
|
811 |
|
812 fun afold f arr x = Array.foldl (uncurry f) x arr |
|
813 |
|
814 fun msize M = afold (afold (curry op + o length)) M 0 |
|
815 |
|
816 fun TestM () = |
|
817 let |
|
818 val M = array2 16 ([] : scg list) |
|
819 val _ = Array.update (M, 4, Array.fromList R467913) |
|
820 val _ = Array.update (M, 6, Array.fromList R467913) |
|
821 val _ = Array.update (M, 7, Array.fromList R467913) |
|
822 val _ = Array.update (M, 9, Array.fromList R467913) |
|
823 val _ = Array.update (M, 13, Array.fromList R467913) |
|
824 |
|
825 val _ = map (fn (i,j) => mupdate i j (K [swap]) M) swapPos |
|
826 val _ = map (fn (i,j) => mupdate i j (K [BTopRBot]) M) BRPos |
|
827 val _ = map (fn (i,j) => mupdate i j (K [RTopBBot]) M) RBPos |
|
828 |
|
829 val _ = mupdate 1 14 (K [swapRTop]) M |
|
830 val _ = mupdate 2 15 (K [swapRTop]) M |
|
831 |
|
832 val G = [QQuad (QNode LEQ, QNode LESS, QEmpty, QNode LESS)] |
|
833 val _ = mupdate 5 1 (K G) M |
|
834 val _ = mupdate 8 2 (K G) M |
|
835 val _ = mupdate 12 2 (K G) M |
|
836 |
|
837 val G = [QQuad (QNode LESS, QEmpty, QNode LESS, QNode LEQ)] |
|
838 val _ = mupdate 10 14 (K G) M |
|
839 |
|
840 val G = [QQuad (QEmpty, QNode LEQ, QNode LESS, QNode LESS)] |
|
841 val _ = mupdate 14 1 (K G) M |
|
842 val _ = mupdate 14 2 (K G) M |
|
843 val _ = mupdate 15 1 (K G) M |
|
844 val _ = mupdate 15 2 (K G) M |
|
845 in |
|
846 M |
|
847 end |
|
848 |
|
849 |
|
850 |
|
851 |
|
852 |
|
853 fun add_edge x QEmpty = QNode x |
|
854 | add_edge x (QNode y) = QNode (add_sedge x y) |
|
855 |
|
856 |
|
857 fun sedge2ML (Const ("SCT_Definition.sedge.LESS", _)) = LESS |
|
858 | sedge2ML (Const ("SCT_Definition.sedge.LEQ", _)) = LEQ |
|
859 |
|
860 |
|
861 |
|
862 |
|
863 |
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 |
|
875 end |
479 end |
876 |
480 |
877 |
481 |
878 |
482 |
879 |
483 |