gstaichi 0.1.25.dev0__cp313-cp313-macosx_15_0_arm64.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.
Files changed (168) hide show
  1. gstaichi/__init__.py +40 -0
  2. gstaichi/__main__.py +5 -0
  3. gstaichi/_funcs.py +706 -0
  4. gstaichi/_kernels.py +420 -0
  5. gstaichi/_lib/__init__.py +3 -0
  6. gstaichi/_lib/core/__init__.py +0 -0
  7. gstaichi/_lib/core/gstaichi_python.cpython-313-darwin.so +0 -0
  8. gstaichi/_lib/core/gstaichi_python.pyi +2939 -0
  9. gstaichi/_lib/core/py.typed +0 -0
  10. gstaichi/_lib/runtime/libMoltenVK.dylib +0 -0
  11. gstaichi/_lib/runtime/runtime_arm64.bc +0 -0
  12. gstaichi/_lib/utils.py +249 -0
  13. gstaichi/_logging.py +131 -0
  14. gstaichi/_main.py +545 -0
  15. gstaichi/_snode/__init__.py +5 -0
  16. gstaichi/_snode/fields_builder.py +187 -0
  17. gstaichi/_snode/snode_tree.py +34 -0
  18. gstaichi/_test_tools/__init__.py +0 -0
  19. gstaichi/_test_tools/load_kernel_string.py +30 -0
  20. gstaichi/_version.py +1 -0
  21. gstaichi/_version_check.py +103 -0
  22. gstaichi/ad/__init__.py +3 -0
  23. gstaichi/ad/_ad.py +530 -0
  24. gstaichi/algorithms/__init__.py +3 -0
  25. gstaichi/algorithms/_algorithms.py +117 -0
  26. gstaichi/assets/.git +1 -0
  27. gstaichi/assets/Go-Regular.ttf +0 -0
  28. gstaichi/assets/static/imgs/ti_gallery.png +0 -0
  29. gstaichi/examples/minimal.py +28 -0
  30. gstaichi/experimental.py +16 -0
  31. gstaichi/lang/__init__.py +50 -0
  32. gstaichi/lang/_ndarray.py +352 -0
  33. gstaichi/lang/_ndrange.py +152 -0
  34. gstaichi/lang/_template_mapper.py +199 -0
  35. gstaichi/lang/_texture.py +172 -0
  36. gstaichi/lang/_wrap_inspect.py +189 -0
  37. gstaichi/lang/any_array.py +99 -0
  38. gstaichi/lang/argpack.py +411 -0
  39. gstaichi/lang/ast/__init__.py +5 -0
  40. gstaichi/lang/ast/ast_transformer.py +1318 -0
  41. gstaichi/lang/ast/ast_transformer_utils.py +341 -0
  42. gstaichi/lang/ast/ast_transformers/__init__.py +0 -0
  43. gstaichi/lang/ast/ast_transformers/call_transformer.py +267 -0
  44. gstaichi/lang/ast/ast_transformers/function_def_transformer.py +320 -0
  45. gstaichi/lang/ast/checkers.py +106 -0
  46. gstaichi/lang/ast/symbol_resolver.py +57 -0
  47. gstaichi/lang/ast/transform.py +9 -0
  48. gstaichi/lang/common_ops.py +310 -0
  49. gstaichi/lang/exception.py +80 -0
  50. gstaichi/lang/expr.py +180 -0
  51. gstaichi/lang/field.py +466 -0
  52. gstaichi/lang/impl.py +1241 -0
  53. gstaichi/lang/kernel_arguments.py +157 -0
  54. gstaichi/lang/kernel_impl.py +1382 -0
  55. gstaichi/lang/matrix.py +1881 -0
  56. gstaichi/lang/matrix_ops.py +341 -0
  57. gstaichi/lang/matrix_ops_utils.py +190 -0
  58. gstaichi/lang/mesh.py +687 -0
  59. gstaichi/lang/misc.py +778 -0
  60. gstaichi/lang/ops.py +1494 -0
  61. gstaichi/lang/runtime_ops.py +13 -0
  62. gstaichi/lang/shell.py +35 -0
  63. gstaichi/lang/simt/__init__.py +5 -0
  64. gstaichi/lang/simt/block.py +94 -0
  65. gstaichi/lang/simt/grid.py +7 -0
  66. gstaichi/lang/simt/subgroup.py +191 -0
  67. gstaichi/lang/simt/warp.py +96 -0
  68. gstaichi/lang/snode.py +489 -0
  69. gstaichi/lang/source_builder.py +150 -0
  70. gstaichi/lang/struct.py +855 -0
  71. gstaichi/lang/util.py +381 -0
  72. gstaichi/linalg/__init__.py +8 -0
  73. gstaichi/linalg/matrixfree_cg.py +310 -0
  74. gstaichi/linalg/sparse_cg.py +59 -0
  75. gstaichi/linalg/sparse_matrix.py +303 -0
  76. gstaichi/linalg/sparse_solver.py +123 -0
  77. gstaichi/math/__init__.py +11 -0
  78. gstaichi/math/_complex.py +205 -0
  79. gstaichi/math/mathimpl.py +886 -0
  80. gstaichi/profiler/__init__.py +6 -0
  81. gstaichi/profiler/kernel_metrics.py +260 -0
  82. gstaichi/profiler/kernel_profiler.py +586 -0
  83. gstaichi/profiler/memory_profiler.py +15 -0
  84. gstaichi/profiler/scoped_profiler.py +36 -0
  85. gstaichi/sparse/__init__.py +3 -0
  86. gstaichi/sparse/_sparse_grid.py +77 -0
  87. gstaichi/tools/__init__.py +12 -0
  88. gstaichi/tools/diagnose.py +117 -0
  89. gstaichi/tools/np2ply.py +364 -0
  90. gstaichi/tools/vtk.py +38 -0
  91. gstaichi/types/__init__.py +19 -0
  92. gstaichi/types/annotations.py +47 -0
  93. gstaichi/types/compound_types.py +90 -0
  94. gstaichi/types/enums.py +49 -0
  95. gstaichi/types/ndarray_type.py +147 -0
  96. gstaichi/types/primitive_types.py +206 -0
  97. gstaichi/types/quant.py +88 -0
  98. gstaichi/types/texture_type.py +85 -0
  99. gstaichi/types/utils.py +13 -0
  100. gstaichi-0.1.25.dev0.data/data/include/GLFW/glfw3.h +6389 -0
  101. gstaichi-0.1.25.dev0.data/data/include/GLFW/glfw3native.h +594 -0
  102. gstaichi-0.1.25.dev0.data/data/include/spirv-tools/instrument.hpp +268 -0
  103. gstaichi-0.1.25.dev0.data/data/include/spirv-tools/libspirv.h +907 -0
  104. gstaichi-0.1.25.dev0.data/data/include/spirv-tools/libspirv.hpp +375 -0
  105. gstaichi-0.1.25.dev0.data/data/include/spirv-tools/linker.hpp +97 -0
  106. gstaichi-0.1.25.dev0.data/data/include/spirv-tools/optimizer.hpp +970 -0
  107. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/GLSL.std.450.h +114 -0
  108. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv.h +2568 -0
  109. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv.hpp +2579 -0
  110. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cfg.hpp +168 -0
  111. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_common.hpp +1920 -0
  112. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cpp.hpp +93 -0
  113. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross.hpp +1171 -0
  114. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross_c.h +1074 -0
  115. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross_containers.hpp +754 -0
  116. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross_error_handling.hpp +94 -0
  117. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross_parsed_ir.hpp +256 -0
  118. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_cross_util.hpp +37 -0
  119. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_glsl.hpp +1001 -0
  120. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_hlsl.hpp +406 -0
  121. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_msl.hpp +1273 -0
  122. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_parser.hpp +103 -0
  123. gstaichi-0.1.25.dev0.data/data/include/spirv_cross/spirv_reflect.hpp +91 -0
  124. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools/SPIRV-ToolsConfig.cmake +5 -0
  125. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools/SPIRV-ToolsTarget-release.cmake +29 -0
  126. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools/SPIRV-ToolsTarget.cmake +114 -0
  127. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-diff/SPIRV-Tools-diffConfig.cmake +5 -0
  128. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-diff/SPIRV-Tools-diffTargets-release.cmake +19 -0
  129. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-diff/SPIRV-Tools-diffTargets.cmake +123 -0
  130. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-link/SPIRV-Tools-linkConfig.cmake +5 -0
  131. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-link/SPIRV-Tools-linkTargets-release.cmake +19 -0
  132. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-link/SPIRV-Tools-linkTargets.cmake +123 -0
  133. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-lint/SPIRV-Tools-lintConfig.cmake +5 -0
  134. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-lint/SPIRV-Tools-lintTargets-release.cmake +19 -0
  135. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-lint/SPIRV-Tools-lintTargets.cmake +123 -0
  136. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-opt/SPIRV-Tools-optConfig.cmake +5 -0
  137. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-opt/SPIRV-Tools-optTargets-release.cmake +19 -0
  138. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-opt/SPIRV-Tools-optTargets.cmake +123 -0
  139. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-reduce/SPIRV-Tools-reduceConfig.cmake +5 -0
  140. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-reduce/SPIRV-Tools-reduceTarget-release.cmake +19 -0
  141. gstaichi-0.1.25.dev0.data/data/lib/cmake/SPIRV-Tools-reduce/SPIRV-Tools-reduceTarget.cmake +123 -0
  142. gstaichi-0.1.25.dev0.data/data/lib/cmake/glfw3/glfw3Config.cmake +3 -0
  143. gstaichi-0.1.25.dev0.data/data/lib/cmake/glfw3/glfw3ConfigVersion.cmake +65 -0
  144. gstaichi-0.1.25.dev0.data/data/lib/cmake/glfw3/glfw3Targets-release.cmake +19 -0
  145. gstaichi-0.1.25.dev0.data/data/lib/cmake/glfw3/glfw3Targets.cmake +107 -0
  146. gstaichi-0.1.25.dev0.data/data/lib/libSPIRV-Tools-shared.dylib +0 -0
  147. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_c/cmake/spirv_cross_cConfig-release.cmake +19 -0
  148. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_c/cmake/spirv_cross_cConfig.cmake +123 -0
  149. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_core/cmake/spirv_cross_coreConfig-release.cmake +19 -0
  150. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_core/cmake/spirv_cross_coreConfig.cmake +106 -0
  151. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_cpp/cmake/spirv_cross_cppConfig-release.cmake +19 -0
  152. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_cpp/cmake/spirv_cross_cppConfig.cmake +123 -0
  153. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_glsl/cmake/spirv_cross_glslConfig-release.cmake +19 -0
  154. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_glsl/cmake/spirv_cross_glslConfig.cmake +123 -0
  155. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_hlsl/cmake/spirv_cross_hlslConfig-release.cmake +19 -0
  156. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_hlsl/cmake/spirv_cross_hlslConfig.cmake +123 -0
  157. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_msl/cmake/spirv_cross_mslConfig-release.cmake +19 -0
  158. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_msl/cmake/spirv_cross_mslConfig.cmake +123 -0
  159. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_reflect/cmake/spirv_cross_reflectConfig-release.cmake +19 -0
  160. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_reflect/cmake/spirv_cross_reflectConfig.cmake +106 -0
  161. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_util/cmake/spirv_cross_utilConfig-release.cmake +19 -0
  162. gstaichi-0.1.25.dev0.data/data/share/spirv_cross_util/cmake/spirv_cross_utilConfig.cmake +123 -0
  163. gstaichi-0.1.25.dev0.dist-info/METADATA +105 -0
  164. gstaichi-0.1.25.dev0.dist-info/RECORD +168 -0
  165. gstaichi-0.1.25.dev0.dist-info/WHEEL +5 -0
  166. gstaichi-0.1.25.dev0.dist-info/entry_points.txt +2 -0
  167. gstaichi-0.1.25.dev0.dist-info/licenses/LICENSE +201 -0
  168. gstaichi-0.1.25.dev0.dist-info/top_level.txt +1 -0
gstaichi/_main.py ADDED
@@ -0,0 +1,545 @@
1
+ # type: ignore
2
+
3
+ import argparse
4
+ import math
5
+ import os
6
+ import runpy
7
+ import shutil
8
+ import subprocess
9
+ import sys
10
+ import timeit
11
+ from collections import defaultdict
12
+ from functools import wraps
13
+ from pathlib import Path
14
+
15
+ import rich
16
+ from colorama import Fore
17
+ from rich.console import Console
18
+
19
+ from gstaichi._lib import core as _ti_core
20
+ from gstaichi._lib import utils
21
+ from gstaichi.lang import impl
22
+ from gstaichi.tools import diagnose
23
+
24
+
25
+ def timer(func):
26
+ """Function decorator to benchmark a function running time."""
27
+
28
+ @wraps(func)
29
+ def wrapper(*args, **kwargs):
30
+ start = timeit.default_timer()
31
+ result = func(*args, **kwargs)
32
+ elapsed = timeit.default_timer() - start
33
+ print(f">>> Running time: {elapsed:.2f}s")
34
+ return result
35
+
36
+ return wrapper
37
+
38
+
39
+ def registerableCLI(cls):
40
+ """Class decorator to register methods with @register into a set."""
41
+ cls.registered_commands = set([])
42
+ for name in dir(cls):
43
+ method = getattr(cls, name)
44
+ if hasattr(method, "registered"):
45
+ cls.registered_commands.add(name)
46
+ return cls
47
+
48
+
49
+ def register(func):
50
+ """Method decorator to register CLI commands."""
51
+ func.registered = True
52
+ return func
53
+
54
+
55
+ @registerableCLI
56
+ class GsTaichiMain:
57
+ def __init__(self, test_mode: bool = False):
58
+ self.banner = f"\n{'*' * 43}\n** GsTaichi Programming Language **\n{'*' * 43}"
59
+ print(self.banner)
60
+
61
+ print(self._get_friend_links())
62
+
63
+ parser = argparse.ArgumentParser(description="GsTaichi CLI", usage=self._usage())
64
+ parser.add_argument("command", help="command from the above list to run")
65
+
66
+ # Flag for unit testing
67
+ self.test_mode = test_mode
68
+
69
+ self.main_parser = parser
70
+
71
+ @timer
72
+ def __call__(self):
73
+ # Print help if no command provided
74
+ if len(sys.argv[1:2]) == 0:
75
+ self.main_parser.print_help()
76
+ return 1
77
+
78
+ # Parse the command
79
+ args = self.main_parser.parse_args(sys.argv[1:2])
80
+
81
+ if args.command not in self.registered_commands: # pylint: disable=E1101
82
+ # TODO: do we really need this?
83
+ if args.command.endswith(".py"):
84
+ GsTaichiMain._exec_python_file(args.command)
85
+ else:
86
+ print(f"{args.command} is not a valid command!")
87
+ self.main_parser.print_help()
88
+ return 1
89
+
90
+ return getattr(self, args.command)(sys.argv[2:])
91
+
92
+ @staticmethod
93
+ def _get_friend_links():
94
+ return (
95
+ "\n"
96
+ "Docs: https://docs.taichi-lang.org/\n"
97
+ "GitHub: https://github.com/taichi-dev/gstaichi/\n"
98
+ "Forum: https://forum.gstaichi.graphics/\n"
99
+ )
100
+
101
+ def _usage(self) -> str:
102
+ """Compose deterministic usage message based on registered_commands."""
103
+ # TODO: add some color to commands
104
+ msg = "\n"
105
+ space = 20
106
+ for command in sorted(self.registered_commands): # pylint: disable=E1101
107
+ msg += f" {command}{' ' * (space - len(command))}|-> {getattr(self, command).__doc__}\n"
108
+ return msg
109
+
110
+ @staticmethod
111
+ def _exec_python_file(filename: str):
112
+ """Execute a Python file based on filename."""
113
+ # TODO: do we really need this?
114
+ subprocess.call([sys.executable, filename] + sys.argv[1:])
115
+
116
+ @staticmethod
117
+ def _get_examples_dir() -> Path:
118
+ """Get the path to the examples directory."""
119
+
120
+ root_dir = utils.package_root
121
+ examples_dir = Path(root_dir) / "examples"
122
+ return examples_dir
123
+
124
+ @staticmethod
125
+ def _get_available_examples() -> set:
126
+ """Get a set of all available example names."""
127
+ examples_dir = GsTaichiMain._get_examples_dir()
128
+ all_examples = examples_dir.rglob("*.py")
129
+ all_example_names = {f.stem: f.parent for f in all_examples}
130
+ return all_example_names
131
+
132
+ @staticmethod
133
+ def _example_choices_type(choices):
134
+ def support_choice_with_dot_py(choice):
135
+ if choice.endswith(".py") and choice.split(".")[0] in choices:
136
+ # try to find and remove python file extension
137
+ return choice.split(".")[0]
138
+ return choice
139
+
140
+ return support_choice_with_dot_py
141
+
142
+ @register
143
+ def example(self, arguments: list = sys.argv[2:]):
144
+ """Run an example by name (or name.py)"""
145
+
146
+ def colormap(index, name):
147
+ from colorsys import hls_to_rgb # pylint: disable=C0415
148
+
149
+ x = (ord(name[0].upper()) - 64.0) / 26.0
150
+ r, g, b = hls_to_rgb(x, 0.4, 1.0)
151
+ r = hex(int(r * 255) % 16)[2:]
152
+ g = hex(int(g * 255) % 16)[2:]
153
+ b = hex(int(b * 255) % 16)[2:]
154
+ return f"{index}: [#{r}{r}{g}{g}{b}{b}]{name}"
155
+
156
+ console = Console()
157
+ table = rich.table.Table(
158
+ box=rich.box.HORIZONTALS,
159
+ show_header=False,
160
+ header_style="bold #2070b2",
161
+ title="[bold][#3fdda4]GSTAICHI[#f8e020] EXAMPLES",
162
+ )
163
+
164
+ ncols = 3
165
+ choices = GsTaichiMain._get_available_examples()
166
+ nrows, rem = divmod(len(choices), ncols)
167
+ if rem > 0:
168
+ nrows += 1
169
+ names = sorted(choices.keys())
170
+ for k in range(nrows):
171
+ table.add_row(*[colormap(j, names[j]) for j in range(k, len(choices), nrows)])
172
+
173
+ parser = argparse.ArgumentParser(prog="ti example", description=f"{self.example.__doc__}")
174
+ parser.add_argument(
175
+ "name",
176
+ type=GsTaichiMain._example_choices_type(choices.keys()),
177
+ choices=sorted(choices.keys()),
178
+ help=console.print(table),
179
+ nargs="?",
180
+ default=None,
181
+ metavar="name",
182
+ )
183
+ parser.add_argument(
184
+ "-p",
185
+ "--print",
186
+ required=False,
187
+ dest="print",
188
+ action="store_true",
189
+ help="Print example source code instead of running it",
190
+ )
191
+ parser.add_argument(
192
+ "-P",
193
+ "--pretty-print",
194
+ required=False,
195
+ dest="pretty_print",
196
+ action="store_true",
197
+ help="Like --print, but print in a rich format with line numbers",
198
+ )
199
+ parser.add_argument(
200
+ "-s",
201
+ "--save",
202
+ required=False,
203
+ dest="save",
204
+ action="store_true",
205
+ help="Save source code to current directory instead of running it",
206
+ )
207
+
208
+ # TODO: Pass the arguments to downstream correctly(#3216).
209
+ args = parser.parse_args(arguments)
210
+
211
+ examples_dir = GsTaichiMain._get_examples_dir()
212
+ example_name = args.name
213
+ if example_name is None:
214
+ try:
215
+ index = input(f"Please input the example index (between 0 and {len(names)}): ")
216
+ while not index.isdigit() or int(index) >= len(names):
217
+ index = input(f"Example [{index}] does not exist. Please try again: ")
218
+ example_name = names[int(index)]
219
+ except KeyboardInterrupt as e:
220
+ print("\nCancelled by user, exiting...")
221
+ return 1
222
+
223
+ target = str((examples_dir / choices[example_name] / f"{example_name}.py").resolve())
224
+ # path for examples needs to be modified for implicit relative imports
225
+ sys.path.append(str((examples_dir / choices[example_name]).resolve()))
226
+
227
+ # Short circuit for testing
228
+ if self.test_mode:
229
+ return args
230
+
231
+ if args.save:
232
+ print(f"Saving example {example_name} to current directory...")
233
+ shutil.copy(target, ".")
234
+ return 0
235
+
236
+ if args.pretty_print:
237
+ syntax = rich.syntax.Syntax.from_path(target, line_numbers=True)
238
+ console = Console()
239
+ console.print(syntax)
240
+ return 0
241
+
242
+ if args.print:
243
+ with open(target) as f:
244
+ print(f.read())
245
+ return 0
246
+
247
+ print(f"Running example {example_name} ...")
248
+
249
+ runpy.run_path(target, run_name="__main__")
250
+
251
+ @staticmethod
252
+ @register
253
+ def changelog(arguments: list = sys.argv[2:]):
254
+ """Display changelog of current version"""
255
+ changelog_md = os.path.join(utils.package_root, "CHANGELOG.md")
256
+ with open(changelog_md) as f:
257
+ print(f.read())
258
+
259
+ @staticmethod
260
+ @register
261
+ def release(arguments: list = sys.argv[2:]):
262
+ """Make source code release"""
263
+ raise RuntimeError("TBD")
264
+
265
+ @staticmethod
266
+ @register
267
+ def doc(arguments: list = sys.argv[2:]):
268
+ """Build documentation"""
269
+ raise RuntimeError("TBD")
270
+
271
+ @staticmethod
272
+ @register
273
+ def format(arguments: list = sys.argv[2:]):
274
+ """Reformat modified source files"""
275
+ raise RuntimeError("Please run `pre-commit run -a` instead")
276
+
277
+ @staticmethod
278
+ @register
279
+ def format_all(arguments: list = sys.argv[2:]):
280
+ """Reformat all source files"""
281
+ raise RuntimeError("Please run `pre-commit run -a` instead")
282
+
283
+ @staticmethod
284
+ def _display_benchmark_regression(xd, yd, args):
285
+ def parse_dat(file):
286
+ _dict = {}
287
+ with open(file) as f:
288
+ for line in f.readlines():
289
+ try:
290
+ a, b = line.strip().split(":")
291
+ except:
292
+ continue
293
+ b = float(b)
294
+ if abs(b % 1.0) < 1e-5: # codegen_*
295
+ b = int(b)
296
+ _dict[a.strip()] = b
297
+ return _dict
298
+
299
+ def parse_name(file):
300
+ if file[0:5] == "test_":
301
+ return file[5:-4].replace("__test_", "::", 1)
302
+ if file[0:10] == "benchmark_":
303
+ return "::".join(reversed(file[10:-4].split("__arch_")))
304
+ raise Exception(f"bad benchmark file name {file}")
305
+
306
+ def get_dats(directory):
307
+ _list = []
308
+ for x in os.listdir(directory):
309
+ if x.endswith(".dat"):
310
+ _list.append(x)
311
+ _dict = {}
312
+ for x in _list:
313
+ name = parse_name(x)
314
+ path = os.path.join(directory, x)
315
+ _dict[name] = parse_dat(path)
316
+ return _dict
317
+
318
+ spec = args.files
319
+ single_line = spec and len(spec) == 1
320
+ xs, ys = get_dats(xd), get_dats(yd)
321
+ scatter = defaultdict(list)
322
+ for name in reversed(sorted(set(xs.keys()).union(ys.keys()))):
323
+ file, func = name.split("::")
324
+ u, v = xs.get(name, {}), ys.get(name, {})
325
+ ret = ""
326
+ for key in set(u.keys()).union(v.keys()):
327
+ if spec and key not in spec:
328
+ continue
329
+ a, b = u.get(key, 0), v.get(key, 0)
330
+ if a == 0:
331
+ if b == 0:
332
+ res = 1.0
333
+ else:
334
+ res = math.inf
335
+ else:
336
+ res = b / a
337
+ scatter[key].append(res)
338
+ if res == 1:
339
+ continue
340
+ if not single_line:
341
+ ret += f"{key:<30}"
342
+ res -= 1
343
+ color = Fore.RESET
344
+ if res > 0:
345
+ color = Fore.RED
346
+ elif res < 0:
347
+ color = Fore.GREEN
348
+ if isinstance(a, float):
349
+ a = f"{a:>7.2}"
350
+ else:
351
+ a = f"{a:>7}"
352
+ if isinstance(b, float):
353
+ b = f"{b:>7.2}"
354
+ else:
355
+ b = f"{b:>7}"
356
+ ret += f"{Fore.MAGENTA}{a}{Fore.RESET} -> "
357
+ ret += f"{Fore.CYAN}{b} {color}{res:>+9.1%}{Fore.RESET}\n"
358
+ if ret != "":
359
+ print(f'{file + "::" + func:_<58}', end="")
360
+ if not single_line:
361
+ print("")
362
+ print(ret, end="")
363
+ if not single_line:
364
+ print("")
365
+
366
+ @staticmethod
367
+ def _get_benchmark_baseline_dir():
368
+ return os.path.join(_ti_core.get_repo_dir(), "benchmarks", "baseline")
369
+
370
+ @staticmethod
371
+ def _get_benchmark_output_dir():
372
+ return os.path.join(_ti_core.get_repo_dir(), "benchmarks", "output")
373
+
374
+ @register
375
+ def regression(self, arguments: list = sys.argv[2:]):
376
+ """Display benchmark regression test result"""
377
+ parser = argparse.ArgumentParser(prog="ti regression", description=f"{self.regression.__doc__}")
378
+ parser.add_argument("files", nargs="*", help="Test file(s) to be run for benchmarking")
379
+ args = parser.parse_args(arguments)
380
+
381
+ # Short circuit for testing
382
+ if self.test_mode:
383
+ return args
384
+
385
+ baseline_dir = GsTaichiMain._get_benchmark_baseline_dir()
386
+ output_dir = GsTaichiMain._get_benchmark_output_dir()
387
+ GsTaichiMain._display_benchmark_regression(baseline_dir, output_dir, args)
388
+
389
+ return None
390
+
391
+ @register
392
+ def baseline(self, arguments: list = sys.argv[2:]):
393
+ """Archive current benchmark result as baseline"""
394
+ parser = argparse.ArgumentParser(prog="ti baseline", description=f"{self.baseline.__doc__}")
395
+ args = parser.parse_args(arguments)
396
+
397
+ # Short circuit for testing
398
+ if self.test_mode:
399
+ return args
400
+
401
+ baseline_dir = GsTaichiMain._get_benchmark_baseline_dir()
402
+ output_dir = GsTaichiMain._get_benchmark_output_dir()
403
+ shutil.rmtree(baseline_dir, True)
404
+ shutil.copytree(output_dir, baseline_dir)
405
+ print(f"[benchmark] baseline data saved to {baseline_dir}")
406
+
407
+ return None
408
+
409
+ @staticmethod
410
+ @register
411
+ def test(self, arguments: list = sys.argv[2:]):
412
+ raise RuntimeError("ti test is deprecated. Please run `python tests/run_tests.py` instead.")
413
+
414
+ @register
415
+ def run(self, arguments: list = sys.argv[2:]):
416
+ """Run a single script"""
417
+ parser = argparse.ArgumentParser(prog="ti run", description=f"{self.run.__doc__}")
418
+ parser.add_argument(
419
+ "filename",
420
+ help="A single (Python) script to run with GsTaichi, e.g. render.py",
421
+ )
422
+ args = parser.parse_args(arguments)
423
+
424
+ # Short circuit for testing
425
+ if self.test_mode:
426
+ return args
427
+
428
+ runpy.run_path(args.filename)
429
+
430
+ return None
431
+
432
+ @register
433
+ def debug(self, arguments: list = sys.argv[2:]):
434
+ """Debug a single script"""
435
+ parser = argparse.ArgumentParser(prog="ti debug", description=f"{self.debug.__doc__}")
436
+ parser.add_argument(
437
+ "filename",
438
+ help="A single (Python) script to run with debugger, e.g. render.py",
439
+ )
440
+ args = parser.parse_args(arguments)
441
+
442
+ # Short circuit for testing
443
+ if self.test_mode:
444
+ return args
445
+
446
+ _ti_core.set_core_trigger_gdb_when_crash(True)
447
+ os.environ["TI_DEBUG"] = "1"
448
+
449
+ runpy.run_path(args.filename, run_name="__main__")
450
+
451
+ return None
452
+
453
+ @staticmethod
454
+ @register
455
+ def diagnose(arguments: list = sys.argv[2:]):
456
+ """System diagnose information"""
457
+ diagnose.main()
458
+
459
+ @staticmethod
460
+ @register
461
+ def repl(arguments: list = sys.argv[2:]):
462
+ """Start GsTaichi REPL / Python shell with 'import gstaichi as ti'"""
463
+
464
+ def local_scope():
465
+ try:
466
+ import IPython # pylint: disable=C0415
467
+
468
+ IPython.embed()
469
+ except ImportError:
470
+ import code # pylint: disable=C0415
471
+
472
+ __name__ = "__console__" # pylint: disable=W0622
473
+ code.interact(local=locals())
474
+
475
+ local_scope()
476
+
477
+ @staticmethod
478
+ @register
479
+ def lint(arguments: list = sys.argv[2:]):
480
+ """Run pylint checker for the Python codebase of GsTaichi"""
481
+ # TODO: support arguments for lint specific files
482
+ # parser = argparse.ArgumentParser(prog='ti lint', description=f"{self.lint.__doc__}")
483
+ # args = parser.parse_args(arguments)
484
+
485
+ options = [os.path.dirname(__file__)]
486
+
487
+ from multiprocessing import cpu_count # pylint: disable=C0415
488
+
489
+ threads = min(8, cpu_count())
490
+ options += ["-j", str(threads)]
491
+
492
+ # http://pylint.pycqa.org/en/latest/user_guide/run.html
493
+ # TODO: support redirect output to lint.log
494
+ import pylint # pylint: disable=C0415
495
+
496
+ pylint.lint.Run(options)
497
+
498
+ @staticmethod
499
+ @register
500
+ def cache(arguments: list = sys.argv[2:]):
501
+ """Manage the offline cache files manually"""
502
+
503
+ def clean(cmd_args, parser):
504
+ parser.add_argument(
505
+ "-p",
506
+ "--offline-cache-file-path",
507
+ dest="offline_cache_file_path",
508
+ default=impl.default_cfg().offline_cache_file_path,
509
+ )
510
+ args = parser.parse_args(cmd_args)
511
+ path = os.path.abspath(args.offline_cache_file_path)
512
+ count = _ti_core.clean_offline_cache_files(path)
513
+ print(f"Deleted {count} offline cache files in {path}")
514
+
515
+ # TODO(PGZXB): Provide more tools to manage the offline cache files
516
+ subcmds_map = {"clean": (clean, "Clean all offline cache files in given path")}
517
+
518
+ def print_help():
519
+ print("usage: ti cache <command> [<args>]")
520
+ for name, value in subcmds_map.items():
521
+ _, description = value
522
+ print(f"\t{name}\t|-> {description}")
523
+
524
+ if not arguments:
525
+ print_help()
526
+ return
527
+
528
+ subcmd = arguments[0]
529
+ if subcmd not in subcmds_map:
530
+ print(f"'ti cache {subcmd}' is not a valid command!")
531
+ print_help()
532
+ return
533
+
534
+ func, description = subcmds_map[subcmd]
535
+ parser = argparse.ArgumentParser(prog=f"ti cache {subcmd}", description=description)
536
+ func(cmd_args=arguments[1:], parser=parser)
537
+
538
+
539
+ def main():
540
+ cli = GsTaichiMain()
541
+ return cli()
542
+
543
+
544
+ if __name__ == "__main__":
545
+ sys.exit(main())
@@ -0,0 +1,5 @@
1
+ # type: ignore
2
+
3
+ from gstaichi._snode.fields_builder import FieldsBuilder
4
+
5
+ __all__ = ["FieldsBuilder"]