src/Tools/Metis/src/KnuthBendixOrder.sml
changeset 39353 7f11d833d65b
parent 23510 4521fead5609
parent 39349 2d0a4361c3ef
child 39443 e330437cd22a
equal deleted inserted replaced
39313:41ce0b56d858 39353:7f11d833d65b
     1 (* ========================================================================= *)
     1 (* ========================================================================= *)
     2 (* KNUTH-BENDIX TERM ORDERING CONSTRAINTS                                    *)
     2 (* KNUTH-BENDIX TERM ORDERING CONSTRAINTS                                    *)
     3 (* Copyright (c) 2002-2006 Joe Hurd, distributed under the BSD License *)
     3 (* Copyright (c) 2002-2006 Joe Hurd, distributed under the BSD License       *)
     4 (* ========================================================================= *)
     4 (* ========================================================================= *)
     5 
     5 
     6 structure KnuthBendixOrder :> KnuthBendixOrder =
     6 structure KnuthBendixOrder :> KnuthBendixOrder =
     7 struct
     7 struct
     8 
     8 
    10 
    10 
    11 (* ------------------------------------------------------------------------- *)
    11 (* ------------------------------------------------------------------------- *)
    12 (* Helper functions.                                                         *)
    12 (* Helper functions.                                                         *)
    13 (* ------------------------------------------------------------------------- *)
    13 (* ------------------------------------------------------------------------- *)
    14 
    14 
    15 fun firstNotEqual f l =
    15 fun notEqualTerm (x,y) = not (Term.equal x y);
    16     case List.find op<> l of
    16 
       
    17 fun firstNotEqualTerm f l =
       
    18     case List.find notEqualTerm l of
    17       SOME (x,y) => f x y
    19       SOME (x,y) => f x y
    18     | NONE => raise Bug "firstNotEqual";
    20     | NONE => raise Bug "firstNotEqualTerm";
    19 
    21 
    20 (* ------------------------------------------------------------------------- *)
    22 (* ------------------------------------------------------------------------- *)
    21 (* The weight of all constants must be at least 1, and there must be at most *)
    23 (* The weight of all constants must be at least 1, and there must be at most *)
    22 (* one unary function with weight 0.                                         *)
    24 (* one unary function with weight 0.                                         *)
    23 (* ------------------------------------------------------------------------- *)
    25 (* ------------------------------------------------------------------------- *)
    34 
    36 
    35 val arityPrecedence : Term.function * Term.function -> order =
    37 val arityPrecedence : Term.function * Term.function -> order =
    36     fn ((f1,n1),(f2,n2)) =>
    38     fn ((f1,n1),(f2,n2)) =>
    37        case Int.compare (n1,n2) of
    39        case Int.compare (n1,n2) of
    38          LESS => LESS
    40          LESS => LESS
    39        | EQUAL => String.compare (f1,f2)
    41        | EQUAL => Name.compare (f1,f2)
    40        | GREATER => GREATER;
    42        | GREATER => GREATER;
    41 
    43 
    42 (* The default order *)
    44 (* The default order *)
    43 
    45 
    44 val default = {weight = uniformWeight, precedence = arityPrecedence};
    46 val default = {weight = uniformWeight, precedence = arityPrecedence};
    60 fun weightIsZero (Weight (m,c)) = c = 0 andalso NameMap.null m;
    62 fun weightIsZero (Weight (m,c)) = c = 0 andalso NameMap.null m;
    61 
    63 
    62 fun weightNeg (Weight (m,c)) = Weight (NameMap.transform ~ m, ~c);
    64 fun weightNeg (Weight (m,c)) = Weight (NameMap.transform ~ m, ~c);
    63 
    65 
    64 local
    66 local
    65   fun add (n1,n2) =
    67   fun add ((_,n1),(_,n2)) =
    66       let
    68       let
    67         val n = n1 + n2
    69         val n = n1 + n2
    68       in
    70       in
    69         if n = 0 then NONE else SOME n
    71         if n = 0 then NONE else SOME n
    70       end;
    72       end;
    72   fun weightAdd (Weight (m1,c1)) (Weight (m2,c2)) =
    74   fun weightAdd (Weight (m1,c1)) (Weight (m2,c2)) =
    73       Weight (NameMap.union add m1 m2, c1 + c2);
    75       Weight (NameMap.union add m1 m2, c1 + c2);
    74 end;
    76 end;
    75 
    77 
    76 fun weightSubtract w1 w2 = weightAdd w1 (weightNeg w2);
    78 fun weightSubtract w1 w2 = weightAdd w1 (weightNeg w2);
    77 
       
    78 fun weightMult 0 _ = weightZero
       
    79   | weightMult 1 w = w
       
    80   | weightMult k (Weight (m,c)) =
       
    81     let
       
    82       fun mult n = k * n
       
    83     in
       
    84       Weight (NameMap.transform mult m, k * c)
       
    85     end;
       
    86 
    79 
    87 fun weightTerm weight =
    80 fun weightTerm weight =
    88     let
    81     let
    89       fun wt m c [] = Weight (m,c)
    82       fun wt m c [] = Weight (m,c)
    90         | wt m c (Term.Var v :: tms) =
    83         | wt m c (Term.Var v :: tms) =
    97           wt m (c + weight (f, length a)) (a @ tms)
    90           wt m (c + weight (f, length a)) (a @ tms)
    98     in
    91     in
    99       fn tm => wt weightEmpty ~1 [tm]
    92       fn tm => wt weightEmpty ~1 [tm]
   100     end;
    93     end;
   101 
    94 
   102 fun weightIsVar v (Weight (m,c)) =
       
   103     c = 0 andalso NameMap.size m = 1 andalso NameMap.peek m v = SOME 1;
       
   104 
       
   105 fun weightConst (Weight (_,c)) = c;
       
   106 
       
   107 fun weightVars (Weight (m,_)) = 
       
   108     NameMap.foldl (fn (v,_,s) => NameSet.add s v) NameSet.empty m;
       
   109 
       
   110 val weightsVars =
       
   111     List.foldl (fn (w,s) => NameSet.union (weightVars w) s) NameSet.empty;
       
   112 
       
   113 fun weightVarList w = NameSet.toList (weightVars w);
       
   114 
       
   115 fun weightNumVars (Weight (m,_)) = NameMap.size m;
       
   116 
       
   117 fun weightNumVarsWithPositiveCoeff (Weight (m,_)) =
       
   118     NameMap.foldl (fn (_,n,z) => if n > 0 then z + 1 else z) 0 m;
       
   119 
       
   120 fun weightCoeff var (Weight (m,_)) = Option.getOpt (NameMap.peek m var, 0);
       
   121 
       
   122 fun weightCoeffs varList w = map (fn var => weightCoeff var w) varList;
       
   123 
       
   124 fun weightCoeffSum (Weight (m,_)) = NameMap.foldl (fn (_,n,z) => n + z) 0 m;
       
   125 
       
   126 fun weightLowerBound (w as Weight (m,c)) =
    95 fun weightLowerBound (w as Weight (m,c)) =
   127     if NameMap.exists (fn (_,n) => n < 0) m then NONE else SOME c;
    96     if NameMap.exists (fn (_,n) => n < 0) m then NONE else SOME c;
   128 
    97 
   129 fun weightNoLowerBound w = not (Option.isSome (weightLowerBound w));
    98 (*MetisDebug
       
    99 val ppWeightList =
       
   100     let
       
   101       fun ppCoeff n =
       
   102           if n < 0 then Print.sequence (Print.addString "~") (ppCoeff (~n))
       
   103           else if n = 1 then Print.skip
       
   104           else Print.ppInt n
   130 
   105 
   131 fun weightAlwaysPositive w =
   106       fun pp_tm (NONE,n) = Print.ppInt n
   132     case weightLowerBound w of NONE => false | SOME n => n > 0;
   107         | pp_tm (SOME v, n) = Print.sequence (ppCoeff n) (Name.pp v)
   133 
       
   134 fun weightUpperBound (w as Weight (m,c)) =
       
   135     if NameMap.exists (fn (_,n) => n > 0) m then NONE else SOME c;
       
   136 
       
   137 fun weightNoUpperBound w = not (Option.isSome (weightUpperBound w));
       
   138 
       
   139 fun weightAlwaysNegative w =
       
   140     case weightUpperBound w of NONE => false | SOME n => n < 0;
       
   141 
       
   142 fun weightGcd (w as Weight (m,c)) =
       
   143     NameMap.foldl (fn (_,i,k) => gcd i k) (Int.abs c) m;
       
   144 
       
   145 fun ppWeightList pp =
       
   146     let
       
   147       fun coeffToString n =
       
   148           if n < 0 then "~" ^ coeffToString (~n)
       
   149           else if n = 1 then ""
       
   150           else Int.toString n
       
   151 
       
   152       fun pp_tm pp ("",n) = Parser.ppInt pp n
       
   153         | pp_tm pp (v,n) = Parser.ppString pp (coeffToString n ^ v)
       
   154     in
   108     in
   155       fn [] => Parser.ppInt pp 0
   109       fn [] => Print.ppInt 0
   156        | tms => Parser.ppSequence " +" pp_tm pp tms
   110        | tms => Print.ppOpList " +" pp_tm tms
   157     end;
   111     end;
   158 
   112 
   159 fun ppWeight pp (Weight (m,c)) =
   113 fun ppWeight (Weight (m,c)) =
   160     let
   114     let
   161       val l = NameMap.toList m
   115       val l = NameMap.toList m
   162       val l = if c = 0 then l else l @ [("",c)]
   116       val l = map (fn (v,n) => (SOME v, n)) l
       
   117       val l = if c = 0 then l else l @ [(NONE,c)]
   163     in
   118     in
   164       ppWeightList pp l
   119       ppWeightList l
   165     end;
   120     end;
   166 
   121 
   167 val weightToString = Parser.toString ppWeight;
   122 val weightToString = Print.toString ppWeight;
       
   123 *)
   168 
   124 
   169 (* ------------------------------------------------------------------------- *)
   125 (* ------------------------------------------------------------------------- *)
   170 (* The Knuth-Bendix term order.                                              *)
   126 (* The Knuth-Bendix term order.                                              *)
   171 (* ------------------------------------------------------------------------- *)
   127 (* ------------------------------------------------------------------------- *)
   172 
   128 
   173 datatype kboOrder = Less | Equal | Greater | SignOf of weight;
   129 fun compare {weight,precedence} =
   174 
       
   175 fun kboOrder {weight,precedence} =
       
   176     let
   130     let
   177       fun weightDifference tm1 tm2 =
   131       fun weightDifference tm1 tm2 =
   178           let
   132           let
   179             val w1 = weightTerm weight tm1
   133             val w1 = weightTerm weight tm1
   180             and w2 = weightTerm weight tm2
   134             and w2 = weightTerm weight tm2
   197           | SOME n => n > 0
   151           | SOME n => n > 0
   198 
   152 
   199       and precedenceLess (Term.Fn (f1,a1)) (Term.Fn (f2,a2)) =
   153       and precedenceLess (Term.Fn (f1,a1)) (Term.Fn (f2,a2)) =
   200           (case precedence ((f1, length a1), (f2, length a2)) of
   154           (case precedence ((f1, length a1), (f2, length a2)) of
   201              LESS => true
   155              LESS => true
   202            | EQUAL => firstNotEqual weightLess (zip a1 a2)
   156            | EQUAL => firstNotEqualTerm weightLess (zip a1 a2)
   203            | GREATER => false)
   157            | GREATER => false)
   204         | precedenceLess _ _ = false
   158         | precedenceLess _ _ = false
   205 
   159 
   206       fun weightDiffGreater w tm1 tm2 = weightDiffLess (weightNeg w) tm2 tm1
   160       fun weightDiffGreater w tm1 tm2 = weightDiffLess (weightNeg w) tm2 tm1
   207 
   161 
   208       fun weightCmp tm1 tm2 =
   162       fun weightCmp tm1 tm2 =
   209           let
   163           let
   210             val w = weightDifference tm1 tm2
   164             val w = weightDifference tm1 tm2
   211           in
   165           in
   212             if weightIsZero w then precedenceCmp tm1 tm2
   166             if weightIsZero w then precedenceCmp tm1 tm2
   213             else if weightDiffLess w tm1 tm2 then Less
   167             else if weightDiffLess w tm1 tm2 then SOME LESS
   214             else if weightDiffGreater w tm1 tm2 then Greater
   168             else if weightDiffGreater w tm1 tm2 then SOME GREATER
   215             else SignOf w
   169             else NONE
   216           end
   170           end
   217 
   171 
   218       and precedenceCmp (Term.Fn (f1,a1)) (Term.Fn (f2,a2)) =
   172       and precedenceCmp (Term.Fn (f1,a1)) (Term.Fn (f2,a2)) =
   219           (case precedence ((f1, length a1), (f2, length a2)) of
   173           (case precedence ((f1, length a1), (f2, length a2)) of
   220              LESS => Less
   174              LESS => SOME LESS
   221            | EQUAL => firstNotEqual weightCmp (zip a1 a2)
   175            | EQUAL => firstNotEqualTerm weightCmp (zip a1 a2)
   222            | GREATER => Greater)
   176            | GREATER => SOME GREATER)
   223         | precedenceCmp _ _ = raise Bug "kboOrder.precendenceCmp"
   177         | precedenceCmp _ _ = raise Bug "kboOrder.precendenceCmp"
   224     in
   178     in
   225       fn (tm1,tm2) => if tm1 = tm2 then Equal else weightCmp tm1 tm2
   179       fn (tm1,tm2) =>
       
   180          if Term.equal tm1 tm2 then SOME EQUAL else weightCmp tm1 tm2
   226     end;
   181     end;
   227 
   182 
   228 fun compare kbo tm1_tm2 =
   183 (*MetisTrace7
   229     case kboOrder kbo tm1_tm2 of
       
   230       Less => SOME LESS
       
   231     | Equal => SOME EQUAL
       
   232     | Greater => SOME GREATER
       
   233     | SignOf _ => NONE;
       
   234 
       
   235 (*TRACE7
       
   236 val compare = fn kbo => fn (tm1,tm2) =>
   184 val compare = fn kbo => fn (tm1,tm2) =>
   237     let
   185     let
   238       val () = Parser.ppTrace Term.pp "KnuthBendixOrder.compare: tm1" tm1
   186       val () = Print.trace Term.pp "KnuthBendixOrder.compare: tm1" tm1
   239       val () = Parser.ppTrace Term.pp "KnuthBendixOrder.compare: tm2" tm2
   187       val () = Print.trace Term.pp "KnuthBendixOrder.compare: tm2" tm2
   240       val result = compare kbo (tm1,tm2)
   188       val result = compare kbo (tm1,tm2)
   241       val () =
   189       val () =
   242           case result of
   190           case result of
   243             NONE => trace "KnuthBendixOrder.compare: result = Incomparable\n"
   191             NONE => trace "KnuthBendixOrder.compare: result = Incomparable\n"
   244           | SOME x =>
   192           | SOME x =>
   245             Parser.ppTrace Parser.ppOrder "KnuthBendixOrder.compare: result" x
   193             Print.trace Print.ppOrder "KnuthBendixOrder.compare: result" x
   246     in
   194     in
   247       result
   195       result
   248     end;
   196     end;
   249 *)
   197 *)
   250 
   198