# ===========================================================================
# GPS — ARC-style goal-driven path example.
#
# This example shows a tiny route planner for western Belgium. Starting in Gent,
# the program works out the available routes to Oostende, compares them, and
# recommends the better one. It does not only print an answer: it also explains
# why that route was chosen and checks that the recommendation is consistent
# with the computed travel metrics.
# ===========================================================================

@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix math: <http://www.w3.org/2000/10/swap/math#>.
@prefix list: <http://www.w3.org/2000/10/swap/list#>.
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
@prefix gps: <https://example.org/gps#>.
@prefix : <https://example.org/gps-case#>.

# -----
# Facts
# -----

:i1 :location :Gent.
:question :text "Which route should we take from Gent to Oostende?".

:routeDirect :label "Gent → Brugge → Oostende".
:routeViaKortrijk :label "Gent → Kortrijk → Brugge → Oostende".

# ----------------------------------------------------------------
# Map of Belgium (kept from the original as backward descriptions)
# ----------------------------------------------------------------

{ :mapBE gps:description ({?S :location :Gent} true {?S :location :Brugge} :drive_gent_brugge 1500.0 0.006 0.96 0.99) }
    <= true.

{ :mapBE gps:description ({?S :location :Gent} true {?S :location :Kortrijk} :drive_gent_kortrijk 1600.0 0.007 0.96 0.99) }
    <= true.

{ :mapBE gps:description ({?S :location :Kortrijk} true {?S :location :Brugge} :drive_kortrijk_brugge 1600.0 0.007 0.96 0.99) }
    <= true.

{ :mapBE gps:description ({?S :location :Brugge} true {?S :location :Oostende} :drive_brugge_oostende 900.0 0.004 0.98 1.0) }
    <= true.

# -----------------------------------------------------
# Logic: compute all paths by chaining map descriptions
# -----------------------------------------------------

# Base: a single map description is already a path.
{ (?From ?To (?Act) ?Dur ?Cost ?Belief ?Comfort) :path true. }
    <=
{ :mapBE gps:description (?From true ?To ?Act ?Dur ?Cost ?Belief ?Comfort). }.

# Recursive: extend a description with the rest of a path.
{ (?From ?To ?Actions ?Dur ?Cost ?Belief ?Comfort) :path true. }
    <=
{ :mapBE gps:description (?From true ?Mid ?Act ?Dur1 ?Cost1 ?Bel1 ?Comf1).
  (?Mid ?To ?RestActs ?Dur2 ?Cost2 ?Bel2 ?Comf2) :path true.
  ((?Act) ?RestActs) list:append ?Actions.
  (?Dur1 ?Dur2) math:sum ?Dur.
  (?Cost1 ?Cost2) math:sum ?Cost.
  (?Bel1 ?Bel2) math:product ?Belief.
  (?Comf1 ?Comf2) math:product ?Comfort. }.

# Query the path relation for the traveller starting in Gent and aiming for Oostende.
{ :i1 :location :Gent.
  ({:i1 :location :Gent} {:i1 :location :Oostende} ?Acts ?Dur ?Cost ?Bel ?Comf) :path true. }
    =>
{ :i1 gps:path (?Acts ?Dur ?Cost ?Bel ?Comf). }.

# Name the two concrete routes that exist in this tiny map.
{ :i1 gps:path ((:drive_gent_brugge :drive_brugge_oostende) ?Dur ?Cost ?Bel ?Comf). }
    =>
{ :routeDirect :duration ?Dur;
               :cost ?Cost;
               :belief ?Bel;
               :comfort ?Comf. }.

{ :i1 gps:path ((:drive_gent_kortrijk :drive_kortrijk_brugge :drive_brugge_oostende) ?Dur ?Cost ?Bel ?Comf). }
    =>
{ :routeViaKortrijk :duration ?Dur;
                    :cost ?Cost;
                    :belief ?Bel;
                    :comfort ?Comf. }.

# ------------------------------------
# Decision: recommend the better route
# ------------------------------------

{ :routeDirect :duration ?D1; :cost ?C1; :belief ?B1; :comfort ?F1.
  :routeViaKortrijk :duration ?D2; :cost ?C2; :belief ?B2; :comfort ?F2.
  ?D1 math:lessThan ?D2.
  ?C1 math:lessThan ?C2.
  ?B1 math:greaterThan ?B2.
  ?F1 math:greaterThan ?F2. }
    =>
{ :decision :recommendedRoute :routeDirect;
            :outcome "Take the direct route via Brugge.". }.

# ---------------------------------------------------
# Presentation: ARC output as one deterministic block
# ---------------------------------------------------

{ :decision :recommendedRoute :routeDirect; :outcome ?Outcome.
  :routeDirect :label ?BestLabel; :duration ?BestDur; :cost ?BestCost; :belief ?BestBel; :comfort ?BestComf.
  :routeViaKortrijk :label ?AltLabel; :duration ?AltDur; :cost ?AltCost; :belief ?AltBel; :comfort ?AltComf.
  (
    "GPS — Goal driven route planning\n\n"
    "Answer\n"
    ?Outcome "\n"
    "Recommended route: " ?BestLabel "\n\n"
    "Reason Why\n"
    "From Gent to Oostende, the planner found two routes in this small map. "
    "The direct route (" ?BestLabel ") takes " ?BestDur " seconds at cost " ?BestCost
    ", with belief " ?BestBel " and comfort " ?BestComf ". "
    "The alternative (" ?AltLabel ") takes " ?AltDur " seconds at cost " ?AltCost
    ", with belief " ?AltBel " and comfort " ?AltComf ". "
    "So the direct route is faster, cheaper, more reliable, and slightly more comfortable.\n\n"
    "Check\n"
    "C1 OK - the direct Gent → Brugge → Oostende route was derived.\n"
    "C2 OK - the alternative Gent → Kortrijk → Brugge → Oostende route was derived.\n"
    "C3 OK - the recommended route is faster than the alternative.\n"
    "C4 OK - the recommended route is cheaper than the alternative.\n"
    "C5 OK - the recommended route has higher belief and comfort scores.\n"
  ) string:concatenation ?Block. }
    =>
{ :report log:outputString ?Block. }.

# -----------------------------------------------------------------------
# Verification: fail loudly if the recommendation contradicts the metrics
# -----------------------------------------------------------------------

{ :decision :recommendedRoute :routeDirect.
  :routeDirect :duration ?D1.
  :routeViaKortrijk :duration ?D2.
  ?D1 math:notLessThan ?D2. }
    => false.

{ :decision :recommendedRoute :routeDirect.
  :routeDirect :cost ?C1.
  :routeViaKortrijk :cost ?C2.
  ?C1 math:notLessThan ?C2. }
    => false.

{ :decision :recommendedRoute :routeDirect.
  :routeDirect :belief ?B1.
  :routeViaKortrijk :belief ?B2.
  ?B1 math:notGreaterThan ?B2. }
    => false.

{ :decision :recommendedRoute :routeDirect.
  :routeDirect :comfort ?F1.
  :routeViaKortrijk :comfort ?F2.
  ?F1 math:notGreaterThan ?F2. }
    => false.
