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个变量),我真的不在乎这里的空间消耗。