From a6924b4702762c4fc3a6efe404395a5c5c5ab572 Mon Sep 17 00:00:00 2001 From: Frederik Hennig <frederik.hennig@fau.de> Date: Fri, 15 Mar 2024 13:32:43 +0100 Subject: [PATCH] update documentation of type system --- docs/source/api/index.rst | 2 +- .../source/api/{types/index.rst => types.rst} | 16 ++- docs/source/api/types/basic_types.rst | 6 - docs/source/api/types/quick.rst | 6 - .../backend/kernelcreation/typification.py | 4 +- src/pystencils/types/__init__.py | 4 +- src/pystencils/types/basic_types.py | 117 +++++++++--------- src/pystencils/types/quick.py | 29 +++-- 8 files changed, 95 insertions(+), 89 deletions(-) rename docs/source/api/{types/index.rst => types.rst} (53%) delete mode 100644 docs/source/api/types/basic_types.rst delete mode 100644 docs/source/api/types/quick.rst diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst index cd608643b..9af45d147 100644 --- a/docs/source/api/index.rst +++ b/docs/source/api/index.rst @@ -7,4 +7,4 @@ API Reference sympyextensions/index kernelcreation/index - types/index + types diff --git a/docs/source/api/types/index.rst b/docs/source/api/types.rst similarity index 53% rename from docs/source/api/types/index.rst rename to docs/source/api/types.rst index 2ac0410f6..1794fd856 100644 --- a/docs/source/api/types/index.rst +++ b/docs/source/api/types.rst @@ -10,9 +10,17 @@ Type System Module (pystencils.types) .. autofunction:: pystencils.types.create_type .. autofunction:: pystencils.types.create_numeric_type -.. toctree:: - :maxdepth: 1 - basic_types - quick +Data Type Class Hierarchy +------------------------- + +.. automodule:: pystencils.types.basic_types + :members: + + +Data Type Abbreviations +----------------------- + +.. automodule:: pystencils.types.quick + :members: \ No newline at end of file diff --git a/docs/source/api/types/basic_types.rst b/docs/source/api/types/basic_types.rst deleted file mode 100644 index 7a8156c45..000000000 --- a/docs/source/api/types/basic_types.rst +++ /dev/null @@ -1,6 +0,0 @@ - -Data Type Class Hierarchy -------------------------- - -.. automodule:: pystencils.types.basic_types - :members: diff --git a/docs/source/api/types/quick.rst b/docs/source/api/types/quick.rst deleted file mode 100644 index 34bc3cae5..000000000 --- a/docs/source/api/types/quick.rst +++ /dev/null @@ -1,6 +0,0 @@ -Data Type Abbreviations ------------------------ - - -.. automodule:: pystencils.types.quick - :members: \ No newline at end of file diff --git a/src/pystencils/backend/kernelcreation/typification.py b/src/pystencils/backend/kernelcreation/typification.py index 259821afa..af9a81d0a 100644 --- a/src/pystencils/backend/kernelcreation/typification.py +++ b/src/pystencils/backend/kernelcreation/typification.py @@ -9,7 +9,7 @@ from ...types import ( PsStructType, PsIntegerType, PsArrayType, - PsSubscriptableType, + PsDereferencableType, PsBoolType, deconstify, ) @@ -224,7 +224,7 @@ class Typifier: arr_tc = TypeContext() self.visit_expr(arr, arr_tc) - if not isinstance(arr_tc.target_type, PsSubscriptableType): + if not isinstance(arr_tc.target_type, PsDereferencableType): raise TypificationError( "Type of subscript base is not subscriptable." ) diff --git a/src/pystencils/types/__init__.py b/src/pystencils/types/__init__.py index 98fd2dd24..2c7bac59b 100644 --- a/src/pystencils/types/__init__.py +++ b/src/pystencils/types/__init__.py @@ -15,7 +15,7 @@ from .basic_types import ( PsNumericType, PsScalarType, PsVectorType, - PsSubscriptableType, + PsDereferencableType, PsPointerType, PsArrayType, PsBoolType, @@ -35,7 +35,7 @@ __all__ = [ "PsType", "PsCustomType", "PsStructType", - "PsSubscriptableType", + "PsDereferencableType", "PsPointerType", "PsArrayType", "PsNumericType", diff --git a/src/pystencils/types/basic_types.py b/src/pystencils/types/basic_types.py index f62571922..7565ea9a5 100644 --- a/src/pystencils/types/basic_types.py +++ b/src/pystencils/types/basic_types.py @@ -12,20 +12,11 @@ from .exception import PsTypeError class PsType(ABC): """Base class for all pystencils types. - **Implementation Notes** - - **Type Equality:** Subclasses must implement ``__eq__``, but may rely on ``_base_equal`` to implement - type equality checks. - - **Hashing:** Each subclass that implements ``__eq__`` must also implement ``__hash__``. + Args: + const: Const-qualification of this type """ def __init__(self, const: bool = False): - """ - Args: - name: Name of this type - const: Const-qualification of this type - """ self._const = const @property @@ -85,7 +76,11 @@ class PsType(ABC): class PsCustomType(PsType): - """Class to model custom types by their names.""" + """Class to model custom types by their names. + + Args: + name: Name of the custom type. + """ __match_args__ = ("name",) @@ -112,7 +107,17 @@ class PsCustomType(PsType): return f"CustomType( {self.name}, const={self.const} )" -class PsSubscriptableType(PsType, ABC): +class PsDereferencableType(PsType, ABC): + """Base class for subscriptable types. + + `PsDereferencableType` represents any type that may be dereferenced and may + occur as the base of a subscript, that is, before the C `[]` operator. + + Args: + base_type: The base type, which is the type of the object obtained by dereferencing. + const: Const-qualification + """ + __match_args__ = ("base_type",) def __init__(self, base_type: PsType, const: bool = False): @@ -125,14 +130,15 @@ class PsSubscriptableType(PsType, ABC): @final -class PsPointerType(PsSubscriptableType): - """Class to model C pointer types.""" +class PsPointerType(PsDereferencableType): + """A C pointer with arbitrary base type. + + `PsPointerType` models C pointer types to arbitrary data, with support for ``restrict``-qualified pointers. + """ __match_args__ = ("base_type",) - def __init__( - self, base_type: PsType, const: bool = False, restrict: bool = True - ): + def __init__(self, base_type: PsType, const: bool = False, restrict: bool = True): super().__init__(base_type, const) self._restrict = restrict @@ -155,28 +161,34 @@ class PsPointerType(PsSubscriptableType): def __repr__(self) -> str: return f"PsPointerType( {repr(self.base_type)}, const={self.const} )" - -class PsArrayType(PsSubscriptableType): - """Class that models one-dimensional C arrays""" - def __init__(self, base_type: PsType, length: int | None = None, const: bool = False): +class PsArrayType(PsDereferencableType): + """C array type of known or unknown size.""" + + def __init__( + self, base_type: PsType, length: int | None = None, const: bool = False + ): self._length = length super().__init__(base_type, const) @property def length(self) -> int | None: return self._length - + def c_string(self) -> str: return f"{self._base_type.c_string()} [{str(self._length) if self._length is not None else ''}]" - + def __eq__(self, other: object) -> bool: if not isinstance(other, PsArrayType): return False - - return self._base_equal(other) and self._base_type == other._base_type and self._length == other._length - + + return ( + self._base_equal(other) + and self._base_type == other._base_type + and self._length == other._length + ) + def __hash__(self) -> int: return hash(("PsArrayType", self._base_type, self._length, self._const)) @@ -185,7 +197,7 @@ class PsArrayType(PsSubscriptableType): class PsStructType(PsType): - """Class to model structured data types. + """Named or anonymous structured data type. A struct type is defined by its sequence of members. The struct may optionally have a name, although the code generator currently does not support named structs @@ -227,7 +239,7 @@ class PsStructType(PsType): if m.name == member_name: return m return None - + def get_member(self, member_name: str) -> PsStructType.Member: m = self.find_member(member_name) if m is None: @@ -237,9 +249,7 @@ class PsStructType(PsType): @property def name(self) -> str: if self._name is None: - raise PsTypeError( - "Cannot retrieve name from anonymous struct type" - ) + raise PsTypeError("Cannot retrieve name from anonymous struct type") return self._name @property @@ -257,9 +267,7 @@ class PsStructType(PsType): def c_string(self) -> str: if self._name is None: - raise PsTypeError( - "Cannot retrieve C string for anonymous struct type" - ) + raise PsTypeError("Cannot retrieve C string for anonymous struct type") return self._name def __str__(self) -> str: @@ -288,8 +296,7 @@ class PsStructType(PsType): class PsNumericType(PsType, ABC): - """Class to model numeric types, which are all types that may occur at the top-level inside - arithmetic-logical expressions. + """Numeric data type, i.e. any type that may occur inside arithmetic-logical expressions. **Constants** @@ -333,7 +340,7 @@ class PsNumericType(PsType, ABC): class PsScalarType(PsNumericType, ABC): - """Class to model scalar numeric types.""" + """Scalar numeric type.""" @abstractmethod def create_literal(self, value: Any) -> str: @@ -359,13 +366,13 @@ class PsScalarType(PsNumericType, ABC): def is_float(self) -> bool: return isinstance(self, PsIeeeFloatType) - + def is_bool(self) -> bool: return isinstance(self, PsBoolType) class PsVectorType(PsNumericType): - """Class to model packed vectors of numeric type. + """Packed vector of numeric type. Args: element_type: Underlying scalar data type @@ -402,7 +409,7 @@ class PsVectorType(PsNumericType): def is_float(self) -> bool: return self._scalar_type.is_float() - + def is_bool(self) -> bool: return self._scalar_type.is_bool() @@ -446,9 +453,7 @@ class PsVectorType(PsNumericType): ) def c_string(self) -> str: - raise PsTypeError( - "Cannot retrieve C type string for generic vector types." - ) + raise PsTypeError("Cannot retrieve C type string for generic vector types.") def __str__(self) -> str: return f"vector[{self._scalar_type}, {self._vector_entries}]" @@ -461,7 +466,7 @@ class PsVectorType(PsNumericType): class PsBoolType(PsScalarType): - """Class to model the boolean type.""" + """Boolean type.""" NUMPY_TYPE = np.bool_ @@ -471,15 +476,15 @@ class PsBoolType(PsScalarType): @property def width(self) -> int: return 8 - + @property def itemsize(self) -> int: return self.width // 8 - + @property def numpy_dtype(self) -> np.dtype | None: return np.dtype(PsBoolType.NUMPY_TYPE) - + def create_literal(self, value: Any) -> str: if value in (1, True, np.True_): return "true" @@ -495,22 +500,22 @@ class PsBoolType(PsScalarType): return np.False_ else: raise PsTypeError(f"Cannot create boolean constant from value {value}") - + def c_string(self) -> str: return "bool" - + def __eq__(self, other: object) -> bool: if not isinstance(other, PsBoolType): return False - + return self._base_equal(other) - + def __hash__(self) -> int: return hash(("PsBoolType", self._const)) class PsIntegerType(PsScalarType, ABC): - """Class to model signed and unsigned integer types. + """Signed and unsigned integer types. `PsIntegerType` cannot be instantiated on its own, but only through `PsSignedIntegerType` and `PsUnsignedIntegerType`. This distinction is meant mostly to help in pattern matching. @@ -579,7 +584,7 @@ class PsIntegerType(PsScalarType, ABC): @final class PsSignedIntegerType(PsIntegerType): - """Class to model signed integers.""" + """Signed integer types.""" __match_args__ = ("width",) @@ -607,7 +612,7 @@ class PsSignedIntegerType(PsIntegerType): @final class PsUnsignedIntegerType(PsIntegerType): - """Class to model unsigned integers.""" + """Unsigned integer types.""" __match_args__ = ("width",) @@ -635,7 +640,7 @@ class PsUnsignedIntegerType(PsIntegerType): @final class PsIeeeFloatType(PsScalarType): - """Class to model IEEE-754 floating point data types""" + """IEEE-754 floating point data types""" __match_args__ = ("width",) diff --git a/src/pystencils/types/quick.py b/src/pystencils/types/quick.py index 7e8628f61..c1a3aadc5 100644 --- a/src/pystencils/types/quick.py +++ b/src/pystencils/types/quick.py @@ -24,18 +24,23 @@ UserTypeSpec = str | type | np.dtype | PsType def create_type(type_spec: UserTypeSpec) -> PsType: """Create a pystencils type object from a variety of specifications. - Possible arguments are: - - Strings (`str`): will be parsed as common C types, throwing an exception if that fails. - To construct a `PsCustomType` instead, use the constructor of `PsCustomType` or its abbreviation - ``types.quick.Custom`` instead - - Python builtin data types (instances of `type`): Attempts to interpret Python numeric types like so: - - `int` becomes a signed 64-bit integer - - `float` becomes a double-precision IEEE-754 float - - No others are supported at the moment - - Supported Numpy scalar data types (see https://numpy.org/doc/stable/reference/arrays.scalars.html) - are converted to pystencils scalar data types - - Instances of `numpy.dtype`: Attempt to interpret scalar types like above, and structured types as structs. - - Instances of `PsType` will be returned as they are + This function converts several possible representations of data types to an instance of `PsType`. + The ``type_spec`` argument can be any of the following: + + - Strings (`str`): will be parsed as common C types, throwing an exception if that fails. + To construct a `PsCustomType` instead, use the constructor of `PsCustomType` + or its abbreviation `types.quick.Custom`. + - Python builtin data types (instances of `type`): Attempts to interpret Python numeric types like so: + - `int` becomes a signed 64-bit integer + - `float` becomes a double-precision IEEE-754 float + - No others are supported at the moment + - Supported Numpy scalar data types (see https://numpy.org/doc/stable/reference/arrays.scalars.html) + are converted to pystencils scalar data types + - Instances of `numpy.dtype`: Attempt to interpret scalar types like above, and structured types as structs. + - Instances of `PsType` will be returned as they are + + Args: + type_spec: The data type, in one of the above formats """ from .parsing import parse_type_string, interpret_python_type, interpret_numpy_dtype -- GitLab