-
Notifications
You must be signed in to change notification settings - Fork 7
Add docstrings to randomstart.py
#20
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
Open
nataliemes
wants to merge
5
commits into
gambitproject:main
Choose a base branch
from
nataliemes:docs/randomstart-docstrings
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4af5572
Add docstrings to randomstart.py
nataliemes 0f510fe
Update error-checking in roundArray()
nataliemes 0059b64
Update roundArray() docstring
nataliemes 2c34c6d
Fix scatter marker sizing
nataliemes 2699bfc
Update error-checking in plot_simplex()
nataliemes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,8 +7,8 @@ | |
| MAX_ACCURACY = 10_000_000 | ||
|
|
||
|
|
||
| # give random n-tuple uniformly from unit simplex | ||
| def randInSimplex(n, naive=False): | ||
| """Generate a random n-tuple uniformly distributed on the unit simplex.""" | ||
| x = [0.0] * n | ||
| if naive: # random numbers re-normalized | ||
| sum = 0 | ||
|
|
@@ -30,11 +30,21 @@ def randInSimplex(n, naive=False): | |
| return x | ||
|
|
||
|
|
||
| # round an array <x> of probabilities to fractions with | ||
| # denominator <accuracy> | ||
| def roundArray(x, accuracy=10000): | ||
| """ | ||
| Round each entry of an array of probabilities `x` | ||
| to the nearest multiple of 1 / `accuracy`. | ||
|
|
||
| The probabilities are multiplied by `accuracy`, then rounded down to their integer parts, | ||
| which will be the numerators, augmented by 1 in order of decreasing size of the remainders | ||
| (which are less than 1) until they sum to `accuracy`. | ||
|
|
||
| Example: accuracy=10, x=[0.18, .35, .47] becomes [2/10, 3/10, 5/10]. | ||
| """ | ||
| if not isinstance(accuracy, int): | ||
| raise TypeError(f"accuracy must be an integer, got {type(accuracy).__name__}") | ||
| if not 1 <= accuracy <= MAX_ACCURACY: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we also check that accuracy is an integer? Essential for this to work. |
||
| raise ValueError(f"accuracy must be between 1 and {MAX_ACCURACY}") | ||
| raise ValueError(f"accuracy must be between 1 and {MAX_ACCURACY}, got {accuracy}") | ||
|
|
||
| n = len(x) | ||
| sum = 0 | ||
|
|
@@ -57,22 +67,85 @@ def roundArray(x, accuracy=10000): | |
| return [fractions.Fraction(k, accuracy) for k in numerator] | ||
|
|
||
|
|
||
| # renormalize list x to sum to one | ||
| def renormalize(x): | ||
| """Rescale a list of numbers so that it sums to one.""" | ||
| s = sum(x) | ||
| if s == 0: | ||
| return x | ||
| return [k / s for k in x] | ||
|
|
||
|
|
||
| # map triple of unit triangle to pair in 2D | ||
| # with corners [0,0] [1,0] [0.5,sqrt(3)/2] | ||
| def maptotriangle(vec): | ||
| """Map a point on the unit triangle (3D) to 2D coordinates | ||
| in a triangle with corners at (0, 0), (1, 0), (0.5, sqrt(3)/2). | ||
| """ | ||
| x = vec[1] + 0.5 * vec[2] | ||
| y = 3 ** .5 / 2 * vec[2] | ||
| return x, y | ||
|
|
||
|
|
||
| def plot_simplex(numpoints=200, accuracy=20, higherdim=3, naiveplot=False): | ||
| """Generate a simplex sampling plot. | ||
|
|
||
| Samples `numpoints` random points from the simplex of dimension `higherdim` | ||
| and projects them onto a 2D triangle (if `higherdim` is greater than 3, | ||
| only the middle 3 components of each point are used, renormalized to sum to 1). | ||
| Plots the raw sampled points in green and their rounded approximations in red. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| numpoints : int | ||
| Number of points to plot. Default is 200. | ||
| accuracy : int | ||
| Denominator x; each coordinate is rounded to the nearest multiple of 1/x. | ||
| Default is 20. Must be between 1 and 10,000,000. | ||
| higherdim : int | ||
| Dimension from which the middle 3 components will be sampled. | ||
| Default is 3. Must be between 3 and 10. | ||
| naiveplot : bool | ||
| Sample naively by normalizing random uniforms (biased toward center). | ||
| Default is False. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If `accuracy` or `higherdim` is out of range. | ||
| """ | ||
| if not isinstance(higherdim, int): | ||
| raise TypeError(f"higherdim must be an integer, got {type(higherdim).__name__}") | ||
| if not 3 <= higherdim <= 10: | ||
| raise ValueError(f"higherdim must be between 3 and 10, got {higherdim}") | ||
| print( | ||
| f"numpoints={numpoints} accuracy={accuracy} higherdim={higherdim} naiveplot={naiveplot}" | ||
| ) | ||
| if higherdim > 3: | ||
| segmentstart = (higherdim - 2) // 2 | ||
| print("show positions", segmentstart, "..", | ||
| segmentstart + 2, "of 0 ..", higherdim - 1) | ||
| fig1, ax = plt.subplots() | ||
| ax.set_box_aspect(.866) | ||
| # plt.axis('square') | ||
| x1, y1 = maptotriangle([1, 0, 0]) | ||
| x2, y2 = maptotriangle([0, 1, 0]) | ||
| x3, y3 = maptotriangle([0, 0, 1]) | ||
| plt.plot([x1, x2, x3, x1], [y1, y2, y3, y1], "black") | ||
|
|
||
| roundedpoints = [] | ||
| for _ in range(numpoints): | ||
| point = randInSimplex(higherdim, naiveplot) | ||
| if higherdim > 3: | ||
| segmentstart = (higherdim - 2) // 2 | ||
| point = renormalize(point[segmentstart:segmentstart + 3]) | ||
| roundedpoints.append(roundArray(point, accuracy)) | ||
| x, y = maptotriangle(point) | ||
| plt.plot([x], [y], "g.") | ||
| for circ in roundedpoints: | ||
| x, y = maptotriangle(circ) | ||
| plt.scatter([x], [y], s=max(20, 10000 // accuracy), facecolors="none", | ||
| edgecolors="r") | ||
| plt.show() | ||
|
|
||
|
|
||
| @click.command( | ||
| context_settings={"help_option_names": ["-?", "-h", "--help"]}, | ||
| ) | ||
|
|
@@ -104,35 +177,12 @@ def maptotriangle(vec): | |
| help="Sample naively by normalizing random uniforms (biased toward center)", | ||
| ) | ||
| def main(numpoints, accuracy, higherdim, naiveplot): | ||
| print( | ||
| f"numpoints={numpoints} accuracy={accuracy} higherdim={higherdim} naiveplot={naiveplot}" | ||
| ) | ||
| if higherdim > 3: | ||
| segmentstart = (higherdim - 2) // 2 | ||
| print("show positions", segmentstart, "..", | ||
| segmentstart + 2, "of 0 ..", higherdim - 1) | ||
| fig1, ax = plt.subplots() | ||
| ax.set_box_aspect(.866) | ||
| # plt.axis('square') | ||
| x1, y1 = maptotriangle([1, 0, 0]) | ||
| x2, y2 = maptotriangle([0, 1, 0]) | ||
| x3, y3 = maptotriangle([0, 0, 1]) | ||
| plt.plot([x1, x2, x3, x1], [y1, y2, y3, y1], "black") | ||
| """Plot random points on the 2-simplex, rounded to rational coordinates. | ||
|
|
||
| roundedpoints = [] | ||
| for _ in range(numpoints): | ||
| point = randInSimplex(higherdim, naiveplot) | ||
| if higherdim > 3: | ||
| segmentstart = (higherdim - 2) // 2 | ||
| point = renormalize(point[segmentstart:segmentstart + 3]) | ||
| roundedpoints.append(roundArray(point, accuracy)) | ||
| x, y = maptotriangle(point) | ||
| plt.plot([x], [y], "g.") | ||
| for circ in roundedpoints: | ||
| x, y = maptotriangle(circ) | ||
| plt.scatter([x], [y], s=10000 // accuracy, facecolors="none", | ||
| edgecolors="r") | ||
| plt.show() | ||
| Green dots are the raw sampled points; | ||
| red circles are their rounded rational approximations. | ||
| """ | ||
| plot_simplex(numpoints, accuracy, higherdim, naiveplot) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
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.
after line 36 add:
The probabilities are multiplied by
accuracy, then rounded down to their integer parts,which will be the numerators, augmented by 1 in order of decreasing size of the remainders
(which are less than 1) until they sum to
accuracy.Example: accuracy=10, x = [0.18, .35, .47] becomes [2/10,3/10,5/10].