Skip to content

Commit 561da36

Browse files
authored
Improve int handling (#395)
Ints can be 'promoted' to floats and ranges and used in their operations. Change int invert semantics to promote to float, consistent with Python behavior.
1 parent 11885f3 commit 561da36

File tree

4 files changed

+26
-22
lines changed

4 files changed

+26
-22
lines changed

compiler/src/main/scala/edg/compiler/ExprEvaluate.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ object ExprEvaluate {
262262
RangeValue(1.0 / valMax, 1.0 / valMin)
263263
case RangeEmpty => RangeEmpty
264264
case FloatValue(opVal) => FloatValue(1.0 / opVal)
265-
case IntValue(opVal) => IntValue(1 / opVal)
265+
case IntValue(opVal) =>
266+
FloatValue(1.0 / opVal.floatValue) // follow Python convention of division promoting to float
266267
case _ => throw new ExprEvaluateException(s"Unknown unary operand type in ${unary.op} ${`val`} from $unary")
267268
}
268269

edg/core/ConstraintExpr.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,16 @@ def _from_lit(cls, pb: edgir.ValueLit) -> int:
285285

286286

287287
FloatLit = Union[float, int]
288-
FloatLike = Union['FloatExpr', float]
289-
class FloatExpr(NumLikeExpr[float, FloatLike]):
288+
FloatLike = Union['FloatExpr', float, int]
289+
class FloatExpr(NumLikeExpr[float, Union[FloatLike, IntExpr]]):
290290
@classmethod
291-
def _to_expr_type(cls, input: FloatLike) -> FloatExpr:
291+
def _to_expr_type(cls, input: Union[FloatLike, IntExpr]) -> FloatExpr:
292292
if isinstance(input, FloatExpr):
293293
assert input._is_bound()
294294
return input
295+
elif isinstance(input, IntExpr):
296+
assert input._is_bound() and input.binding is not None
297+
return FloatExpr()._bind(input.binding)
295298
elif isinstance(input, int) or isinstance(input, float):
296299
return FloatExpr()._bind(FloatLiteralBinding(input))
297300
else:
@@ -316,7 +319,7 @@ def max(self, other: FloatLike) -> FloatExpr:
316319

317320

318321
RangeLike = Union['RangeExpr', Range, Tuple[FloatLike, FloatLike]]
319-
class RangeExpr(NumLikeExpr[Range, Union[RangeLike, FloatLike]]):
322+
class RangeExpr(NumLikeExpr[Range, Union[RangeLike, FloatLike, IntExpr]]):
320323
# Some range literals for defaults
321324
POSITIVE: Range = Range.from_lower(0.0)
322325
NEGATIVE: Range = Range.from_upper(0.0)
@@ -326,11 +329,11 @@ class RangeExpr(NumLikeExpr[Range, Union[RangeLike, FloatLike]]):
326329
EMPTY = Range(float('NaN'), float('NaN')) # special marker to define an empty range, which is subset-eq of any range
327330

328331
@classmethod
329-
def _to_expr_type(cls, input: Union[RangeLike, FloatLike]) -> RangeExpr:
332+
def _to_expr_type(cls, input: Union[RangeLike, FloatLike, IntLike]) -> RangeExpr:
330333
if isinstance(input, RangeExpr):
331334
assert input._is_bound()
332335
return input
333-
elif isinstance(input, (int, float, FloatExpr)):
336+
elif isinstance(input, (int, float, FloatExpr, IntExpr)):
334337
expr = FloatExpr._to_expr_type(input)
335338
return RangeExpr()._bind(RangeBuilderBinding(expr, expr))
336339
elif isinstance(input, tuple) and isinstance(input[0], (int, float)) and isinstance(input[1], (int, float)):
@@ -390,7 +393,7 @@ def within(self, item: RangeLike) -> BoolExpr:
390393
def contains(self, item: Union[RangeLike, FloatLike]) -> BoolExpr:
391394
if isinstance(item, (RangeExpr, tuple, Range)):
392395
return RangeExpr._to_expr_type(item).within(self)
393-
elif isinstance(item, (int, float, FloatExpr)):
396+
elif isinstance(item, (int, float, FloatExpr, IntExpr)):
394397
return self._create_bool_op(FloatExpr._to_expr_type(item), self, OrdOp.within)
395398

396399
def intersect(self, other: Union[RangeLike, FloatLike]) -> RangeExpr:
@@ -411,38 +414,38 @@ def center(self) -> FloatExpr:
411414
@classmethod
412415
def _create_range_float_binary_op(cls,
413416
lhs: RangeExpr,
414-
rhs: Union[RangeExpr, FloatExpr],
417+
rhs: Union[RangeExpr, IntExpr, FloatExpr],
415418
op: Union[NumericOp]) -> RangeExpr:
416419
"""Creates a new expression that is the result of a binary operation on inputs"""
417420
if not isinstance(lhs, RangeExpr):
418421
raise TypeError(f"range mul and div lhs must be range type, "
419422
f"got lhs={lhs} of type {type(lhs)} and rhs={rhs} of type {type(rhs)}")
420423

421-
if not isinstance(rhs, (RangeExpr, FloatExpr)):
422-
raise TypeError(f"range mul and div rhs must be range or float type, "
424+
if not isinstance(rhs, (RangeExpr, FloatExpr, IntExpr)):
425+
raise TypeError(f"range mul and div rhs must be range or float or int type, "
423426
f"got lhs={lhs} of type {type(lhs)} and rhs={rhs} of type {type(rhs)}")
424427

425428
assert lhs._is_bound() and rhs._is_bound()
426429
return lhs._new_bind(BinaryOpBinding(lhs, rhs, op))
427430

428431
# special option to allow range * float
429-
def __mul__(self, rhs: Union[RangeLike, FloatLike]) -> RangeExpr:
432+
def __mul__(self, rhs: Union[RangeLike, FloatLike, IntLike]) -> RangeExpr:
430433
if isinstance(rhs, (int, float)): # TODO clean up w/ literal to expr pass, then type based on that
431-
rhs_cast: Union[FloatExpr, RangeExpr] = FloatExpr._to_expr_type(rhs)
432-
elif not isinstance(rhs, FloatExpr):
433-
rhs_cast = self._to_expr_type(rhs) # type: ignore
434-
else:
434+
rhs_cast: Union[FloatExpr, IntExpr, RangeExpr] = FloatExpr._to_expr_type(rhs)
435+
elif isinstance(rhs, (FloatExpr, IntExpr)):
435436
rhs_cast = rhs
437+
else:
438+
rhs_cast = self._to_expr_type(rhs) # type: ignore
436439
return self._create_range_float_binary_op(self, rhs_cast, NumericOp.mul)
437440

438441
# special option to allow range / float
439-
def __truediv__(self, rhs: Union[RangeLike, FloatLike]) -> RangeExpr:
442+
def __truediv__(self, rhs: Union[RangeLike, FloatLike, IntLike]) -> RangeExpr:
440443
if isinstance(rhs, (int, float)): # TODO clean up w/ literal to expr pass, then type based on that
441-
rhs_cast: Union[FloatExpr, RangeExpr] = FloatExpr._to_expr_type(rhs)
442-
elif not isinstance(rhs, FloatExpr):
443-
rhs_cast = self._to_expr_type(rhs) # type: ignore
444-
else:
444+
rhs_cast: Union[FloatExpr, IntExpr, RangeExpr] = FloatExpr._to_expr_type(rhs)
445+
elif isinstance(rhs, (FloatExpr, IntExpr)):
445446
rhs_cast = rhs
447+
else:
448+
rhs_cast = self._to_expr_type(rhs) # type: ignore
446449
return self * rhs_cast.__mul_inv__()
447450

448451
def abs(self) -> RangeExpr:
7 Bytes
Binary file not shown.

edg/parts/Batteries.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def generate(self):
103103
else:
104104
self.connect(prev_cell.pwr.as_ground(self.pwr.link().current_drawn), cell.gnd)
105105
prev_capacity_min = cell.actual_capacity.lower().min(prev_capacity_min)
106-
prev_capacity_max= cell.actual_capacity.upper().min(prev_capacity_max)
106+
prev_capacity_max = cell.actual_capacity.upper().min(prev_capacity_max)
107107
prev_cell = cell
108108

109109
assert prev_cell is not None, "must generate >=1 cell"

0 commit comments

Comments
 (0)