<_whitenotifier-6>
[amaranth-lang/amaranth-lang.github.io] github-merge-queue[bot] e2db332 - Deploying to main from @ amaranth-lang/amaranth@c4370efcf48b4a92790621e6c8622f0e16910d84 🚀
<whitequark[cis]>
<zyp[m]> "I figure a SimulationTime..." <- subclass of what? for what purpose?
<whitequark[cis]>
time is not a number
<zyp[m]>
it literally is the elapsed number of (femto)seconds
<zyp[m]>
and if you're gonna be doing math on it (for statistics or whatever), I figure it's beneficial if it fits into the regular number system
<whitequark[cis]>
time is a physical quantity that is represented by a number
<whitequark[cis]>
the physical quantity is not a number in the same way a string is not a sequence of bytes
<whitequark[cis]>
(and, yes, regretfully amaranth has some core assumptions that contradict this. that's a problem with Amaranth, though it's not completely clear how solvable it is)
<whitequark[cis]>
consider: what's the physical meaning of (time × time)? if there isn't one, why should it be allowed?
<zyp[m]>
I've never argued it should
<zyp[m]>
but time/time should
<whitequark[cis]>
you proposed making time a subclass of some kind of number
<whitequark[cis]>
which would allow all of the numeric operations
<whitequark[cis]>
that's what subclassing means
<tpw_rules>
(you could override __mul__...)
<zyp[m]>
okay, badly worded
<cr1901>
In general, I believe rationals are generally a horrible datatype, but there should probably be some sort of scale conversion, probably via methods
<whitequark[cis]>
tpw_rules: that breaks LSP
<_whitenotifier-5>
[amaranth] github-merge-queue[bot] created branch gh-readonly-queue/main/pr-1337-c4370efcf48b4a92790621e6c8622f0e16910d84 - https://github.com/amaranth-lang/amaranth
<zyp[m]>
numbers.Rational is mostly abstract anyway, but yeah, subclassing would make isinstance() do the wrong thing
<whitequark[cis]>
it would also be papering over the real problem (which is that time isn't a number)
<cr1901>
I wanted to measure simulation time because I wanted to test that my plugin works when I change the clock frequency I provide to the simulator
<cr1901>
I could parse the output VCDs and measure elapsed time to make sure the new clock frequency took, but having access to that info in sim seems nicer
<whitequark[cis]>
we definitely should have a newtype representing time that's easily convertible to and from a number
<whitequark[cis]>
and the fact that we don't is my fault (years ago)
<cr1901>
I personally think that an integer with implicit scale factor of 10^-15 is fine for amaranth sim's internal use
<whitequark[cis]>
it's just not been a super high priority thing because few people need it and also if you really want it, you can work around it using a public interface (sort of)
<cr1901>
sort of?
<whitequark[cis]>
you can have a process incrementing a nonlocal or global integer in a loop and waiting
<whitequark[cis]>
this can work with any arbitrary resolution you might want. however if you use 1-femtosecond delays you might find it that your simulation takes a rather long time to complete
<whitequark[cis]>
and if you coarsen the resolution, it has to be a gcd of every clock or you get an error
<_whitenotifier-5>
[amaranth-lang/amaranth-lang.github.io] github-merge-queue[bot] f3542d9 - Deploying to main from @ amaranth-lang/amaranth@a7a7d3209948b0f48f9ff275140850cdae408983 🚀
<zyp[m]>
whitequark[cis]: the advantage of making it a `numbers.Rational` is that both `float()` and `Fraction()` would then understand it
<whitequark[cis]>
i consider that a disadvantage, because time is not a number
<cr1901>
(why are Fraction and Rational two different types?)
<whitequark[cis]>
(i will repeat that last part as many times as necessary)
<zyp[m]>
because Rational is abstract
<cr1901>
"Is time a number" - the greatest thread in the history of forums, locked by a moderator after 12,239 pages of heated debate,
<whitequark[cis]>
lol
<zyp[m]>
so how do you turn it into a number?
<cr1901>
Generally I think Rationals are not a good data type because the num and den will explode after relatively few ops if you don't normalize them. And if you do normalize them, well, that's a division/find greatest common factor, etc
<whitequark[cis]>
zyp: yes, but I think zyp offers making time a special kind of Rational whose denominator is fixed
<whitequark[cis]>
which is fine in terms of the implementation (it doesn't suffer from the explosion) but has the problem that time is not a number
<whitequark[cis]>
zyp[m]: like a method?
<zyp[m]>
cr1901: all python floats and ints are Rational
<whitequark[cis]>
actually that milliseconds (and everything else, sans femtoseconds which is explicitly documented to return an int) should return a Rational
<tpw_rules>
how did it get settled on that femtoseconds is right as the base type
<zyp[m]>
which Rational? Fraction?
<whitequark[cis]>
the short names (ms, s, fs, etc) are constructors for the frequently used operations, the long names (milliseconds, seconds) are accessors for the less frequently used operations)
<cr1901>
zyp[m]: Yea to be clear, all my uses of Rational have been ignoring that Rational is an ABC
<cr1901>
apologies
<whitequark[cis]>
zyp[m]: some `Rational` that we find fit for purpose
<cr1901>
By Rational, I specifically meant "has a num and den field"
<whitequark[cis]>
i don't have strong opinions on this topic besides "time is not a number"
<cr1901>
which is probably Fraction in Python terms?
<cr1901>
if python is representing ints as anything besides a machine-word int or a bigint, I have several questions
<whitequark[cis]>
cr1901: the representation is ... complex, but it can basically be thought of as a bigint with optimizations
<cr1901>
I really hope numerator/denominator field is a property :P
<tpw_rules>
according to my python float is not a Rational
<cr1901>
ahhh
<whitequark[cis]>
that doesn't prevent int from implementing the abstract base class numbers.Rational because an integer is, mathematically, a rational number
* cr1901
nods
<zyp[m]>
tpw_rules: you're right, I was thinking of `float.as_integer_ratio()`
<whitequark[cis]>
floats aren't rational numbers due to +Inf, NaN, and other shenanigans
<whitequark[cis]>
Python actually respects the Liskov substitution principle here, so I'm not going to merge an interface that breaks it
<whitequark[cis]>
actually, sim should probably have both Frequency and Duration
<whitequark[cis]>
or perhaps `Period
<zyp[m]>
whitequark[cis]: I think it should probably be `Fraction` then, since it's the only builtin type that guarantees perfect representation, and is implicitly convertible to float
<whitequark[cis]>
* or perhaps Period
<cr1901>
If we promise not to make denominators explode, which seems to be the gameplan, I'm not attached to any particular Rational implementation. And agreed re: Duration
<whitequark[cis]>
cr1901: well, the simulator's gonna use femtoseconds one way or another, so any interface would have to be compatible enough with that
<tpw_rules>
why femtoseconds in particular?
<whitequark[cis]>
which pretty much excludes exploding denominators
<whitequark[cis]>
tpw_rules: picoseconds are too coarse
<whitequark[cis]>
propagation delays through gates are usually specified in hundreds or tens of picoseconds
<tpw_rules>
and attoseconds are too fine?
<whitequark[cis]>
so if we go 1000x finer than that, we should be able to represent just about any time quantity in semiconductors we want
<whitequark[cis]>
they're not too fine strictly speaking
<tpw_rules>
fair enough
<whitequark[cis]>
but INT64_MAX of femtoseconds is still a reasonable amount
<whitequark[cis]>
and INT64_MAX of attoseconds is too little
<tpw_rules>
thank you
<cr1901>
2^64 femtoseconds is 5 hours, for those curious
<cr1901>
2^64 attoseconds is 18 seconds. I have simulations lasting longer than that
<whitequark[cis]>
actually, CXXRTL uses a 128-bit number of femtoseconds to represent time
<whitequark[cis]>
because 153 minutes is still pretty low (hm, how come me and cr1901 get different numbers?)
<cr1901>
2^63
<cr1901>
vs 2^64
<zyp[m]>
if femtoseconds weren't already decided, I would have argued for ratios since most of the time you're just accumulating reciprocals of frequencies anyway
<whitequark[cis]>
oh yeah i was using INT64_MAX specifically
<whitequark[cis]>
zyp[m]: how are you going to manage that in cxxrtl?
<cr1901>
I almost started blaming Google's AI :P
<zyp[m]>
whitequark[cis]: I'm not, I don't find it worthwhile to try arguing to change it at this point
<cr1901>
If we go by the jt51 demo, cxxrtl is ~20% of realtime for a moderately complex circuit. I could see someone leave a cxxrtl test running overnight, so 64-bit fs isn't enough
<tpw_rules>
jt51 demo?
<whitequark[cis]>
zyp: it's not strictly speaking fixed, it's just that we need some representation that's reasonably easy to manipulate in C++ and to have in FFI
<cr1901>
I _might_ have added every single process with add_process instead of add_testbench
<cr1901>
by accident
<cr1901>
When I swap to add_testbench, as I intended, all the sims fail and I have to adjust for the new behavior of "yield foo.eq(bar) takes place immediately"
<cr1901>
which is today's task
<cr1901>
(might not be all sims that fail, but there's definitely failures now)
<zyp[m]>
<whitequark[cis]> "zyp: it's not strictly speaking..." <- a ratio is just a `num`, `den` tuple, and I figure it wouldn't be about how easy it was to represent, but how easy it is to make it performant -- most of the time you could precalculate a common `den` as LCD of all the clock periods, until you run into a testbench that does a delay with an indivisible duration and have to recalculate it…
<whitequark[cis]>
yes, exactly
<whitequark[cis]>
cxxrtl doesn't have the notion of a clock at all
<whitequark[cis]>
it deals with async signals, and it doesn't intrinsically know anything about time (or care)
<whitequark[cis]>
it does now have a cxxrtl_time but that's used for presentation; even the time travel debugging internally records time as a monotonically increasing step number
<zyp[m]>
and that's why cxxsim still generates clocks from python…
<whitequark[cis]>
hm, no
<whitequark[cis]>
the bigger issue with cxxsim is that there's no real c++/python interop layer
<whitequark[cis]>
namely, the asynchronous events aren't properly conveyed across the boundary. this is the same reason cxxsim is still not merged, as well
<whitequark[cis]>
iirc if clocks were generated in c++ (like if i generated a testbench by templating c++), then python processes wouldn't be properly triggered
<whitequark[cis]>
of course i also simply do not want to generate c++ by templating it, but that's a secondary problem
<whitequark[cis]>
and the reason there's no real c++/python interop layer is that, until recently, i actually did not fully comprehend the complex async simulation model that arises from the way cxxrtl is designed
<whitequark[cis]>
so i bumped into the limits of my understanding and couldn't progress. it took a few years to form a solid theoretical basis for further work
<zyp[m]>
<whitequark[cis]> "or perhaps `Period" <- so you could do both e.g. `Period.ns(10)` and `Period.mhz(100)`?
<whitequark[cis]>
that sounds sensible
<zyp[m]>
I don't think a separate Frequency type would be overly useful, since it'd pretty much exclusively be used to take the reciprocal to get a Period anyway
<whitequark[cis]>
i think Period.MHz might be better
<whitequark[cis]>
since mhz could be megahertz or millihertz
<zyp[m]>
yes, I expected that bikeshed
<whitequark[cis]>
but we also could decide that documentation exists and we don't care about millihertz
<whitequark[cis]>
(there's a subset of people who will care, but maybe they're not important)
<whitequark[cis]>
hey, I get to talk about the color of the bike shed after designing and shipping that nuclear power plant :p
<cr1901>
from packaging.requirements import Requirement")
<whitequark[cis]>
hm, interesting
<whitequark[cis]>
i would personally use importlib.metadata
<whitequark[cis]>
but this is also a legitimate way to do this
<whitequark[cis]>
(you may get different answers, because the installed package in your venv may not necessarily match pyproject.toml)
<whitequark[cis]>
and i guess if you use a git revision of amaranth that code will fail
<whitequark[cis]>
whereas importlib.metadata.version("amaranth") will succeed
<cr1901>
If the git revision is used, I assume it's latest
<cr1901>
(I'm assuming you're not gonna change "latest" in the URL for the latest docs :P)
<whitequark[cis]>
i don't plan to change that
<cr1901>
Excellent, I have RTD compat and amaranth docs compat. If it needs to be more complex, then maybe I'll make a small sphinx plugin. I can already see me forgetting to update intersphinx mappings
<cr1901>
(swapping between git amaranth for dev branch, and pypi amaranth for releases)
<zyp[m]>
Catherine: I started drafting the RFC and got to the point where I have to ask «should it have operators at all?» I figure `period ± period -> period`, `period * real -> period` and `period / period -> real` could make sense to have
<zyp[m]>
potentially also `period % period -> period`
<whitequark[cis]>
real?
<whitequark[cis]>
sorry, I mean, which Python type would that be?
<zyp[m]>
wasn't really what I planned on doing tonight, but I didn't manage to stop thinking about it after we discussed it, so I figured I might as well… was going to at some point anyway :)
<cr1901>
Do it while it's fresh in your head :D
<zyp[m]>
exactly
<zyp[m]>
I also took the liberty to name the SimulatorContext that I left unnamed in RFC #36, turns out that even if types aren't meant to be user instanceable, they get annoying to refer to without proper names
<zyp[m]>
* I also took the liberty to name the SimulatorContext that I left unnamed in RFC #36. Turns out that even if types aren't meant to be user instanceable, they get annoying to refer to without proper names
<Wanda[cis]>
zyp: I'd throw in `__truediv__` by a `Real`
<zyp[m]>
yeah, that's equivalent to the multiplication of the reciprocal so that makes sense