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 = """ let score (input : double list) = let func0 = if ((1.0) = (1.0)) then 1.0 else 2.0 let func1 = if (((func0) + (2.0)) >= ((1.0) / (2.0))) then 1.0 else input.[0] func1 """ interpreter = FSharpInterpreter() 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 = """ let score (input : double list) = let func0 = if ((1.0) = (1.0)) then 1.0 else 2.0 let func1 = if ((1.0) = ((func0) + (2.0))) then if ((1.0) = ((func0) + (2.0))) then input.[2] else 2.0 else 2.0 func1 """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_pow_expr(): expr = ast.PowExpr(ast.NumVal(2.0), ast.NumVal(3.0)) expected_code = """ let score (input : double list) = (2.0) ** (3.0) """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_raw_array(): expr = ast.VectorVal([ast.NumVal(3), ast.NumVal(4)]) expected_code = """ let score (input : double list) = [3.0; 4.0] """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_log_expr(): expr = ast.LogExpr(ast.NumVal(2.0)) expected_code = """ let score (input : double list) = log (2.0) """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_atan_expr(): expr = ast.AtanExpr(ast.NumVal(2.0)) expected_code = """ let score (input : double list) = atan (2.0) """ interpreter = FSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_exp_expr(): expr = ast.ExpExpr(ast.NumVal(1.0)) expected_code = """ let score (input : double list) = exp (1.0) """ interpreter = FSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_abs_expr(): expr = ast.AbsExpr(ast.NumVal(-1.0)) expected_code = """ let score (input : double list) = abs (-1.0) """ interpreter = FSharpInterpreter() 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 = """ let score (input : double list) = ((input.[0]) / (-2.0)) * (2.0) """ interpreter = FSharpInterpreter() utils.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 = """ let score (input : double list) = let func0 = exp (1.0) (func0) / (func0) """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_log1p_expr(): expr = ast.Log1pExpr(ast.NumVal(2.0)) expected_code = """ let private chebyshevBroucke i coeffs = let step k (b0, b1, _) = ((k + i * 2.0 * b0 - b1), b0, b1) let fini (b0, _, b2) = (b0 - b2) * 0.5 fini (List.foldBack step coeffs (0.0, 0.0, 0.0)) let private log1p x = let x' = abs x let chebCoeffs = [ 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] match x with | 0.0 -> 0.0 | -1.0 -> -infinity | i when i < -1.0 -> nan | i when x' < System.Double.Epsilon * 0.5 -> x | i when (x > 0.0 && x < 1e-8) || (x > -1e-9 && x < 0.0) -> x * (1.0 - x * 0.5) | i when x' < 0.375 -> x * (1.0 - x * chebyshevBroucke (x / 0.375) chebCoeffs) | _ -> log (1.0 + x) let score (input : double list) = log1p (2.0) """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_bin_vector_num_expr(): expr = ast.BinVectorNumExpr(ast.VectorVal([ast.NumVal(1), ast.NumVal(2)]), ast.NumVal(1), ast.BinNumOpType.MUL) expected_code = """ let private addVectors v1 v2 = List.map2 (+) v1 v2 let private mulVectorNumber v1 num = List.map (fun i -> i * num) v1 let score (input : double list) = mulVectorNumber ([1.0; 2.0]) (1.0) """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_softmax_expr(): expr = ast.SoftmaxExpr([ast.NumVal(2.0), ast.NumVal(3.0)]) expected_code = """ let private softmax x = let maxElem = List.reduce max x let exps = List.map (fun i -> exp (i - maxElem)) x let sumExps = List.sum exps List.map (fun i -> i / sumExps) exps let score (input : double list) = softmax ([2.0; 3.0]) """ interpreter = FSharpInterpreter() assert_code_equal(interpreter.interpret(expr), expected_code)
def test_sigmoid_expr(): expr = ast.SigmoidExpr(ast.NumVal(2.0)) expected_code = """ let private sigmoid x = let z = exp x match x with | i when i < 0.0 -> z / (1.0 + z) | _ -> 1.0 / (1.0 + exp (-x)) let score (input : double list) = sigmoid (2.0) """ interpreter = FSharpInterpreter() 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 = """ let score (input : double list) = let func0 = if ((1.0) = (input.[0])) then 2.0 else 3.0 func0 """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
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 = """ let score (input : double list) = let func0 = if ((1.0) = (1.0)) then [1.0; 2.0] else [3.0; 4.0] func0 """ interpreter = FSharpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
class FSharpExecutor(BaseExecutor): target_exec_dir = None project_name = "test_model" def __init__(self, model): self.model = model self.interpreter = FSharpInterpreter() 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", "F#" ]) def prepare(self): if self.model_ast.output_size > 1: print_code = PRINT_VECTOR else: print_code = PRINT_SCALAR code = EXECUTOR_CODE_TPL.format(print_code=print_code, model_code=self.interpreter.interpret( self.model_ast)) file_name = self._global_tmp_dir / "Program.fs" utils.write_content_to_file(code, file_name) subprocess.call([ "dotnet", "build", str(self._global_tmp_dir / f"{self.project_name}.fsproj"), "--output", str(self.target_exec_dir) ])
def __init__(self, model): self.model = model self.interpreter = FSharpInterpreter() assembler_cls = get_assembler_cls(model) self.model_ast = assembler_cls(model).assemble()