Prolog 如何冻结变量列表的目标?
我的最终目标是制作一个具体化版本的automaton/3,如果传递给它的序列中有任何变量,它就会冻结。i、 我不希望自动机实例化变量 (fd_长度/3,如果_/3等由此处的其他人定义) 首先,我有一个针对单变量的具体化测试:Prolog 如何冻结变量列表的目标?,prolog,clpfd,automaton,prolog-coroutining,Prolog,Clpfd,Automaton,Prolog Coroutining,我的最终目标是制作一个具体化版本的automaton/3,如果传递给它的序列中有任何变量,它就会冻结。i、 我不希望自动机实例化变量 (fd_长度/3,如果_/3等由此处的其他人定义) 首先,我有一个针对单变量的具体化测试: var_t(X,T):- var(X) -> T=true; T=false. 这使我能够实施: if_var_freeze(X,Goal):- if_(var_t(X),freeze(X,Goal),Goal). 所以我可以这样做: ?-X=bo
var_t(X,T):-
var(X) ->
T=true;
T=false.
这使我能够实施:
if_var_freeze(X,Goal):-
if_(var_t(X),freeze(X,Goal),Goal).
所以我可以这样做:
?-X=bob,Goal =format("hello ~w\n",[X]),if_var_freeze(X,Goal).
其行为与:
?-Goal =format("hello ~w\n",[X]),if_var_freeze(X,Goal),X=bob.
当所有变量都已实例化时,如何将其展开以处理变量列表,从而只调用一次目标?
在这种方法中,如果我有多个变量,我可以得到我不想要的行为:
?-List=[X,Y],Goal = format("hello, ~w and ~w\n",List),
if_var_freeze(X,Goal),
if_var_freeze(Y,Goal),X=bob.
hello, bob and _G3322
List = [bob, Y],
X = bob,
Goal = format("hello, ~w and ~w\n", [bob, Y]),
freeze(Y, format("hello, ~w and ~w\n", [bob, Y])).
我试过:
freeze_list(List,Goal):-
freeze_list_h(List,Goal,FrozenList),
call(FrozenList).
freeze_list_h([X],Goal,freeze(X,Goal)).
freeze_list_h(List,Goal,freeze(H,Frozen)):-
List=[H|T],
freeze_list_h(T,Goal,Frozen).
其工作原理如下:
?- X=bob,freeze_list([X,Y,Z],format("Hello ~w, ~w and ~w\n",[X,Y,Z])),Y=fred.
X = bob,
Y = fred,
freeze(Z, format("Hello ~w, ~w and ~w\n", [bob, fred, Z])) .
?- X=bob,freeze_list([X,Y,Z],format("Hello ~w, ~w and ~w\n",[X,Y,Z])),Y=fred,Z=sue.
Hello bob, fred and sue
X = bob,
Y = fred,
Z = sue .
这似乎没问题,但我在将其应用于automaton/3时遇到了问题。
重申其目的是制作一个具体化版本的automaton/3,如果传递给它的序列中有任何变量,它就会冻结。i、 我不希望自动机实例化变量
这就是我所拥有的:
ga(Seq,G) :-
G=automaton(Seq, [source(a),sink(c)],
[arc(a,0,a), arc(a,1,b),
arc(b,0,a), arc(b,1,c),
arc(c,0,c), arc(c,1,c)]).
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each member of seq
maplist(=(false),Var_T_List), %check that all are false i.e no uninstaninated vars
call(A),!,
T=true.
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each member of seq
maplist(=(false),Var_T_List), %check that all are false i.e no uninstaninated vars
\+call(A),!,
T=false.
max_seq_automaton_t(Max,Seq,A,true):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each
memberd_t(true,Var_T_List,true), %at least one var
freeze_list_h(Seq,A,FrozenList),
call(FrozenList),
call(A).
max_seq_automaton_t(Max,Seq,A,false):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each
memberd_t(true,Var_T_List,true), %at least one var
freeze_list_h(Seq,A,FrozenList),
call(FrozenList),
\+call(A).
这不起作用,在实例化X之前,应冻结以下目标:
?- Seq=[X,1],ga(Seq,A),max_seq_automaton_t(3,Seq,A,T).
Seq = [1, 1],
X = 1,
A = automaton([1, 1], [source(a), sink(c)], [arc(a, 0, a), arc(a, 1, b), arc(b, 0, a), arc(b, 1, c), arc(c, 0, c), arc(c, 1, c)]),
T = true
更新这是我现在所拥有的,我认为这是我最初想要的,但我正在消化@Mat所说的,如果这真的是我想要的。明天将进一步更新
goals_to_conj([G|Gs],Conj) :-
goals_to_conj_(Gs,G,Conj).
goals_to_conj_([],G,nonvar(G)).
goals_to_conj_([G|Gs],G0,(nonvar(G0),Conj)) :-
goals_to_conj_(Gs,G,Conj).
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each member of seq
maplist(=(false),Var_T_List), %check that all are false i.e no uninstaninated vars
call(A),!,
T=true.
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each member of seq
maplist(=(false),Var_T_List), %check that all are false i.e no uninstaninated vars
\+call(A),!,
T=false.
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each
memberd_t(true,Var_T_List,true), %at least one var
goals_to_conj(Seq,GoalForWhen),
when(GoalForWhen,(A,T=true)).
max_seq_automaton_t(Max,Seq,A,T):-
Max #>=L,
fd_length(Seq,L),
maplist(var_t,Seq,Var_T_List), %find var_t for each
memberd_t(true,Var_T_List,true), %at least one var
goals_to_conj(Seq,GoalForWhen),
when(GoalForWhen,(\+A,T=false)).
在我看来,您在Prolog方面取得了很大的进步。不过,在这一点上,采取更谨慎的行动是有道理的。原则上,你所要求的一切都可以很容易地解决。您只需要一个
freeze/2
的泛化,它在/2时作为提供
然而,让我们后退一步,更深入地思考这里到底发生了什么。< /P>
声明性地说,当我们声明一个约束时,我们的意思是它保持不变。我们的意思不是“只有当所有东西都实例化时它才有效”,因为这将把约束简化为一个简单的检查器,从而产生一种“生成并测试”的方法。约束的要点就是尽可能地删减,在许多情况下会大大减少搜索空间
具体化的约束也是如此。当我们发布物化约束时,我们声明物化有效。不仅在所有东西都实例化的情况下,而且总是。关键是(具体化的)约束可以在所有方向上使用。如果被具体化的约束已经包含,我们就会知道它。同样,如果它不能坚持,我们也会了解它。如果有任何一种可能,我们都需要明确地寻找解决方案,或者确定不存在任何解决方案。如果我们想要坚持被物化的约束是成立的,这是很容易的;等等
然而,在所有情况下,重点都是我们可以关注约束的声明性语义,而不需要额外的逻辑和过程性考虑,比如实例化什么以及何时实例化。如果我回答了你字面上的问题,它将使你更接近操作考虑,比你实际需要或想要的要近得多
因此,我不打算回答你的字面问题。但我会给你一个解决你的实际问题的方法
重点是重新定义自动机/3
。约束具体化本身不会删减任何内容,只要它是开放的,无论被具体化的约束是否实际持有。只有当我们坚持要具体化的约束成立时,传播才会发生
通过具体化构成其分解的约束的连接,很容易具体化自动机/3
。以下是一种方法,它基于SWI Prolog中免费提供的代码:
:- use_module(library(clpfd)).
automaton(Vs, Ns, As, T) :-
must_be(list(list), [Vs,Ns,As]),
include_args1(source, Ns, Sources),
include_args1(sink, Ns, Sinks),
phrase((arcs_relation(As, Relation),
nodes_nums(Sinks, SinkNums0),
nodes_nums(Sources, SourceNums0)), [[]-0], _),
phrase(transitions(Vs, Start, End), Tuples),
list_to_drep(SinkNums0, SinkDrep),
list_to_drep(SourceNums0, SourceDrep),
( Start in SourceDrep #/\
End in SinkDrep #/\
tuples_in(Tuples, Relation)) #<==> T.
include_args1(Goal, Ls0, As) :-
include(Goal, Ls0, Ls),
maplist(arg(1), Ls, As).
list_to_drep([L|Ls], Drep) :-
foldl(drep_, Ls, L, Drep).
drep_(L, D0, D0\/L).
transitions([], S, S) --> [].
transitions([Sig|Sigs], S0, S) --> [[S0,Sig,S1]],
transitions(Sigs, S1, S).
nodes_nums([], []) --> [].
nodes_nums([Node|Nodes], [Num|Nums]) -->
node_num(Node, Num),
nodes_nums(Nodes, Nums).
arcs_relation([], []) --> [].
arcs_relation([arc(S0,L,S1)|As], [[From,L,To]|Rs]) -->
node_num(S0, From),
node_num(S1, To),
arcs_relation(As, Rs).
node_num(Node, Num), [Nodes-C] --> [Nodes0-C0],
{ ( member(N-I, Nodes0), N == Node ->
Num = I, C = C0, Nodes = Nodes0
; Num = C0, C is C0 + 1, Nodes = [Node-C0|Nodes0]
) }.
sink(sink(_)).
source(source(_)).
示例:
?- seq([X,1], T).
结果(省略):发布约束,不传播任何内容
下一个例子:
?- seq([X,1], T), X = 3.
X = 3,
T = 0.
?- seq([1,1], T), indomain(T).
T = 0 ;
T = 1.
显然,在这种情况下,具体化的自动机/3
约束并不成立。然而,具体化约束当然仍然保持不变,这就是为什么在这种情况下T=0
下一个例子:
?- seq([X,1], T), X = 3.
X = 3,
T = 0.
?- seq([1,1], T), indomain(T).
T = 0 ;
T = 1.
哦哦!这是怎么回事?约束怎么可能是真的和假的?这是因为我们没有看到本例中实际发布的所有约束。使用call\u residence\u vars/2
查看全部真相
事实上,请在更简单的示例中尝试:
?- call_residue_vars(seq([1,1],0), Vs).
在这种情况下,仍需满足的未决剩余约束为:
_G1496 in 0..1,
_G1502#/\_G1496#<==>_G1511,
tuples_in([[_G1505,1,_G1514]], [[0,0,0],[0,1,1],[1,0,0],[1,1,2],[2,0,2], [2,1,2]])#<==>_G825,
tuples_in([[_G831,1,_G827]], [[0,0,0],[0,1,1],[1,0,0],[1,1,2],[2,0,2],[2,1,2]])#<==>_G826,
_G829 in 0#<==>_G830,
_G830 in 0..1,
_G830#/\_G828#<==>_G831,
_G828 in 0..1,
_G827 in 2#<==>_G828,
_G829 in 0..1,
_G829#/\_G826#<==>0,
_G826 in 0..1,
_G825 in 0..1
现在,我们可以粘贴剩余程序(由CLP(FD)约束组成),并使用label_fixpoint/1
标记域有限的变量:
?- Vs0 = [_G1496, _G1499, _G1502, _G1505, _G1508, _G1511, _G1514, _G1517, _G1520, _G1523, _G1526],
_G1496 in 0..1,
_G1502#/\_G1496#<==>_G1511,
tuples_in([[_G1505,1,_G1514]], [[0,0,0],[0,1,1],[1,0,0],[1,1,2],[2,0,2], [2,1,2]])#<==>_G825,
tuples_in([[_G831,1,_G827]], [[0,0,0],[0,1,1],[1,0,0],[1,1,2],[2,0,2],[2,1,2]])#<==>_G826,
_G829 in 0#<==>_G830, _G830 in 0..1,
_G830#/\_G828#<==>_G831, _G828 in 0..1,
_G827 in 2#<==>_G828, _G829 in 0..1,
_G829#/\_G826#<==>0, _G826 in 0..1, _G825 in 0..1,
include(finite, Vs0, Vs),
label(Vs).
练习:无论多么间接,原始查询(即seq([1,1],0)
)是否无法保持
因此,总结一下:
约束具体化本身不会导致正在具体化的约束的传播
约束具体化通常可以让您检测到约束无法保持
一般来说,CLP(FD)传播必然是不完整的,也就是说,我们不能仅仅因为查询成功就确定有解决方案
labeling/2
允许您查看如果域是有限的,是否存在具体的解决方案
要查看所有挂起的约束,请将查询包装在call\u residence\u vars/2
中
只要未决约束仍然存在,这只是一个有条件的答案
<强>推荐< /强>:为了确保不存在挣扎的约束,请在CalueSudiueVAs/2 中查找查询,并查找TopPurror上的任何剩余约束。
< P>考虑使用广泛可用的谓词<代码> //< 2 /代码>(详情请考虑阅读)。
请注意,原则上,您可以这样实现freeze/2
:
freeze(V,Goal) :-
when(nonvar(V),Goal).
在我看来,您正在实施的是以下内容的变体:
delayed_until_ground_t(Goal,T) :-
( ground(Goal)
-> ( call(Goal)
-> T = true
; T = false
)
; T = true, when(ground(Goal),once(Goal))
; T = false, when(ground(Goal), \+(Goal))
).
延迟到地面(目标,t):-
(地面(目标)
->(c)
freeze(V,Goal) :-
when(nonvar(V),Goal).
delayed_until_ground_t(Goal,T) :-
( ground(Goal)
-> ( call(Goal)
-> T = true
; T = false
)
; T = true, when(ground(Goal),once(Goal))
; T = false, when(ground(Goal), \+(Goal))
).