2022-01-23 10:35:06 +08:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import importlib.util
|
|
|
|
import importlib.machinery
|
2023-11-02 14:56:35 +08:00
|
|
|
import math
|
2023-10-10 16:56:38 +08:00
|
|
|
import numpy as np
|
2023-11-17 17:30:27 +08:00
|
|
|
import numpy.typing as npt
|
2024-08-01 18:43:06 +08:00
|
|
|
import scipy as sp
|
2022-01-23 10:35:06 +08:00
|
|
|
import pathlib
|
|
|
|
|
2022-03-08 21:54:27 +08:00
|
|
|
from numpy import int32, int64, uint32, uint64
|
2023-11-23 13:32:08 +08:00
|
|
|
from scipy import special
|
2023-11-17 17:30:27 +08:00
|
|
|
from typing import TypeVar, Generic, Literal, Union
|
2022-01-23 10:35:06 +08:00
|
|
|
|
2022-03-26 15:09:15 +08:00
|
|
|
T = TypeVar('T')
|
|
|
|
class Option(Generic[T]):
|
|
|
|
_nac3_option: T
|
|
|
|
|
|
|
|
def __init__(self, v: T):
|
|
|
|
self._nac3_option = v
|
|
|
|
|
|
|
|
def is_none(self):
|
|
|
|
return self._nac3_option is None
|
|
|
|
|
|
|
|
def is_some(self):
|
|
|
|
return not self.is_none()
|
|
|
|
|
|
|
|
def unwrap(self):
|
|
|
|
return self._nac3_option
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
if self.is_none():
|
|
|
|
return "none"
|
|
|
|
else:
|
|
|
|
return "Some({})".format(repr(self._nac3_option))
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
if self.is_none():
|
|
|
|
return "none"
|
|
|
|
else:
|
|
|
|
return "Some({})".format(str(self._nac3_option))
|
|
|
|
|
|
|
|
def Some(v: T) -> Option[T]:
|
|
|
|
return Option(v)
|
|
|
|
|
|
|
|
none = Option(None)
|
2022-01-23 10:35:06 +08:00
|
|
|
|
2023-12-05 14:37:08 +08:00
|
|
|
class _ConstGenericMarker:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def ConstGeneric(name, constraint):
|
|
|
|
return TypeVar(name, _ConstGenericMarker, constraint)
|
|
|
|
|
2023-11-17 17:30:27 +08:00
|
|
|
N = TypeVar("N", bound=np.uint64)
|
|
|
|
class _NDArrayDummy(Generic[T, N]):
|
|
|
|
pass
|
|
|
|
|
|
|
|
# https://stackoverflow.com/questions/67803260/how-to-create-a-type-alias-with-a-throw-away-generic
|
|
|
|
NDArray = Union[npt.NDArray[T], _NDArrayDummy[T, N]]
|
|
|
|
|
2024-04-25 15:47:16 +08:00
|
|
|
def _bool(x):
|
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
return np.bool_(x)
|
|
|
|
else:
|
|
|
|
return bool(x)
|
|
|
|
|
|
|
|
def _float(x):
|
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
return np.float_(x)
|
|
|
|
else:
|
|
|
|
return float(x)
|
|
|
|
|
2023-11-02 14:56:35 +08:00
|
|
|
def round_away_zero(x):
|
2024-04-25 15:47:16 +08:00
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
return np.vectorize(round_away_zero)(x)
|
|
|
|
else:
|
|
|
|
if x >= 0.0:
|
|
|
|
return math.floor(x + 0.5)
|
|
|
|
else:
|
|
|
|
return math.ceil(x - 0.5)
|
|
|
|
|
|
|
|
def _floor(x):
|
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
return np.vectorize(_floor)(x)
|
|
|
|
else:
|
|
|
|
return math.floor(x)
|
|
|
|
|
|
|
|
def _ceil(x):
|
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
return np.vectorize(_ceil)(x)
|
2023-11-02 14:56:35 +08:00
|
|
|
else:
|
2024-04-25 15:47:16 +08:00
|
|
|
return math.ceil(x)
|
2023-11-02 14:56:35 +08:00
|
|
|
|
2022-01-23 10:35:06 +08:00
|
|
|
def patch(module):
|
2023-10-10 16:56:38 +08:00
|
|
|
def dbl_nan():
|
|
|
|
return np.nan
|
|
|
|
|
|
|
|
def dbl_inf():
|
|
|
|
return np.inf
|
|
|
|
|
2022-01-23 10:35:06 +08:00
|
|
|
def output_asciiart(x):
|
|
|
|
if x < 0:
|
|
|
|
sys.stdout.write("\n")
|
|
|
|
else:
|
|
|
|
sys.stdout.write(" .,-:;i+hHM$*#@ "[x])
|
|
|
|
|
2023-09-29 15:15:18 +08:00
|
|
|
def output_float(x):
|
|
|
|
print("%f" % x)
|
|
|
|
|
2024-07-08 12:53:51 +08:00
|
|
|
def output_strln(x):
|
|
|
|
print(x, end='')
|
|
|
|
|
2023-10-03 18:02:45 +08:00
|
|
|
def dbg_stack_address(_):
|
|
|
|
return 0
|
|
|
|
|
2022-01-23 10:35:06 +08:00
|
|
|
def extern(fun):
|
|
|
|
name = fun.__name__
|
2023-10-10 16:56:38 +08:00
|
|
|
if name == "dbl_nan":
|
|
|
|
return dbl_nan
|
|
|
|
elif name == "dbl_inf":
|
|
|
|
return dbl_inf
|
|
|
|
elif name == "output_asciiart":
|
2022-01-23 10:35:06 +08:00
|
|
|
return output_asciiart
|
2023-09-29 15:15:18 +08:00
|
|
|
elif name == "output_float64":
|
|
|
|
return output_float
|
2024-07-08 12:53:51 +08:00
|
|
|
elif name == "output_str":
|
|
|
|
return output_strln
|
2022-03-08 21:54:27 +08:00
|
|
|
elif name in {
|
2023-10-03 17:24:02 +08:00
|
|
|
"output_bool",
|
2022-03-08 21:54:27 +08:00
|
|
|
"output_int32",
|
|
|
|
"output_int64",
|
|
|
|
"output_int32_list",
|
|
|
|
"output_uint32",
|
|
|
|
"output_uint64",
|
2024-07-08 12:53:51 +08:00
|
|
|
"output_strln",
|
2024-07-09 12:59:26 +08:00
|
|
|
"output_range",
|
2022-03-08 21:54:27 +08:00
|
|
|
}:
|
2022-01-23 10:35:06 +08:00
|
|
|
return print
|
2023-10-03 18:02:45 +08:00
|
|
|
elif name == "dbg_stack_address":
|
|
|
|
return dbg_stack_address
|
2022-01-23 10:35:06 +08:00
|
|
|
else:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
module.int32 = int32
|
|
|
|
module.int64 = int64
|
2022-03-08 21:54:27 +08:00
|
|
|
module.uint32 = uint32
|
|
|
|
module.uint64 = uint64
|
2024-04-25 15:47:16 +08:00
|
|
|
module.bool = _bool
|
|
|
|
module.float = _float
|
2022-03-19 09:14:27 +08:00
|
|
|
module.TypeVar = TypeVar
|
2023-12-05 14:37:08 +08:00
|
|
|
module.ConstGeneric = ConstGeneric
|
2022-03-19 09:14:27 +08:00
|
|
|
module.Generic = Generic
|
2023-12-18 08:50:49 +08:00
|
|
|
module.Literal = Literal
|
2022-01-23 10:35:06 +08:00
|
|
|
module.extern = extern
|
2022-03-26 15:09:15 +08:00
|
|
|
module.Option = Option
|
|
|
|
module.Some = Some
|
|
|
|
module.none = none
|
2022-01-23 10:35:06 +08:00
|
|
|
|
2023-11-02 14:56:35 +08:00
|
|
|
# Builtin Math functions
|
|
|
|
module.round = round_away_zero
|
|
|
|
module.round64 = round_away_zero
|
2023-11-23 13:45:07 +08:00
|
|
|
module.np_round = np.round
|
2024-04-25 15:47:16 +08:00
|
|
|
module.floor = _floor
|
|
|
|
module.floor64 = _floor
|
2023-11-23 13:45:07 +08:00
|
|
|
module.np_floor = np.floor
|
2024-04-25 15:47:16 +08:00
|
|
|
module.ceil = _ceil
|
|
|
|
module.ceil64 = _ceil
|
2023-11-23 13:45:07 +08:00
|
|
|
module.np_ceil = np.ceil
|
2023-11-02 14:56:35 +08:00
|
|
|
|
2024-07-22 17:06:14 +08:00
|
|
|
# NumPy NDArray factory functions
|
2023-11-17 17:30:27 +08:00
|
|
|
module.ndarray = NDArray
|
|
|
|
module.np_ndarray = np.ndarray
|
|
|
|
module.np_empty = np.empty
|
|
|
|
module.np_zeros = np.zeros
|
|
|
|
module.np_ones = np.ones
|
|
|
|
module.np_full = np.full
|
|
|
|
module.np_eye = np.eye
|
|
|
|
module.np_identity = np.identity
|
2024-06-11 15:30:57 +08:00
|
|
|
module.np_array = np.array
|
2023-11-17 17:30:27 +08:00
|
|
|
|
2024-08-20 16:17:52 +08:00
|
|
|
# NumPy NDArray view functions
|
2024-08-22 09:59:58 +08:00
|
|
|
module.np_broadcast_to = np.broadcast_to
|
2024-08-20 16:17:52 +08:00
|
|
|
module.np_transpose = np.transpose
|
|
|
|
module.np_reshape = np.reshape
|
|
|
|
|
2024-08-20 15:29:10 +08:00
|
|
|
# NumPy NDArray property getters
|
|
|
|
module.np_shape = np.shape
|
|
|
|
module.np_strides = lambda ndarray: ndarray.strides
|
|
|
|
|
2023-10-06 17:48:31 +08:00
|
|
|
# NumPy Math functions
|
2023-11-23 13:32:08 +08:00
|
|
|
module.np_isnan = np.isnan
|
|
|
|
module.np_isinf = np.isinf
|
2024-05-08 17:42:19 +08:00
|
|
|
module.np_min = np.min
|
2024-05-08 18:29:11 +08:00
|
|
|
module.np_minimum = np.minimum
|
2024-07-12 19:27:52 +08:00
|
|
|
module.np_argmin = np.argmin
|
2024-05-08 17:42:19 +08:00
|
|
|
module.np_max = np.max
|
2024-05-08 18:29:11 +08:00
|
|
|
module.np_maximum = np.maximum
|
2024-07-12 19:27:52 +08:00
|
|
|
module.np_argmax = np.argmax
|
2023-11-23 13:32:08 +08:00
|
|
|
module.np_sin = np.sin
|
|
|
|
module.np_cos = np.cos
|
|
|
|
module.np_exp = np.exp
|
|
|
|
module.np_exp2 = np.exp2
|
|
|
|
module.np_log = np.log
|
|
|
|
module.np_log10 = np.log10
|
|
|
|
module.np_log2 = np.log2
|
|
|
|
module.np_fabs = np.fabs
|
|
|
|
module.np_trunc = np.trunc
|
|
|
|
module.np_sqrt = np.sqrt
|
|
|
|
module.np_rint = np.rint
|
|
|
|
module.np_tan = np.tan
|
|
|
|
module.np_arcsin = np.arcsin
|
|
|
|
module.np_arccos = np.arccos
|
|
|
|
module.np_arctan = np.arctan
|
|
|
|
module.np_sinh = np.sinh
|
|
|
|
module.np_cosh = np.cosh
|
|
|
|
module.np_tanh = np.tanh
|
|
|
|
module.np_arcsinh = np.arcsinh
|
|
|
|
module.np_arccosh = np.arccosh
|
|
|
|
module.np_arctanh = np.arctanh
|
|
|
|
module.np_expm1 = np.expm1
|
|
|
|
module.np_cbrt = np.cbrt
|
|
|
|
module.np_arctan2 = np.arctan2
|
|
|
|
module.np_copysign = np.copysign
|
|
|
|
module.np_fmax = np.fmax
|
|
|
|
module.np_fmin = np.fmin
|
|
|
|
module.np_ldexp = np.ldexp
|
|
|
|
module.np_hypot = np.hypot
|
|
|
|
module.np_nextafter = np.nextafter
|
2023-10-06 17:48:31 +08:00
|
|
|
|
2024-07-22 17:06:14 +08:00
|
|
|
# SciPy Math functions
|
2023-11-23 13:32:08 +08:00
|
|
|
module.sp_spec_erf = special.erf
|
|
|
|
module.sp_spec_erfc = special.erfc
|
|
|
|
module.sp_spec_gamma = special.gamma
|
|
|
|
module.sp_spec_gammaln = special.gammaln
|
|
|
|
module.sp_spec_j0 = special.j0
|
|
|
|
module.sp_spec_j1 = special.j1
|
2023-10-10 16:56:38 +08:00
|
|
|
|
2024-07-25 12:17:32 +08:00
|
|
|
# Linalg functions
|
|
|
|
module.np_dot = np.dot
|
|
|
|
module.np_linalg_cholesky = np.linalg.cholesky
|
|
|
|
module.np_linalg_qr = np.linalg.qr
|
|
|
|
module.np_linalg_svd = np.linalg.svd
|
|
|
|
module.np_linalg_inv = np.linalg.inv
|
|
|
|
module.np_linalg_pinv = np.linalg.pinv
|
2024-07-31 18:02:54 +08:00
|
|
|
module.np_linalg_matrix_power = np.linalg.matrix_power
|
|
|
|
module.np_linalg_det = np.linalg.det
|
2024-07-25 12:17:32 +08:00
|
|
|
|
|
|
|
module.sp_linalg_lu = lambda x: sp.linalg.lu(x, True)
|
|
|
|
module.sp_linalg_schur = sp.linalg.schur
|
|
|
|
module.sp_linalg_hessenberg = lambda x: sp.linalg.hessenberg(x, True)
|
|
|
|
|
2022-01-23 10:35:06 +08:00
|
|
|
def file_import(filename, prefix="file_import_"):
|
|
|
|
filename = pathlib.Path(filename)
|
|
|
|
modname = prefix + filename.stem
|
|
|
|
|
|
|
|
path = str(filename.resolve().parent)
|
|
|
|
sys.path.insert(0, path)
|
|
|
|
|
|
|
|
try:
|
|
|
|
spec = importlib.util.spec_from_loader(
|
|
|
|
modname,
|
|
|
|
importlib.machinery.SourceFileLoader(modname, str(filename)),
|
|
|
|
)
|
|
|
|
module = importlib.util.module_from_spec(spec)
|
|
|
|
patch(module)
|
|
|
|
spec.loader.exec_module(module)
|
|
|
|
finally:
|
|
|
|
sys.path.remove(path)
|
|
|
|
|
|
|
|
return module
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
demo = file_import(sys.argv[1])
|
|
|
|
demo.run()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|