Grounding a problem in pyRDDLGym.

Grounding a problem in pyRDDLGym.#

This rudimentary example shows how to ground a domain and instance from lifted form.

First install and import the required packages:

%pip install --quiet --upgrade pip
%pip install --quiet git+https://github.com/pyrddlgym-project/pyRDDLGym.git
%pip install --quiet git+https://github.com/pyrddlgym-project/rddlrepository.git
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.

Import the required packages:

import pyRDDLGym
from pyRDDLGym.core.debug.decompiler import RDDLDecompiler
from pyRDDLGym.core.grounder import RDDLGrounder

We will use the Wildfire domain, instance 1, to illustrate how grounding works:

env = pyRDDLGym.make('Wildfire_MDP_ippc2014', '1')

Let’s take a look at the state-fluents and the conditional probability functions for them:

for fluent, expr in RDDLDecompiler().decompile_exprs(env.model)['cpfs'].items():
    print(f'state-fluent {fluent} has the following cpf:')
    print(expr)
    print()
state-fluent burning' has the following cpf:
if (put-out(?x, ?y))
	then false
	else ( if (( ~out-of-fuel(?x, ?y) ) ^ ( ~burning(?x, ?y) ))
		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-fluent out-of-fuel' has the following cpf:
( out-of-fuel(?x, ?y) | burning(?x, ?y) ) | ( ( ~TARGET(?x, ?y) ) ^ cut-out(?x, ?y) )

There are two state fluent variables with parameterized expressions. The purpose of grounding is separate out this expression into a set of expressions, one per parameter evaluation, that is parameter-free. To do this, we will instantiate and call the grounder on the domain as follows:

grounded_model = RDDLGrounder(env.model.ast).ground()

Let’s decompile the new conditional probability functions and check that they are free of parameters:

for fluent, expr in RDDLDecompiler().decompile_exprs(grounded_model)['cpfs'].items():
    print(f'state-fluent {fluent} has the following cpf:')
    print(expr)
    print()
state-fluent burning___x1__y1' has the following cpf:
if (put-out___x1__y1)
	then false
	else ( if (( ~out-of-fuel___x1__y1 ) ^ ( ~burning___x1__y1 ))
		then ( if (TARGET___x1__y1 ^ ( ~( ( NEIGHBOR___x1__y1__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x1__y1__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x1__y1__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x1__y1__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x1__y1__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x1__y1__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x1__y1__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x1__y1__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x1__y1__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x1__y1__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x1__y1__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x1__y1__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x1__y1__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x1__y1__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x1__y1__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x1__y1__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x1__y1__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x1__y1__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x1__y1 )

state-fluent burning___x1__y2' has the following cpf:
if (put-out___x1__y2)
	then false
	else ( if (( ~out-of-fuel___x1__y2 ) ^ ( ~burning___x1__y2 ))
		then ( if (TARGET___x1__y2 ^ ( ~( ( NEIGHBOR___x1__y2__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x1__y2__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x1__y2__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x1__y2__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x1__y2__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x1__y2__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x1__y2__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x1__y2__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x1__y2__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x1__y2__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x1__y2__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x1__y2__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x1__y2__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x1__y2__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x1__y2__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x1__y2__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x1__y2__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x1__y2__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x1__y2 )

state-fluent burning___x1__y3' has the following cpf:
if (put-out___x1__y3)
	then false
	else ( if (( ~out-of-fuel___x1__y3 ) ^ ( ~burning___x1__y3 ))
		then ( if (TARGET___x1__y3 ^ ( ~( ( NEIGHBOR___x1__y3__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x1__y3__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x1__y3__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x1__y3__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x1__y3__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x1__y3__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x1__y3__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x1__y3__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x1__y3__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x1__y3__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x1__y3__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x1__y3__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x1__y3__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x1__y3__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x1__y3__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x1__y3__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x1__y3__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x1__y3__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x1__y3 )

state-fluent burning___x2__y1' has the following cpf:
if (put-out___x2__y1)
	then false
	else ( if (( ~out-of-fuel___x2__y1 ) ^ ( ~burning___x2__y1 ))
		then ( if (TARGET___x2__y1 ^ ( ~( ( NEIGHBOR___x2__y1__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x2__y1__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x2__y1__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x2__y1__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x2__y1__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x2__y1__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x2__y1__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x2__y1__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x2__y1__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x2__y1__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x2__y1__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x2__y1__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x2__y1__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x2__y1__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x2__y1__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x2__y1__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x2__y1__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x2__y1__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x2__y1 )

state-fluent burning___x2__y2' has the following cpf:
if (put-out___x2__y2)
	then false
	else ( if (( ~out-of-fuel___x2__y2 ) ^ ( ~burning___x2__y2 ))
		then ( if (TARGET___x2__y2 ^ ( ~( ( NEIGHBOR___x2__y2__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x2__y2__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x2__y2__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x2__y2__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x2__y2__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x2__y2__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x2__y2__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x2__y2__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x2__y2__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x2__y2__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x2__y2__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x2__y2__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x2__y2__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x2__y2__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x2__y2__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x2__y2__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x2__y2__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x2__y2__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x2__y2 )

state-fluent burning___x2__y3' has the following cpf:
if (put-out___x2__y3)
	then false
	else ( if (( ~out-of-fuel___x2__y3 ) ^ ( ~burning___x2__y3 ))
		then ( if (TARGET___x2__y3 ^ ( ~( ( NEIGHBOR___x2__y3__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x2__y3__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x2__y3__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x2__y3__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x2__y3__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x2__y3__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x2__y3__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x2__y3__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x2__y3__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x2__y3__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x2__y3__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x2__y3__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x2__y3__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x2__y3__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x2__y3__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x2__y3__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x2__y3__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x2__y3__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x2__y3 )

state-fluent burning___x3__y1' has the following cpf:
if (put-out___x3__y1)
	then false
	else ( if (( ~out-of-fuel___x3__y1 ) ^ ( ~burning___x3__y1 ))
		then ( if (TARGET___x3__y1 ^ ( ~( ( NEIGHBOR___x3__y1__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x3__y1__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x3__y1__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x3__y1__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x3__y1__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x3__y1__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x3__y1__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x3__y1__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x3__y1__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x3__y1__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x3__y1__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x3__y1__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x3__y1__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x3__y1__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x3__y1__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x3__y1__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x3__y1__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x3__y1__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x3__y1 )

state-fluent burning___x3__y2' has the following cpf:
if (put-out___x3__y2)
	then false
	else ( if (( ~out-of-fuel___x3__y2 ) ^ ( ~burning___x3__y2 ))
		then ( if (TARGET___x3__y2 ^ ( ~( ( NEIGHBOR___x3__y2__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x3__y2__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x3__y2__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x3__y2__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x3__y2__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x3__y2__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x3__y2__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x3__y2__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x3__y2__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x3__y2__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x3__y2__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x3__y2__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x3__y2__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x3__y2__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x3__y2__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x3__y2__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x3__y2__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x3__y2__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x3__y2 )

state-fluent burning___x3__y3' has the following cpf:
if (put-out___x3__y3)
	then false
	else ( if (( ~out-of-fuel___x3__y3 ) ^ ( ~burning___x3__y3 ))
		then ( if (TARGET___x3__y3 ^ ( ~( ( NEIGHBOR___x3__y3__x1__y1 ^ burning___x1__y1 ) | ( NEIGHBOR___x3__y3__x1__y2 ^ burning___x1__y2 ) | ( NEIGHBOR___x3__y3__x1__y3 ^ burning___x1__y3 ) | ( NEIGHBOR___x3__y3__x2__y1 ^ burning___x2__y1 ) | ( NEIGHBOR___x3__y3__x2__y2 ^ burning___x2__y2 ) | ( NEIGHBOR___x3__y3__x2__y3 ^ burning___x2__y3 ) | ( NEIGHBOR___x3__y3__x3__y1 ^ burning___x3__y1 ) | ( NEIGHBOR___x3__y3__x3__y2 ^ burning___x3__y2 ) | ( NEIGHBOR___x3__y3__x3__y3 ^ burning___x3__y3 ) ) ))
			then false
			else Bernoulli(1.0 / ( 1.0 + exp[4.5 - ( ( NEIGHBOR___x3__y3__x1__y1 ^ burning___x1__y1 ) + ( NEIGHBOR___x3__y3__x1__y2 ^ burning___x1__y2 ) + ( NEIGHBOR___x3__y3__x1__y3 ^ burning___x1__y3 ) + ( NEIGHBOR___x3__y3__x2__y1 ^ burning___x2__y1 ) + ( NEIGHBOR___x3__y3__x2__y2 ^ burning___x2__y2 ) + ( NEIGHBOR___x3__y3__x2__y3 ^ burning___x2__y3 ) + ( NEIGHBOR___x3__y3__x3__y1 ^ burning___x3__y1 ) + ( NEIGHBOR___x3__y3__x3__y2 ^ burning___x3__y2 ) + ( NEIGHBOR___x3__y3__x3__y3 ^ burning___x3__y3 ) )] )) )
		else burning___x3__y3 )

state-fluent out-of-fuel___x1__y1' has the following cpf:
( out-of-fuel___x1__y1 | burning___x1__y1 ) | ( ( ~TARGET___x1__y1 ) ^ cut-out___x1__y1 )

state-fluent out-of-fuel___x1__y2' has the following cpf:
( out-of-fuel___x1__y2 | burning___x1__y2 ) | ( ( ~TARGET___x1__y2 ) ^ cut-out___x1__y2 )

state-fluent out-of-fuel___x1__y3' has the following cpf:
( out-of-fuel___x1__y3 | burning___x1__y3 ) | ( ( ~TARGET___x1__y3 ) ^ cut-out___x1__y3 )

state-fluent out-of-fuel___x2__y1' has the following cpf:
( out-of-fuel___x2__y1 | burning___x2__y1 ) | ( ( ~TARGET___x2__y1 ) ^ cut-out___x2__y1 )

state-fluent out-of-fuel___x2__y2' has the following cpf:
( out-of-fuel___x2__y2 | burning___x2__y2 ) | ( ( ~TARGET___x2__y2 ) ^ cut-out___x2__y2 )

state-fluent out-of-fuel___x2__y3' has the following cpf:
( out-of-fuel___x2__y3 | burning___x2__y3 ) | ( ( ~TARGET___x2__y3 ) ^ cut-out___x2__y3 )

state-fluent out-of-fuel___x3__y1' has the following cpf:
( out-of-fuel___x3__y1 | burning___x3__y1 ) | ( ( ~TARGET___x3__y1 ) ^ cut-out___x3__y1 )

state-fluent out-of-fuel___x3__y2' has the following cpf:
( out-of-fuel___x3__y2 | burning___x3__y2 ) | ( ( ~TARGET___x3__y2 ) ^ cut-out___x3__y2 )

state-fluent out-of-fuel___x3__y3' has the following cpf:
( out-of-fuel___x3__y3 | burning___x3__y3 ) | ( ( ~TARGET___x3__y3 ) ^ cut-out___x3__y3 )

As you can see, all state-fluents with parameters have been replaced by new state-fluents without parameters, and expressions are replaced with equivalent operations that are parameter-free.