Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
WIP Params
Browse files Browse the repository at this point in the history
  • Loading branch information
iopapamanoglou committed Sep 4, 2024
1 parent 5f5bf1c commit f26ac50
Show file tree
Hide file tree
Showing 19 changed files with 236 additions and 268 deletions.
5 changes: 3 additions & 2 deletions src/faebryk/core/graphinterface.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is part of the faebryk project
# SPDX-License-Identifier: MIT
import logging
from typing import TYPE_CHECKING, Mapping, Optional, cast
from typing import TYPE_CHECKING, Mapping, Optional

from typing_extensions import Self, deprecated

Expand All @@ -18,7 +18,8 @@

logger = logging.getLogger(__name__)

Graph = GraphImpl["GraphInterface"]

class Graph(GraphImpl["GraphInterface"]): ...


class GraphInterface(FaebrykLibObject):
Expand Down
75 changes: 75 additions & 0 deletions src/faebryk/core/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
from typing import (
Callable,
Concatenate,
Optional,
Sequence,
)
Expand All @@ -12,6 +13,7 @@
from faebryk.core.graphinterface import GraphInterface
from faebryk.core.node import Node
from faebryk.core.trait import Trait
from faebryk.libs.units import Quantity, UnitsContainer, to_si_str

Check failure on line 16 in src/faebryk/core/parameter.py

View workflow job for this annotation

GitHub Actions / test

Ruff (F401)

src/faebryk/core/parameter.py:16:58: F401 `faebryk.libs.units.to_si_str` imported but unused
from faebryk.libs.util import Tree, TwistArgs, is_type_pair, try_avoid_endless_recursion

logger = logging.getLogger(__name__)
Expand All @@ -33,6 +35,19 @@ def wrap(*args):
return wrap


def _resolved_self[PV, O, **P](
func: Callable[Concatenate["Parameter[PV]", P], O],
) -> Callable[Concatenate["PV | set[PV] | tuple[PV, PV] | Parameter[PV]", P], O]:
def wrap(
p: "PV | set[PV] | tuple[PV, PV] | Parameter[PV]",
*args: P.args,
**kwargs: P.kwargs,
):
return func(Parameter.from_literal(p).get_most_narrow(), *args, **kwargs)

return wrap


class Parameter[PV](Node):
type LIT = PV | set[PV] | tuple[PV, PV]
type LIT_OR_PARAM = LIT | "Parameter[PV]"
Expand Down Expand Up @@ -416,3 +431,63 @@ def get_tree_param(self, include_root: bool = True) -> Tree["Parameter"]:
if include_root:
out = Tree[Parameter]({self: out})
return out

# TODO make those all abstract ------------------------------------------------------

Check failure on line 435 in src/faebryk/core/parameter.py

View workflow job for this annotation

GitHub Actions / test

Ruff (E501)

src/faebryk/core/parameter.py:435:89: E501 Line too long (89 > 88)
@_resolved_self
def enum_parameter_representation(
self: "Parameter[PV]", required: bool = False
) -> str:
return self._enum_parameter_representation(required=required)

def _enum_parameter_representation(self, required: bool = False) -> str:
return self.as_unit("", required=required)

@_resolved_self
def as_unit(
self: "Parameter[PV]",
unit: UnitsContainer,
base: int = 1000,
required: bool = False,
) -> str:
if base != 1000:
raise NotImplementedError("Only base 1000 supported")

return self._as_unit(unit, base=base, required=required)

def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str:
raise ValueError(f"Unsupported {self}")

@_resolved_self
def as_unit_with_tolerance(
self: "Parameter[PV]",
unit: UnitsContainer,
base: int = 1000,
required: bool = False,
) -> str:
return self._as_unit_with_tolerance(unit, base=base, required=required)

def _as_unit_with_tolerance(
self, unit: UnitsContainer, base: int, required: bool
) -> str:
return self._as_unit(unit, base=base, required=required)

@_resolved_self
def get_max(self: "Parameter[PV]") -> PV:
return self._max()

def _max(self):
raise ValueError(f"Can't get max for {self}")

def with_same_unit(
self: "Quantity | float | int | LIT_OR_PARAM",
to_convert: float | int,
):
from faebryk.library.Constant import Constant

if isinstance(self, Constant) and isinstance(self.value, Quantity):
return Quantity(to_convert, self.value.units)
if isinstance(self, Quantity):
return Quantity(to_convert, self.units)
if isinstance(self, (float, int)):
return to_convert
raise NotImplementedError(f"Unsupported {self=}")
160 changes: 3 additions & 157 deletions src/faebryk/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,133 +2,18 @@
# SPDX-License-Identifier: MIT

import logging
from enum import Enum
from textwrap import indent
from typing import (
Callable,
Iterable,
Sequence,
cast,
)
from typing import Iterable

from typing_extensions import deprecated

import faebryk.library._F as F
from faebryk.core.graphinterface import (
Graph,
GraphInterface,
GraphInterfaceSelf,
)
from faebryk.core.link import Link, LinkDirect
from faebryk.core.module import Module
from faebryk.core.graphinterface import Graph, GraphInterfaceSelf
from faebryk.core.moduleinterface import ModuleInterface
from faebryk.core.node import Node
from faebryk.core.parameter import Parameter
from faebryk.core.trait import Trait
from faebryk.libs.units import Quantity, UnitsContainer, to_si_str
from faebryk.libs.util import NotNone, Tree, cast_assert, zip_dicts_by_key, zip_exhaust

logger = logging.getLogger(__name__)

# Parameter ----------------------------------------------------------------------------


def enum_parameter_representation(param: Parameter, required: bool = False) -> str:
if isinstance(param, F.Constant):
return param.value.name if isinstance(param.value, Enum) else str(param.value)
elif isinstance(param, F.Range):
return (
f"{enum_parameter_representation(param.min)} - "
f"{enum_parameter_representation(param.max)}"
)
elif isinstance(param, F.Set):
return f"Set({', '.join(map(enum_parameter_representation, param.params))})"
elif isinstance(param, F.TBD):
return "TBD" if required else ""
elif isinstance(param, F.ANY):
return "ANY" if required else ""
else:
return type(param).__name__


def as_unit(
param: Parameter[Quantity],
unit: str | UnitsContainer,
base: int = 1000,
required: bool = False,
) -> str:
if base != 1000:
raise NotImplementedError("Only base 1000 supported")
if isinstance(param, F.Constant):
return to_si_str(param.value, unit)
elif isinstance(param, F.Range):
return (
as_unit(param.min, unit, base=base)
+ " - "
+ as_unit(param.max, unit, base=base, required=True)
)
elif isinstance(param, F.Set):
return (
"Set("
+ ", ".join(map(lambda x: as_unit(x, unit, required=True), param.params))
+ ")"
)
elif isinstance(param, F.TBD):
return "TBD" if required else ""
elif isinstance(param, F.ANY):
return "ANY" if required else ""

raise ValueError(f"Unsupported {param=}")


def as_unit_with_tolerance(
param: Parameter, unit: str, base: int = 1000, required: bool = False
) -> str:
if isinstance(param, F.Constant):
return as_unit(param, unit, base=base)
elif isinstance(param, F.Range):
center, delta = param.as_center_tuple(relative=True)
delta_percent_str = f"±{to_si_str(delta.value, "%", 0)}"
return (
f"{as_unit(center, unit, base=base, required=required)} {delta_percent_str}"
)
elif isinstance(param, F.Set):
return (
"Set("
+ ", ".join(
map(lambda x: as_unit_with_tolerance(x, unit, base), param.params)
)
+ ")"
)
elif isinstance(param, F.TBD):
return "TBD" if required else ""
elif isinstance(param, F.ANY):
return "ANY" if required else ""
raise ValueError(f"Unsupported {param=}")


def get_parameter_max(param: Parameter):
if isinstance(param, F.Constant):
return param.value
if isinstance(param, F.Range):
return param.max
if isinstance(param, F.Set):
return max(map(get_parameter_max, param.params))
raise ValueError(f"Can't get max for {param}")


def with_same_unit(to_convert: float | int, param: Parameter | Quantity | float | int):
if isinstance(param, F.Constant) and isinstance(param.value, Quantity):
return Quantity(to_convert, param.value.units)
if isinstance(param, Quantity):
return Quantity(to_convert, param.units)
if isinstance(param, (float, int)):
return to_convert
raise NotImplementedError(f"Unsupported {param=}")


# --------------------------------------------------------------------------------------

# Graph Querying -----------------------------------------------------------------------


Expand Down Expand Up @@ -183,41 +68,6 @@ def get_all_nodes_of_types(g: Graph, t: tuple[type[Node], ...]) -> set[Node]:
return {n for n in node_projected_graph(g) if isinstance(n, t)}


def get_direct_connected_nodes[T: Node](
gif: GraphInterface, ty: type[T] = Node
) -> set[T]:
out = Node.get_nodes_from_gifs(
g for g, t in gif.edges.items() if isinstance(t, LinkDirect)
)
assert all(isinstance(n, ty) for n in out)
return cast(set[T], out)


def get_mif_tree(
obj: ModuleInterface | Module,
) -> dict[ModuleInterface, dict[ModuleInterface, dict]]:
mifs = obj.get_children(direct_only=True, types=ModuleInterface)

return {mif: get_mif_tree(mif) for mif in mifs}


def format_mif_tree(tree: dict[ModuleInterface, dict[ModuleInterface, dict]]) -> str:
def str_tree(
tree: dict[ModuleInterface, dict[ModuleInterface, dict]],
) -> dict[str, dict]:
def get_name(k: ModuleInterface):
# get_parent never none, since k gotten from parent
return NotNone(k.get_parent())[1]

return {
f"{get_name(k)} ({type(k).__name__})": str_tree(v) for k, v in tree.items()
}

import json

return json.dumps(str_tree(tree), indent=4)


# --------------------------------------------------------------------------------------


Expand All @@ -229,7 +79,7 @@ def use_interface_names_as_net_names(node: Node, name: str | None = None):

name_prefix = node.get_full_name()

el_ifs = {n for n in get_all_nodes(node) if isinstance(n, F.Electrical)}
el_ifs = node.get_children(types=F.Electrical, direct_only=False)

# for el_if in el_ifs:
# print(el_if)
Expand Down Expand Up @@ -295,7 +145,3 @@ def use_interface_names_as_net_names(node: Node, name: str | None = None):
net.part_of.connect(el_if)
logger.debug(f"Created {net_name} for {el_if}")
nets[net_name] = net, el_if


def with_names[N: Node](nodes: Iterable[N]) -> dict[str, N]:
return {n.get_name(): n for n in nodes}
4 changes: 4 additions & 0 deletions src/faebryk/library/ANY.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT

from faebryk.core.parameter import Parameter
from faebryk.libs.units import UnitsContainer


class ANY[PV](Parameter[PV]):
Expand All @@ -19,3 +20,6 @@ def __eq__(self, __value: object) -> bool:

def __hash__(self) -> int:
return super().__hash__()

def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str:
return "ANY" if required else ""
21 changes: 6 additions & 15 deletions src/faebryk/library/Capacitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,17 @@ def can_bridge(self):

@L.rt_field
def simple_value_representation(self):
from faebryk.core.util import (
as_unit,
as_unit_with_tolerance,
enum_parameter_representation,
)

return F.has_simple_value_representation_based_on_params(
(
self.capacitance,
self.rated_voltage,
self.temperature_coefficient,
),
lambda ps: " ".join(
filter(
None,
[
as_unit_with_tolerance(ps[0], "F"),
as_unit(ps[1], "V"),
enum_parameter_representation(ps[2].get_most_narrow()),
],
)
lambda c, v, t: " ".join(
[
c.as_unit_with_tolerance("F"),
v.as_unit("V"),
t.enum_parameter_representation(),
],
),
)
19 changes: 12 additions & 7 deletions src/faebryk/library/Comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,24 @@ class OutputType(Enum):

@L.rt_field
def simple_value_representation(self):
from faebryk.core.util import as_unit

return F.has_simple_value_representation_based_on_params(
[
(
self.common_mode_rejection_ratio,
self.input_bias_current,
self.input_hysteresis_voltage,
self.input_offset_voltage,
self.propagation_delay,
],
lambda p: (
f"{p[0]} CMRR, {as_unit(p[1], 'A')} Ib, {as_unit(p[2], 'V')} Vhys, "
f"{as_unit(p[3], 'V')} Vos, {as_unit(p[4], 's')} tpd"
),
lambda cmrr, ib, vhys, vos, tpd: (
", ".join(
[
f"{cmrr} CMRR",
f"{ib.as_unit('A')} Ib",
f"{vhys.as_unit('V')} Vhys",
f"{vos.as_unit('V')} Vos",
f"{tpd.as_unit('s')} tpd",
]
)
),
)

Expand Down
Loading

0 comments on commit f26ac50

Please sign in to comment.