-
Notifications
You must be signed in to change notification settings - Fork 928
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
model: Ensure the seed is initialized with current timestamp when it is None #1814
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #1814 +/- ##
==========================================
- Coverage 81.36% 81.29% -0.08%
==========================================
Files 15 15
Lines 891 893 +2
Branches 191 170 -21
==========================================
+ Hits 725 726 +1
- Misses 142 143 +1
Partials 24 24
☔ View full report in Codecov by Sentry. |
mesa/model.py
Outdated
obj._seed = kwargs.get("seed", None) | ||
obj._seed = kwargs.get("seed") | ||
if obj._seed is None: | ||
# See https://docs.python.org/3/library/random.html#random.seed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is not 100% accurate, but I think it can be removed completely anyway. I don't think the rational is important here (it should go into the commit message if you want to preserve it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make it more concise. But I think a new rule of thumb is that if ChatGPT can't deduce the purpose of the code that matches this comment, then the comment is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, having to view the blame for a small helpful comment is inconvenient.
mesa/model.py
Outdated
# datetime.now().timestamp() is more cross-platform than using | ||
# time.time(), and guarantees that the precision is to the | ||
# microsecond. | ||
current_timestamp = datetime.datetime.now(datetime.timezone.utc).timestamp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why we need that additional precision here - time.time seems to be simpler and should in any case be sufficient for just having a known seed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well at the beginning of https://docs.python.org/3/library/time.html#module-time it says that time() will always return the most accurate time available. There is simply no logical way for datetime to achieve a higher precision. This might have been different in the past, the answer is from 2014
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The answer is from 2014, but that comment is from 2023.
From https://docs.python.org/3/library/time.html#time.time
Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but if the operating system doesn't provide a better accuracy, how should datetime have a higher precision?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you assume that the OS can't provide higher precision with datetime.now()
? It's just that time.time()
and datetime.now()
may output different precision, depending on the system. Don't just conclude on your own whim that your assumption of the inner workings of time.time()
and datetime.now()
were correct in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I worked a lot with datetimes and once with an embedded system that had no subsecond precision. Not at the same time, but I think it's fine to say my understanding is a bit more than a "whim". Plus,as I quoted, it says in front of the time docs that time() uses the best precision available.
But I definitely agree that we can quit this conversation now. I just wanted to help you understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.python.org/3/library/datetime.html#datetime.datetime.now
If optional argument tz is None or not specified, this is like today(), but, if possible, supplies more precision than can be gotten from going through a time.time() timestamp (for example, this may be possible on platforms supplying the C gettimeofday() function).
Is this not clear enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with moving on. I didn't see your last message before my comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let's talk considerately to each other. I am going to resolve this conversation
I approved, but added 2 comments. That should mean you can make suggested or leave it as is if you strongly disagree. Its not important. I haven't merged yet, because I don't know if this should go into the 2.1.2. release (which would need to be updated - might be easier to merge later) |
mesa/model.py
Outdated
if obj._seed is None: | ||
# We explicitly specify the seed here so that we know its value in | ||
# advance. This value matches random.Random's default seed, which | ||
# is the current timestamp. Note: datetime.now().timestamp() is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It usually isn't the default seed.
If a is omitted or None, the current system time is used. If randomness sources are provided by the operating system, they are used instead of the system time (see the os.urandom() function for details on availability).
Its hard to find a OS without a randomness source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed the statement that it the timestamp is CPython's default. This is how they do it: https://github.com/python/cpython/blob/d4cea794a7b9b745817d2bd982d35412aef04710/Modules/_randommodule.c#L283. There is a PyObject interface to it, but it is a non-public module, _random.Random
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
os.urandom()
is a cryptographically secure pseudorandom number generator, and is safer in any cases. Overkill for a simulation, but maybe I could replace the timestamp with os.urandom(624)
instead. Do you agree with os.urandom
?
The number 624 is taken from its use in https://github.com/python/cpython/blob/d4cea794a7b9b745817d2bd982d35412aef04710/Modules/_randommodule.c#L250.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say simply random.random() would be the appropriate choice. That also wouldn't require any comment, because the code itself would already "say": just use a random value. And that's what we want. If someone requires cryptographically secure seeds they can provide them. But I can't really imagine a use case for that.
f46f78c
to
0e68333
Compare
if obj._seed is None: | ||
# We explicitly specify the seed here so that we know its value in | ||
# advance. | ||
obj._seed = random.random() # noqa: S311 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to add the ignore, otherwise Ruff said
S311 Standard pseudo-random generators are not suitable for cryptographic purposes
This is a precursor to #1812, and is useful info for debugging purpose, because apparently there is no way to get a
random.Random()
object's seed once it is initialized. At best, you can have its state instead.