Using Atomese as an alternative to PDDL

87 views
Skip to first unread message

Ramin Barati

unread,
Jan 1, 2018, 8:02:46 AM1/1/18
to opencog
Hi Ben, Linas, etc

I am trying to solve a resource allocation problem; assigning planes to flights.

Here is the domain definition in PDDL:

-------------------------------------------------------------------------------------
(define (domain flight-plan)
(:requirements :strips :typing :action-costs)
(:types
location localable leg - object
airport - location
register - localable
)
(:predicates
(at ?o - localable ?l - location)
(assigned ?l - leg)
(assigned-to ?l - leg ?r - register)
(source ?l - leg ?a - airport)
(destination ?l - leg ?a - airport)
)
(:functions
(start ?l - leg) - number
(duration ?l - leg ?r - register) - number
(pax ?l - leg) - number
(capacity ?r - register) - number
(assignement-cost ?l - leg ?r - register) - number
(timeline ?r - register) - number
(total-cost) - number
)
(:action asgn
:parameters (?l - leg ?r - register ?src ?dest - airport)
:precondition (and
(> (start ?l) (timeline ?r))
(source ?l ?src)
(destination ?l ?dest)
(at ?r ?src)
(not (assigned ?l))
(> (capacity ?r) (pax ?l))
)
:effect (and
(decrease (timeline ?r) (timeline ?r))
(increase (timeline ?r) (+ (start ?l) (duration ?l ?r)))
(not (at ?r ?src))
(at ?r ?dest)
(assigned ?l)
(assigned-to ?l ?r)
(increase (total-cost) (assignement-cost ?l ?r))
)
)
(:action shift-left-sixty
:parameters (?l - leg)
:precondition (and
(not (assigned ?l))
(> (start ?l) 60)
)
:effect (and
(decrease (start ?l) 60)
)
)
(:action shift-right-sixty
:parameters (?l - leg)
:precondition (and
(not (assigned ?l))
(< (start ?l) 1380)
)
:effect (and
(increase (start ?l) 60)
)
)
)
-------------------------------------------------------------------------------------  

and here is a sample problem:

-------------------------------------------------------------------------------------
 (define (problem assignment)
(:domain flight-plan)
(:objects
THR-SRY SRY-THR THR-ISF ISF-THR - leg
MOC JHH MNT - register
thr sry isf - airport
)
(:init
(= (total-cost) 0)
(at MOC thr)
(at JHH thr)
(at MNT thr)
(= (capacity MOC) 100)
(= (timeline MOC) 0)
(= (capacity JHH) 200)
(= (timeline JHH) 0)
(= (capacity MNT) 280)
(= (timeline MNT) 0)
(source THR-SRY thr)
(destination THR-SRY sry)
(= (start THR-SRY) 600)
(= (pax THR-SRY) 90)
(source SRY-THR sry)
(destination SRY-THR thr)
(= (start SRY-THR) 720)
(= (pax SRY-THR) 150)
(source THR-ISF thr)
(destination THR-ISF isf)
(= (start THR-ISF) 720)
(= (pax THR-ISF) 220)
(source ISF-THR isf)
(destination ISF-THR thr)
(= (start ISF-THR) 900)
(= (pax ISF-THR) 190)
(= (assignement-cost THR-SRY MOC) 1)
(= (assignement-cost SRY-THR MOC) 1)
(= (assignement-cost THR-ISF MOC) 1)
(= (assignement-cost ISF-THR MOC) 1)
(= (assignement-cost THR-SRY JHH) 1)
(= (assignement-cost SRY-THR JHH) 1)
(= (assignement-cost THR-ISF JHH) 1)
(= (assignement-cost ISF-THR JHH) 1)
(= (assignement-cost THR-SRY MNT) 1)
(= (assignement-cost SRY-THR MNT) 1)
(= (assignement-cost THR-ISF MNT) 1)
(= (assignement-cost ISF-THR MNT) 1)
(= (duration THR-SRY MOC) 180)
(= (duration SRY-THR MOC) 180)
(= (duration THR-ISF MOC) 120)
(= (duration ISF-THR MOC) 120)
(= (duration THR-SRY JHH) 180)
(= (duration SRY-THR JHH) 180)
(= (duration THR-ISF JHH) 120)
(= (duration ISF-THR JHH) 120)
(= (duration THR-SRY MNT) 180)
(= (duration SRY-THR MNT) 180)
(= (duration THR-ISF MNT) 120)
(= (duration ISF-THR MNT) 120)
)
(:goal (and
(at MOC thr)
(at JHH thr)
(at MNT thr)
(assigned THR-SRY)
(assigned SRY-THR)
(assigned THR-ISF)
(assigned ISF-THR)
))
(:metric minimize (total-cost))
)
------------------------------------------------------------------------------------- 

Is it possible to use OpenCog planner and Atomese to solve this problem?

Regards,
Ramin

Ben Goertzel

unread,
Jan 1, 2018, 8:27:23 AM1/1/18
to opencog
PLN backward chainer can solve that in principle, but it may be quite
slow at doing so currently... Nil is working on fancy methods to speed
it up...
> --
> You received this message because you are subscribed to the Google Groups
> "opencog" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to opencog+u...@googlegroups.com.
> To post to this group, send email to ope...@googlegroups.com.
> Visit this group at https://groups.google.com/group/opencog.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/opencog/CAHmauB6Wh6DEJcF_2KoCSD%2BapWaeJtkKSPCT7%2Bd5K96c_tuRnA%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.



--
Ben Goertzel, PhD
http://goertzel.org

"In the province of the mind, what one believes to be true is true or
becomes true, within certain limits to be found experientially and
experimentally. These limits are further beliefs to be transcended. In
the mind, there are no limits.... In the province of connected minds,
what the network believes to be true, either is true or becomes true
within certain limits to be found experientially and experimentally.
These limits are further beliefs to be transcended. In the network's
mind there are no limits." -- John Lilly

Ramin Barati

unread,
Jan 2, 2018, 12:32:27 AM1/2/18
to ope...@googlegroups.com
Hi Ben,

Thank you for your timely response. Are there any documentation, tutorials or examples available on wiki for the planner? If we could show some proof of concept,  we may be able to persuade the biz side to let us help Nil on completing the planner. 

Ben Goertzel

unread,
Jan 2, 2018, 4:39:55 AM1/2/18
to opencog, Nil Geisweiller
HI, we don't have a planner per se in OpenCog right now, what we have
is a probabilistic logic backward chainer...

https://wiki.opencog.org/w/PLN_Backward_Chaining

here are some simple example scripts using the backward chainer

https://github.com/opencog/opencog/tree/master/examples/pln/sumo

Using the backward chainer as a planner would not be hard and could be
done via using special control heuristics and/or explicitly
representing temporal knowledge in the ATomspace...

ben
> https://groups.google.com/d/msgid/opencog/CAHmauB4Lp-SyBwTOgfXvX0VKJ6QBxKHFenLqR-2%3DOKwJwW%2BBdQ%40mail.gmail.com.

Linas Vepstas

unread,
Jan 2, 2018, 2:49:35 PM1/2/18
to opencog
Hi Ramin,

For this kind of problem, I would strongly encourage using answer-set programming.  It looks like prolog (but isn't), it uses modern SAT-solving technology to get tremendous speed.  The Univ Potsdam solver is maybe the best one. It's excellent for solving constraint satisfaction problems.

Here's an example: instead of airplanes, its boats and  oars.  The constraints are:
-- a race every 4 minutes
-- boat must be back in time to unload, reload, and get to starting line viz 12 minutes
-- boat (and oars) obviously cannot be used by someone else while on the water
-- boats are 1x, 2x, 2+, 2-, 4x, 4+, 4-, 8+  (these are different kinds of boats)
-- oars must be a matched set, appropriate for that boat style.
-- boats are constrained by the race that they are in.
-- certain crews insist on using certain equipment, and have priority
-- certain crews can select only a subset (e.g. mens crews cannot use the lightweight boats)

It turns out that the problem is not too hard, until you throw the oars into the mix, and then it gets a lot harder.

Here's the solver (it works):

%
% regatta team equipment scheduling
%
% The problem of scheduling equipment for a regatta is a constraint
% problem -- two crews cannot use the same boat at the same time,
% and, indeed, there must be enough time between crews to rig the boat,
% launch it, warm up, race, and return to the dock, before the next
% crew can use it.  Because this is a classic constraint problem,
% implementing this via answer-set programming seems like the easiest,
% most direct way to accomplish this.
%
% Initial version: Linas Vepstas April 2012
%
% Copyright (c) 2012 Linas Vepstas
% The GNU GPLv3 applies.
%

% -- List of fundamental boat classes.  We must distinguish sweeps
% from sculls, and quads, doubles, singles, etc.  in order to be
% able to count the number of oars needed, for oar reservations.
% That's why these are the "fundamental" types.
boat(BOAT) :- sweep_boat(BOAT).
boat(BOAT) :- scull_boat(BOAT).

sweep_boat(BOAT) :- eight(BOAT).
sweep_boat(BOAT) :- fourplus(BOAT).
sweep_boat(BOAT) :- fourminus(BOAT).
sweep_boat(BOAT) :- pair(BOAT).

scull_boat(BOAT) :- quad(BOAT).
scull_boat(BOAT) :- double(BOAT).
scull_boat(BOAT) :- single(BOAT).

%%% ========================================================== %%%
%% The actual scheduling algorithm. Short and simple, huh?
%% DO NOT MODIFY ANYTHING BELOW THIS LINE!
%% (Unless you really, really know what you're doing, and
%% you probably don't.)  Just write me with questions, requests.
%%% ========================================================== %%%

% Some priority assignments:
boat_reserve_priority(12). % top priority
oar_reserve_priority(11).  % 2nd highest priority
boat_hotseat_priority(10). % 3rd priority
oar_hotseat_priority(9).   % 4th priority
boat_choice_priority(8).
oar_choice_priority(7).
num_boats_priority(6).
num_oars_priority(5).

% Below follows the core available/request/reserve logic.

% A boat is available if its not in use by any crew.
available(RACE, BOAT) :- racenum(RACE), crew(CREW), boat(BOAT),
                         not inuse(RACE, CREW, BOAT).

% Reserve the boat if it is requested and available.
reserve(RACE, CREW, BOAT) :- racenum(RACE), crew(CREW), boat(BOAT),
                             request(RACE, CREW, BOAT),
                             available(RACE, BOAT).

% If a boat is reserved, then it will be in use at least CENTER races
% beforehand. That is, the crew needs CENTER-1 races to launch and
% warmup before the race.
inuse(ONWATER, CREW, BOAT) :- reserve(RACE, CREW, BOAT),
                              heat(SCH, RACE),
                              SCHMN = SCH - N,
                              heat(SCHMN, ONWATER),
                              N = 1..CENTER-1,
                              center(CENTER).

% Its on the water for the next race, too.
inuse(ONWATER, CREW, BOAT) :- reserve(RACE, CREW, BOAT),
                              heat(SCH, RACE),
                              heat(SCH+1, ONWATER).

% Cannot reserve a boat that is in use.
:- reserve(RACE, CREW, BOAT), inuse(RACE, OTHER_CREW, BOAT),
   racenum(RACE), crew(CREW), crew(OTHER_CREW), boat(BOAT).

% Cannot request a boat if its in use.
% This rule isn't needed right now, comment it out.
% :- request(RACE, CREW, BOAT), inuse(RACE, OTHER_CREW, BOAT).

% Two different crews cannot reserve same boat for the same race.
:- reserve(RACE, CREW, BOAT), reserve(RACE, OTHER_CREW, BOAT),
   CREW != OTHER_CREW,
   racenum(RACE), crew(CREW), crew(OTHER_CREW), boat(BOAT).

% ----------------------
% Preference indication.

% choice must be a number, 1 to 4.
choice(CHOICE) :- CHOICE=1..4.

% The total universe of all possible boat assignments, to a given
% crew and race.  In this universe, only one boat is ever assigned.
1 { boat_universe(RACE, CREW, BOAT) : boat(BOAT) } 1 :-
   crew(CREW), racenum(RACE).

% Out of a list of desired boats, choose only one boat.
request(RACE, CREW, BOAT) :- prefer(RACE, CREW, BOAT, CHOICE),
                             boat_universe(RACE, CREW, BOAT).

% A crew wants to race in a race if they've expressed a boat preference.
% or if they've requested a specific boat.
want_to_race(RACE, CREW) :- prefer(RACE, CREW, BOAT, CHOICE).
want_to_race(RACE, CREW) :- request(RACE, CREW, BOAT).

% A crew got a boat if it has a reservation.
got_a_boat(RACE, CREW) :- reserve(RACE, CREW, BOAT).

% We sure want every boat request to be granted. Must flag any crews
% that want to race a race, but we can't find them a boat.
% This flag must be highly visible.
boat_reservation_failure(RACE, CREW) :- want_to_race(RACE, CREW),
                                        not got_a_boat(RACE, CREW).

% The above rules do allow a situation where some crews can't get
% a boat.  Thus, we have to maximize for number of reservations
% granted.  This must be at the highest priority, higher than the
% hot-seat avoidance priority.
#minimize [boat_reservation_failure(RACE, CREW)
                   : boat_reserve_priority(BRP)
                   : racenum(RACE)
                   : crew(CREW) @BRP ].

% We're going to try to honour everyone's top preferences.
% So CHOICE=1 is first choice, CHOICE=2 is second choice, etc.
#minimize [request(RACE, CREW, BOAT)
                : boat_choice_priority(BCP)
                : prefer(RACE, CREW, BOAT, CHOICE) = CHOICE@BCP ].

% ----------------------
% Hotseat notifications and minimization.
% Basically, we try to find assignments with the fewest hot-seats.

% True if boat will be hotseated at the dock.
hotseat(RACE, BOAT) :- reserve(RACE, CREW, BOAT),
                       reserve(OTHER_RACE, OTHER_CREW, BOAT),
                       heat(SCH, RACE),
                       heat(SCH-CENTER-M, OTHER_RACE),
                       center(CENTER),
                       M=0..HOTS, hotseat_warn(HOTS).

% True if crew should hurry back because boat is needed.
% Currently, not used for anything, except as a printout for the
% convenience of the crews.
hurry_back(RACE, CREW, BOAT) :-
                       reserve(RACE, CREW, BOAT),
                       reserve(OTHER_RACE, OTHER_CREW, BOAT),
                       heat(SCH, RACE),
                       heat(SCH+CENTER+M, OTHER_RACE),
                       center(CENTER),
                       M=0..HOTS, hotseat_warn(HOTS).

% Minimize the number of boats that are hot-seated.
% The @10 just means that minimizing the number of hot-seats is
% top priority -- higher priority than honoring desired boats.
#minimize [hotseat(RACE, BOAT) @BHP : boat_hotseat_priority(BHP)].


% ----------------------
% Equipment list.  Stuff to take to the venue.
take_to_venue(BOAT) :- reserve(RACE, CREW, BOAT).

% This seems to make things run a bit slower... and yeilds nothing
% noteworthy, since specific boats are being aasked for in almost
% all cases, and so te below can't cut down on anything.
% It seems to add 5% or so tot toal run time ...
#minimize [take_to_venue(BOAT)
                   : num_boats_priority(NBP) @NBP ].

% ----------------------
% Look for a typo in the name of the boat, crew or race.
% Typos can screw everything up, so flag these.
bad_boat_name(BOAT) :- request(RACE,CREW,BOAT), not boat(BOAT).
bad_crew_name(CREW) :- request(RACE,CREW,BOAT), not crew(CREW).
bad_race_num(RACE)  :- request(RACE,CREW,BOAT), not racenum(RACE).

bad_boat_name(BOAT) :- prefer(RACE,CREW,BOAT,CHOICE), not boat(BOAT).
bad_crew_name(CREW) :- prefer(RACE,CREW,BOAT,CHOICE), not crew(CREW).
bad_race_num(RACE)  :- prefer(RACE,CREW,BOAT,CHOICE), not racenum(RACE).
bad_preference(CHOICE) :- prefer(RACE,CREW,BOAT,CHOICE), not choice(CHOICE).

#hide.
#show boat_reservation_failure/2.
#show bad_boat_name/1.
#show bad_crew_name/1.
#show bad_race_num/1.
#show bad_preference/1.
#show reserve/3.
#show hotseat/2.
#show hurry_back/3.
#show take_to_venue/1.
% #show request/2.
% #show inuse/2.
% #show available/2.



--
You received this message because you are subscribed to the Google Groups "opencog" group.
To unsubscribe from this group and stop receiving emails from it, send an email to opencog+unsubscribe@googlegroups.com.



--
"The problem is not that artificial intelligence will get too smart and take over the world," computer scientist Pedro Domingos writes, "the problem is that it's too stupid and already has."

Linas Vepstas

unread,
Jan 2, 2018, 2:56:16 PM1/2/18
to opencog
Oh, I forgot, here is an actual dataset that the solver can solve, this was for an actual race in 2012.

Note that the dataset is larger than the solver itself.

I don't expect you to understand this; its more of an example of what a typical constraint satisfaction problem would actually look like, when written in ASP.   It gives a hint of the syntax and style.

%
% trc_boats.asp
% Texas Rowing Center Boats
%
% This file lists the boats and boat classes used by TRC.  By making use
% of the #include directive, this listing can be reused for different
% regattas.

%
% Initial version: Linas Vepstas April 2012
%
% Copyright (c) 2012 Linas Vepstas
% The GNU GPLv3 applies.
%

% -- List of boat classes.  Can add new boat classes here, if desired.
quad(BOAT) :- heavy_quad(BOAT).
quad(BOAT) :- midheavy_quad(BOAT).
quad(BOAT) :- midweight_quad(BOAT).
quad(BOAT) :- midlight_quad(BOAT).
quad(BOAT) :- lightweight_quad(BOAT).

double(BOAT) :- heavy_double(BOAT).
double(BOAT) :- midweight_double(BOAT).
double(BOAT) :- lightweight_double(BOAT).

single(BOAT) :- heavy_single(BOAT).
single(BOAT) :- midweight_single(BOAT).
single(BOAT) :- lightweight_single(BOAT).
single(BOAT) :- flyweight_single(BOAT).
single(BOAT) :- adaptive_single(BOAT).
single(BOAT) :- club_racer(BOAT).

% --- Generic boat classes.
hv_or_mid_quad(BOAT) :- heavy_quad(BOAT).
hv_or_mid_quad(BOAT) :- midheavy_quad(BOAT).
hv_or_mid_quad(BOAT) :- midweight_quad(BOAT).
lt_or_mid_quad(BOAT) :- midweight_quad(BOAT).
lt_or_mid_quad(BOAT) :- midlight_quad(BOAT).
lt_or_mid_quad(BOAT) :- lightweight_quad(BOAT).

any_quad(BOAT) :- hv_or_mid_quad(BOAT).
any_quad(BOAT) :- lt_or_mid_quad(BOAT).

% --------
hv_or_mid_double(BOAT) :- heavy_double(BOAT).
hv_or_mid_double(BOAT) :- midweight_double(BOAT).

lt_or_mid_double(BOAT) :- lightweight_double(BOAT).
lt_or_mid_double(BOAT) :- midweight_double(BOAT).

any_double(BOAT) :- hv_or_mid_double(BOAT).
any_double(BOAT) :- lt_or_mid_double(BOAT).

% --------
hv_or_mid_single(BOAT) :- heavy_single(BOAT).
hv_or_mid_single(BOAT) :- midweight_single(BOAT).

lt_or_mid_single(BOAT) :- lightweight_single(BOAT).
lt_or_mid_single(BOAT) :- midweight_single(BOAT).

any_single(BOAT) :- hv_or_mid_single(BOAT).
any_single(BOAT) :- lt_or_mid_single(BOAT).
any_single(BOAT) :- flyweight_single(BOAT).

% --- Describe the boats, according to boat class.
% Kaitlin is a heavy 8, Sophie a mid-weight.
eight(kaitlin).
eight(sophie).

% Judie is a midweight, Berverly a heavy
% Marty's 4- is a midweight
fourplus(judie).
fourplus(beverly).
fourminus(martys_4minus).

% Quads
heavy_quad(orange).
heavy_quad(black).
midheavy_quad(parents).
midheavy_quad(masters).
midheavy_quad(mcdiarmid).

midweight_quad(yellow).
midlight_quad(green).
midlight_quad(blue).
lightweight_quad(red).

% Doubles
heavy_double(maas).
heavy_double(jakob).
heavy_double(barksdales).

midweight_double(swinford).
midweight_double(bass).
lightweight_double(thrash).

% Pairs -- 41 is heavyweight, 30 is midweight.
pair(41).
pair(30).

% Singles.
heavy_single(dunya).  % Actually its a superheavy.
heavy_single(knifty).
heavy_single(director).
heavy_single(cantu).
midweight_single(somers).
midweight_single(marty_n_saloni).
midweight_single(blair).
lightweight_single(pete).
lightweight_single(veronica).
lightweight_single(unnamed).
flyweight_single(fly).
adaptive_single(intrepid).

% Club racers.
club_racer(rogers).
club_racer(kryzinski).
club_racer(hamilton).

%
% trc_oars.asp
% Texas Rowing Center Oars
%
% This file lists the oars and oar types used by TRC.  By making use
% of the #include directive, this listing can be reused for different
% regattas.

%
% Initial version: Linas Vepstas April 2012
%
% Copyright (c) 2012 Linas Vepstas
% The GNU GPLv3 applies.
%

% -- List of oar types.  Can add new types here, if desired.
scull_oars(OARS, COUNT) :- fatties(OARS, COUNT).
scull_oars(OARS, COUNT) :- big_grip(OARS, COUNT).
scull_oars(OARS, COUNT) :- thin_grip(OARS, COUNT).

% We're going to attempt to race without the clunkers, if we can...
% scull_oars(OARS, COUNT) :- novice(OARS, COUNT).  % the clunky ones.

% --- List of oars.
sweep_oars(purple, 4).
sweep_oars(orange, 4).
sweep_oars(blue, 4).
sweep_oars(wood, 4).
sweep_oars(pair, 1).

% --- Scull oars in order according to rack position.
% -- Private oars half-rack on left.
thin_grip(blue_white, 4).
fatties(blue_blue, 4).
fatties(red_red, 4).

% -- Main competitive crew rack.
fatties(purple_green, 4).
thin_grip(red_blue, 4).
fatties(yellow_purple, 4).
thin_grip(blue_orange, 4).
fatties(orange_orange, 4).
big_grip(orange_blue, 4).
big_grip(red_yellow, 4).
fatties(purple_red, 4).

% -- Novice rack, on right.
novice(blue_purple, 4).
% XX incomplete set...!?? of what color??
big_grip(green_white, 4).
big_grip(purple_white, 4).
novice(blue_yellow, 4).
big_grip(green_blue, 4).
novice(orange_purple, 4).
novice(red_white, 4).

% That's all folks.



%
% regatta team equipment scheduling
% Texas Rowing Center Boats
% Texas Rowing Championsips 2012

%
% The problem of scheduling equipment for a regatta is a constraint
% problem -- two crews cannot use the same boat at the same time,
% and, indeed, there must be enough time between crews to rig the boat,
% launch it, warmp up, race, and return to the dock, before the next

% crew can use it.  Because this is a classic constraint problem,
% implementing this via answer-set programming seems like the easiest,
% most direct way to accomplish this.
%
% Initial version: Linas Vepstas April 2012
%
% Copyright (c) 2012 Linas Vepstas
% The GNU GPLv3 applies.
%

% -- List of boat classes.
#include "trc_boats.asp".
#include "trc_oars.asp".

% -- Special boats for this race.
pair(borrowed_pair).
fourplus(borrowed_four).

boat(BOAT) :- double(BOAT).
double(private_double).  % Phil's from Dallas
double(empacher).  % private

double("30x").  % 30 rigged as a 2x
pair(thrash_pair). % thrash rigged as pair

single(private_bolton).
single(private_cullicott).
single(private_ellis).
single(private_lynch).
single(private_mast).

scull_oars(private_oars_sue, 1).
scull_oars(private_oars_bolton, 1).
scull_oars(private_oars_cullicott, 1).
scull_oars(private_oars_ellis, 2).
scull_oars(private_oars_lynch, 2).
scull_oars(private_oars_mast, 1).

% No one is going to race the maas.
:- request(RACE, CREW, maas), racenum(RACE), crew(CREW).

% --- Name the rowers.
rower(adams).     % Connie Adams
rower(bolton).    % Scott Bolton
rower(brennan).   % Rober Brennan
rower(carter).    % Sue Carter
rower(crawford).  % Jeff Crawford
rower(cullicott). % John Collicott
rower(daniels).   % Sarah Daniels
rower(ellis).     % Phil Ellis
rower(feicht).    % Doug Feicht
rower(gates).     % Ken Gates
rower(hicks).     % Connie Hicks
rower(kho).       % Suzanne Kho
rower(knifton).   % Matt Knifton
rower(lynch).     % Robb Lynch
rower(mari).
rower(mast).      % Steve Mast  (Intermediate crew)
rower(morey).     % Justin Morey
rower(nicot).     % JP Nicot
rower(oppliger).  % Wade Oppliger
rower(scheer).    % Veronica Scheer
rower(smith).     % Bill Smith  (Saloni's Crew).
rower(vepstas).   % Linas Vepstas
rower(wolf).      % Bettina Wolf

% --- Describe crew types.
crew(PERSON) :- rower(PERSON).
crew(juniors).
crew(juniors_a).
crew(juniors_b).
crew(juniors_c).
crew(juniors_d).
crew(advanced).
crew(advanced_a).
crew(advanced_b).
crew(advanced_c).
crew(advanced_d).
crew(intermediate).
crew(intermediate_a).
crew(intermediate_b).
crew(intermediate_c).
crew(intermediate_d).
crew(novice).

% --- List the races
% racenum(NUM) :- NUM=101..116.   % Saturday.
% racenum(NUM) :- NUM=201..231.   % Sunday.

% Wow. Yuck. There's gotta be an easier way!
racenum(NUM) :- heat(CENTER, NUM).

% Number on the left is just a linear ordering of the events,
% including heats.  The numbers on the left must increase by one
% (they indicate time; leave gaps for breaks!)  The numbers on
% the right are race numbers. They *must* be quoted if they contain
% decimal points.
%
% Unfortunately, currently there is no easy way of managing this
% list.  I'll try to fix this someday ...
heat(501, "201").
heat(502, "202").
heat(503, gap).
heat(504, "203.1").
heat(505, "203.2").
heat(506, "203.3").
heat(507, "204").
heat(508, "205").
heat(509, gap).
heat(510, "206.1").
heat(511, "206.2").
heat(512, "207").
heat(513, "208").
heat(514, "209").
heat(515, gap).
heat(516, "210.1").
heat(517, "210.2").
heat(518, "212").
heat(519, "213").
heat(520, "214").
heat(521, "215").
heat(522, "216").
heat(523, "217.1").
heat(524, "217.2").
heat(525, gap).
heat(526, "219").
heat(527, "220.1").
heat(528, "220.2").
heat(529, "221.1").
heat(530, "221.2").
heat(531, "222").
heat(532, gap).
heat(533, "224.1").
heat(534, "224.2").
heat(535, "225").
heat(536, "228").
heat(537, "229").
heat(538, "230.1").
heat(539, "230.2").
heat(540, "231").

% --- Specify minimum number of races between equipment reuse.
% In this case, the boat cannot be reserved for the previous 2 races.
center(3).
% Print a hotseat warning if there is just 1 center to get the boat
% back to the dock.  Change to 2 if you want more hotseat warning
% printed.
hotseat_warn(2).

% --- Restrictions.
% Juniors are never allowed to take out the black quad.
:- request(RACE, juniors, black), racenum(RACE).

% --- List boat requests.
%- Saturday, Apr 28
%- 101          Womens Jr JV 4x
%- 102          Womens Jr. Novice 2x
%- 103          Mens Jr JV 4x
%- 104          Mens Jr Novice 2x
%- 105          Womens Jr Varsity 4x
%- 106          Womens Jr JV 2x
%- 107          Mens Jr Varsity 4x
%- 108          Mens Jr JV 2x
%- 109          Womens Jr Varsity 2x
%- 110          Womens Jr Novice 4x
%- 111          Mens Jr Varsity 2x
%- 112          Mens Jr Novice 4x
%- 113          Womens Jr 1x
%- 114          Womens Jr Ltwt 2x
%- 115          Mens Jr 1x
%- 116          Mens Jr Ltwt 2x
%- Sunday, Apr 29
%- 201          Womens Masters 2-
%- 202          Mens Masters 4+
% 1{ request("202", intermediate, BOAT) : fourplus(BOAT) }1.
request("202", intermediate, beverly).
oar_request("202", intermediate, wood, 1).

%- 203          Mens Masters 1x
request("203.1", bolton, private_bolton).
oar_prefer("203.1", bolton, private_oars_bolton, 1).

request("203.2", cullicott, private_cullicott).
oar_prefer("203.1", cullicott, private_oars_cullicott, 1).

request("203.2", mast, private_mast).
oar_prefer("203.2", mast, private_oars_mast, 1).

% 1{ request("203.2", smith, BOAT) : club_racer(BOAT) }1.
request("203.2", smith, rogers).
oar_prefer("203.2", smith, purple_white, 1).

request("203.3", ellis, private_ellis).
oar_prefer("203.3", ellis, private_oars_ellis, 1).
request("203.3", lynch, private_lynch).
oar_prefer("203.3", lynch, private_oars_lynch, 1).

% 1{ request("203.3", brennan, BOAT) : club_racer(BOAT) }1.
request("203.3", brennan, kryzinski).
oar_request("203.3", brennan, purple_white, 1).

% 1{ request("203.3", feicht, BOAT) : heavy_single(BOAT) }1.
request("203.3", feicht, cantu).
oar_prefer("203.3", feicht, yellow_purple, 1).

prefer("203.3", gates, dunya, 1).
oar_prefer("203.3", gates, blue_blue, 1).

% 1{ request("203.3", nicot, BOAT) : club_racer(BOAT) }1.
request("203.3", nicot, hamilton).
oar_prefer("203.3", nicot, blue_blue, 1).

% 1{ request("203.3", oppliger, BOAT) : heavy_single(BOAT) }1.
request("203.3", oppliger, director).
oar_prefer("203.3", oppliger, purple_green, 1).

%- 204          Mens Jr 8+
request("204", juniors, sophie).
oar_prefer("204", juniors, purple, 1).

%- 205          Womens Jr 2-
request("205", juniors_a, thrash_pair).
oar_prefer("205", juniors_a, pair, 1).

request("205", juniors_b, 30).
oar_prefer("205", juniors_b, blue, 1).

request("205", juniors_c, borrowed_pair).
oar_prefer("205", juniors_c, blue, 1).

%- 206          Womens Masters 4x
% 1{ request("206.1", daniels, BOAT) : lt_or_mid_quad(BOAT) }1.
request("206.1", daniels, red).
oar_prefer("206.1", daniels, orange_orange, 1).

% racenum("206.2").
% 1{ request("206.2", intermediate, BOAT) : lt_or_mid_quad(BOAT) }1.
request("206.2", intermediate, green).
oar_request("206.2", intermediate, blue_white, 1).

% 1{ request("206.2", wolf, BOAT) : lt_or_mid_quad(BOAT) }1.  % 206.2
request("206.2", wolf, masters).  % w/ suzanne kho
oar_prefer("206.2", wolf, purple_red, 1).

% greyhounds
prefer("206.2", hicks, blue, 1).
oar_prefer("206.2", hicks, yellow_purple, 1).

%- 207          Mens Jr Novice 4+
request("207", juniors_a, judie).
oar_prefer("207", juniors_a, blue, 1).
oar_prefer("207", juniors_a, wood, 2).

request("207", juniors_b, borrowed_four).
oar_prefer("207", juniors_b, orange, 1).

%- 208          Womens Jr Novice 8+
request("208", juniors, sophie).
oar_prefer("208", juniors, purple, 1).

%- 209          Mens Masters 2-
%- 210          Mixed Masters 4x

% 3{ request("210", intermediate, BOAT) : any_quad(BOAT) }3.
request("210.1", morey, orange).
oar_prefer("210.1", morey, red_yellow, 1).

request("210.1", nicot, green).
oar_prefer("210.1", nicot, red_blue, 1).

request("210.1", intermediate_c, mcdiarmid).
oar_prefer("210.1", intermediate_c, orange_blue, 1).

request("210.2", vepstas, masters).  % connie, sue, jeff, linas
oar_prefer("210.2", vepstas, yellow_purple, 1).

request("210.2", novice, blue).
oar_prefer("210.2", novice, purple_red, 1).

%- 211          Mens Jr Ltwt 4+
%- 212          Womens Masters 8+
% 1{request("212", intermediate, BOAT) : eight(BOAT) }1.
request("212", intermediate, kaitlin).
oar_request("212", intermediate, orange).

%- 213          Mens Jr 2-
request("213", juniors, 30).
oar_prefer("213", juniors, pair, 1).

%- 214          Mens Masters 4x
% 1{ request("214", advanced_a, BOAT) : hv_or_mid_quad(BOAT) }1.
% 1{ request("214", intermediate_a, BOAT) : hv_or_mid_quad(BOAT) }1.
request("214", knifton, black).
oar_prefer("214", knifton, blue_blue, 1).

request("214", advanced, orange).
oar_prefer("214", advanced, purple_green, 1).

%- 215          Womens Jr Ltwt 4+
request("215", juniors_a, judie).
oar_prefer("215", juniors_a, blue, 1).

request("215", juniors_b, borrowed_four).
oar_prefer("215", juniors_b, blue, 1).

%- 216          Mens Jr Novice 8+
request("216", juniors, sophie).
oar_prefer("216", juniors, purple, 1).

%- 217          Womens Masters 1x
% 1{ request("217.1", intermediate, BOAT) : lightweight_single(BOAT) }1.
request("217.1", intermediate, marty_n_saloni).
oar_prefer("217.1", intermediate, purple_white, 1).

prefer("217.2", carter, somers, 1).
oar_prefer("217.2", carter, private_oars_sue, 1).

%- 218          Mixed Adaptive 4x
%- 219          Womens Jr Novice 4+
% 3{ request("219", juniors, BOAT) : fourplus(BOAT) }3.
request("219", juniors_a, judie).
oar_prefer("219", juniors_a, blue, 1).

request("219", juniors_b, borrowed_four).
oar_prefer("219", juniors_b, blue, 1).

request("219", juniors_c, beverly).
oar_prefer("219", juniors_c, orange, 1).

%- 220          Mixed Masters 8+
request("220.1", advanced, kaitlin).
oar_prefer("220.1", advanced, purple, 1).

%- 221          Mens Masters 2x
request("221.1", knifton, empacher). % ken and matt
oar_prefer("221.1", knifton, blue_blue, 1).

request("221.2", vepstas, private_double). % linas and phil
oar_prefer("221.2", vepstas, blue_blue, 1).

request("221.2", lynch, bass).  % robb and phil
oar_prefer("221.2", lynch, private_oars_lynch, 1).

% XXX I guess this is scratched!?
% 1{ request("221.2", advanced_b, BOAT) : hv_or_mid_double(BOAT) }1. % ted

% request("221.2", feicht, jakob). % saloni
request("221.2", feicht, barksdales). % saloni
oar_prefer("221.2", feicht, yellow_purple, 1).

%- 222          Womens Jr 4+
% XXXX this is a hotseat problem!!
request("222", juniors_a, judie).
oar_prefer("222", juniors_a, blue, 1).

request("222", juniors_b, borrowed_four).
oar_prefer("222", juniors_b, blue, 1).

%- 223          Mens Jr Ltwt 8+
%- 224          Womens Masters 2x

request("224.1", daniels, swinford).  % & veronica
oar_prefer("224.1", daniels, red_red, 1).

request("224.1", intermediate_a, bass).
oar_prefer("224.1", intermediate_a, purple_white, 1).

request("224.1", scheer, thrash). % & mari (folco??)
oar_prefer("224.1", scheer, red_red, 1).

% the other double will be the 30 re-rigged
% 1{ request("224.2", intermediate, BOAT) : any_double(BOAT) }1.
request("224.2", intermediate, "30x").

%- 225          Mixed Adaptive 2x
%- 226          Mens Jr 4+
%- 227          Womens Jr Ltwt 8+
%- 228          Mens Masters 8+
%- 229          Mixed Masters 2x
prefer("229", crawford, thrash, 1).   % connie_h
prefer("229", crawford, swinford, 2).
oar_prefer("229", crawford, yellow_purple, 1).

% 1{ request("229", gates, BOAT) : heavy_double(BOAT) }1.  % & connie a
request("229", gates, barksdales).  % with adams
oar_prefer("229", gates, blue_blue, 1).

%- 230          Womens Masters 4+
request("230.1", intermediate_c, borrowed_four).
oar_prefer("230.1", intermediate_c, orange, 1).
oar_prefer("230.1", intermediate_c, wood, 2).

request("230.2", intermediate_a, beverly).
oar_prefer("230.2", intermediate_a, blue, 1).

request("230.2", intermediate_b, judie).
oar_prefer("230.2", intermediate_b, blue, 1).

%- 231          Womens Jr 8+
request("231", juniors, sophie).
oar_prefer("231", juniors, purple, 1).


%%% ========================== %%%

%% The actual scheduling algorithm.
%%% ========================== %%%

#include "solver.asp".
#include "oar_solver.asp" .


Linas Vepstas

unread,
Jan 2, 2018, 4:41:48 PM1/2/18
to opencog, Zarathustra Goertzel, Nil Geisweiller, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt
For Ben and Nil,

If you wish to ponder this some more, here is a short atomese <--> ASP syntax conversion guide.  Some ruminations about performance below.

So: English: "every sweep boat is a boat"

written in ASP:   boat(BOAT) :- sweep_boat(BOAT).

written in Atomese:

Implication
    Evaluation
        Predicate "sweep_boat"
        List
             Variable BOAT
    Evaluation
        Predicate "boat"
        List
             Variable BOAT

Clearly Atomese is verbose.

Here's another:


% A boat is available if its not in use by any crew.
available(RACE, BOAT) :- racenum(RACE), crew(CREW), boat(BOAT),
                         not inuse(RACE, CREW, BOAT).

The first three clauses are "typechecking": the variable CREW must be of type "crew", etc.
The last clause is a non-trivial constraint.

Implication
    And
        Evaluation
              Predicate "racenum"
              List
                   Variable RACE

        Evaluation
              Predicate "crew"
              List
                   Variable CREW

        Evaluation
              Predicate "boat"
              List
                   Variable BOAT

        Not
              Evaluation
                  Predicate "inuse"
                  List
                       Variable RACE
                       Variable CREW
                       Variable BOAT

    Evaluation
         Predicate "available"
         List
              Variable RACE
              Variable BOAT


I'm totally unclear on the performance profile for atomese.  So, for example: one could use the pattern matcher only, and implement naive forward chaining.  The statement  "eight(sophie)" declares a fact without any variables: "sophie" is an "eight", and since "sweep_boat(BOAT) :- eight(BOAT)"  then one run of the pattern matcher will generate the fact that "sophie" is a "sweep_boat", and a second pass will generate the fact that "sophie" is a "boat".  Turning the crank in this way will eventually generate every possible fact that can be deduced.

This naive approach pollutes the atomspace with lots and lots of redundant facts. In this particular case, its manageable: although a combinatorial explosion is possible in principle, its absent in practice (there are just barely enough boats for everyone, and sometimes not enough - the problem is sometimes not satisfiable)

The forward chainer is supposed to avoid this pollution. I'm somewhat unclear on how its actually implemented.  I'm also unclear on the backward chainer.

The ASP solver treats the assertions as a graph: In my infamous, unfinished, unliked "sheaf" paper, the expression "available(RACE, BOAT) :- racenum(RACE), crew(CREW), boat(BOAT),  not inuse(RACE, CREW, BOAT)." would be a "seed" (jigsaw-puzzle piece) having three connectors - BOAT, CREW and RACE, and the task is to connect together all such "puzzle pieces" to find the answer.  The ASP solvers do this by pruning all trivial, unidirectional connections (e.g. "sophie" is a "sweep_boat" is trivial, since there are no conflicts that prevent the deduction of this fact).   After pruning all deductions that are not conflicting, what is left is some tight knot of conflicting deductions, which the ASP solver examines exhaustively, exploring every possible case.   Then for each possible solution, the trivial connections are reattached, and the result is reported to the user.  Bingo.

To the best of my knowledge, this is not how the backward chainer works.   One problem with PLN and probabilistic rules is that *every* possibility needs to be explored, since the truth values are not crisp T/F.    By contrast, ASP assumes crisp T/F making the problem much much simpler.  (both airplane scheduling, and boat scheduling are crisp T/F).

Nil and I very briefly discussed the possibility of using ASP as a probabilistic solver for PLN.  That is, we would randomly assign T/F values to atoms, run ASP on them, see what it deduces, and then increment the count on the corresponding atom. After running this enough times, a probability distribution becomes clear.  Again, this is one of the points of the "sheaf" paper.  A different point is that neural nets also take these structures, but use a different algo to arrive at a likely probability distribution. I have yet to finish writing that part of the paper.  It raises the interesting possibility of implementing PLN as a neural net.

--linas

p.s. I forgot to post the oar solver. Here it is:

%
% regatta team oar scheduling

%
% The problem of scheduling equipment for a regatta is a constraint
% problem -- two crews cannot use the same boat at the same time,
% and, indeed, there must be enough time between crews to rig the boat,
% launch it, warm up, race, and return to the dock, before the next
% crew can use it.  Because this is a classic constraint problem,
% implementing this via answer-set programming seems like the easiest,
% most direct way to accomplish this.
%
% Initial version: Linas Vepstas April 2012
%
% Copyright (c) 2012 Linas Vepstas
% The GNU GPLv3 applies.
%

% Two fundamental oar classes; we need this for consistent reservations.
oars(OARS, sweep, COUNT) :- sweep_oars(OARS, COUNT).
oars(OARS, scull, COUNT) :- scull_oars(OARS, COUNT).

oar_type(OARS, TYPE) :- oars(OARS, TYPE, COUNT).

% Enumerate all possible pairs of oars, given the declaration,
% and the count of how many pairs there are.
oarpair(OARS, TYPE, PAIR) :- oars(OARS, TYPE, COUNT), PAIR=1..COUNT.

% The number of oars needed, for a given boat type.
oarpairs_needed(BOAT, sweep, 4) :- eight(BOAT).
oarpairs_needed(BOAT, sweep, 2) :- fourplus(BOAT).
oarpairs_needed(BOAT, sweep, 2) :- fourminus(BOAT).
oarpairs_needed(BOAT, sweep, 1) :- pair(BOAT).

oarpairs_needed(BOAT, scull, 4) :- quad(BOAT).
oarpairs_needed(BOAT, scull, 2) :- double(BOAT).
oarpairs_needed(BOAT, scull, 1) :- single(BOAT).


% ----------------------
% Preference indication.

% choice must be a number, 1 to 4.
oar_choice(CHOICE) :- CHOICE=1..4.


%%% ========================================================== %%%
%% The actual scheduling algorithm.
%% DO NOT MODIFY ANYTHING BELOW THIS LINE!
%% (Unless you really, really know what you're doing, and
%% you probably don't.)  Just write me with questions, requests.
%%% ========================================================== %%%
% ----------------------
% oarset logic
%
% The total possible number of matchings of sets of oars to boats.
% The division is done so that out of a set of 4 pairs of oars, a
% quad gets just one set, a double gets set 1 or 2, while singles
% get set 1,2,3 or 4.  By contrast, if there are only three pairs of
% oars, then the quads get zero, while doubles and singles can still
% get a set.
oarsets_possible(BOAT, OARS, NSETS) :-
          oarpairs_needed(BOAT, TYPE, COUNT),
          oars(OARS, TYPE, SETCOUNT),
          NSETS = SETCOUNT/COUNT,
          NSETS != 0.

% The total universe of oar-set assignments. Any boat will only ever
% get one set of oars.  Out of a set of 4 pairs of oars, a quad will
% get the whole set, a double can get set 1 or set 2, while singles
% can get one and only one of the sets 1,2,3 or 4.
% crew and racenum are "free variables", so an orset is generated for
% every possible crew+race combination.
1 { set_universe(RACE, CREW, BOAT, OARS, SET) :
      SET=1..NSETS :
      oars(OARS, TYPE, COUNT) :
      oarsets_possible(BOAT, OARS, NSETS)
 } 1 :-
          crew(CREW), racenum(RACE).

% Out of a list of desired oars, choose only one set of oars.
oarset_request(RACE, CREW, OARS, SET) :-
             oar_prefer(RACE, CREW, OARS, CHOICE),
             set_universe(RACE, CREW, BOAT, OARS, SET).

% Two different crews cannot make a request for the same oarset
% for the same race.
:- oarset_request(RACE, CREW, OARS, SET),
   oarset_request(RACE, OTHER_CREW, OARS, SET),
   CREW != OTHER_CREW.

% ----------------------
% Every boat reservation must have an oar reservation.
% If a crew did not express an oar choice, make a request for them,
% ask for something, anything.
expressed_oar_pref(RACE, CREW) :- oar_prefer(RACE, CREW, OARS, CHOICE).

auto_oar_req(RACE, CREW) :-
           got_a_boat(RACE, CREW),
           not expressed_oar_pref(RACE, CREW).

oarset_request(RACE, CREW, OARS, SET) :-
           auto_oar_req(RACE, CREW),
           set_universe(RACE, CREW, BOAT, OARS, SET).

% ----------------------
% Convert oarset requests into oarpair requests.  Basically, just take
% the oarset, and multiply by the number of oarpairs needed for a given
% boat class.  This is the magic where sets of oars can be split up
% between doubles, singles.

% Note also: a request is not made unless a boat is reserved.

oarpair_request(RACE, CREW, OARS, TYPE, PAIR) :-
           reserve(RACE, CREW, BOAT),
           oarset_request(RACE, CREW, OARS, SET),
           oarpairs_needed(BOAT, TYPE, COUNT),
           N = 1..COUNT,
           PAIR = N + (SET-1)* COUNT.

% ----------------------
% The core reservation/inuse logic. Vaguely resembles that used for the
% boats, but has more arguments.

% Oars are available if not in use by any crew.
oarpair_available(RACE, OARS, TYPE, PAIR) :-
           racenum(RACE), crew(CREW),
           oarpair(OARS, TYPE, PAIR),
           not oarpair_inuse(RACE, CREW, OARS, TYPE, PAIR).

% Reserve oar pairs if they are requested and available.
oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR) :-
            oarpair_available(RACE, OARS, TYPE, PAIR),
            oarpair_request(RACE, CREW, OARS, TYPE, PAIR).

% If oarpair is reserved, then it will be in use at least CENTER races

% beforehand. That is, the crew needs CENTER-1 races to launch and
% warmup before the race.
oarpair_inuse(ONWATER, CREW, OARS, TYPE, PAIR) :-
           oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
           heat(SCH, RACE),
           SCHMN = SCH - N,
           heat(SCHMN, ONWATER),
           N = 1..CENTER-1,
           center(CENTER).

% Oars are on the water for race immediately after, too.
oarpair_inuse(ONWATER, CREW, OARS, TYPE, PAIR) :-
           oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
           heat(SCH, RACE),
           heat(SCH+1, ONWATER).

% Cannot reserve oars that are in use.
:- oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
   oarpair_inuse(RACE, OTHER_CREW, OARS, TYPE, PAIR),
   racenum(RACE), crew(CREW), crew(OTHER_CREW), oarpair(OARS, TYPE, PAIR).

% Cannot request oars if they're in use.

% This rule isn't needed right now, comment it out.
% :- oar_request(RACE, CREW, OARS), oar_inuse(RACE, OTHER_CREW, OARS, PAIR).

% Two different crews cannot reserve same oars for the same race.
% I think this may be a redundant constraint, not sure.  I think an
% earlier constraint on oarpair_request by different crews already
% guarantees this.
:- oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
   oarpair_reserve(RACE, OTHER_CREW, OARS, TYPE, PAIR),
   CREW != OTHER_CREW,
   racenum(RACE), crew(CREW), crew(OTHER_CREW), oarpair(OARS, TYPE, PAIR).

% ---------------------------------
% Second guess everything.  The above should be enough, I think, to
% properly reserve oars. But, just in case ...
% After a bit of experimentation, it seems that this improves
% performance: the solver can find a solution faster, with this code
% in place.

% Make sure that quads and eights get four pairs of oars, and not less.
% Start by counting how many oarparis we actually got.
got_four_oarpairs(RACE, CREW, OARS, TYPE) :-
           oarpair_reserve(RACE, CREW, OARS, TYPE, PA),
           oarpair_reserve(RACE, CREW, OARS, TYPE, PB),
           oarpair_reserve(RACE, CREW, OARS, TYPE, PC),
           oarpair_reserve(RACE, CREW, OARS, TYPE, PD),
           PA != PB, PA != PC, PA != PD,
           PB != PC, PB != PD, PC != PD.

% Doubles, fours need only two pairs of oars.
got_two_oarpairs(RACE, CREW, OARS, TYPE) :-
           oarpair_reserve(RACE, CREW, OARS, TYPE, PA),
           oarpair_reserve(RACE, CREW, OARS, TYPE, PB),
           PA != PB.

% We got enough oar pairs if ... etc, depending on boat type.
got_enough_oarpairs(RACE, CREW, OARS, TYPE) :-
           got_four_oarpairs(RACE, CREW, OARS, TYPE),
           oarpairs_needed(BOAT, TYPE, 4),
           reserve(RACE, CREW, BOAT).

got_enough_oarpairs(RACE, CREW, OARS, TYPE) :-
           got_two_oarpairs(RACE, CREW, OARS, TYPE),
           oarpairs_needed(BOAT, TYPE, 2),
           reserve(RACE, CREW, BOAT).

got_enough_oarpairs(RACE, CREW, OARS, TYPE) :-
           oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
           oarpairs_needed(BOAT, TYPE, 1),
           reserve(RACE, CREW, BOAT).

% Whoops, this is true if we got something, but did NOT get enough.
not_got_enough_oarpairs(RACE, CREW, OARS, TYPE) :-
           not got_enough_oarpairs(RACE, CREW, OARS, TYPE),
           oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR).

% Double-negative: must get enough.
:- not_got_enough_oarpairs(RACE, CREW, OARS, TYPE).

% --------------------
% minimize oar reservation conflicts.

% A crew has a reservation if it has one or more oar pairs.
oar_reserve(RACE, CREW, OARS, TYPE) :-
             oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR).

% A crew got oars if it has a reservation.
got_oars(RACE, CREW) :- oar_reserve(RACE, CREW, OARS, TYPE).

% We sure want every oar request to be granted. Must flag any crews
% that got boats, but we can't find them oarpair.

% This flag must be highly visible.
oar_reservation_failure(RACE, CREW) :- got_a_boat(RACE, CREW),
                                       not got_oars(RACE, CREW).


% The above rules do allow a situation where some crews can't get
% oars.  Thus, we have to maximize for number of reservations

% granted.  This must be at the highest priority, higher than the
% hot-seat avoidance priority.
#minimize [oar_reservation_failure(RACE, CREW)
                   : oar_reserve_priority(ORP)
                   : racenum(RACE)
                   : crew(CREW) @ORP ].


% We're going to try to honour everyone's top preferences.
% So CHOICE=1 is first choice, CHOICE=2 is second choice, etc.
% XXX  disabled right now, enable later.
% #minimize [oar_request(RACE, CREW, OARS)
%                : oar_choice_priority(OCP)
%                : oar_prefer(RACE, CREW, OARS, CHOICE) = CHOICE@OCP ].


% ----------------------
% Hotseat notifications and minimization.
% Basically, we try to find assignments with the fewest hot-seats.

% True if oars will be hotseated at the dock.
% XXX M should be M=0..HOTS but this spews cpu time right now
% and is borken.  fixme later.
oar_hotseat(RACE, OARS) :-
          oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
          oarpair_reserve(OTHER_RACE, OTHER_CREW, OARS, TYPE, PAIR),

          heat(SCH, RACE),
          heat(SCH-CENTER-M, OTHER_RACE),
          center(CENTER),
          M=1..HOTS, hotseat_warn(HOTS).

% True if crew should hurry back because oarpair are needed.

% Currently, not used for anything, except as a printout for the
% convenience of the crews.
oar_hurry_back(RACE, CREW, OARS) :-
          oarpair_reserve(RACE, CREW, OARS, TYPE, PAIR),
          oarpair_reserve(OTHER_RACE, OTHER_CREW, OARS, TYPE, PAIR),

          heat(SCH, RACE),
          heat(SCH+CENTER+M, OTHER_RACE),
          center(CENTER),
          M=1..HOTS, hotseat_warn(HOTS).

% Minimize the number of oars that are hot-seated.
#minimize [oar_hotseat(RACE, OARS) @OHP : oar_hotseat_priority(OHP)].



% ----------------------
% Equipment list.  Stuff to take to the venue.
take_oars_to_venue(OARS, TYPE) :- oar_reserve(RACE, CREW, OARS, TYPE).

% XXX Caution: enabling this can chew up huge amounts of CPU time!
% #minimize [take_oars_to_venue(OARS, TYPE)
%                   : num_oars_priority(NOP) @NOP ].

% ----------------------
% Look for a typo in the name of the oarpair, crew or race.

% Typos can screw everything up, so flag these.
% fixme, use some kind of aggregate.
% bad_oar_count(OARS) :- oars(OARS,TYPE,COUNT), not COUNT=1..8.

oarname(OARS) :- oars(OARS, TYPE, COUNT).
bad_oar_name(OARS) :- oar_prefer(RACE,CREW,OARS,CH), not oarname(OARS).
bad_crew_name(CREW) :- oar_prefer(RACE,CREW,OARS,CH), not crew(CREW).
bad_race_num(RACE) :- oar_prefer(RACE,CREW,OARS,CH), not racenum(RACE).

bad_oar_name(OARS) :- oar_prefer(RACE,CREW,OARS,CHOICE), not oarname(OARS).
bad_crew_name(CREW) :- oar_prefer(RACE,CREW,OARS,CHOICE), not crew(CREW).
bad_race_num(RACE) :- oar_prefer(RACE,CREW,OARS,CHOICE), not racenum(RACE).
bad_oar_preference(CHOICE) :- oar_prefer(RACE,CREW,OARS,CHOICE), not choice(CHOICE).

#show oar_reservation_failure/2.
#show bad_oar_count/1.
#show bad_oar_name/1.
#show bad_oar_preference/1.
% #show got_four_oarpairs/4.
% #show got_enough_oarpairs/4.
% #show not_got_enough_oarpairs/4.
#show oar_reserve/4.
#show oar_hotseat/2.
#show oar_hurry_back/3.
#show take_oars_to_venue/2.
% #show oar_request/3.
% #show oarpair_inuse/5.
% #show oarpair_available/4.
% #show oarpairs_needed/3.
% #show set_universe/5.
% #show oarsets_possible/3.
% #show oarset_request/4.
% #show oarpair_request/5.
% #show oarpair_reserve/5.






On Tue, Jan 2, 2018 at 1:49 PM, Linas Vepstas <linasv...@gmail.com> wrote:

Nil Geisweiller

unread,
Jan 3, 2018, 10:57:43 AM1/3/18
to linasv...@gmail.com, opencog, Zarathustra Goertzel, Nil Geisweiller, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt
On 01/02/2018 11:41 PM, Linas Vepstas wrote:
> So: English: "every sweep boat is a boat"
>
> written in ASP:   boat(BOAT) :- sweep_boat(BOAT).
>
> written in Atomese:
>
> Implication
>     Evaluation
>         Predicate "sweep_boat"
>         List
>              Variable BOAT
>     Evaluation
>         Predicate "boat"
>         List
>              Variable BOAT

Actually you'd have to use an ImplicationScope, not an Implication

> Clearly Atomese is verbose.

Yes although due to eta-conversion between

(Lambda (Evaluation <predicate> <argument>))

and

<predicate>

this can be simplified into

Implication
Predicate "sweep boat"
Predicate "boat"

which PLN already supports.
Correct with the exception again that it should be an ImplicationScope,
also the List over the unary arguments can be removed, so it becomes

> ImplicationScope
> And
> Evaluation
> Predicate "racenum"
> Variable RACE
>
> Evaluation
> Predicate "crew"
> Variable CREW
>
> Evaluation
> Predicate "boat"
> Variable BOAT
>
> Not
> Evaluation
> Predicate "inuse"
> List
> Variable RACE
> Variable CREW
> Variable BOAT
>
> Evaluation
> Predicate "available"
> List
> Variable RACE
> Variable BOAT

Which is still verbose. However I believed it can be simplify that by
using Cartesian product (via ListLink) and
function-composition/beta-reduction (via PutLink). For instance

Lambda
Variable RACE
Variable CREW
Variable BOAT
And
Evaluation
Predicate "racenum"
Variable RACE
Evaluation
Predicate "crew"
Variable CREW
Evaluation
Predicate "boat"
Variable BOAT

is equivalent to

List
Predicate "racenum"
Predicate "crew"
Predicate "boat"

I don't think PLN supports that though, not yet.

> I'm totally unclear on the performance profile for atomese.  So, for
> example: one could use the pattern matcher only, and implement naive
> forward chaining.  The statement  "eight(sophie)" declares a fact
> without any variables: "sophie" is an "eight", and since
> "sweep_boat(BOAT) :- eight(BOAT)"  then one run of the pattern matcher
> will generate the fact that "sophie" is a "sweep_boat", and a second
> pass will generate the fact that "sophie" is a "boat".  Turning the
> crank in this way will eventually generate every possible fact that can
> be deduced.
>
> This naive approach pollutes the atomspace with lots and lots of
> redundant facts. In this particular case, its manageable: although a
> combinatorial explosion is possible in principle, its absent in practice
> (there are just barely enough boats for everyone, and sometimes not
> enough - the problem is sometimes not satisfiable)
>
> The forward chainer is supposed to avoid this pollution. I'm somewhat
> unclear on how its actually implemented.  I'm also unclear on the
> backward chainer.

I don't think the forward chainer avoids this pollution. The backward
chainer does however, by only executing inference trees that can
possibly infer the target, and by only adding the proven targets to the
atomspace, not the intermediary results (well, users might want to
change that though).

The forward chainer is much less mature that the backward chainer, and
ultimately both should be unified into one elegant chainer that can go
both backward and forward (I more or less see how it should be done,
just need the time).

> The ASP solver treats the assertions as a graph: In my infamous,
> unfinished, unliked "sheaf" paper, the expression "available(RACE, BOAT)
> :- racenum(RACE), crew(CREW), boat(BOAT),  not inuse(RACE, CREW, BOAT)."
> would be a "seed" (jigsaw-puzzle piece) having three connectors - BOAT,
> CREW and RACE, and the task is to connect together all such "puzzle
> pieces" to find the answer.  The ASP solvers do this by pruning all
> trivial, unidirectional connections (e.g. "sophie" is a "sweep_boat" is
> trivial, since there are no conflicts that prevent the deduction of this
> fact).   After pruning all deductions that are not conflicting, what is
> left is some tight knot of conflicting deductions, which the ASP solver
> examines exhaustively, exploring every possible case.   Then for each
> possible solution, the trivial connections are reattached, and the
> result is reported to the user.  Bingo.

Oh, very much like a type checker engine in fact (where mutual recursive
functions form cliques of bidirectional connections). Unsurprisingly
since both are satisfyability solvers. Certainly one should be able to
emulate that sort of strategy with adequate inference control rules, not
sure how hard that would be though. But as efficient as it might be in
practice I suspect there are cases where open-ended inference can solve
the problem in a few steps while such a solver would take millions.

Nil

Nil Geisweiller

unread,
Jan 3, 2018, 11:09:06 AM1/3/18
to Ben Goertzel, opencog, Nil Geisweiller

Linas Vepstas

unread,
Jan 3, 2018, 10:51:15 PM1/3/18
to Nil Geisweiller, opencog, Zarathustra Goertzel, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt
On Wed, Jan 3, 2018 at 9:57 AM, Nil Geisweiller <ngei...@googlemail.com> wrote:


Actually you'd have to use an ImplicationScope, not an Implication

Are you sure?  I thought ImplicationScope did something very different; didn't we conclude this conversation a few weeks ago?


 But as efficient as it might be in practice I suspect there are cases where open-ended inference can solve the problem in a few steps while such a solver would take millions.

Well, not everything in life is a satisfiability problem. I recall some lecture with a diagram that showed "problems reducible to satisfiability problems" and  "other problems that are not reducible to satisfiability problems", and in the "other" category were some examples of reasonable things you might want to do. I don't recall what they were.

"would take millions" can be still be done in seconds on modern CPU's, and that's the break-through. 

For things like airplane scheduling, where crisp logic is desirable, constraint satisfaction is the way to go.

For things like common-sense reasoning, well, I remain confused.  I'm heads-down paying attention to other things.

--linas


Nil

Ramin Barati

unread,
Jan 6, 2018, 2:00:51 PM1/6/18
to ope...@googlegroups.com, Nil Geisweiller, Zarathustra Goertzel, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt

Hi Linas,

ASP is the right tool for the job, though I must admit that it has a learning curve; from my POV at least.

Currently we have decided to use PDDL for prototyping and then implement an ASP version when the biz constraints become quite concrete.

Thank you for your generous help.


--
You received this message because you are subscribed to the Google Groups "opencog" group.
To unsubscribe from this group and stop receiving emails from it, send an email to opencog+u...@googlegroups.com.

To post to this group, send email to ope...@googlegroups.com.
Visit this group at https://groups.google.com/group/opencog.

Linas Vepstas

unread,
Jan 6, 2018, 2:33:44 PM1/6/18
to opencog, Nil Geisweiller, Zarathustra Goertzel, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt
On Sat, Jan 6, 2018 at 1:00 PM, Ramin Barati <rek...@gmail.com> wrote:

Hi Linas,

ASP is the right tool for the job, though I must admit that it has a learning curve; from my POV at least.

Oh, yes it does.  I didn't want to scare you, but I can say it now:

It took me a week to understand how to make the simplest possible modification to the most basic "hello world" program. Not joking, it was this hard.

It took another week (40-hour week, this time, reading the specs, trying thingsover and over)  to write a 5-line long program that seemed to do what I wanted.

Then a light-bulb went on, I started to understand ... it took another 3 days or a week before that light stayed on for good.  And after that it was mostly easy and obvious.  Its really hard to get the basic idea, but once you got it, its .. obvious.

One important clue that I can give you: if  A is a variable, then "not A"  should be treated as a completely independent variable, instead of forcing it to be the opposite of A.  That is because A has three states: true, false and unknown.  The starting point is that both A and notA are unknown, and if you try to force notA to not be A, then you get "not unknown" which makes the solver go really slow, or hit an inf loop, or go crazy and crash, or get unwanted results.   So instead, just pretend that these are two completely different, unrelated variables.  At the end of you program, you can then ask:

"is A==true satisfiable?"

and
"is notA == true satisfiable?"

It might be better to not even think of true&false, and instead think that A has three states: satisfiable, not satisfiable, and unknown.   Once you stop thinking that its boolean logic, then all of a sudden, it should become clear how it works.

Currently we have decided to use PDDL for prototyping and then implement an ASP version when the biz constraints become quite concrete.


I strongly recommend continuing to bang away at it, and if it takes you a week to understand basic example #3 --- that is normal.  Prototyping in PDDL will just leave you with a big effort to translate the rules later on, and that will be hard to do.

The boat-scheduling code is now on github:  https://github.com/linas/crew

--linas


 

Thank you for your generous help.

Ramin Barati

unread,
Jan 7, 2018, 6:02:09 AM1/7/18
to ope...@googlegroups.com, Nil Geisweiller, Zarathustra Goertzel, Matthew Ikle, 练睿婷, Anton Kolonin, Oleg Baskov, Andres Suarez, Jim Rutt
On Sat, Jan 6, 2018 at 11:03 PM Linas Vepstas <linasv...@gmail.com> wrote:
On Sat, Jan 6, 2018 at 1:00 PM, Ramin Barati <rek...@gmail.com> wrote:

Hi Linas,

ASP is the right tool for the job, though I must admit that it has a learning curve; from my POV at least.

Oh, yes it does.  I didn't want to scare you, but I can say it now:

It took me a week to understand how to make the simplest possible modification to the most basic "hello world" program. Not joking, it was this hard.

It took another week (40-hour week, this time, reading the specs, trying thingsover and over)  to write a 5-line long program that seemed to do what I wanted.

Then a light-bulb went on, I started to understand ... it took another 3 days or a week before that light stayed on for good.  And after that it was mostly easy and obvious.  Its really hard to get the basic idea, but once you got it, its .. obvious.

One important clue that I can give you: if  A is a variable, then "not A"  should be treated as a completely independent variable, instead of forcing it to be the opposite of A.  That is because A has three states: true, false and unknown.  The starting point is that both A and notA are unknown, and if you try to force notA to not be A, then you get "not unknown" which makes the solver go really slow, or hit an inf loop, or go crazy and crash, or get unwanted results.   So instead, just pretend that these are two completely different, unrelated variables.  At the end of you program, you can then ask:

"is A==true satisfiable?"

and
"is notA == true satisfiable?"

It might be better to not even think of true&false, and instead think that A has three states: satisfiable, not satisfiable, and unknown.   Once you stop thinking that its boolean logic, then all of a sudden, it should become clear how it works.

Currently we have decided to use PDDL for prototyping and then implement an ASP version when the biz constraints become quite concrete.


I strongly recommend continuing to bang away at it, and if it takes you a week to understand basic example #3 --- that is normal.  Prototyping in PDDL will just leave you with a big effort to translate the rules later on, and that will be hard to do.
 
There is a PDDL to ASP translator in Potassco github account which, hopefully, would help with that. Nevertheless, I will continue reading Potassco manual just in case.


The boat-scheduling code is now on github:  https://github.com/linas/crew

--linas


 

Thank you for your generous help.


--
"The problem is not that artificial intelligence will get too smart and take over the world," computer scientist Pedro Domingos writes, "the problem is that it's too stupid and already has."

--
You received this message because you are subscribed to the Google Groups "opencog" group.
To unsubscribe from this group and stop receiving emails from it, send an email to opencog+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
Visit this group at https://groups.google.com/group/opencog.
Reply all
Reply to author
Forward
0 new messages