(*
* lablai - An ML Artificial Inteligence library
* Copyright (C) 2006 Till Crueger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
(* File $RCSfile$ *)
(* last edited by $Author: till_crueger $ *)
(* $Date: 2007-12-15 19:53:03 +0100 (Sa, 15 Dez 2007) $, $Revision: 29 $ *)
type formula = True
| False
| Not of formula
| Var of string
| And of formula * formula
| Or of formula * formula
| Implicates of formula * formula
| Equals of formula * formula
;;
(* all the assignments are kept in a simple association table*)
type model = (string * bool) list;;
type assignment = model -> model;;
exception Var_unbound;;
let empty : model = [];;
let rec lookup ~var model =
(*just try to look up the variable directely*)
try
List.assoc var model
with
Not_found -> raise Var_unbound
;;
let assign ~var value model =
let rec loop vars =
match vars with
(* see if the variable was bound before *)
((var2,assig) :: vars) ->
if var2 =var then
(* then bind it to the new value *)
(var2,value) :: vars
else
(var2,assig) :: (loop vars)
| [] ->
(* else introduce a new binding*)
(var,value) :: []
in
loop model
;;
let combine assig1 assig2 =
fun model -> assig1 (assig2 model)
;;
let create assigs =
let folder model assig = assig model in
List.fold_left folder empty assigs
;;
let rec solve formula model =
(* straightforward translation of the formula *)
match formula with
True -> true
| False -> false
| Not alpha -> not (solve alpha model)
| Var var -> lookup ~var model
| And (alpha, beta) -> (solve alpha model ) && (solve beta model)
| Or (alpha, beta) -> (solve alpha model) || (solve beta model)
| Implicates (alpha, beta) -> (not (solve alpha model) ) || (solve beta model)
| Equals (alpha, beta) -> (solve alpha model) = (solve beta model)
;;
let find_vars formula=
(* get a list of all variables *)
let rec find formula =
match formula with
Var alpha -> [alpha]
| Not alpha -> find alpha
| And (alpha,beta) -> (find alpha) @ (find beta)
| Or (alpha,beta) -> (find alpha) @ (find beta)
| Implicates (alpha,beta) -> (find alpha) @ (find beta)
| Equals (alpha,beta) -> (find alpha) @ (find beta)
| True -> []
| False -> []
in
let vars = find formula in
(* eliminate duplicates *)
let rec eliminate vars =
match vars with
var :: vars ->
if List.exists (fun a -> a=var) vars then
eliminate vars
else
var :: (eliminate vars)
| [] -> []
in
eliminate vars
;;
let print_bool b = if b then print_string "true" else print_string "false";;
let print_model m =
print_string "[\n";
let rec printer m =
match m with
(a,assig) :: rest ->
print_string " ";
print_string a;
print_string "=";
print_bool assig;
print_string "\n";
printer rest
| [] -> ()
in
printer m;
print_endline "]"
;;
let is_solvable formula =
(* get all the variables*)
let vars = find_vars formula in
(* functions for the search using the uninf_search part of this lib *)
(* Nodes of the search space are represented as a tuple of the unbound variables
and a model containing the bindings for the bound ones*)
let childgen incomplete =
(* see if we can bind a variable *)
match incomplete with
(*bind it to true and false and remove it from the list of unbound vars *)
(var :: vars , model) -> [(vars, assign ~var true model);
(vars, assign ~var false model)]
| ([], _) -> [];
and
goaltest incomplete =
(* as long as there are unbound variables we cannot have a solution *)
match incomplete with
([], model) -> solve formula model
| _ -> false
and
combinator a b c =
(*just see if we have a solution and return the bindings in that case *)
if b then
(
let (_,res) = a in
Some res
)
else
c
in
let res = Uninf_search.dfsearch ~start:(vars,empty) ~childgen ~goaltest ~combinator in
res
;;
let find_models formula =
(* get all the variables*)
let vars = find_vars formula in
(* functions for the search using the uninf_search part of this lib *)
(* Nodes of the search space are represented as a tuple of the unbound variables
and a model containing the bindings for the bound ones*)
let childgen incomplete =
(* see if we can bind a variable *)
match incomplete with
(*bind it to true and false and remove it from the list of unbound vars *)
(var :: vars , model) -> [(vars, assign ~var true model);
(vars, assign ~var false model)]
| ([], _) -> [];
and
goaltest incomplete =
(* as long as there are unbound variables we cannot have a solution *)
match incomplete with
([], model) -> solve formula model
| _ -> false
and
combinator a b c =
(*just see if we have a solution and return the bindings in that case *)
if b then
(
let (_,res) = a in
Some res
)
else
c
in
let res = Uninf_search.exhaustive_search ~start:(vars,empty) ~childgen ~goaltest ~combinator in
res
;;
(*
* $Log$
* Revision 1.8 2007/12/15 18:52:58 till_crueger
* - Updated documentation
* - Moved Log-Tags to a better position in the sources
*
* Revision 1.7 2006/03/26 17:58:24 till_crueger
* Major code cleanup and improvment of the documentation.
*
* Revision 1.6 2006/02/22 18:13:27 till
* Changed several filenames
*
* Revision 1.5 2006/02/20 20:21:46 till
* Added LGPL to all files
* Added LGPL to package
*
* Revision 1.4 2006/02/20 17:36:01 till
* Improved Makefile
*
* Fixed some minor problems so they won't cause warnings
*
* Revision 1.3 2006/02/11 11:17:33 till
* removed example to seperate file
*
* Revision 1.2 2006/02/11 11:11:12 till
* Added CVS Tags
*
*)