src/HOL/Tools/Presburger/cooper_dec.ML
changeset 15107 f233706d9fce
parent 14981 e73f8140af78
child 15164 5d7c96e0f9dc
equal deleted inserted replaced
15106:e8cef6993701 15107:f233706d9fce
    40   val has_bound : term -> bool
    40   val has_bound : term -> bool
    41   val minusinf : term -> term -> term
    41   val minusinf : term -> term -> term
    42   val plusinf : term -> term -> term
    42   val plusinf : term -> term -> term
    43   val onatoms : (term -> term) -> term -> term
    43   val onatoms : (term -> term) -> term -> term
    44   val evalc : term -> term
    44   val evalc : term -> term
       
    45   val cooper_w : string list -> term -> (term option * term)
    45   val integer_qelim : Term.term -> Term.term
    46   val integer_qelim : Term.term -> Term.term
    46   val mk_presburger_oracle : (Sign.sg * exn) -> term
    47   val mk_presburger_oracle : (Sign.sg * exn) -> term
    47 end;
    48 end;
    48 
    49 
    49 structure  CooperDec : COOPER_DEC =
    50 structure  CooperDec : COOPER_DEC =
   195         if is_numeral s' then (linear_cmul (dest_numeral s') t') 
   196         if is_numeral s' then (linear_cmul (dest_numeral s') t') 
   196         else if is_numeral t' then (linear_cmul (dest_numeral t') s') 
   197         else if is_numeral t' then (linear_cmul (dest_numeral t') s') 
   197  
   198  
   198          else (warning "lint: apparent nonlinearity"; raise COOPER)
   199          else (warning "lint: apparent nonlinearity"; raise COOPER)
   199          end 
   200          end 
   200   |_ =>   (error "COOPER:lint: unknown term  ")
   201   |_ =>  error ("COOPER:lint: unknown term  \n");
   201    
   202    
   202  
   203  
   203  
   204  
   204 (* ------------------------------------------------------------------------- *) 
   205 (* ------------------------------------------------------------------------- *) 
   205 (* Linearize the atoms in a formula, and eliminate non-strict inequalities.  *) 
   206 (* Linearize the atoms in a formula, and eliminate non-strict inequalities.  *) 
   412   |_ => fm; 
   413   |_ => fm; 
   413  
   414  
   414 (* ------------------------------------------------------------------------- *) 
   415 (* ------------------------------------------------------------------------- *) 
   415 (* Evaluation of constant expressions.                                       *) 
   416 (* Evaluation of constant expressions.                                       *) 
   416 (* ------------------------------------------------------------------------- *) 
   417 (* ------------------------------------------------------------------------- *) 
   417  
   418 
       
   419 (* An other implementation of divides, that covers more cases*) 
       
   420 
       
   421 exception DVD_UNKNOWN
       
   422 
       
   423 fun dvd_op (d, t) = 
       
   424  if not(is_numeral d) then raise DVD_UNKNOWN
       
   425  else let 
       
   426    val dn = dest_numeral d
       
   427    fun coeffs_of x = case x of 
       
   428      Const(p,_) $ tl $ tr => 
       
   429        if p = "op +" then (coeffs_of tl) union (coeffs_of tr)
       
   430           else if p = "op *" 
       
   431 	        then if (is_numeral tr) 
       
   432 		 then [(dest_numeral tr) * (dest_numeral tl)] 
       
   433 		 else [dest_numeral tl]
       
   434 	        else []
       
   435     |_ => if (is_numeral t) then [dest_numeral t]  else []
       
   436    val ts = coeffs_of t
       
   437    in case ts of
       
   438      [] => raise DVD_UNKNOWN
       
   439     |_  => foldr (fn(k,r) => r andalso (k mod dn = 0)) (ts,true)
       
   440    end;
       
   441 
       
   442 
   418 val operations = 
   443 val operations = 
   419   [("op =",op=), ("op <",op<), ("op >",op>), ("op <=",op<=) , ("op >=",op>=), 
   444   [("op =",op=), ("op <",op<), ("op >",op>), ("op <=",op<=) , ("op >=",op>=), 
   420    ("Divides.op dvd",fn (x,y) =>((y mod x) = 0))]; 
   445    ("Divides.op dvd",fn (x,y) =>((y mod x) = 0))]; 
   421  
   446  
   422 fun applyoperation (Some f) (a,b) = f (a, b) 
   447 fun applyoperation (Some f) (a,b) = f (a, b) 
   423     |applyoperation _ (_, _) = false; 
   448     |applyoperation _ (_, _) = false; 
   424  
   449  
   425 (*Evaluation of constant atomic formulas*) 
   450 (*Evaluation of constant atomic formulas*) 
   426  
   451  (*FIXME : This is an optimation but still incorrect !! *)
       
   452 (*
   427 fun evalc_atom at = case at of  
   453 fun evalc_atom at = case at of  
   428       (Const (p,_) $ s $ t) =>(  
   454   (Const (p,_) $ s $ t) =>
   429          case assoc (operations,p) of 
   455    (if p="Divides.op dvd" then 
   430              Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then HOLogic.true_const else HOLogic.false_const)  
   456      ((if dvd_op(s,t) then HOLogic.true_const
   431               handle _ => at) 
   457      else HOLogic.false_const)
   432              | _ =>  at) 
   458       handle _ => at)
   433      |Const("Not",_)$(Const (p,_) $ s $ t) =>(  
   459     else
   434          case assoc (operations,p) of 
   460   case assoc (operations,p) of 
   435              Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then 
   461     Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then HOLogic.true_const else HOLogic.false_const)  
   436 	     HOLogic.false_const else HOLogic.true_const)  
   462     handle _ => at) 
   437               handle _ => at) 
   463       | _ =>  at) 
   438              | _ =>  at) 
   464       |Const("Not",_)$(Const (p,_) $ s $ t) =>(  
   439      | _ =>  at; 
   465   case assoc (operations,p) of 
   440  
   466     Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then 
   441 (*Function onatoms apllys function f on the atomic formulas involved in a.*) 
   467     HOLogic.false_const else HOLogic.true_const)  
       
   468     handle _ => at) 
       
   469       | _ =>  at) 
       
   470       | _ =>  at; 
       
   471 
       
   472 *)
       
   473 
       
   474 fun evalc_atom at = case at of  
       
   475   (Const (p,_) $ s $ t) =>
       
   476    ( case assoc (operations,p) of 
       
   477     Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then HOLogic.true_const else HOLogic.false_const)  
       
   478     handle _ => at) 
       
   479       | _ =>  at) 
       
   480       |Const("Not",_)$(Const (p,_) $ s $ t) =>(  
       
   481   case assoc (operations,p) of 
       
   482     Some f => ((if (f ((dest_numeral s),(dest_numeral t))) then 
       
   483     HOLogic.false_const else HOLogic.true_const)  
       
   484     handle _ => at) 
       
   485       | _ =>  at) 
       
   486       | _ =>  at; 
       
   487 
       
   488  (*Function onatoms apllys function f on the atomic formulas involved in a.*) 
   442  
   489  
   443 fun onatoms f a = if (is_arith_rel a) then f a else case a of 
   490 fun onatoms f a = if (is_arith_rel a) then f a else case a of 
   444  
   491  
   445   	(Const ("Not",_) $ p) => if is_arith_rel p then HOLogic.Not $ (f p) 
   492   	(Const ("Not",_) $ p) => if is_arith_rel p then HOLogic.Not $ (f p) 
   446 				 
   493 				 
   650     fun stage j = list_disj (linrep vars x (mk_numeral j) p_inf :: map (p_element j) aset)
   697     fun stage j = list_disj (linrep vars x (mk_numeral j) p_inf :: map (p_element j) aset)
   651    in (list_disj (map stage js))
   698    in (list_disj (map stage js))
   652    end
   699    end
   653   | _ => error "cooper: not an existential formula";
   700   | _ => error "cooper: not an existential formula";
   654   
   701   
       
   702 
       
   703 (* Try to find a withness for the formula *)
       
   704 
       
   705 fun inf_w mi d vars x p = 
       
   706   let val f = if mi then minusinf else plusinf in
       
   707    case (simpl (minusinf x p)) of
       
   708    Const("True",_)  => (Some (mk_numeral 1), HOLogic.true_const)
       
   709   |Const("False",_) => (None,HOLogic.false_const)
       
   710   |F => 
       
   711       let 
       
   712       fun h n =
       
   713        case ((simpl o evalc) (linrep vars x (mk_numeral n) F)) of 
       
   714 	Const("True",_) => (Some (mk_numeral n),HOLogic.true_const)
       
   715        |F' => if n=1 then (None,F')
       
   716 	     else let val (rw,rf) = h (n-1) in 
       
   717 	       (rw,HOLogic.mk_disj(F',rf))
       
   718 	     end
       
   719 
       
   720       in (h d)
       
   721       end
       
   722   end;
       
   723 
       
   724 fun set_w d b st vars x p = let 
       
   725     fun h ns = case ns of 
       
   726     [] => (None,HOLogic.false_const)
       
   727    |n::nl => ( case ((simpl o evalc) (linrep vars x n p)) of
       
   728       Const("True",_) => (Some n,HOLogic.true_const)
       
   729       |F' => let val (rw,rf) = h nl 
       
   730              in (rw,HOLogic.mk_disj(F',rf)) 
       
   731 	     end)
       
   732     val f = if b then linear_add else linear_sub
       
   733     val p_elements = foldr (fn (i,l) => l union (map (fn e => f [] e (mk_numeral i)) st)) (1 upto d,[])
       
   734     in h p_elements
       
   735     end;
       
   736 
       
   737 fun withness d b st vars x p = case (inf_w b d vars x p) of 
       
   738    (Some n,_) => (Some n,HOLogic.true_const)
       
   739   |(None,Pinf) => (case (set_w d b st vars x p) of 
       
   740     (Some n,_) => (Some n,HOLogic.true_const)
       
   741     |(_,Pst) => (None,HOLogic.mk_disj(Pinf,Pst)));
       
   742 
       
   743 
   655 
   744 
   656 
   745 
   657 (*Cooper main procedure*) 
   746 (*Cooper main procedure*) 
   658   
   747   
   659 fun cooper vars1 fm =
   748 fun cooper vars1 fm =
   676    in (list_disj (map stage js))
   765    in (list_disj (map stage js))
   677    end
   766    end
   678   | _ => error "cooper: not an existential formula";
   767   | _ => error "cooper: not an existential formula";
   679 
   768 
   680 
   769 
       
   770 (* A Version of cooper that returns a withness *)
       
   771 fun cooper_w vars1 fm =
       
   772   case fm of
       
   773    Const ("Ex",_) $ Abs(x0,T,p0) => let 
       
   774     val (xn,p1) = variant_abs (x0,T,p0)
       
   775     val x = Free (xn,T)
       
   776     val vars = (xn::vars1)
       
   777 (*     val p = unitycoeff x  (posineq (simpl p1)) *)
       
   778     val p = unitycoeff x  p1 
       
   779     val ast = aset x p
       
   780     val bst = bset x p
       
   781     val d = divlcm x p
       
   782     val (p_inf,S ) = 
       
   783     if (length bst) <= (length ast) 
       
   784      then (true,bst)
       
   785      else (false,ast)
       
   786     in withness d p_inf S vars x p 
       
   787 (*    fun p_element j a = linrep vars x (f vars a (mk_numeral j)) p
       
   788     fun stage j = list_disj (linrep vars x (mk_numeral j) p_inf :: map (p_element j) S)
       
   789    in (list_disj (map stage js))
       
   790 *)
       
   791    end
       
   792   | _ => error "cooper: not an existential formula";
   681 
   793 
   682  
   794  
   683 (*Function itlist applys a double parametred function f : 'a->'b->b iteratively to a List l : 'a 
   795 (*Function itlist applys a double parametred function f : 'a->'b->b iteratively to a List l : 'a 
   684 list With End condition b. ict calculates f(e1,f(f(e2,f(e3,...(...f(en,b))..))))) 
   796 list With End condition b. ict calculates f(e1,f(f(e2,f(e3,...(...f(en,b))..))))) 
   685  assuming l = [e1,e2,...,en]*) 
   797  assuming l = [e1,e2,...,en]*) 
   809 val integer_qelim = simpl o evalc o (lift_qelim linform (cnnf posineq o evalc) cooper is_arith_rel) ; 
   921 val integer_qelim = simpl o evalc o (lift_qelim linform (cnnf posineq o evalc) cooper is_arith_rel) ; 
   810 
   922 
   811 fun mk_presburger_oracle (sg,COOPER_ORACLE t) = 
   923 fun mk_presburger_oracle (sg,COOPER_ORACLE t) = 
   812     if (!quick_and_dirty) 
   924     if (!quick_and_dirty) 
   813     then HOLogic.mk_Trueprop (HOLogic.mk_eq(t,integer_qelim t))
   925     then HOLogic.mk_Trueprop (HOLogic.mk_eq(t,integer_qelim t))
   814     else raise COOPER_ORACLE t;
   926     else raise COOPER_ORACLE t
   815 
   927     |mk_presburger_oracle (sg,_) = error "Oops";
   816 end;
   928 end;
   817 
   929 
   818 
   930