Clingo/ASP: Best way to generate characters in a s

2019-08-29 15:37发布

I am trying to write a story generator in Clingo.

I am trying to say "new characters can be born if existing characters give birth to them." I define new characters as entity(<int\>), which is the best way I could think of to representing entities. I cannot hardcode this as varying number of entities can be created in a story.

My code is :

% Create instances of time, only 3 for testing
time(0..2).

% Arrow of time flows forward
next_t(T, T+1) :- time(T), time(T+1).

% Entity 1 exists at time 0.
entity(1, 0).

% If an entity ever existed, that ID is taken and cannot be assigned to
% other entities
entity_id(ID) :- entity(ID, _).

% If an entity exists, he can give birth to a new entity
% The ID of the new entity will be 1 more than ID of all current entities.
birth(X, Y, T) :- entity(Y, T), X = #max{X1+1:entity_id(X1)}, time(T).

% At each time instant, only 1 entity can be born, as only 1 event can happen per time instant.
% This also should prevent infinite entities to be created.
:- birth(X1, _, T), birth(Y1, _, T), X1!=Y1.

% In case of a birth, create a new entiti the next time instant.
entity(X, T1) :- birth(X, _, T), next(T, T1).

#show entity_id/1.
#show entity/2.
#show birth/3 .

However, output is :

entity_id(1) entity(1,0) birth(2,1,0)

entity(2, 1) is never created, nor are entity(3, 2) or entity(4, 3).

What am I doing wrong? Is there a better way to do this?

1条回答
何必那么认真
2楼-- · 2019-08-29 15:53

You seem to be thinking that ASP statements happen in order from first to last or something like that. But in fact they're just rules about a collection of atoms. The rules always hold. In particular, the rule:

entity_id(ID) :- entity(ID, _).

says nothing about duplicates. It just says that for every entity which has an ID ID, ID is an entity_id. If you want to encode the rule that each ID is used once, you should write it as:

:- {entity(ID,_)} > 1; entity_id(ID).

Also you try to construct "ID's" which are "one more than all current entities", but there's no such thing as "current" entities. All we have to guide us are the time-steps.

Let's try writing this in a way that keeps our timesteps explicit throughout.


% Create instances of time, only 3 for testing
time(0..2).

% Entity eve exists at time 0.
entity(1, 0).

nextID(2, 0).

% If an entity existed at the previous time-step, they continue to exist
% at the next time-step (as I understand, no entity dies).
entity(ID, T) :- entity(ID, T-1); time(T).

% Any entity who was alive on the previous time-step can give birth to
% a child at time T. This child's ID is the current `nextID`
% Note this is a _choice_ rule. The entity _can_ give birth, they don't
% have to. Also we only allow at most one of these births to happen at
% each time-step.
{birth(ChildID, ParentID, T) : entity(ParentID,T-1)} <= 1 :- nextID(ChildID,T).

% Once born, an ID becomes an entity.
entity(ID,T) :- birth(ID,_,T).

% If an entity was born at the previous time-step, the nextID increases by one
% for this time-step.
nextID(ID+1,T) :- nextID(ID,T-1); time(T); entity(ID,T-1).
% Otherwise it stays the same.
nextID(ID,T) :- nextID(ID,T-1); time(T); not entity(ID,T-1).

#show birth/3.

Running this I find there are 5 models.

$ clingo entities.asp 0
clingo version 5.3.1
Reading from entities.asp
Solving...
Answer: 1

% ^ Nobody is ever born
Answer: 2
birth(2,1,2)
% ^ Nobody born at time 1. 1 births a child at time 2
Answer: 3
birth(2,1,1) birth(3,2,2)
% ^ 1 births a child at time 1 and that child gives birth at time 2.
Answer: 4
birth(2,1,1)
% ^ 1 births a child at time 1. Nobody is born at time 2.
Answer: 5
birth(2,1,1) birth(3,1,2)
% ^ 1 births two children; one at time 1 and another at time 2.
SATISFIABLE

Models       : 5
Calls        : 1
Time         : 0.011s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time     : 0.004s
查看更多
登录 后发表回答