let eval_predicate ~result state pred =
  let rec do_eval state p =
    match p.content with
    | Ptrue -> True
    | Pfalse -> False
    | Pand (p1,p2 ) ->
        begin match do_eval state p1 with
        | True -> do_eval state p2
        | False -> False
        | Unknown ->
            begin match do_eval (reduce_by_predicate ~result state true p1) p2 with
              False -> False
            | _ -> Unknown
            end
        end
    | Por (p1,p2 ) ->
(*        begin match do_eval state p1,do_eval state p2 with
        | True, _| _, True ->  True
        | False, False -> False
        | _ -> Unknown
        end *)

        begin match do_eval state p1 with
        | True ->  True
        | False -> do_eval state p2
        | Unknown ->
            begin match do_eval (reduce_by_predicate ~result state false p1) p2 with
              True -> True
            | _ -> Unknown
            end
        end
    | Pxor (p1,p2) ->
        begin match do_eval state p1, do_eval state p2 with
          | TrueTrue -> False
          | FalseFalse -> False
          | TrueFalse | FalseTrue -> True
          | Unknown, _ | _, Unknown -> Unknown
        end
    | Piff (p1,p2 ) ->
        begin match do_eval state p1,do_eval state p2 with
        | TrueTrue | FalseFalse ->  True
        | Unknown, _ | _, Unknown -> Unknown
        | _ -> False
        end
    | Papp _ (* | Pnamed _ *) | Pold _ | Pat _ -> Unknown
    | Pvalid tsets -> begin
        try
          let cexps = !Db.Properties.Interp.loc_to_exp ~result tsets in
          List.fold_left
            (fun res cexp ->
               match res with
                   Unknown | False -> res
                 | True ->
                    let typ = typeOf cexp in
                     if isPointerType typ then
                       let evaled =
                         loc_bytes_to_loc_bits
                           (eval_expr ~with_alarms:warn_raise_mode state cexp)
                       in
                       let size = sizeof_pointed typ in
                       let loc = Locations.make_loc evaled size in
                       if Locations.is_valid loc
                       then True
                       else Unknown
                         (* TODO: the else case can be improved
                            by distinguishing the locations made only
                            of invalid values (-> False)*)

                     else Unknown(*TODO: global arrays fall here *))
            True cexps
        with
            Invalid_argument "not an lvalue" -> Unknown
          | Predicate_alarm -> Unknown
      end
    | Prel (op,t1,t2) ->
        begin
          try
            let cexp1 = !Db.Properties.Interp.term_to_exp ~result t1 in
            let cexp2 = !Db.Properties.Interp.term_to_exp ~result t2 in
            let cops =
              dummy_exp (BinOp(lop_to_cop op,
                    cexp1,
                    cexp2,
                    intType))
            in
            let evaled = eval_expr ~with_alarms:warn_raise_mode state cops in
            if Location_Bytes.equal
              evaled
              Location_Bytes.singleton_zero
            then
              False
            else if Location_Bytes.equal
              evaled
              Location_Bytes.singleton_one
            then
              True
            else Unknown
          with
            Invalid_argument "not an lvalue" -> Unknown
          | Predicate_alarm -> Unknown
        end
    | Pexists (varl, p1) | Pforall (varl, p1) ->
        let result =
          begin try
          let state = List.fold_left
            (fun acc var ->
               match var.lv_origin with
                 None -> raise Exit
               | Some vi ->
                   let loc = loc_of_varinfo vi in
                   Relations_type.Model.add_binding
                     ~with_alarms:warn_raise_mode ~exact:true
                     acc loc Location_Bytes.top)
            state
            varl
          in
          do_eval state p1
        with
          Exit -> Unknown
        | Predicate_alarm -> Unknown
        end
        in
        begin match p.content with
        | Pexists _ -> if result = False then False else Unknown
        | Pforall _ -> if result = True then True else Unknown
        | _ -> assert false
        end

    | Pnot p ->  begin match do_eval state p with
      | True -> False
      | False -> True
      | Unknown -> Unknown
      end
    | Pimplies (p1,p2) ->
        do_eval state (Logic_const.por ((Logic_const.pnot p1), p2))
    | Pseparated (_tset_l) -> Unknown
    | Pfresh _
    | Pvalid_range (_, _, _)| Pvalid_index (_, _)
    | Plet (_, _) | Pif (_, _, _) -> Unknown
    | Psubtype _
        -> Unknown

  in
  try
    match State_set.fold
      (fun s acc ->
         match do_eval s pred with
         | Unknown -> raise Stop
         |True | False ) as arg ->
            (match acc with
             | None -> Some arg
             | Some old when old = arg -> Some arg
             | _ -> raise Stop))
      state
      None
    with
    | None -> True
    | Some v -> v
  with Stop -> Unknown