QuLab 2.1.0__cp310-cp310-win_amd64.whl → 2.1.2__cp310-cp310-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/METADATA +1 -1
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/RECORD +17 -15
- qulab/__init__.py +3 -1
- qulab/fun.cp310-win_amd64.pyd +0 -0
- qulab/scan/__init__.py +1 -1
- qulab/scan/{query_record.py → query.py} +16 -12
- qulab/scan/record.py +495 -0
- qulab/scan/recorder.py +18 -499
- qulab/scan/scan.py +121 -147
- qulab/scan/server.py +4 -6
- qulab/scan/space.py +172 -0
- qulab/scan/utils.py +48 -0
- qulab/version.py +1 -1
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/LICENSE +0 -0
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/WHEEL +0 -0
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/entry_points.txt +0 -0
- {QuLab-2.1.0.dist-info → QuLab-2.1.2.dist-info}/top_level.txt +0 -0
qulab/scan/scan.py
CHANGED
|
@@ -1,35 +1,56 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import copy
|
|
3
|
-
import datetime
|
|
4
3
|
import inspect
|
|
5
4
|
import itertools
|
|
6
5
|
import os
|
|
7
6
|
import re
|
|
8
7
|
import sys
|
|
9
8
|
import uuid
|
|
10
|
-
import warnings
|
|
11
9
|
from concurrent.futures import ProcessPoolExecutor
|
|
12
10
|
from graphlib import TopologicalSorter
|
|
13
11
|
from pathlib import Path
|
|
14
|
-
from
|
|
15
|
-
from typing import Any, Awaitable, Callable, Iterable, Type
|
|
12
|
+
from typing import Any, Awaitable, Callable, Iterable
|
|
16
13
|
|
|
17
14
|
import dill
|
|
18
15
|
import numpy as np
|
|
19
|
-
import skopt
|
|
20
16
|
import zmq
|
|
21
|
-
from skopt.space import Categorical, Integer, Real
|
|
22
|
-
from tqdm.notebook import tqdm
|
|
23
17
|
|
|
24
18
|
from ..sys.rpc.zmq_socket import ZMQContextManager
|
|
25
19
|
from .expression import Env, Expression, Symbol
|
|
26
20
|
from .optimize import NgOptimizer
|
|
27
|
-
from .
|
|
28
|
-
from .
|
|
21
|
+
from .record import Record
|
|
22
|
+
from .recorder import default_record_port
|
|
23
|
+
from .space import Optimizer, OptimizeSpace, Space
|
|
24
|
+
from .utils import async_zip, call_function, dump_globals
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
from tqdm.notebook import tqdm
|
|
28
|
+
except:
|
|
29
|
+
|
|
30
|
+
class tqdm():
|
|
31
|
+
|
|
32
|
+
def update(self, n):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def close(self):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
def reset(self):
|
|
39
|
+
pass
|
|
40
|
+
|
|
29
41
|
|
|
30
42
|
__process_uuid = uuid.uuid1()
|
|
31
43
|
__task_counter = itertools.count()
|
|
32
44
|
|
|
45
|
+
if os.getenv('QULAB_SERVER'):
|
|
46
|
+
default_server = os.getenv('QULAB_SERVER')
|
|
47
|
+
else:
|
|
48
|
+
default_server = f'tcp://127.0.0.1:{default_record_port}'
|
|
49
|
+
if os.getenv('QULAB_EXECUTOR'):
|
|
50
|
+
default_executor = os.getenv('QULAB_EXECUTOR')
|
|
51
|
+
else:
|
|
52
|
+
default_executor = default_server
|
|
53
|
+
|
|
33
54
|
|
|
34
55
|
def task_uuid():
|
|
35
56
|
return uuid.uuid3(__process_uuid, str(next(__task_counter)))
|
|
@@ -55,79 +76,6 @@ def _get_depends(func: Callable):
|
|
|
55
76
|
return args
|
|
56
77
|
|
|
57
78
|
|
|
58
|
-
class OptimizeSpace():
|
|
59
|
-
|
|
60
|
-
def __init__(self, optimizer: 'Optimizer', space):
|
|
61
|
-
self.optimizer = optimizer
|
|
62
|
-
self.space = space
|
|
63
|
-
self.name = None
|
|
64
|
-
|
|
65
|
-
def __len__(self):
|
|
66
|
-
return self.optimizer.maxiter
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class Optimizer():
|
|
70
|
-
|
|
71
|
-
def __init__(self,
|
|
72
|
-
scanner: 'Scan',
|
|
73
|
-
name: str,
|
|
74
|
-
level: int,
|
|
75
|
-
method: str | Type = skopt.Optimizer,
|
|
76
|
-
maxiter: int = 1000,
|
|
77
|
-
minimize: bool = True,
|
|
78
|
-
**kwds):
|
|
79
|
-
self.scanner = scanner
|
|
80
|
-
self.method = method
|
|
81
|
-
self.maxiter = maxiter
|
|
82
|
-
self.dimensions = {}
|
|
83
|
-
self.name = name
|
|
84
|
-
self.level = level
|
|
85
|
-
self.kwds = kwds
|
|
86
|
-
self.minimize = minimize
|
|
87
|
-
|
|
88
|
-
def create(self):
|
|
89
|
-
return self.method(list(self.dimensions.values()), **self.kwds)
|
|
90
|
-
|
|
91
|
-
def Categorical(self,
|
|
92
|
-
categories,
|
|
93
|
-
prior=None,
|
|
94
|
-
transform=None,
|
|
95
|
-
name=None) -> OptimizeSpace:
|
|
96
|
-
return OptimizeSpace(self,
|
|
97
|
-
Categorical(categories, prior, transform, name))
|
|
98
|
-
|
|
99
|
-
def Integer(self,
|
|
100
|
-
low,
|
|
101
|
-
high,
|
|
102
|
-
prior="uniform",
|
|
103
|
-
base=10,
|
|
104
|
-
transform=None,
|
|
105
|
-
name=None,
|
|
106
|
-
dtype=np.int64) -> OptimizeSpace:
|
|
107
|
-
return OptimizeSpace(
|
|
108
|
-
self, Integer(low, high, prior, base, transform, name, dtype))
|
|
109
|
-
|
|
110
|
-
def Real(self,
|
|
111
|
-
low,
|
|
112
|
-
high,
|
|
113
|
-
prior="uniform",
|
|
114
|
-
base=10,
|
|
115
|
-
transform=None,
|
|
116
|
-
name=None,
|
|
117
|
-
dtype=float) -> OptimizeSpace:
|
|
118
|
-
return OptimizeSpace(
|
|
119
|
-
self, Real(low, high, prior, base, transform, name, dtype))
|
|
120
|
-
|
|
121
|
-
def __getstate__(self) -> dict:
|
|
122
|
-
state = self.__dict__.copy()
|
|
123
|
-
del state['scanner']
|
|
124
|
-
return state
|
|
125
|
-
|
|
126
|
-
def __setstate__(self, state: dict) -> None:
|
|
127
|
-
self.__dict__.update(state)
|
|
128
|
-
self.scanner = None
|
|
129
|
-
|
|
130
|
-
|
|
131
79
|
class Promise():
|
|
132
80
|
__slots__ = ['task', 'key', 'attr']
|
|
133
81
|
|
|
@@ -180,7 +128,7 @@ class Scan():
|
|
|
180
128
|
app: str = 'task',
|
|
181
129
|
tags: tuple[str] = (),
|
|
182
130
|
database: str | Path
|
|
183
|
-
| None =
|
|
131
|
+
| None = default_server,
|
|
184
132
|
dump_globals: bool = False,
|
|
185
133
|
max_workers: int = 4,
|
|
186
134
|
max_promise: int = 100,
|
|
@@ -192,6 +140,7 @@ class Scan():
|
|
|
192
140
|
'app': app,
|
|
193
141
|
'tags': tags,
|
|
194
142
|
'loops': {},
|
|
143
|
+
'intrinsic_loops': {},
|
|
195
144
|
'consts': {},
|
|
196
145
|
'functions': {},
|
|
197
146
|
'getters': {},
|
|
@@ -201,6 +150,8 @@ class Scan():
|
|
|
201
150
|
'actions': {},
|
|
202
151
|
'dependents': {},
|
|
203
152
|
'order': {},
|
|
153
|
+
'axis': {},
|
|
154
|
+
'independent_variables': set(),
|
|
204
155
|
'filters': {},
|
|
205
156
|
'total': {},
|
|
206
157
|
'database': database,
|
|
@@ -341,10 +292,10 @@ class Scan():
|
|
|
341
292
|
else:
|
|
342
293
|
return Symbol(name)
|
|
343
294
|
|
|
344
|
-
def
|
|
295
|
+
def _add_search_space(self, name: str, level: int, space):
|
|
345
296
|
if level not in self.description['loops']:
|
|
346
297
|
self.description['loops'][level] = []
|
|
347
|
-
self.description['loops'][level].append((name,
|
|
298
|
+
self.description['loops'][level].append((name, space))
|
|
348
299
|
|
|
349
300
|
def add_depends(self, name: str, depends: list[str]):
|
|
350
301
|
if isinstance(depends, str):
|
|
@@ -353,7 +304,7 @@ class Scan():
|
|
|
353
304
|
self.description['dependents'][name] = set()
|
|
354
305
|
self.description['dependents'][name].update(depends)
|
|
355
306
|
|
|
356
|
-
def add_filter(self, func: Callable, level: int):
|
|
307
|
+
def add_filter(self, func: Callable, level: int = -1):
|
|
357
308
|
"""
|
|
358
309
|
Add a filter function to the scan.
|
|
359
310
|
|
|
@@ -365,7 +316,11 @@ class Scan():
|
|
|
365
316
|
self.description['filters'][level] = []
|
|
366
317
|
self.description['filters'][level].append(func)
|
|
367
318
|
|
|
368
|
-
def set(self,
|
|
319
|
+
def set(self,
|
|
320
|
+
name: str,
|
|
321
|
+
value,
|
|
322
|
+
depends: Iterable[str] | None = None,
|
|
323
|
+
setter: Callable | None = None):
|
|
369
324
|
try:
|
|
370
325
|
dill.dumps(value)
|
|
371
326
|
except:
|
|
@@ -374,31 +329,54 @@ class Scan():
|
|
|
374
329
|
self.add_depends(name, value.symbols())
|
|
375
330
|
self.description['functions'][name] = value
|
|
376
331
|
elif callable(value):
|
|
377
|
-
|
|
378
|
-
|
|
332
|
+
if depends:
|
|
333
|
+
self.add_depends(name, depends)
|
|
334
|
+
s = ','.join(depends)
|
|
335
|
+
self.description['functions'][f'_tmp_{name}'] = value
|
|
336
|
+
self.description['functions'][name] = eval(
|
|
337
|
+
f"lambda self, {s}: self.description['functions']['_tmp_{name}']({s})"
|
|
338
|
+
)
|
|
339
|
+
else:
|
|
340
|
+
self.add_depends(name, _get_depends(value))
|
|
341
|
+
self.description['functions'][name] = value
|
|
379
342
|
else:
|
|
343
|
+
try:
|
|
344
|
+
value = Space.fromarray(value)
|
|
345
|
+
except:
|
|
346
|
+
pass
|
|
380
347
|
self.description['consts'][name] = value
|
|
381
348
|
if setter:
|
|
382
349
|
self.description['setters'][name] = setter
|
|
383
350
|
|
|
384
351
|
def search(self,
|
|
385
352
|
name: str,
|
|
386
|
-
|
|
353
|
+
space: Iterable | Expression | Callable | OptimizeSpace,
|
|
387
354
|
level: int | None = None,
|
|
388
|
-
setter: Callable | None = None
|
|
355
|
+
setter: Callable | None = None,
|
|
356
|
+
intrinsic: bool = False):
|
|
389
357
|
if level is not None:
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
self.
|
|
358
|
+
if not intrinsic:
|
|
359
|
+
assert level >= 0, 'level must be greater than or equal to 0.'
|
|
360
|
+
if intrinsic:
|
|
361
|
+
assert isinstance(space, (np.ndarray, list, tuple, range, Space)), \
|
|
362
|
+
'space must be an instance of np.ndarray, list, tuple, range or Space.'
|
|
363
|
+
self.description['intrinsic_loops'][name] = level
|
|
364
|
+
self.set(name, space)
|
|
365
|
+
elif isinstance(space, OptimizeSpace):
|
|
366
|
+
space.name = name
|
|
367
|
+
space.optimizer.dimensions[name] = space.space
|
|
368
|
+
self._add_search_space(name, space.optimizer.level, space)
|
|
369
|
+
self.add_depends(space.optimizer.name, [name])
|
|
396
370
|
else:
|
|
397
371
|
if level is None:
|
|
398
372
|
raise ValueError('level must be provided.')
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
373
|
+
try:
|
|
374
|
+
space = Space.fromarray(space)
|
|
375
|
+
except:
|
|
376
|
+
pass
|
|
377
|
+
self._add_search_space(name, level, space)
|
|
378
|
+
if isinstance(space, Expression) or callable(space):
|
|
379
|
+
self.add_depends(name, space.symbols())
|
|
402
380
|
if setter:
|
|
403
381
|
self.description['setters'][name] = setter
|
|
404
382
|
|
|
@@ -481,7 +459,14 @@ class Scan():
|
|
|
481
459
|
|
|
482
460
|
self._variables = {'self': self}
|
|
483
461
|
|
|
484
|
-
|
|
462
|
+
consts = {}
|
|
463
|
+
for k, v in self.description['consts'].items():
|
|
464
|
+
if isinstance(v, Space):
|
|
465
|
+
consts[k] = v.toarray()
|
|
466
|
+
else:
|
|
467
|
+
consts[k] = v
|
|
468
|
+
|
|
469
|
+
await update_variables(self._variables, consts,
|
|
485
470
|
self.description['setters'])
|
|
486
471
|
for level, total in self.description['total'].items():
|
|
487
472
|
if total == np.inf:
|
|
@@ -527,7 +512,7 @@ class Scan():
|
|
|
527
512
|
import asyncio
|
|
528
513
|
self._main_task = asyncio.create_task(self.run())
|
|
529
514
|
|
|
530
|
-
async def submit(self, server=
|
|
515
|
+
async def submit(self, server=default_executor):
|
|
531
516
|
assymbly(self.description)
|
|
532
517
|
async with ZMQContextManager(zmq.DEALER, connect=server) as socket:
|
|
533
518
|
await socket.send_pyobj({
|
|
@@ -640,51 +625,6 @@ class Scan():
|
|
|
640
625
|
return await awaitable
|
|
641
626
|
|
|
642
627
|
|
|
643
|
-
class Unpicklable:
|
|
644
|
-
|
|
645
|
-
def __init__(self, obj):
|
|
646
|
-
self.type = str(type(obj))
|
|
647
|
-
self.id = id(obj)
|
|
648
|
-
|
|
649
|
-
def __repr__(self):
|
|
650
|
-
return f'<Unpicklable: {self.type} at 0x{id(self):x}>'
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
class TooLarge:
|
|
654
|
-
|
|
655
|
-
def __init__(self, obj):
|
|
656
|
-
self.type = str(type(obj))
|
|
657
|
-
self.id = id(obj)
|
|
658
|
-
|
|
659
|
-
def __repr__(self):
|
|
660
|
-
return f'<TooLarge: {self.type} at 0x{id(self):x}>'
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
def dump_globals(ns=None, *, size_limit=10 * 1024 * 1024, warn=False):
|
|
664
|
-
import __main__
|
|
665
|
-
|
|
666
|
-
if ns is None:
|
|
667
|
-
ns = __main__.__dict__
|
|
668
|
-
|
|
669
|
-
namespace = {}
|
|
670
|
-
|
|
671
|
-
for name, value in ns.items():
|
|
672
|
-
try:
|
|
673
|
-
buf = dill.dumps(value)
|
|
674
|
-
except:
|
|
675
|
-
namespace[name] = Unpicklable(value)
|
|
676
|
-
if warn:
|
|
677
|
-
warnings.warn(f'Unpicklable: {name} {type(value)}')
|
|
678
|
-
if len(buf) > size_limit:
|
|
679
|
-
namespace[name] = TooLarge(value)
|
|
680
|
-
if warn:
|
|
681
|
-
warnings.warn(f'TooLarge: {name} {type(value)}')
|
|
682
|
-
else:
|
|
683
|
-
namespace[name] = buf
|
|
684
|
-
|
|
685
|
-
return namespace
|
|
686
|
-
|
|
687
|
-
|
|
688
628
|
def assymbly(description):
|
|
689
629
|
import __main__
|
|
690
630
|
from IPython import get_ipython
|
|
@@ -810,6 +750,38 @@ def assymbly(description):
|
|
|
810
750
|
if ready:
|
|
811
751
|
description['order'][level].append(ready)
|
|
812
752
|
keys -= set(ready)
|
|
753
|
+
|
|
754
|
+
axis = {}
|
|
755
|
+
independent_variables = set(description['intrinsic_loops'].keys())
|
|
756
|
+
|
|
757
|
+
for name in description['consts']:
|
|
758
|
+
axis[name] = ()
|
|
759
|
+
for level, range_list in description['loops'].items():
|
|
760
|
+
for name, iterable in range_list:
|
|
761
|
+
if isinstance(iterable, OptimizeSpace):
|
|
762
|
+
axis[name] = tuple(range(level + 1))
|
|
763
|
+
continue
|
|
764
|
+
elif isinstance(iterable, (np.ndarray, list, tuple, range, Space)):
|
|
765
|
+
independent_variables.add(name)
|
|
766
|
+
axis[name] = (level, )
|
|
767
|
+
|
|
768
|
+
for level, group in description['order'].items():
|
|
769
|
+
for names in group:
|
|
770
|
+
for name in names:
|
|
771
|
+
if name not in description['dependents']:
|
|
772
|
+
if name not in axis:
|
|
773
|
+
axis[name] = (level, )
|
|
774
|
+
else:
|
|
775
|
+
d = set()
|
|
776
|
+
for n in description['dependents'][name]:
|
|
777
|
+
d.update(axis[n])
|
|
778
|
+
if name not in axis:
|
|
779
|
+
axis[name] = tuple(sorted(d))
|
|
780
|
+
else:
|
|
781
|
+
axis[name] = tuple(sorted(set(axis[name]) | d))
|
|
782
|
+
description['axis'] = axis
|
|
783
|
+
description['independent_variables'] = independent_variables
|
|
784
|
+
|
|
813
785
|
return description
|
|
814
786
|
|
|
815
787
|
|
|
@@ -845,6 +817,8 @@ async def _iter_level(variables,
|
|
|
845
817
|
opts[iter.optimizer.name] = iter.optimizer.create()
|
|
846
818
|
elif isinstance(iter, Expression):
|
|
847
819
|
iters_d[name] = iter.eval(env)
|
|
820
|
+
elif isinstance(iter, Space):
|
|
821
|
+
iters_d[name] = iter.toarray()
|
|
848
822
|
elif callable(iter):
|
|
849
823
|
iters_d[name] = await call_function(iter, variables)
|
|
850
824
|
else:
|
qulab/scan/server.py
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import pickle
|
|
3
|
-
|
|
4
|
-
import time
|
|
5
|
-
import uuid
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from .scan import Scan
|
|
3
|
+
|
|
8
4
|
import click
|
|
9
5
|
import dill
|
|
10
|
-
import numpy as np
|
|
11
6
|
import zmq
|
|
12
7
|
from loguru import logger
|
|
13
8
|
|
|
14
9
|
from qulab.sys.rpc.zmq_socket import ZMQContextManager
|
|
15
10
|
|
|
11
|
+
from .scan import Scan
|
|
12
|
+
|
|
16
13
|
pool = {}
|
|
17
14
|
|
|
15
|
+
|
|
18
16
|
class Request():
|
|
19
17
|
__slots__ = ['sock', 'identity', 'msg', 'method']
|
|
20
18
|
|
qulab/scan/space.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from typing import Type
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import skopt
|
|
5
|
+
from skopt.space import Categorical, Integer, Real
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Space():
|
|
9
|
+
|
|
10
|
+
def __init__(self, function, *args, **kwds):
|
|
11
|
+
self.function = function
|
|
12
|
+
self.args = args
|
|
13
|
+
self.kwds = kwds
|
|
14
|
+
|
|
15
|
+
def __repr__(self):
|
|
16
|
+
if self.function == 'asarray':
|
|
17
|
+
return repr(self.args[0])
|
|
18
|
+
args = ', '.join(map(repr, self.args))
|
|
19
|
+
kwds = ', '.join(f'{k}={v!r}' for k, v in self.kwds.items())
|
|
20
|
+
return f"{self.function}({args}, {kwds})"
|
|
21
|
+
|
|
22
|
+
def __len__(self):
|
|
23
|
+
return len(self.toarray())
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def fromarray(cls, array):
|
|
27
|
+
if isinstance(array, Space):
|
|
28
|
+
return array
|
|
29
|
+
if isinstance(array, (list, tuple)):
|
|
30
|
+
array = np.array(array)
|
|
31
|
+
try:
|
|
32
|
+
a = np.linspace(array[0], array[-1], len(array), dtype=array.dtype)
|
|
33
|
+
if np.allclose(a, array):
|
|
34
|
+
return cls('linspace',
|
|
35
|
+
array[0],
|
|
36
|
+
array[-1],
|
|
37
|
+
len(array),
|
|
38
|
+
dtype=array.dtype)
|
|
39
|
+
except:
|
|
40
|
+
pass
|
|
41
|
+
try:
|
|
42
|
+
a = np.logspace(np.log10(array[0]),
|
|
43
|
+
np.log10(array[-1]),
|
|
44
|
+
len(array),
|
|
45
|
+
base=10,
|
|
46
|
+
dtype=array.dtype)
|
|
47
|
+
if np.allclose(a, array):
|
|
48
|
+
return cls('logspace',
|
|
49
|
+
np.log10(array[0]),
|
|
50
|
+
np.log10(array[-1]),
|
|
51
|
+
len(array),
|
|
52
|
+
base=10,
|
|
53
|
+
dtype=array.dtype)
|
|
54
|
+
except:
|
|
55
|
+
pass
|
|
56
|
+
try:
|
|
57
|
+
a = np.logspace(np.log2(array[0]),
|
|
58
|
+
np.log2(array[-1]),
|
|
59
|
+
len(array),
|
|
60
|
+
base=2,
|
|
61
|
+
dtype=array.dtype)
|
|
62
|
+
if np.allclose(a, array):
|
|
63
|
+
return cls('logspace',
|
|
64
|
+
np.log2(array[0]),
|
|
65
|
+
np.log2(array[-1]),
|
|
66
|
+
len(array),
|
|
67
|
+
base=2,
|
|
68
|
+
dtype=array.dtype)
|
|
69
|
+
except:
|
|
70
|
+
pass
|
|
71
|
+
try:
|
|
72
|
+
a = np.geomspace(array[0],
|
|
73
|
+
array[-1],
|
|
74
|
+
len(array),
|
|
75
|
+
dtype=array.dtype)
|
|
76
|
+
if np.allclose(a, array):
|
|
77
|
+
return cls('geomspace',
|
|
78
|
+
array[0],
|
|
79
|
+
array[-1],
|
|
80
|
+
len(array),
|
|
81
|
+
dtype=array.dtype)
|
|
82
|
+
except:
|
|
83
|
+
pass
|
|
84
|
+
return array
|
|
85
|
+
|
|
86
|
+
def toarray(self):
|
|
87
|
+
return getattr(np, self.function)(*self.args, **self.kwds)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def logspace(start, stop, num=50, endpoint=True, base=10):
|
|
91
|
+
return Space('logspace', start, stop, num, endpoint=endpoint, base=base)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def linspace(start, stop, num=50, endpoint=True):
|
|
95
|
+
return Space('linspace', start, stop, num, endpoint=endpoint)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def geomspace(start, stop, num=50, endpoint=True):
|
|
99
|
+
return Space('geomspace', start, stop, num, endpoint=endpoint)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class OptimizeSpace():
|
|
103
|
+
|
|
104
|
+
def __init__(self, optimizer: 'Optimizer', space):
|
|
105
|
+
self.optimizer = optimizer
|
|
106
|
+
self.space = space
|
|
107
|
+
self.name = None
|
|
108
|
+
|
|
109
|
+
def __len__(self):
|
|
110
|
+
return self.optimizer.maxiter
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class Optimizer():
|
|
114
|
+
|
|
115
|
+
def __init__(self,
|
|
116
|
+
scanner,
|
|
117
|
+
name: str,
|
|
118
|
+
level: int,
|
|
119
|
+
method: str | Type = skopt.Optimizer,
|
|
120
|
+
maxiter: int = 1000,
|
|
121
|
+
minimize: bool = True,
|
|
122
|
+
**kwds):
|
|
123
|
+
self.scanner = scanner
|
|
124
|
+
self.method = method
|
|
125
|
+
self.maxiter = maxiter
|
|
126
|
+
self.dimensions = {}
|
|
127
|
+
self.name = name
|
|
128
|
+
self.level = level
|
|
129
|
+
self.kwds = kwds
|
|
130
|
+
self.minimize = minimize
|
|
131
|
+
|
|
132
|
+
def create(self):
|
|
133
|
+
return self.method(list(self.dimensions.values()), **self.kwds)
|
|
134
|
+
|
|
135
|
+
def Categorical(self,
|
|
136
|
+
categories,
|
|
137
|
+
prior=None,
|
|
138
|
+
transform=None,
|
|
139
|
+
name=None) -> OptimizeSpace:
|
|
140
|
+
return OptimizeSpace(self,
|
|
141
|
+
Categorical(categories, prior, transform, name))
|
|
142
|
+
|
|
143
|
+
def Integer(self,
|
|
144
|
+
low,
|
|
145
|
+
high,
|
|
146
|
+
prior="uniform",
|
|
147
|
+
base=10,
|
|
148
|
+
transform=None,
|
|
149
|
+
name=None,
|
|
150
|
+
dtype=np.int64) -> OptimizeSpace:
|
|
151
|
+
return OptimizeSpace(
|
|
152
|
+
self, Integer(low, high, prior, base, transform, name, dtype))
|
|
153
|
+
|
|
154
|
+
def Real(self,
|
|
155
|
+
low,
|
|
156
|
+
high,
|
|
157
|
+
prior="uniform",
|
|
158
|
+
base=10,
|
|
159
|
+
transform=None,
|
|
160
|
+
name=None,
|
|
161
|
+
dtype=float) -> OptimizeSpace:
|
|
162
|
+
return OptimizeSpace(
|
|
163
|
+
self, Real(low, high, prior, base, transform, name, dtype))
|
|
164
|
+
|
|
165
|
+
def __getstate__(self) -> dict:
|
|
166
|
+
state = self.__dict__.copy()
|
|
167
|
+
del state['scanner']
|
|
168
|
+
return state
|
|
169
|
+
|
|
170
|
+
def __setstate__(self, state: dict) -> None:
|
|
171
|
+
self.__dict__.update(state)
|
|
172
|
+
self.scanner = None
|
qulab/scan/utils.py
CHANGED
|
@@ -1,11 +1,59 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import asyncio
|
|
3
3
|
import inspect
|
|
4
|
+
import warnings
|
|
4
5
|
from typing import Any, Callable
|
|
5
6
|
|
|
7
|
+
import dill
|
|
8
|
+
|
|
6
9
|
from .expression import Env, Expression
|
|
7
10
|
|
|
8
11
|
|
|
12
|
+
class Unpicklable:
|
|
13
|
+
|
|
14
|
+
def __init__(self, obj):
|
|
15
|
+
self.type = str(type(obj))
|
|
16
|
+
self.id = id(obj)
|
|
17
|
+
|
|
18
|
+
def __repr__(self):
|
|
19
|
+
return f'<Unpicklable: {self.type} at 0x{id(self):x}>'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TooLarge:
|
|
23
|
+
|
|
24
|
+
def __init__(self, obj):
|
|
25
|
+
self.type = str(type(obj))
|
|
26
|
+
self.id = id(obj)
|
|
27
|
+
|
|
28
|
+
def __repr__(self):
|
|
29
|
+
return f'<TooLarge: {self.type} at 0x{id(self):x}>'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def dump_globals(ns=None, *, size_limit=10 * 1024 * 1024, warn=False):
|
|
33
|
+
import __main__
|
|
34
|
+
|
|
35
|
+
if ns is None:
|
|
36
|
+
ns = __main__.__dict__
|
|
37
|
+
|
|
38
|
+
namespace = {}
|
|
39
|
+
|
|
40
|
+
for name, value in ns.items():
|
|
41
|
+
try:
|
|
42
|
+
buf = dill.dumps(value)
|
|
43
|
+
except:
|
|
44
|
+
namespace[name] = Unpicklable(value)
|
|
45
|
+
if warn:
|
|
46
|
+
warnings.warn(f'Unpicklable: {name} {type(value)}')
|
|
47
|
+
if len(buf) > size_limit:
|
|
48
|
+
namespace[name] = TooLarge(value)
|
|
49
|
+
if warn:
|
|
50
|
+
warnings.warn(f'TooLarge: {name} {type(value)}')
|
|
51
|
+
else:
|
|
52
|
+
namespace[name] = buf
|
|
53
|
+
|
|
54
|
+
return namespace
|
|
55
|
+
|
|
56
|
+
|
|
9
57
|
def is_valid_identifier(s: str) -> bool:
|
|
10
58
|
"""
|
|
11
59
|
Check if a string is a valid identifier.
|
qulab/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.1.
|
|
1
|
+
__version__ = "2.1.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|