def test_pow_expr(): expr = ast.PowExpr(ast.NumVal(2.0), ast.NumVal(3.0)) expected_code = """ using static System.Math; namespace ML { public static class Model { public static double Score(double[] input) { return Pow(2.0, 3.0); } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_tanh_expr(): expr = ast.TanhExpr(ast.NumVal(2.0)) expected_code = """ using static System.Math; namespace ML { public static class Model { public static double Score(double[] input) { return Tanh(2.0); } } } """ interpreter = CSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_nested_condition(): left = ast.BinNumExpr( ast.IfExpr( ast.CompExpr(ast.NumVal(1), ast.NumVal(1), ast.CompOpType.EQ), ast.NumVal(1), ast.NumVal(2)), ast.NumVal(2), ast.BinNumOpType.ADD) bool_test = ast.CompExpr(ast.NumVal(1), left, ast.CompOpType.EQ) expr_nested = ast.IfExpr(bool_test, ast.FeatureRef(2), ast.NumVal(2)) expr = ast.IfExpr(bool_test, expr_nested, ast.NumVal(2)) expected_code = """ namespace ML { public static class Model { public static double Score(double[] input) { double var0; double var1; if ((1.0) == (1.0)) { var1 = 1.0; } else { var1 = 2.0; } if ((1.0) == ((var1) + (2.0))) { double var2; if ((1.0) == (1.0)) { var2 = 1.0; } else { var2 = 2.0; } if ((1.0) == ((var2) + (2.0))) { var0 = input[2]; } else { var0 = 2.0; } } else { var0 = 2.0; } return var0; } } } """ interpreter = CSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_bin_num_expr(): expr = ast.BinNumExpr( ast.BinNumExpr(ast.FeatureRef(0), ast.NumVal(-2), ast.BinNumOpType.DIV), ast.NumVal(2), ast.BinNumOpType.MUL) expected_code = """ namespace ML { public static class Model { public static double Score(double[] input) { return ((input[0]) / (-2.0)) * (2.0); } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_reused_expr(): reused_expr = ast.ExpExpr(ast.NumVal(1.0), to_reuse=True) expr = ast.BinNumExpr(reused_expr, reused_expr, ast.BinNumOpType.DIV) expected_code = """ using static System.Math; namespace ML { public static class Model { public static double Score(double[] input) { double var0; var0 = Exp(1.0); return (var0) / (var0); } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_dependable_condition(): left = ast.BinNumExpr( ast.IfExpr( ast.CompExpr(ast.NumVal(1), ast.NumVal(1), ast.CompOpType.EQ), ast.NumVal(1), ast.NumVal(2)), ast.NumVal(2), ast.BinNumOpType.ADD) right = ast.BinNumExpr(ast.NumVal(1), ast.NumVal(2), ast.BinNumOpType.DIV) bool_test = ast.CompExpr(left, right, ast.CompOpType.GTE) expr = ast.IfExpr(bool_test, ast.NumVal(1), ast.FeatureRef(0)) expected_code = """ namespace ML { public static class Model { public static double Score(double[] input) { double var0; double var1; if ((1) == (1)) { var1 = 1; } else { var1 = 2; } if (((var1) + (2)) >= ((1) / (2))) { var0 = 1; } else { var0 = input[0]; } return var0; } } } """ interpreter = CSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_if_expr(): expr = ast.IfExpr( ast.CompExpr(ast.NumVal(1), ast.FeatureRef(0), ast.CompOpType.EQ), ast.NumVal(2), ast.NumVal(3)) expected_code = """ namespace ML { public static class Model { public static double Score(double[] input) { double var0; if ((1.0) == (input[0])) { var0 = 2.0; } else { var0 = 3.0; } return var0; } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_sigmoid_expr(): expr = ast.SigmoidExpr(ast.NumVal(2.0)) expected_code = """ using static System.Math; namespace ML { public static class Model { public static double Score(double[] input) { return Sigmoid(2.0); } private static double Sigmoid(double x) { if (x < 0.0) { double z = Exp(x); return z / (1.0 + z); } return 1.0 / (1.0 + Exp(-x)); } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
class CSharpExecutor(BaseExecutor): target_exec_dir = None project_name = "test_model" def __init__(self, model): self.model = model self.interpreter = CSharpInterpreter() assembler_cls = get_assembler_cls(model) self.model_ast = assembler_cls(model).assemble() def predict(self, X): exec_args = [ str(self.target_exec_dir / self.project_name), *map(utils.format_arg, X) ] return utils.predict_from_commandline(exec_args) @classmethod def prepare_global(cls, **kwargs): super().prepare_global(**kwargs) if cls.target_exec_dir is None: cls.target_exec_dir = cls._global_tmp_dir / "bin" subprocess.call([ "dotnet", "new", "console", "--output", str(cls._global_tmp_dir), "--name", cls.project_name, "--language", "C#" ]) def prepare(self): if self.model_ast.output_size > 1: print_code = EXECUTE_AND_PRINT_VECTOR else: print_code = EXECUTE_AND_PRINT_SCALAR executor_code = EXECUTOR_CODE_TPL.format(print_code=print_code) model_code = self.interpreter.interpret(self.model_ast) model_file_name = self._global_tmp_dir / "Model.cs" executor_file_name = self._global_tmp_dir / "Program.cs" utils.write_content_to_file(model_code, model_file_name) utils.write_content_to_file(executor_code, executor_file_name) subprocess.call([ "dotnet", "build", str(self._global_tmp_dir / f"{self.project_name}.csproj"), "--output", str(self.target_exec_dir) ])
def test_multi_output(): expr = ast.IfExpr( ast.CompExpr(ast.NumVal(1), ast.NumVal(1), ast.CompOpType.EQ), ast.VectorVal([ast.NumVal(1), ast.NumVal(2)]), ast.VectorVal([ast.NumVal(3), ast.NumVal(4)])) expected_code = """ namespace ML { public static class Model { public static double[] Score(double[] input) { double[] var0; if ((1.0) == (1.0)) { var0 = new double[2] {1.0, 2.0}; } else { var0 = new double[2] {3.0, 4.0}; } return var0; } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_log1p_expr(): expr = ast.Log1pExpr(ast.NumVal(2.0)) expected_code = """ using static System.Math; namespace ML { public static class Model { public static double Score(double[] input) { return Log1p(2.0); } private static double Log1p(double x) { if (x == 0.0) return 0.0; if (x == -1.0) return double.NegativeInfinity; if (x < -1.0) return double.NaN; double xAbs = Abs(x); if (xAbs < 0.5 * double.Epsilon) return x; if ((x > 0.0 && x < 1e-8) || (x > -1e-9 && x < 0.0)) return x * (1.0 - x * 0.5); if (xAbs < 0.375) { double[] coeffs = { 0.10378693562743769800686267719098e+1, -0.13364301504908918098766041553133e+0, 0.19408249135520563357926199374750e-1, -0.30107551127535777690376537776592e-2, 0.48694614797154850090456366509137e-3, -0.81054881893175356066809943008622e-4, 0.13778847799559524782938251496059e-4, -0.23802210894358970251369992914935e-5, 0.41640416213865183476391859901989e-6, -0.73595828378075994984266837031998e-7, 0.13117611876241674949152294345011e-7, -0.23546709317742425136696092330175e-8, 0.42522773276034997775638052962567e-9, -0.77190894134840796826108107493300e-10, 0.14075746481359069909215356472191e-10, -0.25769072058024680627537078627584e-11, 0.47342406666294421849154395005938e-12, -0.87249012674742641745301263292675e-13, 0.16124614902740551465739833119115e-13, -0.29875652015665773006710792416815e-14, 0.55480701209082887983041321697279e-15, -0.10324619158271569595141333961932e-15}; return x * (1.0 - x * ChebyshevBroucke(x / 0.375, coeffs)); } return Log(1.0 + x); } private static double ChebyshevBroucke(double x, double[] coeffs) { double b0, b1, b2, x2; b2 = b1 = b0 = 0.0; x2 = x * 2; for (int i = coeffs.Length - 1; i >= 0; --i) { b2 = b1; b1 = b0; b0 = x2 * b1 - b2 + coeffs[i]; } return (b0 - b2) * 0.5; } } } """ interpreter = CSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def __init__(self, model): self.model = model self.interpreter = CSharpInterpreter() assembler_cls = get_assembler_cls(model) self.model_ast = assembler_cls(model).assemble()