prefab 1.4.1__py3-none-any.whl → 1.5.0__py3-none-any.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.
- prefab/__init__.py +1 -1
- prefab/__main__.py +2 -2
- prefab/predict.py +82 -89
- {prefab-1.4.1.dist-info → prefab-1.5.0.dist-info}/METADATA +2 -6
- {prefab-1.4.1.dist-info → prefab-1.5.0.dist-info}/RECORD +8 -8
- {prefab-1.4.1.dist-info → prefab-1.5.0.dist-info}/WHEEL +0 -0
- {prefab-1.4.1.dist-info → prefab-1.5.0.dist-info}/entry_points.txt +0 -0
- {prefab-1.4.1.dist-info → prefab-1.5.0.dist-info}/licenses/LICENSE +0 -0
prefab/__init__.py
CHANGED
prefab/__main__.py
CHANGED
|
@@ -18,8 +18,8 @@ def store_jwt(jwt, refresh_token):
|
|
|
18
18
|
print(
|
|
19
19
|
f"Token successfully stored in {prefab_file_path}.\n\n"
|
|
20
20
|
"🎉 Welcome to PreFab.\n"
|
|
21
|
-
"See our examples at https://docs.prefabphotonics.com
|
|
22
|
-
"Reach out to us at
|
|
21
|
+
"See our examples at https://docs.prefabphotonics.com to start.\n"
|
|
22
|
+
"Reach out to us at support@prefabphotonics.com for support."
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
prefab/predict.py
CHANGED
|
@@ -3,9 +3,9 @@ Serverless prediction interface for nanofabrication modeling.
|
|
|
3
3
|
|
|
4
4
|
This module provides functions for predicting nanofabrication outcomes using machine
|
|
5
5
|
learning models hosted on a serverless platform. It supports multiple input formats
|
|
6
|
-
(ndarrays, polygons, GDSII files) and model types (prediction
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
(ndarrays, polygons, GDSII files) and model types (prediction and correction). Gradient
|
|
7
|
+
computation is available for inverse design applications using automatic
|
|
8
|
+
differentiation.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import base64
|
|
@@ -26,8 +26,17 @@ from PIL import Image
|
|
|
26
26
|
from .geometry import binarize_hard
|
|
27
27
|
from .models import Model
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
BASE_URL = "https://prefab-photonics"
|
|
30
|
+
|
|
31
|
+
# Endpoint versions
|
|
32
|
+
PREDICT_VERSION = "3"
|
|
33
|
+
PREDICT_POLY_VERSION = "3"
|
|
34
|
+
VJP_VERSION = "3"
|
|
35
|
+
|
|
36
|
+
# Endpoint URLs
|
|
37
|
+
PREDICT_ENDPOINT = f"{BASE_URL}--predict-v{PREDICT_VERSION}.modal.run"
|
|
38
|
+
PREDICT_POLY_ENDPOINT = f"{BASE_URL}--predict-poly-v{PREDICT_POLY_VERSION}.modal.run"
|
|
39
|
+
VJP_ENDPOINT = f"{BASE_URL}--vjp-v{VJP_VERSION}.modal.run"
|
|
31
40
|
|
|
32
41
|
|
|
33
42
|
def predict_array(
|
|
@@ -75,7 +84,7 @@ def predict_array(
|
|
|
75
84
|
ValueError
|
|
76
85
|
If the server returns an error or invalid response.
|
|
77
86
|
"""
|
|
78
|
-
endpoint_url =
|
|
87
|
+
endpoint_url = PREDICT_ENDPOINT
|
|
79
88
|
predict_data = {
|
|
80
89
|
"device_array": _encode_array(np.squeeze(device_array)),
|
|
81
90
|
"model": model.to_json(),
|
|
@@ -167,7 +176,7 @@ def _predict_poly(
|
|
|
167
176
|
"eta": eta,
|
|
168
177
|
}
|
|
169
178
|
|
|
170
|
-
endpoint_url =
|
|
179
|
+
endpoint_url = PREDICT_POLY_ENDPOINT
|
|
171
180
|
headers = _prepare_headers()
|
|
172
181
|
|
|
173
182
|
try:
|
|
@@ -364,47 +373,28 @@ def predict_gdstk(
|
|
|
364
373
|
return result_cell
|
|
365
374
|
|
|
366
375
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
) -> tuple[npt.NDArray[Any], npt.NDArray[Any]]:
|
|
370
|
-
"""
|
|
371
|
-
Predict the nanofabrication outcome of a device array and compute its gradient.
|
|
376
|
+
# Storage for caching prediction results for VJP computation
|
|
377
|
+
_diff_cache: dict[int, tuple[npt.NDArray[Any], Model]] = {}
|
|
372
378
|
|
|
373
|
-
This function predicts the outcome of the nanofabrication process for a given
|
|
374
|
-
device array using a specified model. It also computes the gradient of the
|
|
375
|
-
prediction with respect to the input device array.
|
|
376
|
-
|
|
377
|
-
Parameters
|
|
378
|
-
----------
|
|
379
|
-
device_array : np.ndarray
|
|
380
|
-
A 2D array representing the planar geometry of the device.
|
|
381
|
-
model : Model
|
|
382
|
-
The model to use for prediction, representing a specific fabrication process.
|
|
383
|
-
|
|
384
|
-
Returns
|
|
385
|
-
-------
|
|
386
|
-
tuple[np.ndarray, np.ndarray]
|
|
387
|
-
The predicted output array and gradient array.
|
|
388
379
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
"""
|
|
380
|
+
def _compute_vjp(
|
|
381
|
+
device_array: npt.NDArray[Any],
|
|
382
|
+
upstream_gradient: npt.NDArray[Any],
|
|
383
|
+
model: Model,
|
|
384
|
+
) -> npt.NDArray[Any]:
|
|
385
|
+
"""Compute J.T @ upstream_gradient via the server-side VJP endpoint."""
|
|
396
386
|
headers = _prepare_headers()
|
|
397
|
-
|
|
387
|
+
vjp_data = {
|
|
398
388
|
"device_array": _encode_array(np.squeeze(device_array)),
|
|
389
|
+
"upstream_gradient": _encode_array(np.squeeze(upstream_gradient)),
|
|
399
390
|
"model": model.to_json(),
|
|
400
391
|
"model_type": "p",
|
|
401
|
-
"binary": False,
|
|
402
392
|
}
|
|
403
|
-
endpoint_url =
|
|
393
|
+
endpoint_url = VJP_ENDPOINT
|
|
404
394
|
|
|
405
395
|
try:
|
|
406
396
|
response = requests.post(
|
|
407
|
-
endpoint_url, data=json.dumps(
|
|
397
|
+
endpoint_url, data=json.dumps(vjp_data), headers=headers
|
|
408
398
|
)
|
|
409
399
|
response.raise_for_status()
|
|
410
400
|
|
|
@@ -414,89 +404,87 @@ def _predict_array_with_grad(
|
|
|
414
404
|
response_data = response.json()
|
|
415
405
|
|
|
416
406
|
if "error" in response_data:
|
|
417
|
-
raise ValueError(f"
|
|
407
|
+
raise ValueError(f"VJP error: {response_data['error']}")
|
|
418
408
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return (prediction_array, gradient_array)
|
|
409
|
+
vjp_array = _decode_array(response_data["vjp_array"])
|
|
410
|
+
vjp_min = response_data["vjp_min"]
|
|
411
|
+
vjp_max = response_data["vjp_max"]
|
|
412
|
+
vjp_range = vjp_max - vjp_min
|
|
413
|
+
vjp_array = vjp_array * vjp_range + vjp_min
|
|
414
|
+
return vjp_array
|
|
426
415
|
|
|
427
416
|
except requests.exceptions.RequestException as e:
|
|
428
|
-
raise RuntimeError(f"
|
|
417
|
+
raise RuntimeError(f"VJP request failed: {e}") from e
|
|
429
418
|
except json.JSONDecodeError as e:
|
|
430
419
|
raise ValueError(f"JSON decode error: {e}") from e
|
|
431
420
|
|
|
432
421
|
|
|
433
422
|
@primitive
|
|
434
|
-
def
|
|
423
|
+
def predict_array_diff(
|
|
435
424
|
device_array: npt.NDArray[Any], model: Model
|
|
436
425
|
) -> npt.NDArray[Any]:
|
|
437
426
|
"""
|
|
438
|
-
|
|
427
|
+
Differentiable fab prediction with exact gradient support.
|
|
439
428
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
prediction with respect to the input device array, making it suitable for use in
|
|
443
|
-
automatic differentiation applications (e.g., autograd).
|
|
429
|
+
Compatible with autograd for automatic differentiation. Gradients are computed via
|
|
430
|
+
a server-side VJP endpoint during the backward pass.
|
|
444
431
|
|
|
445
432
|
Parameters
|
|
446
433
|
----------
|
|
447
434
|
device_array : np.ndarray
|
|
448
435
|
A 2D array representing the planar geometry of the device.
|
|
449
436
|
model : Model
|
|
450
|
-
The model to use for prediction
|
|
437
|
+
The model to use for prediction.
|
|
451
438
|
|
|
452
439
|
Returns
|
|
453
440
|
-------
|
|
454
441
|
np.ndarray
|
|
455
|
-
The predicted
|
|
456
|
-
|
|
457
|
-
Raises
|
|
458
|
-
------
|
|
459
|
-
RuntimeError
|
|
460
|
-
If the request to the prediction service fails.
|
|
461
|
-
ValueError
|
|
462
|
-
If the server returns an error or invalid response.
|
|
442
|
+
The predicted fabrication outcome array.
|
|
463
443
|
"""
|
|
464
|
-
|
|
465
|
-
|
|
444
|
+
# Use standard forward pass
|
|
445
|
+
prediction_array = predict_array(
|
|
446
|
+
device_array=device_array,
|
|
447
|
+
model=model,
|
|
448
|
+
model_type="p",
|
|
449
|
+
binarize=False,
|
|
466
450
|
)
|
|
467
|
-
|
|
451
|
+
|
|
452
|
+
# Cache the input for VJP computation during backward pass
|
|
453
|
+
_diff_cache[id(prediction_array)] = (device_array.copy(), model)
|
|
454
|
+
|
|
468
455
|
return prediction_array
|
|
469
456
|
|
|
470
457
|
|
|
471
|
-
def
|
|
472
|
-
ans: npt.NDArray[Any], device_array: npt.NDArray[Any],
|
|
458
|
+
def _predict_array_diff_vjp(
|
|
459
|
+
ans: npt.NDArray[Any], device_array: npt.NDArray[Any], model: Model
|
|
473
460
|
) -> Any:
|
|
474
|
-
"""
|
|
475
|
-
|
|
461
|
+
"""Define the exact VJP for predict_array_diff using server-side computation."""
|
|
462
|
+
cache_key = id(ans)
|
|
463
|
+
cached_device_array, cached_model = _diff_cache.get(
|
|
464
|
+
cache_key, (device_array, model)
|
|
465
|
+
)
|
|
476
466
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
467
|
+
def vjp(g: npt.NDArray[Any]) -> tuple[npt.NDArray[Any], None]:
|
|
468
|
+
# Compute exact VJP: J.T @ g via server endpoint
|
|
469
|
+
vjp_result = _compute_vjp(
|
|
470
|
+
device_array=cached_device_array,
|
|
471
|
+
upstream_gradient=g,
|
|
472
|
+
model=cached_model,
|
|
473
|
+
)
|
|
474
|
+
# Clean up cache
|
|
475
|
+
_diff_cache.pop(cache_key, None)
|
|
476
|
+
# Return gradient for device_array, None for model (not differentiable)
|
|
477
|
+
return (vjp_result, None)
|
|
485
478
|
|
|
486
|
-
|
|
487
|
-
-------
|
|
488
|
-
function
|
|
489
|
-
A function that computes the VJP given an upstream gradient `g`.
|
|
490
|
-
"""
|
|
491
|
-
grad_x = predict_array_with_grad.gradient_array # pyright: ignore[reportFunctionMemberAccess]
|
|
479
|
+
return vjp
|
|
492
480
|
|
|
493
|
-
def vjp(g: npt.NDArray[Any]) -> npt.NDArray[Any]:
|
|
494
|
-
return g * grad_x # type: ignore[no-any-return]
|
|
495
481
|
|
|
496
|
-
|
|
482
|
+
defvjp(predict_array_diff, _predict_array_diff_vjp)
|
|
497
483
|
|
|
498
484
|
|
|
499
|
-
|
|
485
|
+
# Alias for backward compatibility with existing code
|
|
486
|
+
predict_array_with_grad = predict_array_diff
|
|
487
|
+
"""Alias for predict_array_diff. Deprecated, use predict_array_diff directly."""
|
|
500
488
|
|
|
501
489
|
|
|
502
490
|
def _encode_array(array: npt.NDArray[Any]) -> str:
|
|
@@ -517,6 +505,12 @@ def _decode_array(encoded_png: str) -> npt.NDArray[Any]:
|
|
|
517
505
|
|
|
518
506
|
def _prepare_headers() -> dict[str, str]:
|
|
519
507
|
"""Prepare HTTP headers for a server request."""
|
|
508
|
+
# Check for API key first (for headless/server environments)
|
|
509
|
+
api_key = os.environ.get("PREFAB_API_KEY")
|
|
510
|
+
if api_key:
|
|
511
|
+
return {"X-API-Key": api_key}
|
|
512
|
+
|
|
513
|
+
# Fall back to token file (browser OAuth flow)
|
|
520
514
|
token_file_path = os.path.expanduser("~/.prefab.toml")
|
|
521
515
|
try:
|
|
522
516
|
with open(token_file_path) as file:
|
|
@@ -532,7 +526,6 @@ def _prepare_headers() -> dict[str, str]:
|
|
|
532
526
|
except FileNotFoundError:
|
|
533
527
|
raise FileNotFoundError(
|
|
534
528
|
"Could not validate user.\n"
|
|
535
|
-
+ "
|
|
536
|
-
+ "Signup/login and generate a new token.\n"
|
|
529
|
+
+ "Set PREFAB_API_KEY environment variable, or run 'prefab setup'.\n"
|
|
537
530
|
+ "See https://docs.prefabphotonics.com/."
|
|
538
531
|
) from None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: prefab
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: Artificial nanofabrication of integrated photonic circuits using deep learning
|
|
5
5
|
Project-URL: Homepage, https://prefabphotonics.com
|
|
6
6
|
Project-URL: Repository, https://github.com/PreFab-Photonics/PreFab
|
|
@@ -511,14 +511,13 @@ License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
|
511
511
|
|
|
512
512
|
That's all there is to it!
|
|
513
513
|
License-File: LICENSE
|
|
514
|
-
Keywords:
|
|
514
|
+
Keywords: electronic-design-automation,integrated-photonics,inverse-design,lithography,nanofabrication,photonics,semiconductor-manufacturing,silicon-photonics
|
|
515
515
|
Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)
|
|
516
516
|
Classifier: Operating System :: OS Independent
|
|
517
517
|
Classifier: Programming Language :: Python :: 3
|
|
518
518
|
Requires-Python: >=3.9
|
|
519
519
|
Requires-Dist: autograd
|
|
520
520
|
Requires-Dist: gdstk>=0.9.55
|
|
521
|
-
Requires-Dist: ipykernel>=6.31.0
|
|
522
521
|
Requires-Dist: matplotlib
|
|
523
522
|
Requires-Dist: numpy
|
|
524
523
|
Requires-Dist: opencv-python-headless
|
|
@@ -528,9 +527,6 @@ Requires-Dist: requests
|
|
|
528
527
|
Requires-Dist: scikit-image
|
|
529
528
|
Requires-Dist: scipy
|
|
530
529
|
Requires-Dist: toml
|
|
531
|
-
Provides-Extra: dev
|
|
532
|
-
Requires-Dist: jupyter; extra == 'dev'
|
|
533
|
-
Requires-Dist: jupyterlab; extra == 'dev'
|
|
534
530
|
Provides-Extra: docs
|
|
535
531
|
Requires-Dist: mkdocs; extra == 'docs'
|
|
536
532
|
Requires-Dist: mkdocs-material; extra == 'docs'
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
prefab/__init__.py,sha256=
|
|
2
|
-
prefab/__main__.py,sha256=
|
|
1
|
+
prefab/__init__.py,sha256=shfnU_-iDY4MavJaXVb-Xzr9Y7w2_9zhShi4INgEPg4,425
|
|
2
|
+
prefab/__main__.py,sha256=uL6AdCeimPbXiWv0gnq9TDeZhAIrxGwJsEKNYbg9MZg,3454
|
|
3
3
|
prefab/compare.py,sha256=aX7nr9tznSebYeeztvqIPz57npnJ4-iUeKEedrZdksE,3676
|
|
4
4
|
prefab/device.py,sha256=1O6vTOq4wQRGVYvFWLH0uj1XhhYCfnDnIapDEYnBKHw,47996
|
|
5
5
|
prefab/geometry.py,sha256=-nTaGjdw3KN1SVoyvqdcrE2GJP7OqPF6ivUhrO78rUk,11244
|
|
6
|
-
prefab/predict.py,sha256=
|
|
6
|
+
prefab/predict.py,sha256=xEpzyS8uRMZFohBlTGmL90LmVsIn_41ZN7RRhwsw7Ww,18413
|
|
7
7
|
prefab/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
prefab/read.py,sha256=5BmvFemobA72urxs4j2VZRVvanZZGu1mDB1Uh-epyvI,8635
|
|
9
9
|
prefab/shapes.py,sha256=mRGwsPS-A9XsW3jgvUuMCEeNv9BLXsEnJkytlIHUAKE,28802
|
|
10
10
|
prefab/models/__init__.py,sha256=rRrjcOcHPcob98Coksc0tbvYcXbm6SoLEb-Md233Jvo,1391
|
|
11
11
|
prefab/models/base.py,sha256=t4VNMsOztPedj3kN5fZ1-4tk0SRHWrMuqnIVHztsCs4,1514
|
|
12
12
|
prefab/models/evaluation.py,sha256=2_Klui6tY8xPvOSVD8VpZCVAnT1RX15FONqWG-_x-J8,484
|
|
13
|
-
prefab-1.
|
|
14
|
-
prefab-1.
|
|
15
|
-
prefab-1.
|
|
16
|
-
prefab-1.
|
|
17
|
-
prefab-1.
|
|
13
|
+
prefab-1.5.0.dist-info/METADATA,sha256=f8778_o8nPf4DIewUWqsK_2VfImxJish5I390Y9mtww,33754
|
|
14
|
+
prefab-1.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
prefab-1.5.0.dist-info/entry_points.txt,sha256=h1_A9O9F3NAIoKXD1RPb3Eo-WCSiHhMB_AnagBi6XTQ,48
|
|
16
|
+
prefab-1.5.0.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
17
|
+
prefab-1.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|