3535 ConstantValue ,
3636 Divider ,
3737 FormulaStep ,
38+ Maximizer ,
3839 MetricFetcher ,
40+ Minimizer ,
3941 Multiplier ,
4042 OpenParen ,
4143 Subtractor ,
4547_logger = logging .Logger (__name__ )
4648
4749_operator_precedence = {
48- "(" : 0 ,
49- "/" : 1 ,
50- "*" : 2 ,
51- "-" : 3 ,
52- "+" : 4 ,
53- ")" : 5 ,
50+ "max" : 0 ,
51+ "min" : 1 ,
52+ "(" : 2 ,
53+ "/" : 3 ,
54+ "*" : 4 ,
55+ "-" : 5 ,
56+ "+" : 6 ,
57+ ")" : 7 ,
5458}
5559
5660
@@ -168,6 +172,36 @@ def __truediv__(
168172 """
169173 return self ._higher_order_builder (self , self ._create_method ) / other # type: ignore
170174
175+ def _max (
176+ self , other : _GenericEngine | _GenericHigherOrderBuilder | QuantityT
177+ ) -> _GenericHigherOrderBuilder :
178+ """Return a formula engine that outputs the maximum of `self` and `other`.
179+
180+ Args:
181+ other: A formula receiver, a formula builder or a QuantityT instance
182+ corresponding to a sub-expression.
183+
184+ Returns:
185+ A formula builder that can take further expressions, or can be built
186+ into a formula engine.
187+ """
188+ return self ._higher_order_builder (self , self ._create_method ).max (other ) # type: ignore
189+
190+ def _min (
191+ self , other : _GenericEngine | _GenericHigherOrderBuilder | QuantityT
192+ ) -> _GenericHigherOrderBuilder :
193+ """Return a formula engine that outputs the minimum of `self` and `other`.
194+
195+ Args:
196+ other: A formula receiver, a formula builder or a QuantityT instance
197+ corresponding to a sub-expression.
198+
199+ Returns:
200+ A formula builder that can take further expressions, or can be built
201+ into a formula engine.
202+ """
203+ return self ._higher_order_builder (self , self ._create_method ).min (other ) # type: ignore
204+
171205
172206class FormulaEngine (
173207 Generic [QuantityT ],
@@ -467,6 +501,10 @@ def push_oper(self, oper: str) -> None:
467501 self ._build_stack .append (Divider ())
468502 elif oper == "(" :
469503 self ._build_stack .append (OpenParen ())
504+ elif oper == "max" :
505+ self ._build_stack .append (Maximizer ())
506+ elif oper == "min" :
507+ self ._build_stack .append (Minimizer ())
470508
471509 def push_metric (
472510 self ,
@@ -653,15 +691,15 @@ def _push(
653691 self ._steps .append ((TokenType .OPER , ")" ))
654692 self ._steps .append ((TokenType .OPER , oper ))
655693
656- # pylint: disable=protected-access
657694 if isinstance (other , (FormulaEngine , FormulaEngine3Phase )):
658695 self ._steps .append ((TokenType .COMPONENT_METRIC , other ))
659- elif isinstance (other , (Quantity , float )):
696+ elif isinstance (other , (Quantity , float , int )):
660697 match oper :
661- case "+" | "-" :
698+ case "+" | "-" | "max" | "min" :
662699 if not isinstance (other , Quantity ):
663700 raise RuntimeError (
664- f"A Quantity must be provided for addition or subtraction to { other } "
701+ "A Quantity must be provided for addition,"
702+ f" subtraction, min or max to { other } "
665703 )
666704 case "*" | "/" :
667705 if not isinstance (other , (float , int )):
@@ -671,9 +709,8 @@ def _push(
671709 self ._steps .append ((TokenType .CONSTANT , other ))
672710 elif isinstance (other , _BaseHOFormulaBuilder ):
673711 self ._steps .append ((TokenType .OPER , "(" ))
674- self ._steps .extend (other ._steps )
712+ self ._steps .extend (other ._steps ) # pylint: disable=protected-access
675713 self ._steps .append ((TokenType .OPER , ")" ))
676- # pylint: enable=protected-access
677714 else :
678715 raise RuntimeError (f"Can't build a formula from: { other } " )
679716 assert isinstance (
@@ -804,6 +841,66 @@ def __truediv__(
804841 """
805842 return self ._push ("/" , other )
806843
844+ @overload
845+ def max (
846+ self , other : _CompositionType1Phase
847+ ) -> HigherOrderFormulaBuilder [QuantityT ]:
848+ ...
849+
850+ @overload
851+ def max (
852+ self , other : _CompositionType3Phase | QuantityT
853+ ) -> HigherOrderFormulaBuilder3Phase [QuantityT ]:
854+ ...
855+
856+ def max (
857+ self , other : _CompositionType | QuantityT
858+ ) -> (
859+ HigherOrderFormulaBuilder [QuantityT ]
860+ | HigherOrderFormulaBuilder3Phase [QuantityT ]
861+ ):
862+ """Return a formula builder that calculates the maximum of `self` and `other`.
863+
864+ Args:
865+ other: A formula receiver, or a formula builder instance corresponding to a
866+ sub-expression.
867+
868+ Returns:
869+ A formula builder that can take further expressions, or can be built
870+ into a formula engine.
871+ """
872+ return self ._push ("max" , other )
873+
874+ @overload
875+ def min (
876+ self , other : _CompositionType1Phase
877+ ) -> HigherOrderFormulaBuilder [QuantityT ]:
878+ ...
879+
880+ @overload
881+ def min (
882+ self , other : _CompositionType3Phase | QuantityT
883+ ) -> HigherOrderFormulaBuilder3Phase [QuantityT ]:
884+ ...
885+
886+ def min (
887+ self , other : _CompositionType | QuantityT
888+ ) -> (
889+ HigherOrderFormulaBuilder [QuantityT ]
890+ | HigherOrderFormulaBuilder3Phase [QuantityT ]
891+ ):
892+ """Return a formula builder that calculates the minimum of `self` and `other`.
893+
894+ Args:
895+ other: A formula receiver, or a formula builder instance corresponding to a
896+ sub-expression.
897+
898+ Returns:
899+ A formula builder that can take further expressions, or can be built
900+ into a formula engine.
901+ """
902+ return self ._push ("min" , other )
903+
807904
808905class HigherOrderFormulaBuilder (Generic [QuantityT ], _BaseHOFormulaBuilder [QuantityT ]):
809906 """A specialization of the _BaseHOFormulaBuilder for `FormulaReceiver`."""
0 commit comments