mplang-nightly 0.1.dev330__tar.gz → 0.1.dev332__tar.gz

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.
Files changed (240) hide show
  1. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/PKG-INFO +1 -1
  2. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/mem.py +71 -65
  3. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/__init__.py +5 -0
  4. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/comm_context.py +16 -6
  5. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/http.py +35 -35
  6. mplang_nightly-0.1.dev332/mplang/backends/simp_worker/infra.py +108 -0
  7. mplang_nightly-0.1.dev332/mplang/backends/simp_worker/request.py +80 -0
  8. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/spu_state.py +70 -20
  9. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/runtime/interpreter.py +63 -178
  10. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_comm_context.py +14 -0
  11. mplang_nightly-0.1.dev332/tests/backends/simp_worker/test_request_isolation.py +182 -0
  12. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/.gitignore +0 -0
  13. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/LICENSE +0 -0
  14. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/README.md +0 -0
  15. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/examples/.gitkeep +0 -0
  16. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/hatch_build.py +0 -0
  17. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/__init__.py +0 -0
  18. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/__init__.py +0 -0
  19. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/bfv_impl.py +0 -0
  20. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/channel.py +0 -0
  21. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/crypto_impl.py +0 -0
  22. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/field_impl.py +0 -0
  23. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/func_impl.py +0 -0
  24. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/phe_impl.py +0 -0
  25. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_design.md +0 -0
  26. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/__init__.py +0 -0
  27. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/http.py +0 -0
  28. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/ops.py +0 -0
  29. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/state.py +0 -0
  30. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_driver/values.py +0 -0
  31. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/base.py +0 -0
  32. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/collective_algorithms.py +0 -0
  33. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/collectives.py +0 -0
  34. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/mem.py +0 -0
  35. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/ops.py +0 -0
  36. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/simp_worker/state.py +0 -0
  37. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/spu_impl.py +0 -0
  38. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/store_impl.py +0 -0
  39. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/table_impl.py +0 -0
  40. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/tee_impl.py +0 -0
  41. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/tensor_impl.py +0 -0
  42. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/backends/util.py +0 -0
  43. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/cli.py +0 -0
  44. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/cli_guide.md +0 -0
  45. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/__init__.py +0 -0
  46. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/_jax_utils.py +0 -0
  47. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/bfv.py +0 -0
  48. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/crypto.py +0 -0
  49. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/dtypes.py +0 -0
  50. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/field.py +0 -0
  51. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/func.py +0 -0
  52. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/phe.py +0 -0
  53. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/simp.py +0 -0
  54. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/spu.py +0 -0
  55. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/store.py +0 -0
  56. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/table.py +0 -0
  57. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/tee.py +0 -0
  58. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/dialects/tensor.py +0 -0
  59. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/README.md +0 -0
  60. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/__init__.py +0 -0
  61. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/context.py +0 -0
  62. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/graph.py +0 -0
  63. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/object.py +0 -0
  64. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/primitive.py +0 -0
  65. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/printer.py +0 -0
  66. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/program.py +0 -0
  67. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/registry.py +0 -0
  68. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/serde.py +0 -0
  69. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/tracer.py +0 -0
  70. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/edsl/typing.py +0 -0
  71. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/extend/__init__.py +0 -0
  72. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/extend/arrow/__init__.py +0 -0
  73. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/extend/arrow/compute.py +0 -0
  74. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/extend/arrow/util.py +0 -0
  75. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/extend/arrow/vector.py +0 -0
  76. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/Makefile +0 -0
  77. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/__init__.py +0 -0
  78. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/gf128.cpp +0 -0
  79. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/ldpc.cpp +0 -0
  80. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/okvs.cpp +0 -0
  81. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/okvs_opt.cpp +0 -0
  82. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/kernels/py_kernels.py +0 -0
  83. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/collective.py +0 -0
  84. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/device/__init__.py +0 -0
  85. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/device/api.py +0 -0
  86. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/device/cluster.py +0 -0
  87. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/ml/__init__.py +0 -0
  88. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/ml/sgb.py +0 -0
  89. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/__init__.py +0 -0
  90. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/_utils.py +0 -0
  91. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/analytics/__init__.py +0 -0
  92. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/analytics/aggregation.py +0 -0
  93. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/analytics/groupby.md +0 -0
  94. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/analytics/groupby.py +0 -0
  95. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/analytics/permutation.py +0 -0
  96. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/common/constants.py +0 -0
  97. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/ot/__init__.py +0 -0
  98. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/ot/base.py +0 -0
  99. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/ot/extension.py +0 -0
  100. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/ot/silent.py +0 -0
  101. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/__init__.py +0 -0
  102. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/cuckoo.py +0 -0
  103. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/okvs.py +0 -0
  104. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/okvs_gct.py +0 -0
  105. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/oprf.py +0 -0
  106. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/rr22.py +0 -0
  107. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/psi/unbalanced.py +0 -0
  108. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/vole/__init__.py +0 -0
  109. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/vole/gilboa.py +0 -0
  110. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/vole/ldpc.py +0 -0
  111. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/libs/mpc/vole/silver.py +0 -0
  112. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/py.typed +0 -0
  113. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/runtime/__init__.py +0 -0
  114. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/runtime/dialect_state.py +0 -0
  115. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/runtime/object_store.py +0 -0
  116. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/runtime/value.py +0 -0
  117. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/tool/__init__.py +0 -0
  118. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/tool/program.py +0 -0
  119. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/utils/__init__.py +0 -0
  120. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/utils/func_utils.py +0 -0
  121. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/mplang/utils/logging.py +0 -0
  122. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/pyproject.toml +0 -0
  123. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/__init__.py +0 -0
  124. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/__init__.py +0 -0
  125. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_driver/__init__.py +0 -0
  126. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_driver/test_http.py +0 -0
  127. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/__init__.py +0 -0
  128. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_async_exec.py +0 -0
  129. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_base.py +0 -0
  130. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_collectives.py +0 -0
  131. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_http.py +0 -0
  132. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_http_communicator.py +0 -0
  133. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_mem.py +0 -0
  134. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/simp_worker/test_shuffle_exec_id_key.py +0 -0
  135. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_bfv_impl.py +0 -0
  136. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_channel.py +0 -0
  137. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_crypto_impl.py +0 -0
  138. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_okvs_binding.py +0 -0
  139. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_simp_integration.py +0 -0
  140. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_simp_object_store.py +0 -0
  141. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_spu_impl.py +0 -0
  142. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_table_impl.py +0 -0
  143. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_tee_impl.py +0 -0
  144. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_tensor_impl.py +0 -0
  145. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_util.py +0 -0
  146. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/backends/test_verify_clean.py +0 -0
  147. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/conftest.py +0 -0
  148. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/__init__.py +0 -0
  149. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_bfv.py +0 -0
  150. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_compile_context.py +0 -0
  151. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_crypto.py +0 -0
  152. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_dtypes.py +0 -0
  153. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_field.py +0 -0
  154. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_func.py +0 -0
  155. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_okvs.py +0 -0
  156. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_okvs_bench.py +0 -0
  157. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_phe.py +0 -0
  158. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_simp.py +0 -0
  159. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_simp_comm.py +0 -0
  160. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_spu.py +0 -0
  161. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_store.py +0 -0
  162. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_table.py +0 -0
  163. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_table_row_dimension.py +0 -0
  164. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_tee.py +0 -0
  165. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/dialects/test_tensor.py +0 -0
  166. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/__init__.py +0 -0
  167. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_compiled_program_artifact.py +0 -0
  168. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_context.py +0 -0
  169. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_graph.py +0 -0
  170. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_primitive.py +0 -0
  171. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_primitive_multi_output.py +0 -0
  172. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_printer.py +0 -0
  173. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_serde.py +0 -0
  174. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_tracer.py +0 -0
  175. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_typing.py +0 -0
  176. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/edsl/test_typing_graph_serde.py +0 -0
  177. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/extend/__init__.py +0 -0
  178. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/extend/test_arrow.py +0 -0
  179. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/__init__.py +0 -0
  180. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/conftest.py +0 -0
  181. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/test_device_api_errors.py +0 -0
  182. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/test_device_dialects.py +0 -0
  183. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/test_device_layouts.py +0 -0
  184. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/device/test_device_tee.py +0 -0
  185. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/ml/__init__.py +0 -0
  186. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/ml/test_sgb.py +0 -0
  187. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/ml/test_sgb_bench.py +0 -0
  188. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/__init__.py +0 -0
  189. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/analytics/__init__.py +0 -0
  190. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/analytics/test_aggregation.py +0 -0
  191. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/analytics/test_groupby.py +0 -0
  192. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/analytics/test_permutation.py +0 -0
  193. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/ot/__init__.py +0 -0
  194. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/ot/test_ot.py +0 -0
  195. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/ot/test_ot_extension.py +0 -0
  196. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/ot/test_silent_ot.py +0 -0
  197. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/__init__.py +0 -0
  198. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/test_okvs_gct.py +0 -0
  199. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/test_oprf.py +0 -0
  200. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/test_psi.py +0 -0
  201. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/test_psi_bench.py +0 -0
  202. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/test_rr22.py +0 -0
  203. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/psi/verify_psi_okvs_logic.py +0 -0
  204. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/test_field_gf128.py +0 -0
  205. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/test_utils.py +0 -0
  206. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/__init__.py +0 -0
  207. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/test_gilboa_manual.py +0 -0
  208. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/test_ldpc.py +0 -0
  209. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/test_silver_vole.py +0 -0
  210. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/test_vole.py +0 -0
  211. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/test_vole_bench.py +0 -0
  212. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/mpc/vole/verify_vole_logic.py +0 -0
  213. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/test_collective.py +0 -0
  214. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/libs/test_simple_guide.py +0 -0
  215. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/runtime/test_interpreter_async.py +0 -0
  216. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/runtime/test_object_store.py +0 -0
  217. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/runtime/test_object_store_fs.py +0 -0
  218. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/runtime/test_value_gc.py +0 -0
  219. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/test_fetch_semantics.py +0 -0
  220. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/test_pytree_io.py +0 -0
  221. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/utils/__init__.py +0 -0
  222. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/utils/tensor_patch.py +0 -0
  223. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/utils/test_func_utils.py +0 -0
  224. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tests/utils/test_logging.py +0 -0
  225. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/00_device_basics.py +0 -0
  226. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/01_function_decorator.py +0 -0
  227. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/02_simulation_and_driver.py +0 -0
  228. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/03_run_jax.py +0 -0
  229. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/04_ir_dump_and_analysis.py +0 -0
  230. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/05_run_sql.py +0 -0
  231. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/06_pipeline.py +0 -0
  232. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/07_stax_nn.py +0 -0
  233. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/08_logging.py +0 -0
  234. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/MIGRATION.md +0 -0
  235. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/README.md +0 -0
  236. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/__init__.py +0 -0
  237. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/data/alice.csv +0 -0
  238. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/data/bob.csv +0 -0
  239. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/data/prepare_vertical_iris.py +0 -0
  240. {mplang_nightly-0.1.dev330 → mplang_nightly-0.1.dev332}/tutorials/run.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mplang-nightly
3
- Version: 0.1.dev330
3
+ Version: 0.1.dev332
4
4
  Summary: Multi-Party Programming Language
5
5
  Author-email: SecretFlow Team <secretflow-contact@service.alipay.com>
6
6
  License: Apache License
@@ -23,9 +23,10 @@ from collections.abc import Callable
23
23
  from typing import TYPE_CHECKING, Any, cast
24
24
 
25
25
  from mplang.backends.simp_driver.state import SimpDriver
26
- from mplang.backends.simp_worker import WORKER_HANDLERS, SimpWorker
27
- from mplang.backends.simp_worker.comm_context import CommContext
26
+ from mplang.backends.simp_worker import WORKER_HANDLERS
27
+ from mplang.backends.simp_worker.infra import DEFAULT_ASYNC_OPS, WorkerInfra
28
28
  from mplang.backends.simp_worker.mem import LocalMesh
29
+ from mplang.backends.simp_worker.request import create_request_interpreter
29
30
  from mplang.runtime.interpreter import ExecutionTracer, Interpreter
30
31
  from mplang.runtime.object_store import FileSystemBackend, ObjectStore
31
32
 
@@ -37,10 +38,14 @@ if TYPE_CHECKING:
37
38
 
38
39
 
39
40
  class MemCluster:
40
- """Orchestrator that creates and manages local worker Interpreters.
41
+ """Orchestrator that creates and manages local worker infrastructure.
41
42
 
42
43
  This class handles worker lifecycle management. It does NOT attach to
43
44
  an Interpreter - instead, it creates a SimpMemDriver that can be attached.
45
+
46
+ Per-request Interpreters are created on-the-fly by ``create_request_interpreter``
47
+ to isolate mutable state (CommContext, SimpWorker, SPUState) across concurrent
48
+ requests.
44
49
  """
45
50
 
46
51
  def __init__(
@@ -75,8 +80,9 @@ class MemCluster:
75
80
  )
76
81
  self.tracer.start()
77
82
 
78
- # Create Workers
79
- self._workers: list[Interpreter] = []
83
+ # Create shared WorkerInfra per rank (replaces per-rank Interpreters)
84
+ self._infras: list[WorkerInfra] = []
85
+ self._stores: list[ObjectStore] = []
80
86
  for rank in range(world_size):
81
87
  worker_root = cluster_root / f"node{rank}"
82
88
  store = ObjectStore(
@@ -84,60 +90,50 @@ class MemCluster:
84
90
  root_path=str(worker_root / "store"),
85
91
  )
86
92
  )
93
+ self._stores.append(store)
87
94
 
88
- worker_state = SimpWorker(
95
+ w_handlers: dict[str, Callable[..., Any]] = {**WORKER_HANDLERS} # type: ignore[dict-item]
96
+ infra = WorkerInfra(
89
97
  rank=rank,
90
98
  world_size=world_size,
91
99
  communicator=self._mesh.comms[rank],
92
100
  store=store,
93
- )
94
-
95
- w_handlers: dict[str, Callable[..., Any]] = {**WORKER_HANDLERS} # type: ignore[dict-item]
96
- comm_ctx = CommContext(
97
- self._mesh.comms[rank],
98
- context_id="ctx",
99
- my_rank=rank,
100
- )
101
- w_interp = Interpreter(
102
- name=f"Worker-{rank}",
101
+ handlers=w_handlers,
103
102
  tracer=self.tracer,
104
103
  trace_pid=rank,
105
- store=store,
106
104
  root_dir=worker_root,
107
- handlers=w_handlers,
108
- comm_ctx=comm_ctx,
105
+ # async_ops has no effect when executor is None (MemCluster
106
+ # runs each request synchronously on the mesh executor thread).
107
+ # We still set it so that WorkerInfra carries the canonical set
108
+ # for introspection and consistency with the HTTP Worker path.
109
+ async_ops=DEFAULT_ASYNC_OPS,
109
110
  )
110
- w_interp.set_dialect_state("simp", worker_state)
111
-
112
- w_interp.async_ops = {
113
- "bfv.add",
114
- "bfv.mul",
115
- "bfv.rotate",
116
- "bfv.batch_encode",
117
- "bfv.relinearize",
118
- "bfv.encrypt",
119
- "bfv.decrypt",
120
- "field.solve_okvs",
121
- "field.decode_okvs",
122
- "field.aes_expand",
123
- "field.mul",
124
- "simp.shuffle",
125
- }
126
- self._workers.append(w_interp)
111
+ self._infras.append(infra)
127
112
 
128
113
  @property
129
114
  def world_size(self) -> int:
130
115
  return self._world_size
131
116
 
132
117
  @property
133
- def workers(self) -> list[Interpreter]:
134
- return self._workers
118
+ def infras(self) -> list[WorkerInfra]:
119
+ return self._infras
120
+
121
+ @property
122
+ def workers(self) -> list[WorkerInfra]:
123
+ """Backward-compatible alias for ``infras``.
124
+
125
+ .. note:: Returns ``WorkerInfra`` objects (not ``Interpreter``). Only
126
+ the ``.store`` attribute is guaranteed by this interface. Callers
127
+ needing full Interpreter access should use
128
+ ``create_request_interpreter(infra, job_id)`` instead.
129
+ """
130
+ return self._infras
135
131
 
136
132
  def create_state(self) -> SimpMemDriver:
137
133
  """Create a SimpMemDriver that can be attached to a Driver Interpreter."""
138
134
  return SimpMemDriver(
139
135
  world_size=self._world_size,
140
- workers=self._workers,
136
+ infras=self._infras,
141
137
  mesh=self._mesh,
142
138
  )
143
139
 
@@ -158,11 +154,11 @@ class SimpMemDriver(SimpDriver):
158
154
  def __init__(
159
155
  self,
160
156
  world_size: int,
161
- workers: list[Interpreter],
157
+ infras: list[WorkerInfra],
162
158
  mesh: Any, # LocalMesh from simp_worker.mem
163
159
  ) -> None:
164
160
  self._world_size = world_size
165
- self._workers = workers
161
+ self._infras = infras
166
162
  self._mesh = mesh
167
163
 
168
164
  def shutdown(self) -> None:
@@ -174,9 +170,18 @@ class SimpMemDriver(SimpDriver):
174
170
  return self._world_size
175
171
 
176
172
  @property
177
- def workers(self) -> list[Interpreter]:
178
- """Worker interpreters (for backward compatibility)."""
179
- return self._workers
173
+ def infras(self) -> list[WorkerInfra]:
174
+ """Worker infrastructure (shared, immutable)."""
175
+ return self._infras
176
+
177
+ @property
178
+ def workers(self) -> list[WorkerInfra]:
179
+ """Backward-compatible alias for ``infras``.
180
+
181
+ .. note:: Returns ``WorkerInfra`` objects (not ``Interpreter``). Only
182
+ the ``.store`` attribute is guaranteed by this interface.
183
+ """
184
+ return self._infras
180
185
 
181
186
  def submit(
182
187
  self, rank: int, graph: Graph, inputs: list[Any], job_id: str | None = None
@@ -205,31 +210,32 @@ class SimpMemDriver(SimpDriver):
205
210
 
206
211
  def fetch(self, rank: int, uri: str) -> Future[Any]:
207
212
  """Fetch directly from worker store."""
208
- worker = self._workers[rank]
209
- worker_ctx = cast(SimpWorker, worker.get_dialect_state("simp"))
210
- return self._mesh.executor.submit(lambda: worker_ctx.store.get(uri)) # type: ignore[no-any-return]
213
+ infra = self._infras[rank]
214
+ return self._mesh.executor.submit(lambda: infra.store.get(uri)) # type: ignore[no-any-return]
211
215
 
212
216
  def _run_worker(
213
217
  self, rank: int, graph: Graph, inputs: list[Any], job_id: str | None = None
214
218
  ) -> Any:
215
- """Execute on worker interpreter."""
216
- worker_interp = self._workers[rank]
217
- worker_ctx = cast(SimpWorker, worker_interp.get_dialect_state("simp"))
218
-
219
- # Resolve URI inputs (None means rank has no data)
220
- resolved_inputs = [
221
- worker_ctx.store.get(inp) if inp is not None else None for inp in inputs
222
- ]
223
-
224
- # Execute
225
- results = worker_interp.evaluate_graph(graph, resolved_inputs, job_id)
226
-
227
- # Store results (results is always a list)
228
- if not graph.outputs:
229
- return None
230
- return [
231
- worker_ctx.store.put(res) if res is not None else None for res in results
232
- ]
219
+ """Execute on a per-request Interpreter."""
220
+ infra = self._infras[rank]
221
+ request_interp = create_request_interpreter(infra, job_id or "anonymous")
222
+ try:
223
+ # Resolve URI inputs (None means rank has no data)
224
+ resolved_inputs = [
225
+ infra.store.get(inp) if inp is not None else None for inp in inputs
226
+ ]
227
+
228
+ # Execute
229
+ results = request_interp.evaluate_graph(graph, resolved_inputs, job_id)
230
+
231
+ # Store results (results is always a list)
232
+ if not graph.outputs:
233
+ return None
234
+ return [
235
+ infra.store.put(res) if res is not None else None for res in results
236
+ ]
237
+ finally:
238
+ request_interp.shutdown()
233
239
 
234
240
 
235
241
  def make_simulator(
@@ -38,11 +38,14 @@ from mplang.backends.simp_worker.http import (
38
38
  RecvTimeoutError,
39
39
  SendTimeoutError,
40
40
  )
41
+ from mplang.backends.simp_worker.infra import DEFAULT_ASYNC_OPS, WorkerInfra
41
42
  from mplang.backends.simp_worker.mem import LocalMesh, ThreadCommunicator
42
43
  from mplang.backends.simp_worker.ops import WORKER_HANDLERS
44
+ from mplang.backends.simp_worker.request import create_request_interpreter
43
45
  from mplang.backends.simp_worker.state import SimpWorker
44
46
 
45
47
  __all__ = [
48
+ "DEFAULT_ASYNC_OPS",
46
49
  "WORKER_HANDLERS",
47
50
  "CommConfig",
48
51
  "CommStats",
@@ -56,6 +59,8 @@ __all__ = [
56
59
  "SendTimeoutError",
57
60
  "SimpWorker",
58
61
  "ThreadCommunicator",
62
+ "WorkerInfra",
63
+ "create_request_interpreter",
59
64
  "testall",
60
65
  "testany",
61
66
  "wait_all",
@@ -62,15 +62,25 @@ class CommContext:
62
62
  def world_size(self) -> int:
63
63
  return self._comm.world_size
64
64
 
65
- def spawn(self) -> CommContext:
65
+ def spawn(self, suffix: str | None = None) -> CommContext:
66
66
  """Create a child context with independent counter namespace.
67
67
 
68
- Child ``context_id = f"{parent_id}.{spawn_seq}"``. ``spawn_seq``
69
- increments in the calling thread's order, so if all ranks call
70
- ``spawn()`` in the same program-order position, children get matching
71
- IDs across ranks.
68
+ Args:
69
+ suffix: Explicit suffix for the child context ID. When provided,
70
+ ``context_id = f"{parent_id}.{suffix}"``. This is used when
71
+ the caller needs a deterministic, content-based ID that is
72
+ stable across ranks regardless of call order (e.g. the async
73
+ DAG scheduler uses ``f"{graph_exec_key}.{op_idx}"``).
74
+
75
+ When *None* (default), an auto-incrementing counter is used:
76
+ ``context_id = f"{parent_id}.{spawn_seq}"``. This is suitable
77
+ for SPMD code where all ranks call ``spawn()`` in the same
78
+ program-order position.
72
79
  """
73
- child_id = f"{self._id}.{self._spawn_counter}"
80
+ if suffix is None:
81
+ child_id = f"{self._id}.{self._spawn_counter}"
82
+ else:
83
+ child_id = f"{self._id}.{self._spawn_counter}.{suffix}"
74
84
  self._spawn_counter += 1
75
85
  return CommContext(self._comm, child_id, self._rank)
76
86
 
@@ -61,10 +61,10 @@ from mplang.backends.simp_worker.base import (
61
61
  wait_all,
62
62
  wait_any,
63
63
  )
64
- from mplang.backends.simp_worker.state import SimpWorker
64
+ from mplang.backends.simp_worker.infra import WorkerInfra
65
65
  from mplang.edsl import serde
66
66
  from mplang.edsl.graph import Graph
67
- from mplang.runtime.interpreter import ExecutionTracer, Interpreter
67
+ from mplang.runtime.interpreter import ExecutionTracer
68
68
  from mplang.runtime.object_store import FileSystemBackend, ObjectStore
69
69
  from mplang.utils.logging import get_logger
70
70
 
@@ -636,7 +636,7 @@ def register_routes(
636
636
  *,
637
637
  rank: int,
638
638
  world_size: int,
639
- worker: Interpreter,
639
+ infra: WorkerInfra,
640
640
  comm: HttpCommunicator,
641
641
  store: ObjectStore,
642
642
  exec_pool: concurrent.futures.ThreadPoolExecutor,
@@ -648,36 +648,38 @@ def register_routes(
648
648
  enabling reuse in custom server setups.
649
649
 
650
650
  Note:
651
- The *worker* ``Interpreter`` must have the ``"simp"`` dialect state
652
- registered (via ``worker.set_dialect_state("simp", ctx)``) before
653
- any request is served, as the ``/fetch`` and ``/objects`` endpoints
654
- rely on it.
651
+ The *infra* ``WorkerInfra`` contains all shared infrastructure needed
652
+ to create per-request Interpreters.
655
653
 
656
654
  Args:
657
655
  app: The FastAPI application to register routes on.
658
656
  rank: This worker's rank.
659
657
  world_size: Total number of workers.
660
- worker: The Interpreter instance for graph execution.
658
+ infra: The WorkerInfra for creating per-request Interpreters.
661
659
  comm: The HttpCommunicator for inter-worker communication.
662
660
  store: The ObjectStore for data persistence.
663
661
  exec_pool: Thread pool for executing graphs.
664
662
  """
665
- from typing import cast
663
+ from mplang.backends.simp_worker.request import create_request_interpreter
666
664
 
667
665
  def _do_execute(graph: Graph, inputs: list[Any], job_id: str | None = None) -> Any:
668
- """Execute graph in worker thread."""
669
- # Resolve URI inputs (None means rank has no data)
670
- resolved_inputs = [
671
- store.get(inp) if inp is not None else None for inp in inputs
672
- ]
666
+ """Execute graph in worker thread with per-request isolation."""
667
+ request_interp = create_request_interpreter(infra, job_id or "anonymous")
668
+ try:
669
+ # Resolve URI inputs (None means rank has no data)
670
+ resolved_inputs = [
671
+ store.get(inp) if inp is not None else None for inp in inputs
672
+ ]
673
673
 
674
- result = worker.evaluate_graph(graph, resolved_inputs)
675
- comm.wait_pending_sends()
674
+ result = request_interp.evaluate_graph(graph, resolved_inputs, job_id)
675
+ comm.wait_pending_sends()
676
676
 
677
- # Store results and return URIs (result is always a list)
678
- if not graph.outputs:
679
- return None
680
- return [store.put(res) if res is not None else None for res in result]
677
+ # Store results and return URIs (result is always a list)
678
+ if not graph.outputs:
679
+ return None
680
+ return [store.put(res) if res is not None else None for res in result]
681
+ finally:
682
+ request_interp.shutdown()
681
683
 
682
684
  # Mutable closure state shared between endpoint handlers and exec_pool threads.
683
685
  async_tasks: dict[str, AsyncTaskState] = {}
@@ -845,8 +847,7 @@ def register_routes(
845
847
  """Fetch data by URI (e.g. ``mem://abc123``, ``fs://ckpt/s100``)."""
846
848
  logger.debug(f"Worker {rank} received fetch request for {req.uri}")
847
849
  try:
848
- state = cast(SimpWorker, worker.get_dialect_state("simp"))
849
- val = state.store.get(req.uri)
850
+ val = store.get(req.uri)
850
851
  return {"result": serde.dumps_b64(val)}
851
852
  except Exception as e:
852
853
  logger.error(f"Worker {rank} fetch failed: {e}")
@@ -856,8 +857,7 @@ def register_routes(
856
857
  def list_objects() -> dict[str, list[str]]:
857
858
  """List all objects in the worker's store (transient + persistent)."""
858
859
  try:
859
- state = cast(SimpWorker, worker.get_dialect_state("simp"))
860
- return {"objects": state.store.list_keys()}
860
+ return {"objects": store.list_keys()}
861
861
  except Exception as e:
862
862
  logger.error(f"Worker {rank} list_objects failed: {e}")
863
863
  raise HTTPException(status_code=500, detail=str(e)) from e
@@ -917,22 +917,22 @@ def create_worker_app(
917
917
  comm = HttpCommunicator(rank, world_size, endpoints, tracer=tracer)
918
918
  if store is None:
919
919
  store = ObjectStore(persistent=FileSystemBackend(root_path=str(root_dir)))
920
- ctx = SimpWorker(rank, world_size, comm, store, spu_endpoints)
921
920
 
922
921
  handlers: dict[str, Callable[..., Any]] = {**WORKER_HANDLERS} # type: ignore[dict-item]
923
922
 
924
- from mplang.backends.simp_worker.comm_context import CommContext
923
+ from mplang.backends.simp_worker.infra import DEFAULT_ASYNC_OPS, WorkerInfra
925
924
 
926
- comm_ctx = CommContext(comm, context_id="ctx", my_rank=rank)
927
- worker = Interpreter(
925
+ infra = WorkerInfra(
926
+ rank=rank,
927
+ world_size=world_size,
928
+ communicator=comm,
929
+ store=store,
930
+ handlers=handlers,
931
+ spu_endpoints=spu_endpoints,
928
932
  tracer=tracer,
929
933
  root_dir=root_dir,
930
- handlers=handlers,
931
- store=store,
932
- comm_ctx=comm_ctx,
934
+ async_ops=DEFAULT_ASYNC_OPS,
933
935
  )
934
- # Register SimpWorker context as 'simp' dialect state
935
- worker.set_dialect_state("simp", ctx)
936
936
 
937
937
  exec_pool = concurrent.futures.ThreadPoolExecutor(
938
938
  max_workers=2, thread_name_prefix=f"exec_{rank}"
@@ -941,7 +941,7 @@ def create_worker_app(
941
941
  @asynccontextmanager
942
942
  async def lifespan(app: FastAPI) -> AsyncIterator[None]:
943
943
  yield
944
- await asyncio.to_thread(worker.shutdown)
944
+ await asyncio.to_thread(infra.shutdown)
945
945
  await asyncio.to_thread(comm.shutdown)
946
946
  await asyncio.to_thread(exec_pool.shutdown, wait=True)
947
947
 
@@ -951,7 +951,7 @@ def create_worker_app(
951
951
  app,
952
952
  rank=rank,
953
953
  world_size=world_size,
954
- worker=worker,
954
+ infra=infra,
955
955
  comm=comm,
956
956
  store=store,
957
957
  exec_pool=exec_pool,
@@ -0,0 +1,108 @@
1
+ # Copyright 2026 Ant Group Co., Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """WorkerInfra: shared infrastructure container for per-request Interpreter creation.
16
+
17
+ Created once at Worker startup. Passed to ``create_request_interpreter()`` for
18
+ each incoming request. All fields are either immutable or thread-safe.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import concurrent.futures
24
+ import pathlib
25
+ import threading
26
+ from collections.abc import Callable
27
+ from dataclasses import dataclass, field
28
+ from typing import Any
29
+
30
+ from mplang.backends.simp_worker.base import CommunicatorProtocol
31
+ from mplang.runtime.interpreter import ExecutionTracer
32
+ from mplang.runtime.object_store import ObjectStore
33
+
34
+ # Opcodes eligible for async DAG scheduling when an Executor is present.
35
+ # Kept as a module-level constant so that both MemCluster and HTTP Worker
36
+ # share the same set without duplication.
37
+ DEFAULT_ASYNC_OPS: frozenset[str] = frozenset({
38
+ "bfv.add",
39
+ "bfv.mul",
40
+ "bfv.rotate",
41
+ "bfv.batch_encode",
42
+ "bfv.relinearize",
43
+ "bfv.encrypt",
44
+ "bfv.decrypt",
45
+ "field.solve_okvs",
46
+ "field.decode_okvs",
47
+ "field.aes_expand",
48
+ "field.mul",
49
+ "simp.shuffle",
50
+ })
51
+
52
+
53
+ @dataclass
54
+ class WorkerInfra:
55
+ """Shared infrastructure for a Worker process.
56
+
57
+ Created once at Worker startup. Passed to each per-request Interpreter
58
+ factory. All fields are either immutable or thread-safe.
59
+ """
60
+
61
+ rank: int
62
+ world_size: int
63
+ communicator: CommunicatorProtocol
64
+ store: ObjectStore
65
+ handlers: dict[str, Callable[..., Any]]
66
+ spu_endpoints: dict[int, str] | None = None
67
+ tracer: ExecutionTracer | None = None
68
+ trace_pid: int | None = None
69
+ root_dir: pathlib.Path | None = None
70
+ executor: concurrent.futures.Executor | None = None
71
+ async_ops: frozenset[str] = field(default_factory=frozenset)
72
+
73
+ # SPU template links (lazily populated, protected by lock).
74
+ # Cache keys are (local_rank, spu_world_size, protocol, field, link_mode).
75
+ # The number of distinct keys is bounded by the Cartesian product of SPU
76
+ # configurations actually used at runtime -- typically 1-3 entries per
77
+ # worker process (one per distinct SPU device declaration).
78
+ _spu_lock: threading.Lock = field(default_factory=threading.Lock, repr=False)
79
+ _spu_template_links: dict[tuple, Any] = field(default_factory=dict, repr=False)
80
+
81
+ def get_or_create_spu_link(
82
+ self,
83
+ cache_key: tuple,
84
+ create_fn: Callable[[], Any],
85
+ ) -> Any:
86
+ """Thread-safe lazy creation of template SPU links.
87
+
88
+ Args:
89
+ cache_key: Tuple identifying the SPU configuration.
90
+ create_fn: Factory function to create a new link context.
91
+
92
+ Returns:
93
+ A libspu.link.Context (template link) for the given configuration.
94
+ """
95
+ with self._spu_lock:
96
+ if cache_key not in self._spu_template_links:
97
+ self._spu_template_links[cache_key] = create_fn()
98
+ return self._spu_template_links[cache_key]
99
+
100
+ def shutdown(self) -> None:
101
+ """Release cached SPU template links.
102
+
103
+ Safe to call multiple times. Should be called during process
104
+ shutdown to eagerly close BRPC connections rather than waiting
105
+ for GC / process exit.
106
+ """
107
+ with self._spu_lock:
108
+ self._spu_template_links.clear()
@@ -0,0 +1,80 @@
1
+ # Copyright 2026 Ant Group Co., Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Per-request Interpreter factory.
16
+
17
+ Creates lightweight Interpreter instances for each incoming request,
18
+ providing full isolation of mutable state (CommContext, SimpWorker,
19
+ SPUState) while sharing immutable infrastructure (Communicator, Store,
20
+ handlers).
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from mplang.backends.simp_worker.comm_context import CommContext
26
+ from mplang.backends.simp_worker.infra import WorkerInfra
27
+ from mplang.backends.simp_worker.state import SimpWorker
28
+ from mplang.backends.spu_state import SPUState
29
+ from mplang.runtime.interpreter import Interpreter
30
+
31
+
32
+ def create_request_interpreter(
33
+ infra: WorkerInfra,
34
+ job_id: str,
35
+ ) -> Interpreter:
36
+ """Create a lightweight Interpreter for a single request.
37
+
38
+ Cost: ~2μs (dict/TLS allocation only).
39
+ SPU Runtime created on-demand via link.spawn() (~120μs).
40
+
41
+ Args:
42
+ infra: Shared WorkerInfra (process-lifetime).
43
+ job_id: Unique request identifier (used as CommContext context_id).
44
+
45
+ Returns:
46
+ Per-request Interpreter with isolated state.
47
+ """
48
+ # Per-request CommContext with unique context_id
49
+ comm_ctx = CommContext(infra.communicator, context_id=job_id, my_rank=infra.rank)
50
+
51
+ # Per-request Interpreter (does not own shared executor/tracer)
52
+ interp = Interpreter(
53
+ name=f"Worker-{infra.rank}-{job_id}",
54
+ tracer=infra.tracer,
55
+ trace_pid=infra.trace_pid,
56
+ store=infra.store,
57
+ root_dir=infra.root_dir,
58
+ handlers=infra.handlers,
59
+ executor=infra.executor,
60
+ comm_ctx=comm_ctx,
61
+ owns_executor=False,
62
+ owns_tracer=False,
63
+ )
64
+ interp.async_ops = set(infra.async_ops)
65
+
66
+ # Per-request SimpWorker: isolates current_parties
67
+ worker_state = SimpWorker(
68
+ rank=infra.rank,
69
+ world_size=infra.world_size,
70
+ communicator=infra.communicator, # raw comm kept for SPU BaseChannel
71
+ store=infra.store,
72
+ spu_endpoints=infra.spu_endpoints,
73
+ )
74
+ interp.set_dialect_state("simp", worker_state)
75
+
76
+ # Per-request SPUState: will use link.spawn() for Runtime isolation
77
+ spu_state = SPUState(infra=infra)
78
+ interp.set_dialect_state("spu", spu_state)
79
+
80
+ return interp