create subset and use each atom only once - answer-set-programming

I am totally new in asp. I need to create a group of teams. Each group must consist of 3 randomly chosen teams. A team can be in only one group.
Thanks in advance. Here is my code
team(fener;galata;besik;van;adana;mardin).
neq(X,Y) :- X!=Y,team(X),team(Y).
count(C) :- C = #count{ T : team(T)}.
C/3 {group(X,Y,Z):team(X),team(Y),team(Z), neq(X,Y),neq(X,Z),neq(Z,Y) } C/3 :- count(C).
#show group/3.
a possible output could be
group(fener;besik;van) group(galata;mardin;adana)

The output you want is not possible:
group(a;b;c).
implies:
group(a). group(b). group(c).
A possible output would be:
group(a,b,c).
But ASP is not really friendly with variable arguments atoms, or list elements as parameters. A simpler output to manage would be:
group(1,a). group(1,b). group(1,c).
And this is very easy to generate, and allows us to avoid the costly #count:
% Data
#const nb_group=2.
group(1..nb_group).
team(fener;galata;besik;van;adana;mardin).
% Assign 3 teams to each group
3{ group(G,T): team(T) }3 :- group(G).
% Two (almost) equilavent constraints:
1{ group(G,T): group(G) }1:- team(T). % a team is in only one group
OR
:- team(T) ; not group(_,T). % a team has no group

I think, have found the solution.
team(fener;galata;besik;van;adana;mardin).
neq(X,Y) :- X!=Y,team(X),team(Y).
count(C) :- C = #count{ T : team(T)}.
C/3 {group(X,Y,Z):team(X),team(Y),team(Z), neq(X,Y),neq(X,Z),neq(Z,Y) } C/3 :- count(C).
exist_in_group(T) :- group(T,_,_).
exist_in_group(T) :- group(_,T,_).
exist_in_group(T) :- group(_,_,T).
:- team(T), not exist_in_group(T).
#show group/3.
The output:
clingo version 5.0.0
Solving...
Answer: 1
group(besik,fener,adana) group(galata,mardin,van)
SATISFIABLE
Models : 1+
Calls : 1
Time : 0.011s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time : 0.000s

Related

How can I define a married couple in Clingo?

I'm trying to create 5 marriages, given 5 women and 5 man and their preferences to each other.
homem(miguel).
homem(joao).
homem(pedro).
homem(marco).
homem(carlos).
mulher(maria).
mulher(paula).
mulher(carla).
mulher(cristina).
mulher(ana).
all the marriages are stable (it is unstable if 2 person outside the marriage prefer each other more than their spouses), and I have their preferences to each other by ranks:
pref(miguel,paula,5).
pref(miguel,ana,4).
pref(miguel,maria,3).
pref(miguel,carla,2).
pref(miguel,cristina,1).
pref(maria,carlos,5).
pref(maria,miguel,4).
pref(maria,marco,3).
pref(maria,joao,2).
pref(maria,pedro,1).
pref(joao,maria,5).
pref(joao,paula,4).
pref(joao,carla,3).
pref(joao,cristina,2).
pref(joao,ana,1).
pref(paula,marco,5).
pref(paula,carlos,4).
pref(paula,joao,3).
pref(paula,miguel,2).
pref(paula,pedro,1).
pref(pedro,paula,5).
pref(pedro,carla,4).
pref(pedro,ana,3).
pref(pedro,cristina,2).
pref(pedro,maria,1).
pref(carla,miguel,5).
pref(carla,marco,4).
pref(carla,joao,3).
pref(carla,pedro,2).
pref(carla,carlos,1).
pref(marco,maria,5).
pref(marco,carla,4).
pref(marco,paula,3).
pref(marco,cristina,2).
pref(marco,ana,1).
pref(cristina,pedro,5).
pref(cristina,joao,4).
pref(cristina,marco,3).
pref(cristina,miguel,2).
pref(cristina,carlos,1).
pref(carlos,ana,5).
pref(carlos,carla,4).
pref(carlos,paula,3).
pref(carlos,maria,2).
pref(carlos,cristina,1).
pref(ana,marco,5).
pref(ana,joao,4).
pref(ana,pedro,3).
pref(ana,carlos,2).
pref(ana,miguel,1).
casamento(1..5).
% every person belongs to one group only.
1{in(H,M): casamento(C)}1 :- homem(H), mulher(M).
:- homem(H1), mulher(M1), homem(H2), mulher(M2),
pref(H1,M2,P1),pref(H1,M1,P2), P1>P2,
pref(M2,H1,P3), pref(M2,H2,P4); P3>P4.
but this does not work and I don't know why.
Problem 1
The rule
1{in(H,M): casamento(C)}1 :- homem(H), mulher(M).
doesn't mean that "every person belongs to one group only", but that "every pair of man and woman belongs to exactly one marriage. This is equivalent to say that every man is married with every woman.
Instead, you should express the contrary: every marriage should "generate" exactly one pair of people:
1{in(H,M,C): homem(H), mulher(M)}1 :- casamento(C) .
But this doesn't prevent a men (or woman) to belong to two different marriages. So you shoul also add:
:- in(H,M1,C1), in(H,M2,C2), C1!=C2 .
:- in(H1,M,C1), in(H2,M,C2), C1!=C2 .
Problem 2
Moreover, in your constraint you're considering every pair of people (not every pair of married people!). So you should replace homem(H1), mulher(M1), homem(H2), mulher(M2) with in(H1,M1,C1), in(H2,M2,C2).
Fixed code
casamento(1..5) .
1{in(H,M,C): homem(H), mulher(M)}1 :- casamento(C) .
:- in(H,M1,C1), in(H,M2,C2), C1!=C2 .
:- in(H1,M,C1), in(H2,M,C2), C1!=C2 .
:- in(H1,M1,C1), in(H2,M2,C2),
pref(H1,M2,P1), pref(H1,M1,P2), P1>P2,
pref(M2,H1,P3), pref(M2,H2,P4), P3>P4 .
This program (plus the EDB in your example) generates the following marriages:
in(miguel,carla,2) in(marco,paula,3) in(joao,cristina,1) in(carlos,maria,4) in(pedro,ana,5)
Optional
If you don't want to hardcode the 5 and make it work for any number of people in input, you can dynamically count the number of women (or men, assuming that it's the same).
So you can replace casamento(1..N). with:
casamento(1..N) :- N = #count{ X : mulher(X) } .

ASP Clingo - getting the exact count of atoms

I'm looking forward to assign a specific count of persons to a specific shift. For example I got six persons and three different shifts. Now I have to assign exact two persons to every shift. I tried something like this but..
NOTE: this won't work, so please edit as fast as possible to misslead people, I even removed the "." after it so nobody is copying it:
person(a)
person(b)
person(c)
person(d)
person(e)
person(f)
shift("mor")
shift("aft")
shift("nig")
shiftCount(2).
{ assign(P,S) : shift(S)} = 1 :- person(P).
% DO NOT COPY THIS! SEE RIGHT ANSWER DOWN BELOW
:- #count{P : assign(P,"mor")} = K, shiftCount(K).
:- #count{P : assign(P,"aft")} = K, shiftCount(K).
:- #count{P : assign(P,"nig")} = K, shiftCount(K).
#show assign/2.
Is this possible to count the number of assigned shifts, so I can assign exactly as many people as a given number?
The output of the code above (when the "." are inserted) is:
clingo version 5.5.0
Reading from stdin
Solving...
Answer: 1
assign(a,"nig") assign(b,"aft") assign(c,"mor") assign(d,"mor")
assign(e,"mor") assign(f,"mor")
SATISFIABLE
Models : 1+
Calls : 1
Time : 0.021s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time : 0.000s
Here you can defently see, that the morning ("mor") shift is used more than two times, as difined in the shiftCount. What do I need to change to get the wanted result?
Replace your 3 lines constraints with
{assign(P,S): person(P)} == K :- shift(S), shiftCount(K).
or alternatively if you want to use the constraint writing:
:- {assign(P,S): person(P)} != K, shift(S), shiftCount(K).
First line states: For a given shiftCount K and for every shift S: the number of assignments over all people P for this shift S is K.
The constraint reads: it can not be the case for a shiftCount K and a shift S that the number of assignments over all people P to the shift S is not K.
Please do not alter your question / sample code dramatically since this may leads to the case that this answer won't work anymore.

Clingo/ASP: Best way to generate characters in a story generator

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?
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

Drools-Compare properties of 2 objects

I have a requirement to determine which train to choose to assign an Employee to.
Let's say I have 2 trains with properties as:
Train 1 Train 2
trainID=1 trainID=2
passengerCount=100 passengerCount=150
numberOfBoxes=12 numberOfBoxes=7
If I pass both these objects to Drools and check like
$train1 : TrainProperties($pasCnt : passengerCount)
$train2 : TrainProperties($pasCnt2 : passengerCount > $pasCnt)
then
Sysout("Train 2 is more important")
end
Now I have to add more conditions based on numberOfBoxes. How can I do it?
As stated in Drools Documentation, you can use a , to create multiple AND conditions inside a pattern. You can also use || to create OR.
So, in your case, you could do something like this:
when
$train1 : TrainProperties($pasCnt : passengerCount, $boxes: numberOfBoxes)
$train2 : TrainProperties($pasCnt2 : passengerCount > $pasCnt, numberOfBoxes > $boxes )
then
Sysout("Train 2 is more important")
end
Hope it helps,

Cannot mix aggregate and non-aggregate comparison with COUNT

I know this is very commom question. But I havenot still known why in my case as follows. Give me your idea about this issue:
Question: I want to count the number of user who appear in list < 3.
- First I created the "calculated Field"
- Here is my function:
If COUNT([User]) < 3 then [User] END
Finally, I count this Meseasure again to gain the final result.
Here's my example:
User
a
a
a
a
b
b
c
b
The result expected: 1 (only c)
Thanks all
Place your IF statement inside the COUNT().