Source code for concepts.dm.crow.planners.regression_utils
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File : regression_utils.py
# Author : Jiayuan Mao
# Email : maojiayuan@gmail.com
# Date : 03/21/2024
#
# This file is part of Project Concepts.
# Distributed under terms of the MIT license.
from typing import Optional, Union, Sequence, Tuple, List
import concepts.dsl.expression as E
from concepts.dsl.dsl_types import Variable
from concepts.dsl.expression import ObjectOrValueOutputExpression
from concepts.dsl.tensor_value import TensorValue
from concepts.dm.crow.behavior import CrowBehavior
from concepts.dm.crow.behavior import CrowUntrackExpression, CrowBindExpression, CrowAssertExpression
from concepts.dm.crow.behavior import CrowRuntimeAssignmentExpression, CrowFeatureAssignmentExpression
from concepts.dm.crow.behavior import CrowBehaviorOrderingSuite
from concepts.dm.crow.behavior_utils import format_behavior_statement
from concepts.dm.crow.controller import CrowControllerApplicationExpression
from concepts.dm.crow.planners.regression_planning import ScopedCrowExpression, SupportedCrowExpressionType
__all__ = ['replace_variable_with_value', 'format_regression_statement', 'canonize_bounded_variables', 'split_simple_sequential']
[docs]
def replace_variable_with_value(expr: ObjectOrValueOutputExpression, scope) -> ObjectOrValueOutputExpression:
"""Replace the variables in the expression with the values in the scope.
Args:
expr: the expression to edit.
scope: the scope containing the variable-value pairs.
Returns:
the expression with all variables replaced.
"""
if isinstance(expr, E.VariableExpression):
if isinstance(scope[expr.variable.name], TensorValue):
return E.ConstantExpression(scope[expr.variable.name])
return E.ObjectConstantExpression(scope[expr.variable.name])
elif isinstance(expr, E.FunctionApplicationExpression):
return E.FunctionApplicationExpression(expr.function, [replace_variable_with_value(x, scope) for x in expr.arguments])
else:
return expr
[docs]
def canonize_bounded_variables(scopes, scope_id):
"""Canonize the bounded variables in the scope. This function is used to resolve the scope references in the regression trace.
Args:
scopes: a set of scopes of the regression trace.
scope_id: the scope id to resolve.
Returns:
the resolved scope in `scopes[scope_id]`.
"""
scope = scopes[scope_id].copy()
for var, value in scope.items():
if isinstance(value, Variable):
assert value.scope > -1
for i in range(100):
if isinstance(value, Variable):
value = scopes[value.scope][value.name]
else:
break
else:
raise RuntimeError('Too deep scope reference.')
scope[var] = value
return scope
[docs]
def split_simple_sequential(program: Sequence[Union[CrowBehavior, CrowBehaviorOrderingSuite]], scope_id: int) -> Tuple[
Sequence[Union[CrowBehavior, CrowBehaviorOrderingSuite]],
List[ScopedCrowExpression]
]:
"""Split a program into a complex part and a simple part. The simple part is a list of statements that can be executed sequentially.
This function extracts a suffix of the program containing only :class:`~concepts.dm.crow.behavior.CrowAssertExpression`,
:class:`~concepts.dm.crow.behavior.CrowControllerApplicationExpression`, :class:`~concepts.dm.crow.behavior.CrowBindExpression`,
:class:`~concepts.dm.crow.behavior.CrowUntrackExpression`, :class:`~concepts.dm.crow.behavior.CrowRuntimeAssignmentExpression`,
and :class:`~concepts.dm.crow.behavior.CrowFeatureAssignmentExpression`.
Args:
program: the program to split.
scope_id: the scope id of the program.
Returns:
the complex part and the simple part.
"""
simple_part = list()
for i in reversed(range(len(program))):
if isinstance(program[i], (CrowAssertExpression, CrowControllerApplicationExpression, CrowBindExpression, CrowUntrackExpression, CrowRuntimeAssignmentExpression, CrowFeatureAssignmentExpression)):
simple_part.append(ScopedCrowExpression(program[i], scope_id))
else:
break
complex_part = program[:len(program) - len(simple_part)]
return complex_part, list(reversed(simple_part))