首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >约束条件下的Picat函数

约束条件下的Picat函数
EN

Stack Overflow用户
提问于 2021-04-18 17:00:46
回答 1查看 73关注 0票数 2

在一个介绍性练习中,我的目标是生成0,1值的模式,但要受各种约束。虽然下面的代码可以很好地处理内置的sum/1函数,但是手工构建的sum 1/1版本会失败(invalid_constraint_expression)。

代码语言:javascript
复制
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的正确方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-18 18:54:53

sum1/1定义的问题在于,您将决策变量(用::定义)和“普通”非决策变量(使用:=)混合在一起。由于不能重新分配决策变量的值(示例中的变量N ),这是行不通的。

此外,不幸的是,在定义约束时不能使用函数。它不能返回决策变量的值(即使用#=)。

我会这么做的。它更复杂一些,因为它支持决策变量在列表中和它们在数组中的时候(如您的例子)。如果它是一个数组(由array(X)检查),那么我们必须将它转换为一个列表,因为[H|T]只在列表上工作,而不是在数组上工作。定义本身就是使用累加器进行逻辑编程的和的“标准”定义。

代码语言:javascript
复制
% 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样式时,这是行不通的:

代码语言:javascript
复制
   sum2([],Sum,Sum) ?=> true. % Matching in head don't work using Picat style.

相反,两个Sum变量在头部必须是不同的,然后在主体中被设置为相等(使用#=),即

代码语言:javascript
复制
   sum2([],Sum1,Sum2) ?=> Sum1 #= Sum2.

这里有一个变体--仍然是递归的--既适用于列表,也适用于数组,而无需转换为列表。其主要区别在于它使用索引(Ix)访问数组/列表X中的值。它有两个累加器:一个用于索引(Ix),用于每个步骤递减,另一个用于中间和(Sum0)。

代码语言:javascript
复制
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-3fold2(X,Predicate,Init,Result)。输入参数是list/array X,一个谓词Pred (参见下面的示例)和一个初始值Init;输出参数是结果Result。在这里我们可以

代码语言:javascript
复制
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 (用于列表/数组中元素的乘积),同样可以检查它是数组还是列表。

代码语言:javascript
复制
% 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).
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67151242

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档