-
Notifications
You must be signed in to change notification settings - Fork 15
perf: batch array-valued distribution parameters into a single fill #171
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
vchamarthi
wants to merge
4
commits into
IntelPython:master
Choose a base branch
from
vchamarthi:perf/array-param-batched-fill
base: master
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.
+325
−18
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
fc22a8b
perf: batch array-valued parameters into a single fill
vchamarthi c4e70de
fix review comments
vchamarthi d34296b
Merge remote-tracking branch 'upstream/master' into perf/array-param-…
vchamarthi 2b71b91
fix pr comments and suggestions
vchamarthi 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
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 |
|---|---|---|
|
|
@@ -762,6 +762,150 @@ cdef object vec_cont2_array( | |
| return arr_obj | ||
|
|
||
|
|
||
| cdef object _param_out_shape(object size, tuple param_shapes): | ||
|
Collaborator
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. It is stricter than the legacy check. This matches NumPy's own semantics and is one-directional (no previously-invalid call now passes). It's arguably a fix, but it's an acceptance-behavior change worth a changelog line. |
||
| """Result shape for a parameterised draw, matching the per-element paths.""" | ||
| cdef object out_shape | ||
| cdef object bshape | ||
|
|
||
| if size is None: | ||
| return np.broadcast_shapes(*param_shapes) | ||
|
|
||
| out_shape = tuple(size) if np.iterable(size) else (size,) | ||
| try: | ||
| bshape = np.broadcast_shapes(out_shape, *param_shapes) | ||
| except ValueError: | ||
| raise ValueError("size is not compatible with inputs") | ||
| if bshape != out_shape: | ||
| raise ValueError("size is not compatible with inputs") | ||
| return out_shape | ||
|
|
||
|
|
||
| cdef object _fill_standard2( | ||
| irk_state *state, | ||
| irk_cont2_vec func, | ||
| object out_shape, | ||
| object lock | ||
| ): | ||
| """Fill an entire request with one call, using standard parameters.""" | ||
| cdef cnp.ndarray array | ||
| cdef cnp.npy_intp n | ||
| cdef double *array_data | ||
|
|
||
| array = <cnp.ndarray>np.empty(out_shape, np.float64) | ||
| n = cnp.PyArray_SIZE(array) | ||
| if n: | ||
| array_data = <double *>cnp.PyArray_DATA(array) | ||
| with lock, nogil: | ||
| func(state, n, array_data, 0.0, 1.0) | ||
| return array | ||
|
|
||
|
|
||
| cdef object vec_loc_scale_array( | ||
|
vchamarthi marked this conversation as resolved.
|
||
| irk_state *state, | ||
| irk_cont2_vec func, | ||
| object size, | ||
| cnp.ndarray oloc, | ||
| cnp.ndarray oscale, | ||
| object lock | ||
| ): | ||
| """Draw a location and scale family with array-valued parameters. | ||
|
|
||
| ``func(0.0, 1.0)`` yields the standardised member, so | ||
| ``loc + scale * standardised`` is exact and needs one call per request. | ||
| """ | ||
| cdef object array | ||
|
|
||
| array = _fill_standard2( | ||
| state, | ||
| func, | ||
| _param_out_shape( | ||
| size, ((<object>oloc).shape, (<object>oscale).shape) | ||
| ), | ||
| lock | ||
| ) | ||
| np.multiply(array, oscale, out=array) | ||
| np.add(array, oloc, out=array) | ||
| return array | ||
|
|
||
|
|
||
| cdef object vec_scale_array( | ||
|
vchamarthi marked this conversation as resolved.
|
||
| irk_state *state, | ||
| irk_cont1_vec func, | ||
| object size, | ||
| cnp.ndarray oscale, | ||
| object lock | ||
| ): | ||
| """Draw a scale family with an array-valued scale, one call per request.""" | ||
| cdef cnp.ndarray array | ||
| cdef cnp.npy_intp n | ||
| cdef double *array_data | ||
|
|
||
| array = <cnp.ndarray>np.empty( | ||
| _param_out_shape(size, ((<object>oscale).shape,)), np.float64 | ||
| ) | ||
| n = cnp.PyArray_SIZE(array) | ||
| if n: | ||
| array_data = <double *>cnp.PyArray_DATA(array) | ||
| with lock, nogil: | ||
| func(state, n, array_data, 1.0) | ||
| np.multiply(array, oscale, out=array) | ||
| return array | ||
|
|
||
|
|
||
| cdef object vec_uniform_array( | ||
| irk_state *state, | ||
| irk_cont2_vec func, | ||
| object size, | ||
| cnp.ndarray olow, | ||
| cnp.ndarray ohigh, | ||
| object lock | ||
| ): | ||
| """Draw uniforms over array-valued bounds, one call per request.""" | ||
| cdef object array | ||
|
|
||
| array = _fill_standard2( | ||
| state, | ||
| func, | ||
| _param_out_shape( | ||
| size, ((<object>olow).shape, (<object>ohigh).shape) | ||
| ), | ||
| lock | ||
| ) | ||
| np.multiply(array, np.subtract(ohigh, olow), out=array) | ||
| np.add(array, olow, out=array) | ||
| return array | ||
|
|
||
|
|
||
| cdef object vec_lognormal_array( | ||
| irk_state *state, | ||
| irk_cont2_vec normal_func, | ||
| object size, | ||
| cnp.ndarray omean, | ||
| cnp.ndarray osigma, | ||
| object lock | ||
| ): | ||
| """Draw lognormals with array-valued parameters, one call per request. | ||
|
|
||
| Uses the normal fill: the parameters sit inside the exponential, so no | ||
| affine step applies to a standardised lognormal, | ||
| but exp(mean + sigma * z) does. | ||
| """ | ||
| cdef object array | ||
|
|
||
| array = _fill_standard2( | ||
| state, | ||
| normal_func, | ||
| _param_out_shape( | ||
| size, ((<object>omean).shape, (<object>osigma).shape) | ||
| ), | ||
| lock | ||
| ) | ||
| np.multiply(array, osigma, out=array) | ||
| np.add(array, omean, out=array) | ||
| np.exp(array, out=array) | ||
| return array | ||
|
|
||
|
|
||
| cdef object vec_cont3_array_sc( | ||
| irk_state *state, | ||
| irk_cont3_vec func, | ||
|
|
@@ -2697,16 +2841,19 @@ cdef class _MKLRandomState: | |
| Samples are uniformly distributed over the half-open interval | ||
| ``[low, high)`` (includes low, but excludes high). In other words, | ||
| any value within the given interval is equally likely to be drawn | ||
| by `uniform`. | ||
| by `uniform`. With array-valued bounds, floating-point rounding | ||
| may include the upper boundary in the returned samples. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| low : float, optional | ||
| Lower boundary of the output interval. All values generated will be | ||
| greater than or equal to low. The default value is 0. | ||
| high : float | ||
| Upper boundary of the output interval. All values generated will be | ||
| less than high. The default value is 1.0. | ||
| Upper boundary of the output interval. With array-valued bounds, | ||
| high may be included due to floating-point rounding in | ||
| ``low + (high - low) * U``, where ``U`` is drawn from ``[0, 1)``. | ||
| The default value is 1.0. | ||
| size : int or tuple of ints, optional | ||
| Output shape. If the given shape is, e.g., ``(m, n, k)``, then | ||
| ``m * n * k`` samples are drawn. Default is None, in which case a | ||
|
|
@@ -2791,7 +2938,7 @@ cdef class _MKLRandomState: | |
| if np.any(olow >= ohigh): | ||
| raise ValueError("low >= high") | ||
|
|
||
| return vec_cont2_array( | ||
| return vec_uniform_array( | ||
| self.internal_state, irk_uniform_vec, size, olow, ohigh, self.lock | ||
| ) | ||
|
|
||
|
|
@@ -3193,23 +3340,23 @@ cdef class _MKLRandomState: | |
| method, [ICDF, BOXMULLER, BOXMULLER2], _method_alias_dict_gaussian | ||
| ) | ||
| if method is ICDF: | ||
| return vec_cont2_array( | ||
| return vec_loc_scale_array( | ||
| self.internal_state, | ||
| irk_normal_vec_ICDF, | ||
| size, | ||
| oloc, | ||
| oscale, self.lock | ||
| ) | ||
| elif method is BOXMULLER2: | ||
| return vec_cont2_array( | ||
| return vec_loc_scale_array( | ||
| self.internal_state, | ||
| irk_normal_vec_BM2, | ||
| size, | ||
| oloc, | ||
| oscale, self.lock | ||
| ) | ||
| else: | ||
| return vec_cont2_array( | ||
| return vec_loc_scale_array( | ||
| self.internal_state, | ||
| irk_normal_vec_BM1, | ||
| size, | ||
|
|
@@ -3348,7 +3495,7 @@ cdef class _MKLRandomState: | |
|
|
||
| if np.any(np.signbit(oscale) | (oscale == 0)): | ||
| raise ValueError("scale <= 0") | ||
| return vec_cont1_array( | ||
| return vec_scale_array( | ||
| self.internal_state, irk_exponential_vec, size, oscale, self.lock | ||
| ) | ||
|
|
||
|
|
@@ -4793,8 +4940,9 @@ cdef class _MKLRandomState: | |
|
|
||
| if np.any(np.signbit(oscale) | np.equal(oscale, 0.0)): | ||
| raise ValueError("scale <= 0") | ||
| return vec_cont2_array( | ||
| self.internal_state, irk_laplace_vec, size, oloc, oscale, self.lock | ||
| return vec_loc_scale_array( | ||
| self.internal_state, irk_laplace_vec, size, oloc, oscale, | ||
| self.lock | ||
| ) | ||
|
|
||
| def gumbel(self, loc=0.0, scale=1.0, size=None): | ||
|
|
@@ -4933,8 +5081,9 @@ cdef class _MKLRandomState: | |
|
|
||
| if np.any(np.signbit(oscale) | np.equal(oscale, 0.0)): | ||
| raise ValueError("scale <= 0") | ||
| return vec_cont2_array( | ||
| self.internal_state, irk_gumbel_vec, size, oloc, oscale, self.lock | ||
| return vec_loc_scale_array( | ||
| self.internal_state, irk_gumbel_vec, size, oloc, oscale, | ||
| self.lock | ||
| ) | ||
|
|
||
| def logistic(self, loc=0.0, scale=1.0, size=None): | ||
|
|
@@ -5034,7 +5183,7 @@ cdef class _MKLRandomState: | |
|
|
||
| if np.any(np.signbit(oscale) | np.equal(oscale, 0.0)): | ||
| raise ValueError("scale <= 0") | ||
| return vec_cont2_array( | ||
| return vec_loc_scale_array( | ||
| self.internal_state, | ||
| irk_logistic_vec, | ||
| size, | ||
|
|
@@ -5195,18 +5344,18 @@ cdef class _MKLRandomState: | |
| method, [ICDF, BOXMULLER], _method_alias_dict_gaussian_short | ||
| ) | ||
| if method is ICDF: | ||
| return vec_cont2_array( | ||
| return vec_lognormal_array( | ||
| self.internal_state, | ||
| irk_lognormal_vec_ICDF, | ||
| irk_normal_vec_ICDF, | ||
| size, | ||
| omean, | ||
| osigma, | ||
| self.lock | ||
| ) | ||
| else: | ||
| return vec_cont2_array( | ||
| return vec_lognormal_array( | ||
| self.internal_state, | ||
| irk_lognormal_vec_BM, | ||
| irk_normal_vec_BM2, | ||
| size, | ||
| omean, | ||
| osigma, | ||
|
|
@@ -5288,7 +5437,7 @@ cdef class _MKLRandomState: | |
|
|
||
| if np.any(np.signbit(oscale) | np.equal(oscale, 0.0)): | ||
| raise ValueError("scale <= 0.0") | ||
| return vec_cont1_array( | ||
| return vec_scale_array( | ||
| self.internal_state, irk_rayleigh_vec, size, oscale, self.lock | ||
| ) | ||
|
|
||
|
|
||
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.