Skip to content

Conversation

@tdavidcl
Copy link
Member

No description provided.

@github-actions
Copy link

Thanks @tdavidcl for opening this PR!

You can do multiple things directly here:
1 - Comment pre-commit.ci run to run pre-commit checks.
2 - Comment pre-commit.ci autofix to apply fixes.
3 - Add label autofix.ci to fix authorship & pre-commit for every commit made.
4 - Add label light-ci to only trigger a reduced & faster version of the CI (need the full one before merge).
5 - Add label trigger-ci to create an empty commit to trigger the CI.

Once the workflow completes a message will appear displaying informations related to the run.

Also the PR gets automatically reviewed by gemini, you can:
1 - Comment /gemini review to trigger a review
2 - Comment /gemini summary for a summary
3 - Tag it using @gemini-code-assist either in the PR or in review comments on files

@gemini-code-assist
Copy link

Summary of Changes

Hello @tdavidcl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new documentation example that illustrates the technique of arbitrary function mapping, specifically using the inverse transform sampling method. The example demonstrates how to transform a set of uniformly distributed random points to follow the distribution of a user-defined symbolic function, involving steps like numerical integration, normalization, and interpolation for practical application.

Highlights

  • New Documentation Example: A new Python script, run_mapping.py, has been added to the doc/sphinx/examples/math directory.
  • Arbitrary Function Mapping: The example demonstrates how to map uniformly distributed random numbers to follow an arbitrary, user-defined function's distribution using the inverse transform sampling method.
  • Library Usage: It showcases the integration of sympy for symbolic function definition, numpy for numerical operations, scipy.interpolate for interpolation, and matplotlib for data visualization.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

Workflow report

workflow report corresponding to commit 51df445
Commiter email is timothee.davidcleris@proton.me

Light CI is enabled. This will only run the basic tests and not the full tests.
Merging a PR require the job "on PR / all" to pass which is disabled in this case.

Pre-commit check report

Some failures were detected in base source checks checks.
Check the On PR / Linting / Base source checks (pull_request) job in the tests for more detailled output

❌ ruff-check

�[1m�[91mNPY002 �[0m�[1mReplace legacy `np.random.seed` call with `np.random.Generator`�[0m
  �[1m�[94m-->�[0m doc/sphinx/examples/math/run_mapping.py:18:1
   �[1m�[94m|�[0m
�[1m�[94m17 |�[0m # random set of points between 0 and 1
�[1m�[94m18 |�[0m np.random.seed(111)
   �[1m�[94m|�[0m �[1m�[91m^^^^^^^^^^^^^^�[0m
�[1m�[94m19 |�[0m points = np.random.rand(1000)[:]
   �[1m�[94m|�[0m

�[1m�[91mNPY002 �[0m�[1mReplace legacy `np.random.rand` call with `np.random.Generator`�[0m
  �[1m�[94m-->�[0m doc/sphinx/examples/math/run_mapping.py:19:10
   �[1m�[94m|�[0m
�[1m�[94m17 |�[0m # random set of points between 0 and 1
�[1m�[94m18 |�[0m np.random.seed(111)
�[1m�[94m19 |�[0m points = np.random.rand(1000)[:]
   �[1m�[94m|�[0m          �[1m�[91m^^^^^^^^^^^^^^�[0m
�[1m�[94m20 |�[0m
�[1m�[94m21 |�[0m range_start = (0, 3)
   �[1m�[94m|�[0m

Found 3 errors (1 fixed, 2 remaining).

❌ end-of-file-fixer

Fixing doc/sphinx/examples/math/run_mapping.py

❌ black

�[1mreformatted doc/sphinx/examples/math/run_mapping.py�[0m

�[1mAll done! ✨ 🍰 ✨�[0m
�[34m�[1m1 file �[0m�[1mreformatted�[0m, �[34m147 files �[0mleft unchanged.

Suggested changes

Detailed changes :
diff --git a/doc/sphinx/examples/math/run_mapping.py b/doc/sphinx/examples/math/run_mapping.py
index 84f72429..7f3e730c 100644
--- a/doc/sphinx/examples/math/run_mapping.py
+++ b/doc/sphinx/examples/math/run_mapping.py
@@ -9,22 +9,21 @@ This example shows how to use the unit vector generator
 
 import matplotlib.pyplot as plt  # plots
 import numpy as np  # sqrt & arctan2
-
-import shamrock
 import sympy as sp
-from scipy.special import erfinv, erf
+from scipy.special import erf, erfinv
 
+import shamrock
 
-#random set of points between 0 and 1
+# random set of points between 0 and 1
 np.random.seed(111)
 points = np.random.rand(1000)[:]
 
-range_start = (0,3)
-range_end = (0,1) # must be between 0 and 1 because of the normalization
+range_start = (0, 3)
+range_end = (0, 1)  # must be between 0 and 1 because of the normalization
 
-#define the function exp(-x^2) using sympy
-x = sp.symbols('x')
-f = sp.Abs(sp.sin(-x**2))
+# define the function exp(-x^2) using sympy
+x = sp.symbols("x")
+f = sp.Abs(sp.sin(-(x**2)))
 
 # Numerical integration of f over range_start
 primitive = []
@@ -70,9 +69,10 @@ plt.xlabel("x")
 plt.ylabel("finv(x)")
 plt.title("finv(x) = inverse(primitive(x))")
 
-#interpolate primitive using scipy.interpolate.interp1d
+# interpolate primitive using scipy.interpolate.interp1d
 from scipy.interpolate import interp1d
-mapping_interp = interp1d(primitive, primitive_x, kind='linear')
+
+mapping_interp = interp1d(primitive, primitive_x, kind="linear")
 
 points_mapped = [mapping_interp(point) for point in points]
 
@@ -96,4 +96,4 @@ plt.plot(r, [f.subs(x, x_val).evalf() for x_val in r])
 plt.xlabel("$r$")
 plt.ylabel("$f(r)$")
 
-plt.show()
\ No newline at end of file
+plt.show()

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a new example script for performing arbitrary function mapping. The script has several issues, including incorrect documentation and comments, unused imports, and inefficient, non-idiomatic Python code. I've provided suggestions to correct the documentation, clean up the code, and improve performance and readability by using more appropriate functions from numpy and scipy.

Comment on lines +2 to +5
Shamrock 3D unit vector generator
=======================================

This example shows how to use the unit vector generator

Choose a reason for hiding this comment

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

high

The docstring appears to be copied from another example and is not relevant to this script. It describes a "3D unit vector generator," whereas this example demonstrates arbitrary function mapping. Updating the docstring will make the example's purpose clear to users.

Shamrock arbitrary function mapping
===================================

This example shows how to map a set of uniformly distributed random points
to a distribution following an arbitrary function.

range_start = (0,3)
range_end = (0,1) # must be between 0 and 1 because of the normalization

#define the function exp(-x^2) using sympy

Choose a reason for hiding this comment

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

high

The comment incorrectly describes the function as exp(-x^2). The actual function being defined is |sin(-x^2)|. This should be corrected to avoid confusion.

# define the function f(x) = |sin(-x^2)| using sympy

Comment on lines +29 to +40
# Numerical integration of f over range_start
primitive = []
primitive_x = []
accum = 0
dx = (range_start[1] - range_start[0]) / 100
for x_val in np.linspace(range_start[0], range_start[1], 100):
primitive.append(accum)
primitive_x.append(x_val)
accum += f.subs(x, x_val).evalf() * dx

primitive = np.array(primitive)
primitive_x = np.array(primitive_x)

Choose a reason for hiding this comment

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

high

The numerical integration is implemented with a Python for loop, which is inefficient and less accurate than available library functions. Using sympy.lambdify for faster function evaluation and scipy.integrate.cumulative_trapezoid for integration will make the code more performant, idiomatic, and accurate. Also, the dx calculation is slightly off for the number of points generated by linspace.

# Lambdify the sympy function for faster evaluation with numpy
f_numpy = sp.lambdify(x, f, 'numpy')

# Numerical integration of f over range_start
# Use more points for a better approximation of the integral
num_points = 1001
primitive_x = np.linspace(range_start[0], range_start[1], num_points)
f_vals = f_numpy(primitive_x)
primitive = cumulative_trapezoid(f_vals, primitive_x, initial=0)

Comment on lines +53 to +57
f_plot = [f.subs(x, x_val).evalf() for x_val in x_plot]
plt.plot(x_plot, f_plot)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.title("f(x) = exp(-x^2)")

Choose a reason for hiding this comment

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

high

The plot title is incorrect and evaluation of the function inside a list comprehension is inefficient. The title should reflect the actual function being plotted, |sin(-x^2)|. For performance, it's better to evaluate the function on the whole x_plot array at once, especially after lambdifying the sympy expression.

f_plot = f_numpy(x_plot)
plt.plot(x_plot, f_plot)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.title("f(x) = |sin(-x^2)|")

from scipy.interpolate import interp1d
mapping_interp = interp1d(primitive, primitive_x, kind='linear')

points_mapped = [mapping_interp(point) for point in points]

Choose a reason for hiding this comment

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

high

Using a list comprehension here is inefficient. The interp1d object can directly accept a NumPy array, which is much faster. Vectorizing this operation is more idiomatic and performant.

points_mapped = mapping_interp(points)

Comment on lines +13 to +15
import shamrock
import sympy as sp
from scipy.special import erfinv, erf

Choose a reason for hiding this comment

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

medium

The modules shamrock, erfinv, and erf are imported but are not used anywhere in the script. It's good practice to remove unused imports to keep the code clean and avoid confusion.

import sympy as sp

Comment on lines +47 to +48
print(f"primitive = {primitive}")
print(f"primitive_x = {primitive_x}")

Choose a reason for hiding this comment

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

medium

These print statements output large arrays to the console, which is generally not desired in gallery examples. Consider removing them to keep the output clean.

plt.title("finv(x) = inverse(primitive(x))")

#interpolate primitive using scipy.interpolate.interp1d
from scipy.interpolate import interp1d

Choose a reason for hiding this comment

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

medium

Imports should be placed at the top of the file, following PEP 8 conventions. This makes it easier to see all dependencies at a glance. Please move this import to the top with the others.

Comment on lines +79 to +80
print(f"points = {points}")
print(f"points_mapped = {points_mapped}")

Choose a reason for hiding this comment

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

medium

These print statements output large arrays to the console. For a gallery example, this is usually not necessary and clutters the output. It's better to remove them.


plt.figure()
hist_r, bins_r = np.histogram(points, bins=101, density=True, range=range_end)
r = np.linspace(bins_r[0], bins_r[-1], 101)

Choose a reason for hiding this comment

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

medium

The variable r is defined here but it is not used in the subsequent plotting code for the first histogram. It should be removed to avoid confusion.

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.

1 participant