# COMP3620/6320 Artificial Intelligence
# The Australian National University – 2021
# Authors: COMP3620 team
“”” Student Details
Student Name: Boxuan Yang
Student ID: u6778195
Email: u6778195@anu.edu.au
Date: May 29, 2021
“””
“””
In this file you will implement some constraints which represent
domain-specific control knowledge for the Logistics domain
(benchmarks/logistics).
These constraints will be used in addition to a standard flat encoding of
the Logistics problem instances, without plan graph mutexes (which you are
assumed to have completed while going through Exercises 1-6).
Those constraints should make solving the problem easier. This may be at
the cost of optimality. That is, your additional constraints may rule out
some solutions to make planning easier — for example, by restricting the
way trucks and planes can move — but they should preserve SOME solution
(the problems might be very easy to solve if you added a contradiction, but
wholly uninteresting!).
Often control knowledge for planning problems is based on LTL (Linear
Temporal Logic – https://en.wikipedia.org/wiki/Linear_temporal_logic) and
you might get inspired by studying this.
We do not expect you to implement an automatic compilation of arbitrary LTL
into SAT, just some control knowledge rules for problems from the Logistics
domain.
As an example rule to get you started, you could assert that if a package
was at its destination, then it cannot leave.
That is you could iterate over the goal of the problem to find the
propositions which talk about where the packages should end up and make
some constraints asserting that if one of the corresponding fluents is true
at step t then it must still be true at step t + 1
You will be marked based on the correctness, inventiveness, and
effectiveness of the control knowledge you devise.
You should aim to make at least three different control rules. Feel free to
leave (but comment out) rules which you abandon if you think they are
interesting and want us to look at them.
Use the flag “-e logistics” to select this encoding and the flag “-p false”
to disable the plangraph mutexes.
“””
from strips_problem import Action, Proposition
from .basic import BasicEncoding
import re
encoding_class = ‘LogisticsEncoding’
class LogisticsEncoding(BasicEncoding):
“”” An encoding which extends BasicEncoding but adds control knowledge
specific for the Logistics domain.
“””
################################################################################
# You need to implement the following methods #
################################################################################
def make_control_knowledge_variables(self, horizon: int) -> None:
“”” Make the variable for the problem.
Use the function self.new_cnf_code(step, name, object) to make
whatever codes for CNF variables you need to make your control
knowledge for the Logistics problem.
You can make variables which mean anything if you can think of
constraints to make that enforce that meaning. As an example, if
you were making control logic for the miconics domain, you might
make variables which keep track if each passenger has ever
been in an elevator and is now not.
For a passenger p, and t > 0:
was_boarded(p)@t <->
(-boarded(p)@t ^ (boarded(p)@t-1 v was_boarded(p)@t-1))
For example, you might make a dictionary called
self.was_boarded_at_t indexed by passenger names, where the values
are lists where the ith index contains the cnf code for
was_boarded(p)@i, which you got by calling self.new_cnf_code(i,
f”was_boarded({was_boarded.passenger})”, was_boarded).
You can see here that this is using an object called was_boarded
which has an attribute “passenger” as the object. This might not be
the simplest way, you might wish to just use a string instead of a
more complicated object. For example, self.new_cnf_code(i,
f”was_boarded({passenger})”, f”was_boarded({passenger})”).
You can then use these variables, along with the fluent and action
variables to make your control knowledge.
Note that the use of `make_control_knowledge_variables` is
completely optional. You don’t have to implement any code
in this method. At the end of the day, the most important thing
is to add new clauses in `make_control_knowledge`.
“””
“”” *** YOUR CODE HERE *** “””
self.airport = set()
self.goal = {}
self.desitinations = set()
for action in self.problem.actions:
if action.name == “fly-airplane”:
loc_from = str(action).split()[2]
loc_to = str(action).split()[3]
self.airport.add(loc_from)
self.airport.add(loc_to)
for g in self.problem.goal:
package = str(g).split()[1]
destination = str(g).split()[2]
self.desitinations.add(destination)
self.goal[package] = destination
def make_control_knowledge(self, horizon: int) -> None:
“”” This is where you should make your control knowledge clauses.
These clauses should have the type “control”.
“””
“”” *** YOUR CODE HERE *** “””
“””
Rule 1:
If a package is delivered at time t, then it remains there after that and we will never
do load to truck for that package.
p@t -> p@t+1, namely not p@t or p@t+1
p@t -> not load to truck, namely not p@t or not load to truck
“””
for goal in self.problem.goal:
g_package = str(goal).split()[1]
for t in range(horizon):
self.add_clause(
[-self.proposition_fluent_codes[(goal, t)], self.proposition_fluent_codes[(goal, t + 1)]],
“control”)
“””
Rule 2:
Do not unload a package to a region where it does not belong to.
“””
for action in self.problem.actions:
if action.name != “unload-airplane”:
continue
package = str(action).split()[1]
curr_loc = str(action).split()[3]
if package not in self.goal:
continue
target_city = self.goal[package]
if curr_loc.split(‘-‘)[0] != target_city.split(‘-‘)[0]:
for t in range(horizon):
self.add_clause(
[-self.action_fluent_codes[(action, t)]],
“control”)
“””
Rule 3:
Do not unload a package to a city where it does not belong to.
“””
for action in self.problem.actions:
if action.name != “unload-truck”:
continue
package = str(action).split()[1]
if package not in self.goal:
continue
curr_loc = str(action).split()[3]
if package not in self.goal:
continue
target_city = self.goal[package]
if curr_loc != target_city and curr_loc not in self.airport:
for t in range(horizon):
self.add_clause(
[-self.action_fluent_codes[(action, t)]],
“control”)
“””
Rule 3:
If we reach a goal at some time step t, then we never load it to truck again
“””
“””for goal in self.problem.goal:
g_package = str(goal).split()[1]
related_actions = []
for action in self.problem.actions:
if action.name != “load-truck”:
continue
a_package = str(action).split()[1]
if a_package == g_package:
related_actions.append(action)
for t in range(horizon – 1):
g_code = self.proposition_fluent_codes[(goal, t)]
for action in related_actions:
a_code = self.action_fluent_codes[(action, t + 1)]
self.add_clause([-g_code, -a_code], “control”)”””
“””
Rule 4:
If a package is in the target region, never load it to plane.
“””
“””for proposition in self.problem.propositions:
if not str(proposition).startswith(“at package”): # if the proposition is “at package[oo] city[oo]-[xx]”
continue
package = str(proposition).split()[1]
if package not in self.goal:
continue
destination = self.goal[package]
curr_loc = str(proposition).split()[2]
if curr_loc.split(‘-‘)[0] != destination.split(‘-‘)[0]:
continue
# proposition is now “at package city”, city here is in same region as destination
for action in self.problem.actions:
if not str(action).startswith(“load-airplane” + ” ” + package):
continue
for t in range(horizon):
a_code = self.action_fluent_codes[(action, t)]
p_code = self.proposition_fluent_codes[(proposition, t)]
self.add_clause([-p_code, -a_code], “control”)”””
“””
Rule:
If a package is not in our goal, never load it to truck
“””
“””for action in self.problem.actions:
if action.name != “upload-truck”:
continue
package = str(action).split()[1]
if package not in self.goal:
for t in range(horizon):
self.add_clause([-self.action_fluent_codes[(action, t)], “control”])”””
“””
Rule:
If we unload the truck, either the package is in airport or it is in destination
“””
“””for action in self.problem.actions:
if action.name != “unload-truck”:
continue
package = str(action).split()[1]
curr_loc = str(action).split()[3]
if curr_loc not in self.airport and curr_loc != self.goal[package]:
for t in range(horizon):
self.add_clause(
[-self.action_fluent_codes[(action, t)]],
“control”)
“””
“””for action in self.problem.actions:
if action.name != “load-truck” and action.name != “load-airplane”:
continue
a_package = str(action).split()[1]
goal = None
for g in self.problem.goal: # find the goal related to that package
if str(g).split()[1] == a_package:
goal = g
break
for t in range(horizon):
self.add_clause(
[-self.proposition_fluent_codes[(goal, t)], -self.action_fluent_codes[(action, t)]],
“control”)”””
“””
Rule 3:
Never do unload truck unless we are in destination
“””
“””for action in self.problem.actions:
if action.name != “unload-truck”:
continue
curr_loc = str(action).split()[3]
a_package = str(action).split()[1]
# find the proposition related to that action
if curr_loc == self.goal[a_package]:
for t in range(horizon):
l = [self.action_fluent_codes[(action, t)]]
for pre in action.preconditions:
pre_code = self.proposition_fluent_codes[(pre, t)]
l.append(-pre_code)
self.add_clause(l, “control”)
“””
“””
Rule 4:
If a package is in goal region but not goal city, then the truck delivers it
as early as possible.
“””
################################################################################
# Do not change the following method #
################################################################################
def encode(self, horizon, exec_semantics, plangraph_constraints):
“”” Make an encoding of self.problem for the given horizon.
For this encoding, we have broken this method up into a number
of sub-methods that you need to implement.
(LogisticsEncoding, int, str, str) -> None
“””
super().encode(horizon, exec_semantics, plangraph_constraints)
self.make_control_knowledge_variables(horizon)
self.make_control_knowledge(horizon)