MilesCranmer commited on
Commit
68ea1be
1 Parent(s): b56466b

Start third attempt at porting to PythonCall

Browse files
Files changed (6) hide show
  1. juliapkg.json +13 -0
  2. pysr/__init__.py +1 -2
  3. pysr/julia_helpers.py +13 -320
  4. pysr/sr.py +23 -39
  5. pysr/version.py +1 -2
  6. requirements.txt +2 -1
juliapkg.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "julia": "1.6",
3
+ "packages": {
4
+ "SymbolicRegression": {
5
+ "uuid": "8254be44-1295-4e6a-a16d-46603ac705cb",
6
+ "version": "0.23.1"
7
+ },
8
+ "ClusterManagers": {
9
+ "uuid": "34f1f09b-3a8b-5176-ab39-66d58a4d544e",
10
+ "version": "0.4"
11
+ }
12
+ }
13
+ }
pysr/__init__.py CHANGED
@@ -12,8 +12,7 @@ from .deprecated import best, best_callable, best_row, best_tex, pysr
12
  from .export_jax import sympy2jax
13
  from .export_torch import sympy2torch
14
  from .feynman_problems import FeynmanProblem, Problem
15
- from .julia_helpers import install
16
- from .sr import PySRRegressor
17
  from .version import __version__
18
 
19
  __all__ = [
 
12
  from .export_jax import sympy2jax
13
  from .export_torch import sympy2torch
14
  from .feynman_problems import FeynmanProblem, Problem
15
+ from .sr import PySRRegressor, jl
 
16
  from .version import __version__
17
 
18
  __all__ = [
pysr/julia_helpers.py CHANGED
@@ -1,13 +1,10 @@
1
  """Functions for initializing the Julia environment and installing deps."""
2
- import os
3
- import subprocess
4
- import sys
5
  import warnings
6
- from pathlib import Path
7
 
8
- from julia.api import JuliaError
 
9
 
10
- from .version import __symbolic_regression_jl_version__, __version__
11
 
12
  juliainfo = None
13
  julia_initialized = False
@@ -15,270 +12,9 @@ julia_kwargs_at_initialization = None
15
  julia_activated_env = None
16
 
17
 
18
- def _load_juliainfo():
19
- """Execute julia.core.JuliaInfo.load(), and store as juliainfo."""
20
- global juliainfo
21
-
22
- if juliainfo is None:
23
- from julia.core import JuliaInfo
24
-
25
- try:
26
- juliainfo = JuliaInfo.load(julia="julia")
27
- except FileNotFoundError:
28
- env_path = os.environ["PATH"]
29
- raise FileNotFoundError(
30
- f"Julia is not installed in your PATH. Please install Julia and add it to your PATH.\n\nCurrent PATH: {env_path}",
31
- )
32
-
33
- return juliainfo
34
-
35
-
36
- def _get_julia_env_dir():
37
- # Have to manually get env dir:
38
- try:
39
- julia_env_dir_str = subprocess.run(
40
- ["julia", "-e using Pkg; print(Pkg.envdir())"],
41
- capture_output=True,
42
- env=os.environ,
43
- ).stdout.decode()
44
- except FileNotFoundError:
45
- env_path = os.environ["PATH"]
46
- raise FileNotFoundError(
47
- f"Julia is not installed in your PATH. Please install Julia and add it to your PATH.\n\nCurrent PATH: {env_path}",
48
- )
49
- return Path(julia_env_dir_str)
50
-
51
-
52
- def _set_julia_project_env(julia_project, is_shared):
53
- if is_shared:
54
- if is_julia_version_greater_eq(version=(1, 7, 0)):
55
- os.environ["JULIA_PROJECT"] = "@" + str(julia_project)
56
- else:
57
- julia_env_dir = _get_julia_env_dir()
58
- os.environ["JULIA_PROJECT"] = str(julia_env_dir / julia_project)
59
- else:
60
- os.environ["JULIA_PROJECT"] = str(julia_project)
61
-
62
-
63
  def _get_io_arg(quiet):
64
  io = "devnull" if quiet else "stderr"
65
- io_arg = f"io={io}" if is_julia_version_greater_eq(version=(1, 6, 0)) else ""
66
- return io_arg
67
-
68
-
69
- def install(julia_project=None, quiet=False, precompile=None): # pragma: no cover
70
- """
71
- Install PyCall.jl and all required dependencies for SymbolicRegression.jl.
72
-
73
- Also updates the local Julia registry.
74
- """
75
- import julia
76
-
77
- _julia_version_assertion()
78
- # Set JULIA_PROJECT so that we install in the pysr environment
79
- processed_julia_project, is_shared = _process_julia_project(julia_project)
80
- _set_julia_project_env(processed_julia_project, is_shared)
81
-
82
- if precompile == False:
83
- os.environ["JULIA_PKG_PRECOMPILE_AUTO"] = "0"
84
-
85
- try:
86
- julia.install(quiet=quiet)
87
- except julia.tools.PyCallInstallError:
88
- # Attempt to reset PyCall.jl's build:
89
- subprocess.run(
90
- [
91
- "julia",
92
- "-e",
93
- f'ENV["PYTHON"] = "{sys.executable}"; import Pkg; Pkg.build("PyCall")',
94
- ],
95
- )
96
- # Try installing again:
97
- try:
98
- julia.install(quiet=quiet)
99
- except julia.tools.PyCallInstallError:
100
- warnings.warn(
101
- "PyCall.jl failed to install on second attempt. "
102
- + "Please consult the GitHub issue "
103
- + "https://github.com/MilesCranmer/PySR/issues/257 "
104
- + "for advice on fixing this."
105
- )
106
-
107
- Main, init_log = init_julia(julia_project, quiet=quiet, return_aux=True)
108
- io_arg = _get_io_arg(quiet)
109
-
110
- if precompile is None:
111
- precompile = init_log["compiled_modules"]
112
-
113
- if not precompile:
114
- Main.eval('ENV["JULIA_PKG_PRECOMPILE_AUTO"] = 0')
115
-
116
- if is_shared:
117
- # Install SymbolicRegression.jl:
118
- _add_sr_to_julia_project(Main, io_arg)
119
-
120
- Main.eval("using Pkg")
121
- Main.eval(f"Pkg.instantiate({io_arg})")
122
-
123
- if precompile:
124
- Main.eval(f"Pkg.precompile({io_arg})")
125
-
126
- if not quiet:
127
- warnings.warn(
128
- "It is recommended to restart Python after installing PySR's dependencies,"
129
- " so that the Julia environment is properly initialized."
130
- )
131
-
132
-
133
- def _import_error():
134
- return """
135
- Required dependencies are not installed or built. Run the following command in your terminal:
136
- python3 -m pysr install
137
- """
138
-
139
-
140
- def _process_julia_project(julia_project):
141
- if julia_project is None:
142
- is_shared = True
143
- processed_julia_project = f"pysr-{__version__}"
144
- elif julia_project[0] == "@":
145
- is_shared = True
146
- processed_julia_project = julia_project[1:]
147
- else:
148
- is_shared = False
149
- processed_julia_project = Path(julia_project)
150
- return processed_julia_project, is_shared
151
-
152
-
153
- def is_julia_version_greater_eq(juliainfo=None, version=(1, 6, 0)):
154
- """Check if Julia version is greater than specified version."""
155
- if juliainfo is None:
156
- juliainfo = _load_juliainfo()
157
- current_version = (
158
- juliainfo.version_major,
159
- juliainfo.version_minor,
160
- juliainfo.version_patch,
161
- )
162
- return current_version >= version
163
-
164
-
165
- def _check_for_conflicting_libraries(): # pragma: no cover
166
- """Check whether there are conflicting modules, and display warnings."""
167
- # See https://github.com/pytorch/pytorch/issues/78829: importing
168
- # pytorch before running `pysr.fit` causes a segfault.
169
- torch_is_loaded = "torch" in sys.modules
170
- if torch_is_loaded:
171
- warnings.warn(
172
- "`torch` was loaded before the Julia instance started. "
173
- "This may cause a segfault when running `PySRRegressor.fit`. "
174
- "To avoid this, please run `pysr.julia_helpers.init_julia()` *before* "
175
- "importing `torch`. "
176
- "For updates, see https://github.com/pytorch/pytorch/issues/78829"
177
- )
178
-
179
-
180
- def init_julia(julia_project=None, quiet=False, julia_kwargs=None, return_aux=False):
181
- """Initialize julia binary, turning off compiled modules if needed."""
182
- global julia_initialized
183
- global julia_kwargs_at_initialization
184
- global julia_activated_env
185
-
186
- if not julia_initialized:
187
- _check_for_conflicting_libraries()
188
-
189
- if julia_kwargs is None:
190
- julia_kwargs = {"optimize": 3}
191
-
192
- from julia.core import JuliaInfo, UnsupportedPythonError
193
-
194
- _julia_version_assertion()
195
- processed_julia_project, is_shared = _process_julia_project(julia_project)
196
- _set_julia_project_env(processed_julia_project, is_shared)
197
-
198
- try:
199
- info = JuliaInfo.load(julia="julia")
200
- except FileNotFoundError:
201
- env_path = os.environ["PATH"]
202
- raise FileNotFoundError(
203
- f"Julia is not installed in your PATH. Please install Julia and add it to your PATH.\n\nCurrent PATH: {env_path}",
204
- )
205
-
206
- if not info.is_pycall_built():
207
- raise ImportError(_import_error())
208
-
209
- from julia.core import Julia
210
-
211
- try:
212
- Julia(**julia_kwargs)
213
- except UnsupportedPythonError:
214
- # Static python binary, so we turn off pre-compiled modules.
215
- julia_kwargs = {**julia_kwargs, "compiled_modules": False}
216
- Julia(**julia_kwargs)
217
- warnings.warn(
218
- "Your system's Python library is static (e.g., conda), so precompilation will be turned off. For a dynamic library, try using `pyenv` and installing with `--enable-shared`: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-with---enable-shared."
219
- )
220
-
221
- using_compiled_modules = (not "compiled_modules" in julia_kwargs) or julia_kwargs[
222
- "compiled_modules"
223
- ]
224
-
225
- from julia import Main as _Main
226
-
227
- Main = _Main
228
-
229
- if julia_activated_env is None:
230
- julia_activated_env = processed_julia_project
231
-
232
- if julia_initialized and julia_kwargs_at_initialization is not None:
233
- # Check if the kwargs are the same as the previous initialization
234
- init_set = set(julia_kwargs_at_initialization.items())
235
- new_set = set(julia_kwargs.items())
236
- set_diff = new_set - init_set
237
- # Remove the `compiled_modules` key, since it is not a user-specified kwarg:
238
- set_diff = {k: v for k, v in set_diff if k != "compiled_modules"}
239
- if len(set_diff) > 0:
240
- warnings.warn(
241
- "Julia has already started. The new Julia options "
242
- + str(set_diff)
243
- + " will be ignored."
244
- )
245
-
246
- if julia_initialized and julia_activated_env != processed_julia_project:
247
- Main.eval("using Pkg")
248
-
249
- io_arg = _get_io_arg(quiet)
250
- # Can't pass IO to Julia call as it evaluates to PyObject, so just directly
251
- # use Main.eval:
252
- Main.eval(
253
- f'Pkg.activate("{_escape_filename(processed_julia_project)}",'
254
- f"shared = Bool({int(is_shared)}), "
255
- f"{io_arg})"
256
- )
257
-
258
- julia_activated_env = processed_julia_project
259
-
260
- if not julia_initialized:
261
- julia_kwargs_at_initialization = julia_kwargs
262
-
263
- julia_initialized = True
264
- if return_aux:
265
- return Main, {"compiled_modules": using_compiled_modules}
266
- return Main
267
-
268
-
269
- def _add_sr_to_julia_project(Main, io_arg):
270
- Main.eval("using Pkg")
271
- Main.eval("Pkg.Registry.update()")
272
- Main.sr_spec = Main.PackageSpec(
273
- name="SymbolicRegression",
274
- url="https://github.com/MilesCranmer/SymbolicRegression.jl",
275
- rev="v" + __symbolic_regression_jl_version__,
276
- )
277
- Main.clustermanagers_spec = Main.PackageSpec(
278
- name="ClusterManagers",
279
- version="0.4",
280
- )
281
- Main.eval(f"Pkg.add([sr_spec, clustermanagers_spec], {io_arg})")
282
 
283
 
284
  def _escape_filename(filename):
@@ -288,60 +24,17 @@ def _escape_filename(filename):
288
  return str_repr
289
 
290
 
291
- def _julia_version_assertion():
292
- if not is_julia_version_greater_eq(version=(1, 6, 0)):
293
- raise NotImplementedError(
294
- "PySR requires Julia 1.6.0 or greater. "
295
- "Please update your Julia installation."
296
- )
297
-
298
-
299
- def _backend_version_assertion(Main):
300
- try:
301
- backend_version = Main.eval("string(SymbolicRegression.PACKAGE_VERSION)")
302
- expected_backend_version = __symbolic_regression_jl_version__
303
- if backend_version != expected_backend_version: # pragma: no cover
304
- warnings.warn(
305
- f"PySR backend (SymbolicRegression.jl) version {backend_version} "
306
- f"does not match expected version {expected_backend_version}. "
307
- "Things may break. "
308
- "Please update your PySR installation with "
309
- "`python3 -m pysr install`."
310
- )
311
- except JuliaError: # pragma: no cover
312
  warnings.warn(
313
- "You seem to have an outdated version of SymbolicRegression.jl. "
 
314
  "Things may break. "
315
- "Please update your PySR installation with "
316
- "`python3 -m pysr install`."
317
  )
318
 
319
 
320
- def _load_cluster_manager(Main, cluster_manager):
321
- Main.eval(f"import ClusterManagers: addprocs_{cluster_manager}")
322
- return Main.eval(f"addprocs_{cluster_manager}")
323
-
324
-
325
- def _update_julia_project(Main, is_shared, io_arg):
326
- try:
327
- if is_shared:
328
- _add_sr_to_julia_project(Main, io_arg)
329
- Main.eval("using Pkg")
330
- Main.eval(f"Pkg.resolve({io_arg})")
331
- except (JuliaError, RuntimeError) as e:
332
- raise ImportError(_import_error()) from e
333
-
334
-
335
- def _load_backend(Main):
336
- try:
337
- # Load namespace, so that various internal operators work:
338
- Main.eval("using SymbolicRegression")
339
- except (JuliaError, RuntimeError) as e:
340
- raise ImportError(_import_error()) from e
341
-
342
- _backend_version_assertion(Main)
343
-
344
- # Load Julia package SymbolicRegression.jl
345
- from julia import SymbolicRegression
346
-
347
- return SymbolicRegression
 
1
  """Functions for initializing the Julia environment and installing deps."""
 
 
 
2
  import warnings
 
3
 
4
+ import juliacall
5
+ import juliapkg
6
 
7
+ jl = juliacall.newmodule("PySR")
8
 
9
  juliainfo = None
10
  julia_initialized = False
 
12
  julia_activated_env = None
13
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def _get_io_arg(quiet):
16
  io = "devnull" if quiet else "stderr"
17
+ return f"io={io}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
 
20
  def _escape_filename(filename):
 
24
  return str_repr
25
 
26
 
27
+ def _backend_version_assertion():
28
+ backend_version = jl.seval("string(SymbolicRegression.PACKAGE_VERSION)")
29
+ expected_backend_version = juliapkg.status(target="SymbolicRegression").version
30
+ if backend_version != expected_backend_version: # pragma: no cover
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  warnings.warn(
32
+ f"PySR backend (SymbolicRegression.jl) version {backend_version} "
33
+ f"does not match expected version {expected_backend_version}. "
34
  "Things may break. "
 
 
35
  )
36
 
37
 
38
+ def _load_cluster_manager(cluster_manager):
39
+ jl.seval(f"using ClusterManagers: addprocs_{cluster_manager}")
40
+ return jl.seval(f"addprocs_{cluster_manager}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pysr/sr.py CHANGED
@@ -32,15 +32,7 @@ from .export_numpy import sympy2numpy
32
  from .export_sympy import assert_valid_sympy_symbol, create_sympy_symbols, pysr2sympy
33
  from .export_torch import sympy2torch
34
  from .feature_selection import run_feature_selection
35
- from .julia_helpers import (
36
- _escape_filename,
37
- _load_backend,
38
- _load_cluster_manager,
39
- _process_julia_project,
40
- _update_julia_project,
41
- init_julia,
42
- is_julia_version_greater_eq,
43
- )
44
  from .utils import (
45
  _csv_filename_to_pkl_filename,
46
  _preprocess_julia_floats,
@@ -48,8 +40,6 @@ from .utils import (
48
  _subscriptify,
49
  )
50
 
51
- Main = None # TODO: Rename to more descriptive name like "julia_runtime"
52
-
53
  already_ran = False
54
 
55
 
@@ -92,7 +82,6 @@ def _process_constraints(binary_operators, unary_operators, constraints):
92
  def _maybe_create_inline_operators(
93
  binary_operators, unary_operators, extra_sympy_mappings
94
  ):
95
- global Main
96
  binary_operators = binary_operators.copy()
97
  unary_operators = unary_operators.copy()
98
  for op_list in [binary_operators, unary_operators]:
@@ -100,7 +89,7 @@ def _maybe_create_inline_operators(
100
  is_user_defined_operator = "(" in op
101
 
102
  if is_user_defined_operator:
103
- Main.eval(op)
104
  # Cut off from the first non-alphanumeric char:
105
  first_non_char = [j for j, char in enumerate(op) if char == "("][0]
106
  function_name = op[:first_non_char]
@@ -1528,7 +1517,6 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1528
  # Need to be global as we don't want to recreate/reinstate julia for
1529
  # every new instance of PySRRegressor
1530
  global already_ran
1531
- global Main
1532
 
1533
  # These are the parameters which may be modified from the ones
1534
  # specified in init, so we define them here locally:
@@ -1549,26 +1537,17 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1549
  if not already_ran and update_verbosity != 0:
1550
  print("Compiling Julia backend...")
1551
 
1552
- Main = init_julia(self.julia_project, julia_kwargs=julia_kwargs)
1553
-
1554
  if cluster_manager is not None:
1555
- cluster_manager = _load_cluster_manager(Main, cluster_manager)
1556
 
1557
- if self.update:
1558
- _, is_shared = _process_julia_project(self.julia_project)
1559
- io = "devnull" if update_verbosity == 0 else "stderr"
1560
- io_arg = (
1561
- f"io={io}" if is_julia_version_greater_eq(version=(1, 6, 0)) else ""
1562
- )
1563
- _update_julia_project(Main, is_shared, io_arg)
1564
-
1565
- SymbolicRegression = _load_backend(Main)
1566
 
1567
- Main.plus = Main.eval("(+)")
1568
- Main.sub = Main.eval("(-)")
1569
- Main.mult = Main.eval("(*)")
1570
- Main.pow = Main.eval("(^)")
1571
- Main.div = Main.eval("(/)")
1572
 
1573
  # TODO(mcranmer): These functions should be part of this class.
1574
  binary_operators, unary_operators = _maybe_create_inline_operators(
@@ -1594,7 +1573,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1594
  nested_constraints_str += f"({inner_k}) => {inner_v}, "
1595
  nested_constraints_str += "), "
1596
  nested_constraints_str += ")"
1597
- nested_constraints = Main.eval(nested_constraints_str)
1598
 
1599
  # Parse dict into Julia Dict for complexities:
1600
  if complexity_of_operators is not None:
@@ -1602,13 +1581,17 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1602
  for k, v in complexity_of_operators.items():
1603
  complexity_of_operators_str += f"({k}) => {v}, "
1604
  complexity_of_operators_str += ")"
1605
- complexity_of_operators = Main.eval(complexity_of_operators_str)
1606
 
1607
- custom_loss = Main.eval(self.loss)
1608
- custom_full_objective = Main.eval(self.full_objective)
 
 
1609
 
1610
- early_stop_condition = Main.eval(
1611
- str(self.early_stop_condition) if self.early_stop_condition else None
 
 
1612
  )
1613
 
1614
  mutation_weights = SymbolicRegression.MutationWeights(
@@ -1626,9 +1609,10 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
1626
 
1627
  # Call to Julia backend.
1628
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
 
1629
  options = SymbolicRegression.Options(
1630
- binary_operators=Main.eval(str(binary_operators).replace("'", "")),
1631
- unary_operators=Main.eval(str(unary_operators).replace("'", "")),
1632
  bin_constraints=bin_constraints,
1633
  una_constraints=una_constraints,
1634
  complexity_of_operators=complexity_of_operators,
 
32
  from .export_sympy import assert_valid_sympy_symbol, create_sympy_symbols, pysr2sympy
33
  from .export_torch import sympy2torch
34
  from .feature_selection import run_feature_selection
35
+ from .julia_helpers import _escape_filename, _load_cluster_manager, jl
 
 
 
 
 
 
 
 
36
  from .utils import (
37
  _csv_filename_to_pkl_filename,
38
  _preprocess_julia_floats,
 
40
  _subscriptify,
41
  )
42
 
 
 
43
  already_ran = False
44
 
45
 
 
82
  def _maybe_create_inline_operators(
83
  binary_operators, unary_operators, extra_sympy_mappings
84
  ):
 
85
  binary_operators = binary_operators.copy()
86
  unary_operators = unary_operators.copy()
87
  for op_list in [binary_operators, unary_operators]:
 
89
  is_user_defined_operator = "(" in op
90
 
91
  if is_user_defined_operator:
92
+ jl.seval(op)
93
  # Cut off from the first non-alphanumeric char:
94
  first_non_char = [j for j, char in enumerate(op) if char == "("][0]
95
  function_name = op[:first_non_char]
 
1517
  # Need to be global as we don't want to recreate/reinstate julia for
1518
  # every new instance of PySRRegressor
1519
  global already_ran
 
1520
 
1521
  # These are the parameters which may be modified from the ones
1522
  # specified in init, so we define them here locally:
 
1537
  if not already_ran and update_verbosity != 0:
1538
  print("Compiling Julia backend...")
1539
 
 
 
1540
  if cluster_manager is not None:
1541
+ cluster_manager = _load_cluster_manager(cluster_manager)
1542
 
1543
+ jl.seval("using SymbolicRegression")
1544
+ SymbolicRegression = jl.SymbolicRegression
 
 
 
 
 
 
 
1545
 
1546
+ jl.plus = jl.seval("(+)")
1547
+ jl.sub = jl.seval("(-)")
1548
+ jl.mult = jl.seval("(*)")
1549
+ jl.pow = jl.seval("(^)")
1550
+ jl.div = jl.seval("(/)")
1551
 
1552
  # TODO(mcranmer): These functions should be part of this class.
1553
  binary_operators, unary_operators = _maybe_create_inline_operators(
 
1573
  nested_constraints_str += f"({inner_k}) => {inner_v}, "
1574
  nested_constraints_str += "), "
1575
  nested_constraints_str += ")"
1576
+ nested_constraints = jl.seval(nested_constraints_str)
1577
 
1578
  # Parse dict into Julia Dict for complexities:
1579
  if complexity_of_operators is not None:
 
1581
  for k, v in complexity_of_operators.items():
1582
  complexity_of_operators_str += f"({k}) => {v}, "
1583
  complexity_of_operators_str += ")"
1584
+ complexity_of_operators = jl.seval(complexity_of_operators_str)
1585
 
1586
+ custom_loss = jl.seval(str(self.loss) if self.loss is not None else "nothing")
1587
+ custom_full_objective = jl.seval(
1588
+ str(self.full_objective) if self.full_objective is not None else "nothing"
1589
+ )
1590
 
1591
+ early_stop_condition = jl.seval(
1592
+ str(self.early_stop_condition)
1593
+ if self.early_stop_condition is not None
1594
+ else "nothing"
1595
  )
1596
 
1597
  mutation_weights = SymbolicRegression.MutationWeights(
 
1609
 
1610
  # Call to Julia backend.
1611
  # See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
1612
+ print(bin_constraints)
1613
  options = SymbolicRegression.Options(
1614
+ binary_operators=jl.seval(str(binary_operators).replace("'", "")),
1615
+ unary_operators=jl.seval(str(unary_operators).replace("'", "")),
1616
  bin_constraints=bin_constraints,
1617
  una_constraints=una_constraints,
1618
  complexity_of_operators=complexity_of_operators,
pysr/version.py CHANGED
@@ -1,2 +1 @@
1
- __version__ = "0.16.9"
2
- __symbolic_regression_jl_version__ = "0.23.1"
 
1
+ __version__ = "0.17.0"
 
requirements.txt CHANGED
@@ -2,7 +2,8 @@ sympy>=1.0.0,<2.0.0
2
  pandas>=0.21.0,<3.0.0
3
  numpy>=1.13.0,<2.0.0
4
  scikit_learn>=1.0.0,<2.0.0
5
- julia>=0.6.0,<0.7.0
 
6
  click>=7.0.0,<9.0.0
7
  setuptools>=50.0.0
8
  typing_extensions>=4.0.0,<5.0.0; python_version < "3.8"
 
2
  pandas>=0.21.0,<3.0.0
3
  numpy>=1.13.0,<2.0.0
4
  scikit_learn>=1.0.0,<2.0.0
5
+ juliacall>=0.9.15,<0.10.0
6
+ juliapkg>=0.1.10,<0.2.0
7
  click>=7.0.0,<9.0.0
8
  setuptools>=50.0.0
9
  typing_extensions>=4.0.0,<5.0.0; python_version < "3.8"