我需要评估两个公式是否相同。在这里,我使用公式的简单定义,这是一个前缀公式。
例如,And(Atom("b"), True)
表示b and true
,而And(Atom("b"), Or(Atom("c"), Not(Atom("c"))))
表示(b and (c or not c))
我的想法很简单,获取所有原子,应用每个组合(对于我的情况,我将有4个组合,这些是真实的,真假的,假真的,假假的)。问题是,我不知道如何创建这些组合。
目前,我已经知道如何获得所有涉及原子,所以如果有5个原子,我应该创建32个组合。如何在OCaml中做到这一点?
答案 0 :(得分:4)
好的,你需要的是一个函数combinations 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]
答案 1 :(得分:1)
如果您将布尔值列表视为固定长度的位列表,则有一个非常简单的解决方案:计数!
如果你想拥有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
当然,你可以使循环的主体更加通用,以便它可以根据上面给出的大小等创建一个布尔列表/数组。 关键是您可以通过枚举要搜索的所有值来解决此问题。如果是这种情况,请计算直到问题大小的所有整数。编写一个函数,从整数生成原始问题的值。把它们放在一起。
此方法的优点是,在开始计算之前,不需要先创建所有组合。对于大问题,这可能会拯救你。对于相当小的大小= 16,你将需要 65535 * sizeof(类型)内存 - 而且这个数量呈指数增长!上述解决方案只需要一定量的 sizeof(type)。
为了科学的缘故:你的问题是 NP-complete ,所以如果你想要精确的解决方案,那将需要指数时间。