如何解决约束中的 Picat 函数
在介绍性练习中,我的目标是生成 0、1 值的模式,受各种约束条件的约束。虽然下面的代码在内置 sum/1 函数中运行良好,但在手工编写的 sum1/1 版本中却失败了(invalid_constraint_expression)。
import cp.
main => fill_0_1(4).
fill_0_1(CodeLen) =>
Codes = new_array(CodeLen),Codes :: 0 .. 1,sum1([Codes[I] : I in 1..CodeLen]) #= 3,solve(Codes),printf("%w\n",Codes).
sum1(FDVars) = N =>
N := 0,foreach (V in FDVars)
N := N + V
end.
创建 sum1 的正确方法是什么?
解决方法
您定义 sum1/1
的问题在于您将决策变量(用 ::
定义)与“普通”非决策变量(使用 :=
)混合。这不起作用,因为您无法重新分配决策变量的值(示例中的变量 N
)。
另外,不幸的是,定义约束时不能使用函数。返回决策变量的值不起作用(即使用 #=
)。
这是我将如何做到的。它有点复杂,因为它支持决策变量何时在列表中以及何时在数组中(如您的示例)。如果它是一个数组(由 array(X)
检查),那么我们必须将它转换为一个列表,因为 [H|T]
的东西只适用于列表,而不是数组。该定义本身是使用累加器进行逻辑编程的总和的“标准”定义。
% If X is an array,convert it to a list and then call sum2/3
sum2(X,Sum),array(X) =>
sum2(X.to_list,Sum).
% X is a list.
sum2(X,list(X) =>
sum2(X,Sum).
% sum2/3 with the accumulator
sum2([],Sum1,Sum2) ?=> Sum1 #= Sum2.
sum2([H|T],Sum0,Sum) ?=>
Sum1 #= Sum0 + H,sum2(T,Sum).
进一步评论:
请注意,head 中的保护条件(array(X)
和 list(X)
)仅适用于定义谓词(?=>
和 =>
)的 Picat 样式,而不适用于 Horn 子句样式(:-
,v3.0 中引入),这意味着不能依赖谓词头部的匹配。因此,这在使用 Picat 样式时不起作用:
sum2([],Sum,Sum) ?=> true. % Matching in head don't work using Picat style.
两个 Sum
变量在头部必须是不同的,然后在主体中相等(使用 #=
),即
sum2([],Sum2) ?=> Sum1 #= Sum2.
这是一个变体 - 仍然是递归的 - 它适用于列表和数组,无需转换为列表。主要区别在于它使用索引 (Ix
) 来访问数组/列表 X
中的值。它有两个累加器:一个用于每一步递减的索引 (Ix
),另一个用于中间和 (Sum0
)。
sum4(X,Sum) ?=>
sum4(X,X.len,Sum).
sum4(X,1,Sum) ?=> Sum #= Sum0 + X[1].
sum4(X,Ix,Sum) ?=>
Ix > 1,Sum1 #= X[Ix] + Sum0,sum4(X,Ix-1,Sum).
更新:这里有一个更通用的版本,它的形式与上面的 sum2/2-3
类似:fold2(X,Predicate,Init,Result)
。输入参数是列表/数组X
、谓词Pred
(元数为3,示例见下文)和初始值Init
;输出参数是结果 Result
。我们可以在这里
fold2([],_P,Res0,Res) ?=> Res #= Res0.
fold2([X|T],P,Res) ?=>
call(P,X,Res1),fold2(T,Res1,Res).
现在我们可以像这样定义 sum/2
和 prod/2
(用于列表/数组中元素的乘积),再次检查它是数组还是列表。
% Multiplication
mult(X,Y,Z) =>
Z #= X * Y.
% Addition
add(X,Z) =>
Z #= X + Y.
% Define sum/2 for array
sum5(X,array(X) ?=>
fold2(X.to_list,add,Sum).
% sum/2 for list
sum5(X,list(X) ?=>
fold2(X,Sum)
% Define prod/2 for array
prod5(X,Prod),Prod).
% prod2/2 for list
prod5(X,Prod).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。