MilesCranmer commited on
Commit
7d62807
2 Parent(s): a5e5da1 197cf0a

Merge pull request #205 from MilesCranmer/version-check-2

Browse files

Faster evaluation & perform explicit version assertion for backend

Files changed (3) hide show
  1. pysr/julia_helpers.py +59 -12
  2. pysr/sr.py +15 -23
  3. pysr/version.py +2 -2
pysr/julia_helpers.py CHANGED
@@ -4,6 +4,7 @@ import subprocess
4
  import warnings
5
  from pathlib import Path
6
  import os
 
7
 
8
  from .version import __version__, __symbolic_regression_jl_version__
9
 
@@ -70,7 +71,7 @@ def install(julia_project=None, quiet=False): # pragma: no cover
70
  """
71
  import julia
72
 
73
- _version_assertion()
74
  # Set JULIA_PROJECT so that we install in the pysr environment
75
  processed_julia_project, is_shared = _process_julia_project(julia_project)
76
  _set_julia_project_env(processed_julia_project, is_shared)
@@ -93,19 +94,15 @@ def install(julia_project=None, quiet=False): # pragma: no cover
93
  )
94
 
95
 
96
- def _import_error_string(julia_project=None):
97
- s = """
 
98
  Required dependencies are not installed or built. Run the following code in the Python REPL:
99
 
100
  >>> import pysr
101
  >>> pysr.install()
102
  """
103
-
104
- if julia_project is not None:
105
- s += f"""
106
- Tried to activate project {julia_project} but failed."""
107
-
108
- return s
109
 
110
 
111
  def _process_julia_project(julia_project):
@@ -157,7 +154,7 @@ def init_julia(julia_project=None, quiet=False):
157
 
158
  from julia.core import JuliaInfo, UnsupportedPythonError
159
 
160
- _version_assertion()
161
  processed_julia_project, is_shared = _process_julia_project(julia_project)
162
  _set_julia_project_env(processed_julia_project, is_shared)
163
 
@@ -170,7 +167,7 @@ def init_julia(julia_project=None, quiet=False):
170
  )
171
 
172
  if not info.is_pycall_built():
173
- raise ImportError(_import_error_string())
174
 
175
  Main = None
176
  try:
@@ -224,9 +221,59 @@ def _escape_filename(filename):
224
  return str_repr
225
 
226
 
227
- def _version_assertion():
228
  if not is_julia_version_greater_eq(version=(1, 6, 0)):
229
  raise NotImplementedError(
230
  "PySR requires Julia 1.6.0 or greater. "
231
  "Please update your Julia installation."
232
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import warnings
5
  from pathlib import Path
6
  import os
7
+ from julia.api import JuliaError
8
 
9
  from .version import __version__, __symbolic_regression_jl_version__
10
 
 
71
  """
72
  import julia
73
 
74
+ _julia_version_assertion()
75
  # Set JULIA_PROJECT so that we install in the pysr environment
76
  processed_julia_project, is_shared = _process_julia_project(julia_project)
77
  _set_julia_project_env(processed_julia_project, is_shared)
 
94
  )
95
 
96
 
97
+ def _import_error():
98
+ raise ImportError(
99
+ """
100
  Required dependencies are not installed or built. Run the following code in the Python REPL:
101
 
102
  >>> import pysr
103
  >>> pysr.install()
104
  """
105
+ )
 
 
 
 
 
106
 
107
 
108
  def _process_julia_project(julia_project):
 
154
 
155
  from julia.core import JuliaInfo, UnsupportedPythonError
156
 
157
+ _julia_version_assertion()
158
  processed_julia_project, is_shared = _process_julia_project(julia_project)
159
  _set_julia_project_env(processed_julia_project, is_shared)
160
 
 
167
  )
168
 
169
  if not info.is_pycall_built():
170
+ _import_error()
171
 
172
  Main = None
173
  try:
 
221
  return str_repr
222
 
223
 
224
+ def _julia_version_assertion():
225
  if not is_julia_version_greater_eq(version=(1, 6, 0)):
226
  raise NotImplementedError(
227
  "PySR requires Julia 1.6.0 or greater. "
228
  "Please update your Julia installation."
229
  )
230
+
231
+
232
+ def _backend_version_assertion(Main):
233
+ try:
234
+ backend_version = Main.eval("string(SymbolicRegression.PACKAGE_VERSION)")
235
+ expected_backend_version = __symbolic_regression_jl_version__
236
+ if backend_version != expected_backend_version: # pragma: no cover
237
+ warnings.warn(
238
+ f"PySR backend (SymbolicRegression.jl) version {backend_version} "
239
+ "does not match expected version {expected_backend_version}. "
240
+ "Things may break. "
241
+ "Please update your PySR installation with "
242
+ "`python -c 'import pysr; pysr.install()'`."
243
+ )
244
+ except JuliaError: # pragma: no cover
245
+ warnings.warn(
246
+ "You seem to have an outdated version of SymbolicRegression.jl. "
247
+ "Things may break. "
248
+ "Please update your PySR installation with "
249
+ "`python -c 'import pysr; pysr.install()'`."
250
+ )
251
+
252
+
253
+ def _load_cluster_manager(Main, cluster_manager):
254
+ Main.eval(f"import ClusterManagers: addprocs_{cluster_manager}")
255
+ return Main.eval(f"addprocs_{cluster_manager}")
256
+
257
+
258
+ def _update_julia_project(Main, is_shared, io_arg):
259
+ try:
260
+ if is_shared:
261
+ _add_sr_to_julia_project(Main, io_arg)
262
+ Main.eval(f"Pkg.resolve({io_arg})")
263
+ except (JuliaError, RuntimeError) as e:
264
+ raise ImportError(_import_error()) from e
265
+
266
+
267
+ def _load_backend(Main):
268
+ try:
269
+ # Load namespace, so that various internal operators work:
270
+ Main.eval("using SymbolicRegression")
271
+ except (JuliaError, RuntimeError) as e:
272
+ raise ImportError(_import_error()) from e
273
+
274
+ _backend_version_assertion(Main)
275
+
276
+ # Load Julia package SymbolicRegression.jl
277
+ from julia import SymbolicRegression
278
+
279
+ return SymbolicRegression
pysr/sr.py CHANGED
@@ -26,8 +26,9 @@ from .julia_helpers import (
26
  _process_julia_project,
27
  is_julia_version_greater_eq,
28
  _escape_filename,
29
- _add_sr_to_julia_project,
30
- _import_error_string,
 
31
  )
32
  from .export_numpy import CallableEquation
33
  from .export_latex import generate_single_table, generate_multiple_tables, to_latex
@@ -1453,8 +1454,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1453
  Main = init_julia(self.julia_project)
1454
 
1455
  if cluster_manager is not None:
1456
- Main.eval(f"import ClusterManagers: addprocs_{cluster_manager}")
1457
- cluster_manager = Main.eval(f"addprocs_{cluster_manager}")
1458
 
1459
  if not already_ran:
1460
  julia_project, is_shared = _process_julia_project(self.julia_project)
@@ -1467,25 +1467,17 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1467
  Main.eval(
1468
  f'Pkg.activate("{_escape_filename(julia_project)}", shared = Bool({int(is_shared)}), {io_arg})'
1469
  )
1470
- from julia.api import JuliaError
1471
 
1472
  if self.update:
1473
- try:
1474
- if is_shared:
1475
- _add_sr_to_julia_project(Main, io_arg)
1476
- Main.eval(f"Pkg.resolve({io_arg})")
1477
- except (JuliaError, RuntimeError) as e:
1478
- raise ImportError(_import_error_string(julia_project)) from e
1479
- try:
1480
- Main.eval("using SymbolicRegression")
1481
- except (JuliaError, RuntimeError) as e:
1482
- raise ImportError(_import_error_string(julia_project)) from e
1483
-
1484
- Main.plus = Main.eval("(+)")
1485
- Main.sub = Main.eval("(-)")
1486
- Main.mult = Main.eval("(*)")
1487
- Main.pow = Main.eval("(^)")
1488
- Main.div = Main.eval("(/)")
1489
 
1490
  # TODO(mcranmer): These functions should be part of this class.
1491
  binary_operators, unary_operators = _maybe_create_inline_operators(
@@ -1542,7 +1534,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1542
 
1543
  # Call to Julia backend.
1544
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
1545
- options = Main.Options(
1546
  binary_operators=Main.eval(str(tuple(binary_operators)).replace("'", "")),
1547
  unary_operators=Main.eval(str(tuple(unary_operators)).replace("'", "")),
1548
  bin_constraints=bin_constraints,
@@ -1615,7 +1607,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1615
 
1616
  # Call to Julia backend.
1617
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/SymbolicRegression.jl
1618
- self.raw_julia_state_ = Main.EquationSearch(
1619
  Main.X,
1620
  Main.y,
1621
  weights=Main.weights,
 
26
  _process_julia_project,
27
  is_julia_version_greater_eq,
28
  _escape_filename,
29
+ _load_cluster_manager,
30
+ _update_julia_project,
31
+ _load_backend,
32
  )
33
  from .export_numpy import CallableEquation
34
  from .export_latex import generate_single_table, generate_multiple_tables, to_latex
 
1454
  Main = init_julia(self.julia_project)
1455
 
1456
  if cluster_manager is not None:
1457
+ cluster_manager = _load_cluster_manager(cluster_manager)
 
1458
 
1459
  if not already_ran:
1460
  julia_project, is_shared = _process_julia_project(self.julia_project)
 
1467
  Main.eval(
1468
  f'Pkg.activate("{_escape_filename(julia_project)}", shared = Bool({int(is_shared)}), {io_arg})'
1469
  )
 
1470
 
1471
  if self.update:
1472
+ _update_julia_project(Main, is_shared, io_arg)
1473
+
1474
+ SymbolicRegression = _load_backend(Main)
1475
+
1476
+ Main.plus = Main.eval("(+)")
1477
+ Main.sub = Main.eval("(-)")
1478
+ Main.mult = Main.eval("(*)")
1479
+ Main.pow = Main.eval("(^)")
1480
+ Main.div = Main.eval("(/)")
 
 
 
 
 
 
 
1481
 
1482
  # TODO(mcranmer): These functions should be part of this class.
1483
  binary_operators, unary_operators = _maybe_create_inline_operators(
 
1534
 
1535
  # Call to Julia backend.
1536
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
1537
+ options = SymbolicRegression.Options(
1538
  binary_operators=Main.eval(str(tuple(binary_operators)).replace("'", "")),
1539
  unary_operators=Main.eval(str(tuple(unary_operators)).replace("'", "")),
1540
  bin_constraints=bin_constraints,
 
1607
 
1608
  # Call to Julia backend.
1609
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/SymbolicRegression.jl
1610
+ self.raw_julia_state_ = SymbolicRegression.EquationSearch(
1611
  Main.X,
1612
  Main.y,
1613
  weights=Main.weights,
pysr/version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.11.4"
2
- __symbolic_regression_jl_version__ = "0.12.2"
 
1
+ __version__ = "0.11.5"
2
+ __symbolic_regression_jl_version__ = "0.12.6"