Logic 评估OCaml中所有可能的解释
我需要评估两个公式是否相等。这里,我使用公式的一个简单定义,它是一个前缀公式 例如,Logic 评估OCaml中所有可能的解释,logic,ocaml,combinations,Logic,Ocaml,Combinations,我需要评估两个公式是否相等。这里,我使用公式的一个简单定义,它是一个前缀公式 例如,和(Atom(“b”),True)表示b和True,而和(Atom(“b”)或(Atom(“c”),而不是(Atom(“c”))表示(b和(c或非c)) 我的想法很简单,得到所有原子,应用每一个组合(对于我的例子,我将有4个组合,它们是真-真、真-假、假-真和假-假)。问题是,我不知道如何创建这些组合 现在,我已经知道如何得到所有涉及的原子,所以如果有5个原子,我应该创建32个组合。如何在OCaml中实现它?好的
和(Atom(“b”),True)
表示b和True
,而和(Atom(“b”)或(Atom(“c”),而不是(Atom(“c”))
表示(b和(c或非c))
我的想法很简单,得到所有原子,应用每一个组合(对于我的例子,我将有4个组合,它们是真-真、真-假、假-真和假-假)。问题是,我不知道如何创建这些组合
现在,我已经知道如何得到所有涉及的原子,所以如果有5个原子,我应该创建32个组合。如何在OCaml中实现它?好的,那么您需要的是一个函数
combines n
,它将生成所有长度n
的布尔组合;让我们将它们表示为布尔值列表(即,单个变量赋值就是布尔值列表)。然后,此函数将完成以下工作:
let rec combinations = function
| 0 -> [[]]
| n ->
let rest = combinations (n - 1) in
let comb_f = List.map (fun l -> false::l) rest in
let comb_t = List.map (fun l -> true::l) rest in
comb_t @ comb_f
只有一个空的长度组合0
,对于n>0
,我们生成n-1
的组合,并用false
和true
作为前缀,以生成所有可能的长度组合n
您可以编写一个函数来打印这样的组合,比如:
let rec combinations_to_string = function
| [] -> ""
| x::xs ->
let rec bools_to_str = function
| [] -> ""
| b::bs -> Printf.sprintf "%s%s" (if b then "T" else "F") (bools_to_str bs)
in
Printf.sprintf "[%s]%s" (bools_to_str x) (combinations_to_string xs)
然后用以下方法进行测试:
let _ =
let n = int_of_string Sys.argv.(1) in
let combs = combinations n in
Printf.eprintf "combinations(%d) = %s\n" n (combinations_to_string combs)
要获得:
> ./combinations 3
combinations(3) = [TTT][TTF][TFT][TFF][FTT][FTF][FFT][FFF]
如果你认为布尔值列表是一个固定长度的比特列表,那么有一个非常简单的解决方案:计数 如果你想得到4个布尔值的所有组合,从0到15(2^4-1)进行计数——然后将每一位解释为一个布尔值。为简单起见,我将使用For循环,但您也可以使用递归:
let size = 4 in
(* '1 lsl size' computes 2^size *)
for i = 0 to (1 lsl size) - 1 do
(* from: is the least significant bit '1'? *)
let b0 = 1 = ((i / 1) mod 2) in
let b1 = 1 = ((i / 2) mod 2) in
let b2 = 1 = ((i / 4) mod 2) in
(* to: is the most significant bit '1'? *)
let b3 = 1 = ((i / 8) mod 2) in
(* do your thing *)
compute b0 b1 b2 b3
done
当然,您可以使循环体更通用,例如,根据上面给出的大小创建布尔值列表/数组等。;
关键是,您可以通过枚举正在搜索的所有值来解决此问题。如果是这种情况,计算所有整数直到你的问题大小。编写一个函数,从整数生成原始问题的值。把它们放在一起
此方法的优点是,在开始计算之前,您不需要首先创建所有组合。对于大问题,这可能会帮你省钱。对于相当小的size=16,您已经需要65535*sizeof(type)内存了——而且这是随着大小呈指数增长的!上述解决方案只需要sizeof(type)的恒定内存量
为了科学起见:你的问题是NP完全的,所以如果你想要精确的解决方案,它需要指数时间。这太不可思议了!你能给我解释一下@there的意思吗?它与List.append相同吗?还有一点,fun l->false::l的含义是什么?@zfm:当然,
@
确实是列表的快捷方式。append
(请参阅)funl->false::l
是一个匿名函数。您可以在List.map ff rest中编写let ff l=false::l,但您可以像上面那样“内联”函数。希望这会有帮助。如果你不能将所有的组合都保存在内存中,请查看我不久前写的一篇文章(使用一些ocaml)以按字典顺序创建组合索引,我同意这个问题是NP完全的,但是因为对于给定的任何公式,其大小都不会很大(小于10个变量),我真的不在乎这里的空间消耗。