Skip to content

The SymbolicDataModel class

SymbolicDataModel

A symbolic backend-independent data model.

A SymbolicDataModel is a container for a JSON schema and can be used to represent data structures in a backend-agnostic way. It can record history and is used in symbolic operations (in the Functional API and to compute output specs).

A "symbolic data model" can be understood as a placeholder for data specification, it does not contain any actual data, only a schema. It can be used for building Functional models, but it cannot be used in actual computations.

Parameters:

Name Type Description Default
data_model DataModel

Optional. The data_model used to extract the schema.

None
schema dict

Optional. The JSON schema to be used. If the schema is not provided, the data_model argument should be used to infer it.

None
record_history bool

Optional. Boolean indicating if the history should be recorded. Defaults to True.

True
name str

Optional. A unique name for the data model. Automatically generated if not set.

None

Examples:

Creating a SymbolicDataModel with a backend data model metaclass:

class Query(synalinks.DataModel):
    query: str = synalinks.Field(
        description="The user query",
    )

data_model = SymbolicDataModel(data_model=Query)

Creating a SymbolicDataModel with a backend data model metaclass's schema:

class Query(synalinks.DataModel):
    query: str = synalinks.Field(
        description="The user query",
    )

data_model = SymbolicDataModel(schema=Query.schema())

Creating a SymbolicDataModel with to_symbolic_data_model():

using a backend data model metaclass

class Query(synalinks.DataModel):
    query: str = synalinks.Field(
        description="The user query",
    )

data_model = Query.to_symbolic_data_model()
Source code in synalinks/src/backend/common/symbolic_data_model.py
@synalinks_export("synalinks.SymbolicDataModel")
class SymbolicDataModel:
    """A symbolic backend-independent data model.

    A `SymbolicDataModel` is a container for a JSON schema and can be used to represent
        data structures in a backend-agnostic way. It can record history and is used in
        symbolic operations (in the Functional API and to compute output specs).

    A "symbolic data model" can be understood as a placeholder for data specification,
        it does not contain any actual data, only a schema. It can be used for building
        Functional models, but it cannot be used in actual computations.

    Args:
        data_model (DataModel): Optional. The data_model used to extract the schema.
        schema (dict): Optional. The JSON schema to be used. If the schema is not
            provided, the data_model argument should be used to infer it.
        record_history (bool): Optional. Boolean indicating if the history
            should be recorded. Defaults to `True`.
        name (str): Optional. A unique name for the data model. Automatically generated
            if not set.

    Examples:

    **Creating a `SymbolicDataModel` with a backend data model metaclass:**

    ```python
    class Query(synalinks.DataModel):
        query: str = synalinks.Field(
            description="The user query",
        )

    data_model = SymbolicDataModel(data_model=Query)
    ```

    **Creating a `SymbolicDataModel` with a backend data model metaclass's schema:**

    ```python
    class Query(synalinks.DataModel):
        query: str = synalinks.Field(
            description="The user query",
        )

    data_model = SymbolicDataModel(schema=Query.schema())
    ```

    **Creating a `SymbolicDataModel` with `to_symbolic_data_model()`:**

    using a backend data model metaclass

    ```python
    class Query(synalinks.DataModel):
        query: str = synalinks.Field(
            description="The user query",
        )

    data_model = Query.to_symbolic_data_model()
    ```
    """

    def __init__(
        self,
        data_model=None,
        schema=None,
        record_history=True,
        name=None,
    ):
        self.name = name or auto_name(self.__class__.__name__)
        self.record_history = record_history
        self._schema = None
        if not schema and not data_model:
            raise ValueError(
                "You should specify at least one argument between "
                "`data_model` or `schema`"
            )
        if schema and data_model:
            if not is_schema_equal(schema, data_model.schema()):
                raise ValueError(
                    "Attempting to create a SymbolicDataModel "
                    "with both `schema` and `data_model` argument "
                    "but their schemas are incompatible "
                    f"received schema={schema} and "
                    f"data_model.schema()={data_model.schema()}."
                )
            self._schema = standardize_schema(schema)
        else:
            if schema:
                self._schema = standardize_schema(schema)
            if data_model:
                self._schema = standardize_schema(data_model.schema())

    @property
    def name(self):
        """The name of the data model."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def record_history(self):
        """Whether the history is being recorded."""
        return self._record_history

    @record_history.setter
    def record_history(self, value):
        self._record_history = value

    def schema(self):
        """The JSON schema of the data model.

        Returns:
            (dict): The JSON schema.
        """
        return self._schema

    def json(self, key):
        """Alias for the JSON object's value (impossible in `SymbolicDataModel`).

        Implemented to help the user to identifying issues.

        Raises:
            ValueError: The help message.
        """
        return self.value()

    def value(self):
        """The current value of the JSON object (impossible in `SymbolicDataModel`).

        Implemented to help the user to identifying issues.

        Raises:
            ValueError: The help message.
        """
        raise ValueError(
            "Attempting to retrieve the JSON value from a symbolic data model "
            "this operation is not possible, make sure that your `call()` "
            "is correctly implemented, if so then you likely need to implement "
            " `compute_output_spec()` in your subclassed module."
        )

    def pretty_schema(self):
        """Get a pretty version of the JSON schema for display.

        Returns:
            (dict): The indented JSON schema.
        """
        return json.dumps(self.schema(), indent=2)

    def __repr__(self):
        return f"<SymbolicDataModel schema={self._schema}, name={self._name}>"

    def __add__(self, other):
        """Concatenates this data model with another.

        Args:
            other (SymbolicDataModel | DataModel):
                The other data model to concatenate with.

        Returns:
            (SymbolicDataModel): The concatenated data model.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Concat().symbolic_call(self, other)
        )

    def __radd__(self, other):
        """Concatenates (reverse) another data model with this one.

        Args:
            other (SymbolicDataModel | DataModel):
                The other data model to concatenate with.

        Returns:
            (SymbolicDataModel): The concatenated data model.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Concat().symbolic_call(other, self)
        )

    def __and__(self, other):
        """Perform a `logical_and` with another data model.

        If one of them is None, output None. If both are provided,
        then concatenates this data model with the other.

        Args:
            other (SymbolicDataModel | DataModel): The other data model to concatenate
                with.

        Returns:
            (SymbolicDataModel | None): The concatenated data model or None
                based on the `logical_and` table.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.And().symbolic_call(self, other)
        )

    def __rand__(self, other):
        """Perform a `logical_and` (reverse) with another data model.

        If one of them is None, output None. If both are provided,
        then concatenates the other data model with this one.

        Args:
            other (SymbolicDataModel | DataModel): The other data model to concatenate
                with.

        Returns:
            (SymbolicDataModel | None): The concatenated data model or None
                based on the `logical_and` table.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.And().symbolic_call(other, self)
        )

    def __or__(self, other):
        """Perform a `logical_or` with another data model

        If one of them is None, output the other one. If both are provided,
        then concatenates this data model with the other.

        Args:
            other (SymbolicDataModel): The other data model to concatenate with.

        Returns:
            (SymbolicDataModel | None): The concatenation of data model if both are
                provided, or the non-None data model or None if none are provided.
                (See `logical_or` table).
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Or().symbolic_call(self, other)
        )

    def __ror__(self, other):
        """Perform a `logical_or` (reverse) with another data model

        If one of them is None, output the other one. If both are provided,
        then concatenates the other data model with this one.

        Args:
            other (SymbolicDataModel | DataModel): The other data model to concatenate
                with.

        Returns:
            (SymbolicDataModel | None): The concatenation of data model if both are
                provided, or the non-None data model or None if none are provided.
                (See `logical_or` table).
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Or().symbolic_call(other, self)
        )

    def factorize(self):
        """Factorizes the data model.

        Returns:
            (SymbolicDataModel): The factorized data model.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Factorize().symbolic_call(self)
        )

    def in_mask(self, mask=None, recursive=True):
        """Applies a mask to **keep only** specified keys of the data model.

        Args:
            mask (list): The mask to be applied (list of keys).
            recursive (bool): Optional. Whether to apply the mask recursively.
                Defaults to `True`.

        Returns:
            (SymbolicDataModel): The data model with the mask applied.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.InMask(mask=mask, recursive=True).symbolic_call(self)
        )

    def out_mask(self, mask=None, recursive=True):
        """Applies an output mask to **remove** specified keys of the data model.

        Args:
            mask (list): The mask to be applied (list of keys).
            recursive (bool): Optional. Whether to apply the mask recursively.
                Defaults to `True`.

        Returns:
            (SymbolicDataModel): The data model with the mask applied.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.OutMask(mask=mask, recursive=True).symbolic_call(self)
        )

    def prefix(self, prefix=None):
        """Add a prefix to **all** the data model fields (non-recursive).

        Args:
            prefix (str): the prefix to add

        Returns:
            (SymbolicDataModel): The data model with the prefix added.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Prefix(prefix=prefix).symbolic_call(self)
        )

    def suffix(self, suffix=None):
        """Add a suffix to **all** the data model fields (non-recursive).

        Args:
            suffix (str): the suffix to add

        Returns:
            (SymbolicDataModel): The data model with the suffix added.
        """
        from synalinks.src import ops

        return asyncio.get_event_loop().run_until_complete(
            ops.Suffix(suffix=suffix).symbolic_call(self)
        )

    def get(self, key):
        """Get wrapper to make easier to access fields.

        Implemented to help the user to identifying issues.

        Args:
            key (str): The key to access.

        Raises:
            ValueError: The help message.
        """
        raise ValueError(
            f"Attempting to get '{key}' from a symbolic data model "
            "this operation is not possible, make sure that your `call()` "
            "is correctly implemented, if so then you likely need to implement "
            " `compute_output_spec()` in your subclassed module."
        )

    def update(self, kv_dict):
        """Update wrapper to make easier to modify fields.

        Implemented to help the user to identifying issues.

        Args:
            kv_dict (dict): The key/value dict to update.

        Raises:
            ValueError: The help message.
        """
        raise ValueError(
            f"Attempting to update keys '{list(kv_dict.keys())}' from a symbolic "
            "data model this operation is not possible, make sure that your `call()` "
            "is correctly implemented, if so then you likely need to implement "
            " `compute_output_spec()` in your subclassed module."
        )

name property writable

The name of the data model.

record_history property writable

Whether the history is being recorded.

__add__(other)

Concatenates this data model with another.

Parameters:

Name Type Description Default
other SymbolicDataModel | DataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel

The concatenated data model.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __add__(self, other):
    """Concatenates this data model with another.

    Args:
        other (SymbolicDataModel | DataModel):
            The other data model to concatenate with.

    Returns:
        (SymbolicDataModel): The concatenated data model.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Concat().symbolic_call(self, other)
    )

__and__(other)

Perform a logical_and with another data model.

If one of them is None, output None. If both are provided, then concatenates this data model with the other.

Parameters:

Name Type Description Default
other SymbolicDataModel | DataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel | None

The concatenated data model or None based on the logical_and table.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __and__(self, other):
    """Perform a `logical_and` with another data model.

    If one of them is None, output None. If both are provided,
    then concatenates this data model with the other.

    Args:
        other (SymbolicDataModel | DataModel): The other data model to concatenate
            with.

    Returns:
        (SymbolicDataModel | None): The concatenated data model or None
            based on the `logical_and` table.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.And().symbolic_call(self, other)
    )

__or__(other)

Perform a logical_or with another data model

If one of them is None, output the other one. If both are provided, then concatenates this data model with the other.

Parameters:

Name Type Description Default
other SymbolicDataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel | None

The concatenation of data model if both are provided, or the non-None data model or None if none are provided. (See logical_or table).

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __or__(self, other):
    """Perform a `logical_or` with another data model

    If one of them is None, output the other one. If both are provided,
    then concatenates this data model with the other.

    Args:
        other (SymbolicDataModel): The other data model to concatenate with.

    Returns:
        (SymbolicDataModel | None): The concatenation of data model if both are
            provided, or the non-None data model or None if none are provided.
            (See `logical_or` table).
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Or().symbolic_call(self, other)
    )

__radd__(other)

Concatenates (reverse) another data model with this one.

Parameters:

Name Type Description Default
other SymbolicDataModel | DataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel

The concatenated data model.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __radd__(self, other):
    """Concatenates (reverse) another data model with this one.

    Args:
        other (SymbolicDataModel | DataModel):
            The other data model to concatenate with.

    Returns:
        (SymbolicDataModel): The concatenated data model.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Concat().symbolic_call(other, self)
    )

__rand__(other)

Perform a logical_and (reverse) with another data model.

If one of them is None, output None. If both are provided, then concatenates the other data model with this one.

Parameters:

Name Type Description Default
other SymbolicDataModel | DataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel | None

The concatenated data model or None based on the logical_and table.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __rand__(self, other):
    """Perform a `logical_and` (reverse) with another data model.

    If one of them is None, output None. If both are provided,
    then concatenates the other data model with this one.

    Args:
        other (SymbolicDataModel | DataModel): The other data model to concatenate
            with.

    Returns:
        (SymbolicDataModel | None): The concatenated data model or None
            based on the `logical_and` table.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.And().symbolic_call(other, self)
    )

__ror__(other)

Perform a logical_or (reverse) with another data model

If one of them is None, output the other one. If both are provided, then concatenates the other data model with this one.

Parameters:

Name Type Description Default
other SymbolicDataModel | DataModel

The other data model to concatenate with.

required

Returns:

Type Description
SymbolicDataModel | None

The concatenation of data model if both are provided, or the non-None data model or None if none are provided. (See logical_or table).

Source code in synalinks/src/backend/common/symbolic_data_model.py
def __ror__(self, other):
    """Perform a `logical_or` (reverse) with another data model

    If one of them is None, output the other one. If both are provided,
    then concatenates the other data model with this one.

    Args:
        other (SymbolicDataModel | DataModel): The other data model to concatenate
            with.

    Returns:
        (SymbolicDataModel | None): The concatenation of data model if both are
            provided, or the non-None data model or None if none are provided.
            (See `logical_or` table).
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Or().symbolic_call(other, self)
    )

factorize()

Factorizes the data model.

Returns:

Type Description
SymbolicDataModel

The factorized data model.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def factorize(self):
    """Factorizes the data model.

    Returns:
        (SymbolicDataModel): The factorized data model.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Factorize().symbolic_call(self)
    )

get(key)

Get wrapper to make easier to access fields.

Implemented to help the user to identifying issues.

Parameters:

Name Type Description Default
key str

The key to access.

required

Raises:

Type Description
ValueError

The help message.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def get(self, key):
    """Get wrapper to make easier to access fields.

    Implemented to help the user to identifying issues.

    Args:
        key (str): The key to access.

    Raises:
        ValueError: The help message.
    """
    raise ValueError(
        f"Attempting to get '{key}' from a symbolic data model "
        "this operation is not possible, make sure that your `call()` "
        "is correctly implemented, if so then you likely need to implement "
        " `compute_output_spec()` in your subclassed module."
    )

in_mask(mask=None, recursive=True)

Applies a mask to keep only specified keys of the data model.

Parameters:

Name Type Description Default
mask list

The mask to be applied (list of keys).

None
recursive bool

Optional. Whether to apply the mask recursively. Defaults to True.

True

Returns:

Type Description
SymbolicDataModel

The data model with the mask applied.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def in_mask(self, mask=None, recursive=True):
    """Applies a mask to **keep only** specified keys of the data model.

    Args:
        mask (list): The mask to be applied (list of keys).
        recursive (bool): Optional. Whether to apply the mask recursively.
            Defaults to `True`.

    Returns:
        (SymbolicDataModel): The data model with the mask applied.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.InMask(mask=mask, recursive=True).symbolic_call(self)
    )

json(key)

Alias for the JSON object's value (impossible in SymbolicDataModel).

Implemented to help the user to identifying issues.

Raises:

Type Description
ValueError

The help message.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def json(self, key):
    """Alias for the JSON object's value (impossible in `SymbolicDataModel`).

    Implemented to help the user to identifying issues.

    Raises:
        ValueError: The help message.
    """
    return self.value()

out_mask(mask=None, recursive=True)

Applies an output mask to remove specified keys of the data model.

Parameters:

Name Type Description Default
mask list

The mask to be applied (list of keys).

None
recursive bool

Optional. Whether to apply the mask recursively. Defaults to True.

True

Returns:

Type Description
SymbolicDataModel

The data model with the mask applied.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def out_mask(self, mask=None, recursive=True):
    """Applies an output mask to **remove** specified keys of the data model.

    Args:
        mask (list): The mask to be applied (list of keys).
        recursive (bool): Optional. Whether to apply the mask recursively.
            Defaults to `True`.

    Returns:
        (SymbolicDataModel): The data model with the mask applied.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.OutMask(mask=mask, recursive=True).symbolic_call(self)
    )

prefix(prefix=None)

Add a prefix to all the data model fields (non-recursive).

Parameters:

Name Type Description Default
prefix str

the prefix to add

None

Returns:

Type Description
SymbolicDataModel

The data model with the prefix added.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def prefix(self, prefix=None):
    """Add a prefix to **all** the data model fields (non-recursive).

    Args:
        prefix (str): the prefix to add

    Returns:
        (SymbolicDataModel): The data model with the prefix added.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Prefix(prefix=prefix).symbolic_call(self)
    )

pretty_schema()

Get a pretty version of the JSON schema for display.

Returns:

Type Description
dict

The indented JSON schema.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def pretty_schema(self):
    """Get a pretty version of the JSON schema for display.

    Returns:
        (dict): The indented JSON schema.
    """
    return json.dumps(self.schema(), indent=2)

schema()

The JSON schema of the data model.

Returns:

Type Description
dict

The JSON schema.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def schema(self):
    """The JSON schema of the data model.

    Returns:
        (dict): The JSON schema.
    """
    return self._schema

suffix(suffix=None)

Add a suffix to all the data model fields (non-recursive).

Parameters:

Name Type Description Default
suffix str

the suffix to add

None

Returns:

Type Description
SymbolicDataModel

The data model with the suffix added.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def suffix(self, suffix=None):
    """Add a suffix to **all** the data model fields (non-recursive).

    Args:
        suffix (str): the suffix to add

    Returns:
        (SymbolicDataModel): The data model with the suffix added.
    """
    from synalinks.src import ops

    return asyncio.get_event_loop().run_until_complete(
        ops.Suffix(suffix=suffix).symbolic_call(self)
    )

update(kv_dict)

Update wrapper to make easier to modify fields.

Implemented to help the user to identifying issues.

Parameters:

Name Type Description Default
kv_dict dict

The key/value dict to update.

required

Raises:

Type Description
ValueError

The help message.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def update(self, kv_dict):
    """Update wrapper to make easier to modify fields.

    Implemented to help the user to identifying issues.

    Args:
        kv_dict (dict): The key/value dict to update.

    Raises:
        ValueError: The help message.
    """
    raise ValueError(
        f"Attempting to update keys '{list(kv_dict.keys())}' from a symbolic "
        "data model this operation is not possible, make sure that your `call()` "
        "is correctly implemented, if so then you likely need to implement "
        " `compute_output_spec()` in your subclassed module."
    )

value()

The current value of the JSON object (impossible in SymbolicDataModel).

Implemented to help the user to identifying issues.

Raises:

Type Description
ValueError

The help message.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def value(self):
    """The current value of the JSON object (impossible in `SymbolicDataModel`).

    Implemented to help the user to identifying issues.

    Raises:
        ValueError: The help message.
    """
    raise ValueError(
        "Attempting to retrieve the JSON value from a symbolic data model "
        "this operation is not possible, make sure that your `call()` "
        "is correctly implemented, if so then you likely need to implement "
        " `compute_output_spec()` in your subclassed module."
    )

any_symbolic_data_models(args=None, kwargs=None)

Checks if any of the arguments are symbolic data models.

Parameters:

Name Type Description Default
args tuple

Optional. The positional arguments to check.

None
kwargs dict

Optional. The keyword arguments to check.

None

Returns:

Type Description
bool

True if any of the arguments are symbolic data models, False otherwise.

Source code in synalinks/src/backend/common/symbolic_data_model.py
def any_symbolic_data_models(args=None, kwargs=None):
    """Checks if any of the arguments are symbolic data models.

    Args:
        args (tuple): Optional. The positional arguments to check.
        kwargs (dict): Optional. The keyword arguments to check.

    Returns:
        (bool): True if any of the arguments are symbolic data models, False otherwise.
    """
    args = args or ()
    kwargs = kwargs or {}
    for x in tree.flatten((args, kwargs)):
        if is_symbolic_data_model(x):
            return True
    return False

is_symbolic_data_model(x)

Returns whether x is a synalinks data model.

A "synalinks data model" is a symbolic data model, such as a data model that was created via Input(). A "symbolic data model" can be understood as a placeholder for data specification -- it does not contain any actual data, only a schema. It can be used for building Functional models, but it cannot be used in actual computations.

Parameters:

Name Type Description Default
x any

The object to check.

required

Returns:

Type Description
bool

True if x is a symbolic data model, False otherwise.

Source code in synalinks/src/backend/common/symbolic_data_model.py
@synalinks_export(
    [
        "synalinks.utils.is_symbolic_data_model",
        "synalinks.backend.is_symbolic_data_model",
    ]
)
def is_symbolic_data_model(x):
    """Returns whether `x` is a synalinks data model.

    A "synalinks data model" is a *symbolic data model*, such as a data model
    that was created via `Input()`. A "symbolic data model"
    can be understood as a placeholder for data specification -- it does not
    contain any actual data, only a schema.
    It can be used for building Functional models, but it
    cannot be used in actual computations.

    Args:
        x (any): The object to check.

    Returns:
        (bool): True if `x` is a symbolic data model, False otherwise.
    """
    return isinstance(x, SymbolicDataModel)