在一个介绍性练习中,我的目标是生成0,1值的模式,但要受各种约束。虽然下面的代码可以很好地处理内置的sum/1函数,但是手工构建的sum 1/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的正确方法是什么?
发布于 2021-04-18 18:54:53
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,0,Sum).
% X is a list.
sum2(X,Sum), list(X) =>
sum2(X,0,Sum).
% sum2/3 with the accumulator
sum2([],Sum1,Sum2) ?=> Sum1 #= Sum2.
sum2([H|T],Sum0,Sum) ?=>
Sum1 #= Sum0 + H,
sum2(T,Sum1,Sum).另请注意: head中的保护条件(array(X)和list(X))仅适用于定义谓词(?=>和=>)的Picat样式,而不适用于角子句样式(:-,在V3.0中引入),这意味着不能依赖谓词头中的匹配。因此,当使用Picat样式时,这是行不通的:
sum2([],Sum,Sum) ?=> true. % Matching in head don't work using Picat style.相反,两个Sum变量在头部必须是不同的,然后在主体中被设置为相等(使用#=),即
sum2([],Sum1,Sum2) ?=> Sum1 #= Sum2.这里有一个变体--仍然是递归的--既适用于列表,也适用于数组,而无需转换为列表。其主要区别在于它使用索引(Ix)访问数组/列表X中的值。它有两个累加器:一个用于索引(Ix),用于每个步骤递减,另一个用于中间和(Sum0)。
sum4(X,Sum) ?=>
sum4(X,X.len,0,Sum).
sum4(X,1,Sum0,Sum) ?=> Sum #= Sum0 + X[1].
sum4(X,Ix,Sum0,Sum) ?=>
Ix > 1,
Sum1 #= X[Ix] + Sum0,
sum4(X,Ix-1,Sum1,Sum).Update:这里有一个更通用的版本,它的形式类似于上面的sum2/2-3:fold2(X,Predicate,Init,Result)。输入参数是list/array X,一个谓词Pred (参见下面的示例)和一个初始值Init;输出参数是结果Result。在这里我们可以
fold2([],_P,Res0,Res) ?=> Res #= Res0.
fold2([X|T],P,Res0,Res) ?=>
call(P,Res0,X,Res1),
fold2(T,P,Res1,Res). 现在我们既可以定义sum/2,也可以定义prod/2 (用于列表/数组中元素的乘积),同样可以检查它是数组还是列表。
% Multiplication
mult(X,Y,Z) =>
Z #= X * Y.
% Addition
add(X,Y,Z) =>
Z #= X + Y.
% Define sum/2 for array
sum5(X,Sum), array(X) ?=>
fold2(X.to_list,add,0,Sum).
% sum/2 for list
sum5(X,Sum), list(X) ?=>
fold2(X,add,0,Sum)
% Define prod/2 for array
prod5(X,Prod), array(X) ?=>
fold2(X.to_list,add,1,Prod).
% prod2/2 for list
prod5(X,Prod), list(X) ?=>
fold2(X,add,1,Prod).https://stackoverflow.com/questions/67151242
复制相似问题