Skip to content
Snippets Groups Projects
Select Git revision
  • a384e10406152246d610eb14a91b453de4822732
  • master default protected
  • v2.0-dev protected
  • zikeliml/Task-96-dotExporterForAST
  • zikeliml/124-rework-tutorials
  • fma
  • fhennig/v2.0-deprecations
  • holzer-master-patch-46757
  • 66-absolute-access-is-probably-not-copied-correctly-after-_eval_subs
  • gpu_bufferfield_fix
  • hyteg
  • vectorization_sqrt_fix
  • target_dh_refactoring
  • const_fix
  • improved_comm
  • gpu_liveness_opts
  • release/1.3.7 protected
  • release/1.3.6 protected
  • release/2.0.dev0 protected
  • release/1.3.5 protected
  • release/1.3.4 protected
  • release/1.3.3 protected
  • release/1.3.2 protected
  • release/1.3.1 protected
  • release/1.3 protected
  • release/1.2 protected
  • release/1.1.1 protected
  • release/1.1 protected
  • release/1.0.1 protected
  • release/1.0 protected
  • release/0.4.4 protected
  • last/Kerncraft
  • last/OpenCL
  • last/LLVM
  • release/0.4.3 protected
  • release/0.4.2 protected
36 results

test_complex_numbers.py

Blame
  • source_components.py 14.56 KiB
    from __future__ import annotations
    
    from abc import ABC
    from enum import Enum, auto
    from typing import TYPE_CHECKING, Sequence, Generator
    from dataclasses import replace
    from itertools import chain
    
    from pystencils import CreateKernelConfig, create_kernel
    from pystencils.astnodes import KernelFunction
    
    from .types import SrcType
    from .source_concepts import SrcObject
    from .exceptions import SfgException
    
    if TYPE_CHECKING:
        from .tree import SfgCallTreeNode
    
    
    class SfgEmptyLines:
        def __init__(self, lines: int):
            self._lines = lines
    
        @property
        def lines(self) -> int:
            return self._lines
    
    
    class SfgHeaderInclude:
        def __init__(
            self, header_file: str, system_header: bool = False, private: bool = False
        ):
            self._header_file = header_file
            self._system_header = system_header
            self._private = private
    
        @property
        def file(self) -> str:
            return self._header_file
    
        @property
        def system_header(self):
            return self._system_header
    
        @property
        def private(self):
            return self._private
    
        def __hash__(self) -> int:
            return hash((self._header_file, self._system_header, self._private))
    
        def __eq__(self, other: object) -> bool:
            return (
                isinstance(other, SfgHeaderInclude)
                and self._header_file == other._header_file
                and self._system_header == other._system_header
                and self._private == other._private
            )
    
    
    class SfgKernelNamespace:
        def __init__(self, ctx, name: str):
            self._ctx = ctx
            self._name = name
            self._asts: dict[str, KernelFunction] = dict()
    
        @property
        def name(self):
            return self._name
    
        @property
        def asts(self):
            yield from self._asts.values()
    
        def add(self, ast: KernelFunction, name: str | None = None):
            """Adds an existing pystencils AST to this namespace.
            If a name is specified, the AST's function name is changed."""
            if name is not None:
                astname = name
            else:
                astname = ast.function_name
    
            if astname in self._asts:
                raise ValueError(
                    f"Duplicate ASTs: An AST with name {astname} already exists in namespace {self._name}"
                )
    
            if name is not None:
                ast.function_name = name
    
            self._asts[astname] = ast
    
            return SfgKernelHandle(self._ctx, astname, self, ast.get_parameters())
    
        def create(
            self,
            assignments,
            name: str | None = None,
            config: CreateKernelConfig | None = None,
        ):
            """Creates a new pystencils kernel from a list of assignments and a configuration.
            This is a wrapper around
            [`pystencils.create_kernel`](
                https://pycodegen.pages.i10git.cs.fau.de/pystencils/
                sphinx/kernel_compile_and_call.html#pystencils.create_kernel
            )
            with a subsequent call to [`add`][pystencilssfg.source_components.SfgKernelNamespace.add].
            """
            if config is None:
                config = CreateKernelConfig()
    
            if name is not None:
                if name in self._asts:
                    raise ValueError(
                        f"Duplicate ASTs: An AST with name {name} already exists in namespace {self._name}"
                    )
                config = replace(config, function_name=name)
    
            # type: ignore
            ast = create_kernel(assignments, config=config)
            return self.add(ast)
    
    
    class SfgKernelHandle:
        def __init__(
            self,
            ctx,
            name: str,
            namespace: SfgKernelNamespace,
            parameters: Sequence[KernelFunction.Parameter],
        ):
            self._ctx = ctx
            self._name = name
            self._namespace = namespace
            self._parameters = parameters
    
            self._scalar_params = set()
            self._fields = set()
    
            for param in self._parameters:
                if param.is_field_parameter:
                    self._fields |= set(param.fields)
                else:
                    self._scalar_params.add(param.symbol)
    
        @property
        def kernel_name(self):
            return self._name
    
        @property
        def kernel_namespace(self):
            return self._namespace
    
        @property
        def fully_qualified_name(self):
            match self._ctx.fully_qualified_namespace:
                case None:
                    return f"{self.kernel_namespace.name}::{self.kernel_name}"
                case fqn:
                    return f"{fqn}::{self.kernel_namespace.name}::{self.kernel_name}"
    
        @property
        def parameters(self):
            return self._parameters
    
        @property
        def scalar_parameters(self):
            return self._scalar_params
    
        @property
        def fields(self):
            return self.fields
    
    
    class SfgFunction:
        def __init__(
            self, name: str, tree: SfgCallTreeNode, return_type: SrcType = SrcType("void")
        ):
            self._name = name
            self._tree = tree
            self._return_type = return_type
    
            from .visitors.tree_visitors import ExpandingParameterCollector
    
            param_collector = ExpandingParameterCollector()
            self._parameters = param_collector.visit(self._tree)
    
        @property
        def name(self):
            return self._name
    
        @property
        def parameters(self):
            return self._parameters
    
        @property
        def tree(self):
            return self._tree
    
        @property
        def return_type(self) -> SrcType:
            return self._return_type
    
    
    class SfgVisibility(Enum):
        DEFAULT = auto()
        PRIVATE = auto()
        PROTECTED = auto()
        PUBLIC = auto()
    
        def __str__(self) -> str:
            match self:
                case SfgVisibility.DEFAULT:
                    return ""
                case SfgVisibility.PRIVATE:
                    return "private"
                case SfgVisibility.PROTECTED:
                    return "protected"
                case SfgVisibility.PUBLIC:
                    return "public"
    
    
    class SfgClassKeyword(Enum):
        STRUCT = auto()
        CLASS = auto()
    
        def __str__(self) -> str:
            match self:
                case SfgClassKeyword.STRUCT:
                    return "struct"
                case SfgClassKeyword.CLASS:
                    return "class"
    
    
    class SfgClassMember(ABC):
        def __init__(self):
            self._cls: SfgClass | None = None
            self._visibility: SfgVisibility | None = None
    
        @property
        def owning_class(self) -> SfgClass:
            if self._cls is None:
                raise SfgException(f"{self} is not bound to a class.")
            return self._cls
    
        @property
        def visibility(self) -> SfgVisibility:
            if self._visibility is None:
                raise SfgException(f"{self} is not bound to a class and therefore has no visibility.")
            return self._visibility
    
        @property
        def is_bound(self) -> bool:
            return self._cls is not None
    
        def _bind(self, cls: SfgClass, vis: SfgVisibility):
            if self.is_bound:
                raise SfgException(
                    f"Binding {self} to class {cls.class_name} failed: "
                    f"{self} was already bound to {self.owning_class.class_name}"
                )
            self._cls = cls
            self._vis = vis
    
    
    class SfgVisibilityBlock:
        def __init__(self, visibility: SfgVisibility) -> None:
            self._vis = visibility
            self._members: list[SfgClassMember] = []
            self._cls: SfgClass | None = None
    
        @property
        def visibility(self) -> SfgVisibility:
            return self._vis
    
        def append_member(self, member: SfgClassMember):
            if self._cls is not None:
                self._cls._add_member(member, self._vis)
            self._members.append(member)
    
        def members(self) -> Generator[SfgClassMember, None, None]:
            yield from self._members
    
        @property
        def is_bound(self) -> bool:
            return self._cls is not None
    
        def _bind(self, cls: SfgClass):
            if self._cls is not None:
                raise SfgException(
                    f"Binding visibility block to class {cls.class_name} failed: "
                    f"was already bound to {self._cls.class_name}"
                )
            self._cls = cls
    
    
    class SfgInClassDefinition(SfgClassMember):
        def __init__(self, text: str):
            SfgClassMember.__init__(self)
            self._text = text
    
        @property
        def text(self) -> str:
            return self._text
    
        def __str__(self) -> str:
            return self._text
    
    
    class SfgMemberVariable(SrcObject, SfgClassMember):
        def __init__(
            self,
            name: str,
            dtype: SrcType
        ):
            SrcObject.__init__(self, name, dtype)
            SfgClassMember.__init__(self)
    
    
    class SfgMethod(SfgFunction, SfgClassMember):
        def __init__(
            self,
            name: str,
            tree: SfgCallTreeNode,
            return_type: SrcType = SrcType("void"),
            inline: bool = False,
            const: bool = False,
        ):
            SfgFunction.__init__(self, name, tree, return_type=return_type)
            SfgClassMember.__init__(self)
    
            self._inline = inline
            self._const = const
    
        @property
        def inline(self) -> bool:
            return self._inline
    
        @property
        def const(self) -> bool:
            return self._const
    
    
    class SfgConstructor(SfgClassMember):
        def __init__(
            self,
            parameters: Sequence[SrcObject] = (),
            initializers: Sequence[str] = (),
            body: str = ""
        ):
            SfgClassMember.__init__(self)
            self._parameters = tuple(parameters)
            self._initializers = tuple(initializers)
            self._body = body
    
        @property
        def parameters(self) -> tuple[SrcObject, ...]:
            return self._parameters
    
        @property
        def initializers(self) -> tuple[str, ...]:
            return self._initializers
    
        @property
        def body(self) -> str:
            return self._body
    
    
    class SfgClass:
        """Models a C++ class.
    
        ### Adding members to classes
    
        Members are never added directly to a class. Instead, they are added to
        a SfgVisibilityBlock which defines their syntactic position and visibility modifier
        in the code.
        At the top of every class, there is a default visibility block
        accessible through the `default` property.
        To add members with custom visibility, create a new SfgVisibilityBlock,
        add members to the block, and add the block using `append_visibility_block`.
    
        A more succinct interface for constructing classes is available through the
        [SfgClassComposer][pystencilssfg.composer.SfgClassComposer].
        """
        def __init__(
            self,
            class_name: str,
            class_keyword: SfgClassKeyword = SfgClassKeyword.CLASS,
            bases: Sequence[str] = (),
        ):
            if isinstance(bases, str):
                raise ValueError("Base classes must be given as a sequence.")
    
            self._class_name = class_name
            self._class_keyword = class_keyword
            self._bases_classes = tuple(bases)
    
            self._default_block = SfgVisibilityBlock(SfgVisibility.DEFAULT)
            self._default_block._bind(self)
            self._blocks = [self._default_block]
    
            self._definitions: list[SfgInClassDefinition] = []
            self._constructors: list[SfgConstructor] = []
            self._methods: dict[str, SfgMethod] = dict()
            self._member_vars: dict[str, SfgMemberVariable] = dict()
    
        @property
        def class_name(self) -> str:
            return self._class_name
    
        @property
        def src_type(self) -> SrcType:
            return SrcType(self._class_name)
    
        @property
        def base_classes(self) -> tuple[str, ...]:
            return self._bases_classes
    
        @property
        def class_keyword(self) -> SfgClassKeyword:
            return self._class_keyword
    
        @property
        def default(self) -> SfgVisibilityBlock:
            return self._default_block
    
        def append_visibility_block(self, block: SfgVisibilityBlock):
            block._bind(self)
            for m in block.members():
                self._add_member(m, block.visibility)
            self._blocks.append(block)
    
        def visibility_blocks(self) -> Generator[SfgVisibilityBlock, None, None]:
            yield from self._blocks
    
        def members(
            self, visibility: SfgVisibility | None = None
        ) -> Generator[SfgClassMember, None, None]:
            yield from chain.from_iterable(
                b.members() for b in filter(lambda b: b.visibility == visibility, self._blocks)
            )
    
        def definitions(
            self, visibility: SfgVisibility | None = None
        ) -> Generator[SfgInClassDefinition, None, None]:
            if visibility is not None:
                yield from filter(lambda m: m.visibility == visibility, self._definitions)
            else:
                yield from self._definitions
    
        def member_variables(
            self, visibility: SfgVisibility | None = None
        ) -> Generator[SfgMemberVariable, None, None]:
            if visibility is not None:
                yield from filter(
                    lambda m: m.visibility == visibility, self._member_vars.values()
                )
            else:
                yield from self._member_vars.values()
    
        def constructors(
            self, visibility: SfgVisibility | None = None
        ) -> Generator[SfgConstructor, None, None]:
            if visibility is not None:
                yield from filter(lambda m: m.visibility == visibility, self._constructors)
            else:
                yield from self._constructors
    
        def methods(
            self, visibility: SfgVisibility | None = None
        ) -> Generator[SfgMethod, None, None]:
            if visibility is not None:
                yield from filter(
                    lambda m: m.visibility == visibility, self._methods.values()
                )
            else:
                yield from self._methods.values()
    
        # PRIVATE
    
        def _add_member(self, member: SfgClassMember, vis: SfgVisibility):
            if isinstance(member, SfgConstructor):
                self._add_constructor(member)
            elif isinstance(member, SfgMemberVariable):
                self._add_member_variable(member)
            elif isinstance(member, SfgMethod):
                self._add_method(member)
            elif isinstance(member, SfgInClassDefinition):
                self._add_definition(member)
            else:
                raise SfgException(f"{member} is not a valid class member.")
    
            member._bind(self, vis)
    
        def _add_definition(self, definition: SfgInClassDefinition):
            self._definitions.append(definition)
    
        def _add_constructor(self, constr: SfgConstructor):
            #   TODO: Check for signature conflicts?
            self._constructors.append(constr)
    
        def _add_method(self, method: SfgMethod):
            if method.name in self._methods:
                raise SfgException(
                    f"Duplicate method name {method.name} in class {self._class_name}"
                )
    
            self._methods[method.name] = method
    
        def _add_member_variable(self, variable: SfgMemberVariable):
            if variable.name in self._member_vars:
                raise SfgException(
                    f"Duplicate field name {variable.name} in class {self._class_name}"
                )
    
            self._member_vars[variable.name] = variable