Bonjour,
J’ai un problème à vous exposer. Je crée une classe RCModel
, pour faire une pseudo-simulation de circuit électrique, qui est basiquement un directed graph sur lequel je rajoute quelques methodes et propriétés. Toutes les propriétés découle de la matrice d’incidence du graphe et des propriétés attachés aux branches et aux noeuds qui sont exprimés comme des expressions SymPy. Par exemple, quand je veux la matrice Ac
de mon modèle, je me retrouve avec une matrice d’expressions SymPy. Voilà un subset de mon code qui me permet de faire ça:
class RCModel(object):
__definition__ = {}
def __init__(self, name=None):
self.name = name
self.network = self.load_from_dict(self.__definition__)
self.m = sum(['capacity' in data for _, data in self.network.nodes(data=True)])
self.n = len(self.network.nodes) - 1 - self.m
# A lot of functions...
@property
def _incidence_matrix(self):
return nx.incidence_matrix(self.network, oriented=True).todense().T
@property
def A(self):
return Matrix(self._incidence_matrix)[:, 1:]
@property
def G(self):
return Matrix(
np.diag(
[
self.sympy_suffix(
sympify(e.get("trigger", 1)) / sympify(e["conductivity"])
)
for _, _, e in self.network.edges(data=True)
]
)
)
@property
def Cs(self):
return Matrix(
np.diag(
[
self.sympy_suffix(sympify(e["capacity"]))
for _, e in self.network.nodes(data=True)
if "capacity" in e
]
)
)
@property
def K(self):
return -self.A.T @ self.G @ self.A
@property
def K11(self):
return self.K[: self.n, : self.n]
# Same type of definitions for K12, K21, K22
@property
def Ac(self):
return self.Cs.inv() @ (-self.K21 @ self.K11.inv() @ self.K12 + self.K22)
Je peux créer un modèle directement en héritant de cette classe, comme avec l’example ci-dessous:
class M3(RCModel):
__definition__ = {
"nodes": [
{"name": "xo", "temperature": "To"},
{"name": "xso", "heat": "Qo"},
{"name": "xi", "capacity": "Cj", "heat": "Qh + Qj"},
{"name": "xw", "capacity": "Cw"},
],
"edges": [
{"from": "xo", "to": "xi", "conductivity": "Rv"},
{"from": "xo", "to": "xso", "conductivity": "Rco"},
{"from": "xso", "to": "xw", "conductivity": "Rw/2"},
{"from": "xw", "to": "xi", "conductivity": "(Rw/2)+Rci"},
],
}
qui me permet de calculer les propriétés on the fly
In [2]: m = M3()
In [3]: m.Ac
Out[3]:
Matrix([
[(-1.0/(Rci + Rw/2) - 1.0/Rv)/Cj, 1.0/(Cj*(Rci + Rw/2))],
[ 1.0/(Cw*(Rci + Rw/2)), (-1.0/(Rci + Rw/2) - 2.0/Rw - 4.0/(Rw**2*(-2.0/Rw - 1.0/Rco)))/Cw]])
Tout ça fonctionne bien, je suis capable de créer des modèles RC qui sont des assemblages de graphes de modèles RCs pre-existants. Mais j’ai du mal à scaler car, pour le moment, calculer les propriétés sont recalculés à chaque appel qui est de plus en plus coûteux avec l’augmentation de la taille du graphe, surtout pour les propriétés qui comportent une inversion de matrice.
Je cherche une stratégie pour cacher ces appels. lru_cache
est une option, mais ça fait tout de même un appel coûteux. Est-ce qu’il y aurait des stratégies pour pré-calculer ces propriétés, qui restent fixes pour une __definition__
de RCModel
donné, dans une phase précédant l’éxécution du code ?
Merci bien