Skip to content
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

Add RandomNumberGenerator::rand_weighted method #88883

Merged
merged 1 commit into from
Mar 1, 2024

Conversation

joaoh82
Copy link
Contributor

@joaoh82 joaoh82 commented Feb 26, 2024

This is the implementation for Add a method to get a random element with weighted probability (similar to random.choices() in Python) as in this Proposal.

Usage

It was added to the core classes as part of the RandomNumberGenerator class, where you pass a PackedFloat32Array to it as the weights.

var rnd = RandomNumberGenerator.new()

var my_array = ["one", "two", "three, "four"]
var weights = PackedFloat32Array([0.5, 1, 1, 2])

# May prints one the four elements in `my_array`.
# It is more likely to print "four", and less likely to print "two".
print(my_array[rng.rand_weighted(weights)])

I also added a test to check if size of both arrays match.

@AThousandShips
Copy link
Member

You used a merge commit to update your branch, please use rebase in the future instead, see here

You also need to use force pushing to update your branch, with git push -f, all this is in the link above for the workflow :)

@joaoh82 joaoh82 force-pushed the add-weighted-random-method branch 2 times, most recently from 9dce2f1 to 5b73724 Compare February 27, 2024 06:45
@joaoh82 joaoh82 requested a review from a team as a code owner February 27, 2024 06:45
@Mickeon
Copy link
Contributor

Mickeon commented Feb 27, 2024

Worth considering whether or not the weights parameter could be a PackedFloat64Array or even PackedFloat32Array. If it needs to be a number I don't see why not to, at a glance. GDScript would also do the conversion from an Array implicitly if it can.

Second, perhaps the method should be called pick_weighted_randomto match pick_random.

And finally, the fact that there's no equivalent in the RandomNumberGenerator class means more "experienced" users can't use it, for predictable RNG with known seeds.

@joaoh82 joaoh82 force-pushed the add-weighted-random-method branch 2 times, most recently from c391b40 to 494a381 Compare February 27, 2024 12:12
@joaoh82
Copy link
Contributor Author

joaoh82 commented Feb 27, 2024

@Mickeon thanks for the review!

Worth considering whether or not the weights parameter could be a PackedFloat64Array or even PackedFloat32Array. If it needs to be a number I don't see why not to, at a glance. GDScript would also do the conversion from an Array implicitly if it can.

I can definitely make this change. Do you think it would perform better or not really?

Second, perhaps the method should be called pick_weighted_randomto match pick_random.

Makes sense. It would make it more straight forward to the developer I guess.

And finally, the fact that there's no equivalent in the RandomNumberGenerator class means more "experienced" users can't use it, for predictable RNG with known seeds.

Not really sure what you mean here. Can you clarify what would be the course of action here?

@Mickeon
Copy link
Contributor

Mickeon commented Feb 28, 2024

I can definitely make this change. Do you think it would perform better or not really?

The performance benefit would come from not having to check for the type of every element being a float, which is quite inefficient and rather silly because PackedFloat32Array would basically guarantee it.

Can you clarify what would be the course of action here?

Okay, so. RandomNumberGenerator is a class that can be used to hold self-sustaining random number generators that do not influence one another.
There is no pick_random in RandomNumberGenerator, but that is okay because it is very simple to recreate. For weighted randomness however, having it present in that class may actually be desirable. It is a more complex algorithm that may also require fine-grained control at times (think of roguelikes and random loot generation for example).

@joaoh82
Copy link
Contributor Author

joaoh82 commented Feb 28, 2024

@Mickeon I took the advice of @smix8 and moved the logic to the RandomNumberGenerator taking a single parameter with a PackedFloat32Array for the weights that returns the picked index. I think it more generic and can be used by anything really.

@joaoh82 joaoh82 force-pushed the add-weighted-random-method branch 2 times, most recently from 3ced89b to 4719652 Compare February 28, 2024 13:47
@AThousandShips AThousandShips removed request for a team February 28, 2024 14:27
@AThousandShips AThousandShips changed the title Add Array::weighted_random(Array weights) method Add RandomNumberGenerator::rand_weighted method Feb 28, 2024
core/math/random_number_generator.h Outdated Show resolved Hide resolved
core/math/random_pcg.h Outdated Show resolved Hide resolved
core/math/random_pcg.cpp Outdated Show resolved Hide resolved
doc/classes/RandomNumberGenerator.xml Outdated Show resolved Hide resolved
modules/mono/glue/runtime_interop.cpp Outdated Show resolved Hide resolved
@joaoh82 joaoh82 force-pushed the add-weighted-random-method branch 2 times, most recently from ae7346c to b9fee07 Compare February 28, 2024 15:25
Copy link
Member

@AThousandShips AThousandShips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to add some tests, but matches the code referenced in godotengine/godot-proposals#3948 (comment)

Looks good and makes sense, some further feedback from the core team would be good though

@Mickeon
Copy link
Contributor

Mickeon commented Feb 28, 2024

The opportunity to have this in core excites me because there may actually be a faster algorithm out there but its obscurity would mean a "common" developer using the engine may not implement it this way and benefit from it.

I've known about it for a while. If/when this PR is merged I'd love to take a stab at trying to implement it.

@AThousandShips
Copy link
Member

The specific implementation is just that, an implementation detail, so we're free to improve it in the future :)

@joaoh82
Copy link
Contributor Author

joaoh82 commented Feb 28, 2024

Absolutely. We can always iterate on it and improve it at any time.

doc/classes/RandomNumberGenerator.xml Outdated Show resolved Hide resolved
doc/classes/RandomNumberGenerator.xml Outdated Show resolved Hide resolved
@joaoh82 joaoh82 force-pushed the add-weighted-random-method branch 2 times, most recently from c7e4588 to 3b6c196 Compare February 29, 2024 06:39
@akien-mga
Copy link
Member

Could you squash the commits? See PR workflow for instructions.

And while doing it, please edit the commit message to match the title of this PR / the new implementation.

@joaoh82
Copy link
Contributor Author

joaoh82 commented Feb 29, 2024

all done! @akien-mga

@joaoh82
Copy link
Contributor Author

joaoh82 commented Mar 1, 2024

I was wondering if I should also add it to the C# API and added it to the Math namespace with the other random methods. @akien-mga @Mickeon @AThousandShips

@Mickeon
Copy link
Contributor

Mickeon commented Mar 1, 2024

It's no longer a requirement since it belongs to RandomNumberGenerator now, and it's how this method can be accessed in C#. I think the PR is completely fine as is.

@akien-mga akien-mga merged commit bd76372 into godotengine:master Mar 1, 2024
16 checks passed
@akien-mga
Copy link
Member

akien-mga commented Mar 1, 2024

Thanks! And congrats for your first merged Godot contribution 🎉

@joaoh82
Copy link
Contributor Author

joaoh82 commented Mar 1, 2024

Thanks for the help all!! Really happy to have contributed!

@luevano
Copy link
Contributor

luevano commented Mar 2, 2024

Hey, I'm looking through the code as I wanted to propose a change/addition related to this PR and the Array::pick_random and noticed the following:

RandomPCG::rand_weighted returns int but the value itself that it's returned (i) is defined as an int64_t.

Shouldn't it be int64_t RandomPCG::rand_weighted?

@guladam
Copy link

guladam commented Aug 22, 2024

Hey everyone,
This was a welcome addition to the core RNG functions in Godot.
I'm just wondering, is there any specific reason why this method is not available in the Global Scope?

@Mickeon
Copy link
Contributor

Mickeon commented Aug 22, 2024

Because (if I recall correctly) we agreed that when working with weighted randomness it would be much more beneficial to have more granular control over it, and RandomNumberGenerator allows this. Although, I don't believe there's much stopping this from being in the Global Scope, as well.

@joaoh82
Copy link
Contributor Author

joaoh82 commented Aug 22, 2024

yeah. what @Mickeon said.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a method to get a random element with weighted probability (similar to random.choices() in Python)
6 participants