///////////////////////////////////////////////////////////////////////////////
//
// A boolean version of the wildfire fighting domain.
//
// V2 CHANGE: modify Wildfire so that a cell stops burning as soon as it is out of fuel
//
// V3 CHANGE: Extend the v2 modification to add a new fluent almost-out-of-fuel that
// allows a fire to burn for three time steps, i.e., a burning cell
// progresses to almost-out-of-fuel then out-of-fuel.
//
// Author: Zhenyu Yu (fry3721@gmail.com)
//
// General reference:
//
// Karafyllidis, I., & Thanailakis, A. (1997).
// A model for predicting forest fire spreading using gridular automata.
// Ecological Modelling, 99(1), 87-97.
// http://www.dpi.inpe.br/gilberto/cursos/st-society-2013/Kara1997.pdf
//
// In a general wildfire scenario, its spread is mostly determined by
// the weather (i.e. wind), terrain slope, and fuel type (i.e. grass, wood).
// In this scenario, a map is represented with grids, size of n*n.
// Each grid has some attributes, including fuel type, terrain elevation.
// Furthermore, the fuel type and terrain elevation will affect the fire
// spreading speed. Some fuel type is more easily on fire than other,
// and higher grids are always easier to catch fire. Cell features and
// effects of wind are not modeled in this simplified version.
//
// In this version, whether a cell would be on fire is determined by its
// neighbor grids, and the fire spreading law is simplified with this function
//
// p(burning(xi, yj)=true) = 1 / (1 + exp(4.5 – k))
//
// where k is the number of neighbors on fire.
//
// The decision task to a emergency manager is to control the fire
// and keep it away from important targets.
//
// Modified for competition and translation purposes by Scott Sanner.
//
///////////////////////////////////////////////////////////////////////////////
domain wildfire_mdp_v3 {
types {
x_pos : object;
y_pos : object;
};
pvariables {
// Action costs and penalties
COST_CUTOUT : {non-fluent, real, default = -5 }; // Cost to cut-out fuel from a cell
COST_PUTOUT : {non-fluent, real, default = -10 }; // Cost to put-out a fire from a cell
PENALTY_TARGET_BURN : {non-fluent, real, default = -100 }; // Penalty for each target cell that is burning
PENALTY_NONTARGET_BURN : {non-fluent, real, default = -5 }; // Penalty for each non-target cell that is burning
// Topology of the cells (can be any neighborhood topology, not necessarily rectangular)
NEIGHBOR(x_pos, y_pos, x_pos, y_pos) : { non-fluent, bool, default = false };
// High value cells that should be protected from fire
TARGET(x_pos, y_pos) : {non-fluent, bool, default = false };
// State fluents
burning(x_pos, y_pos) : { state-fluent, bool, default = false }; // cell currently on fire
out-of-fuel(x_pos, y_pos) : { state-fluent, bool, default = false }; // cell does not have fuel to burn (i.e., cut-out or already burned)
// V3 ADDITION
almost-out-of-fuel(x_pos, y_pos) : { state-fluent, bool, default = false }; // cell is almost out-of-fuel
// Action fluents
put-out(x_pos, y_pos) : { action-fluent, bool, default = false }; // actions to put-out out the fire
cut-out(x_pos, y_pos) : { action-fluent, bool, default = false }; // cut-out out the fuel
};
cpfs {
burning'(?x, ?y) =
// V2 CHANGE: we added the second disjunct so that a cell will stop burning once it is out-of-fuel
if ( put-out(?x, ?y) | out-of-fuel(?x,?y) ) // Intervention to put out fire?
then false
// Modification: targets can only start to burn if at least one neighbor is on fire
else if (~out-of-fuel(?x, ?y) ^ ~burning(?x, ?y)) // Ignition of a new fire? Depends on neighbors.
then [if (TARGET(?x, ?y) ^ ~exists_{?x2: x_pos, ?y2: y_pos} (NEIGHBOR(?x, ?y, ?x2, ?y2) ^ burning(?x2, ?y2)))
then false
else Bernoulli( 1.0 / (1.0 + exp[4.5 – (sum_{?x2: x_pos, ?y2: y_pos} (NEIGHBOR(?x, ?y, ?x2, ?y2) ^ burning(?x2, ?y2)))]) ) ]
else
burning(?x, ?y); // State persists
// Modification: only allow non-target cells to be cut-out (cannot remove fuel from targets, e.g., housing)
// V3 CHANGE: burning no longer leads to out-of-fuel, but almost out-of-fuel leads to out-of-fuel
// OLD: out-of-fuel'(?x, ?y) = out-of-fuel(?x, ?y) | burning(?x,?y) | (~TARGET(?x, ?y) ^ cut-out(?x, ?y));
// NEW:
out-of-fuel'(?x, ?y) = out-of-fuel(?x, ?y) | (almost-out-of-fuel(?x,?y) ^ burning(?x,?y)) | (~TARGET(?x, ?y) ^ cut-out(?x, ?y));
// V3 CHANGE: need to add transition for new fluent — burning can cause, otherwise previous state persists
almost-out-of-fuel'(?x,?y) = almost-out-of-fuel(?x,?y) | burning(?x,?y);
};
reward =
[sum_{?x: x_pos, ?y: y_pos} [ COST_CUTOUT*cut-out(?x, ?y) ]]
+ [sum_{?x: x_pos, ?y: y_pos} [ COST_PUTOUT*put-out(?x, ?y) ]]
// Modification: if a target is out-of-fuel, it was burnt so still penalize (since it could not have been cut-out)
+ [sum_{?x: x_pos, ?y: y_pos} [ PENALTY_TARGET_BURN*[ (burning(?x, ?y) | out-of-fuel(?x, ?y)) ^ TARGET(?x, ?y) ]]]
+ [sum_{?x: x_pos, ?y: y_pos} [ PENALTY_NONTARGET_BURN*[ burning(?x, ?y) ^ ~TARGET(?x, ?y) ]]];
}