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 = """ <?php function score(array $input) { $var0 = null; $var1 = null; if ((1) === (1)) { $var1 = 1; } else { $var1 = 2; } if ((($var1) + (2)) >= ((1) / (2))) { $var0 = 1; } else { $var0 = $input[0]; } return $var0; } """ interpreter = PhpInterpreter() 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 = """ <?php function addVectors(array $v1, array $v2) { $result = array(); for ($i = 0; $i < count($v1); ++$i) { $result[] = $v1[$i] + $v2[$i]; } return $result; } function mulVectorNumber(array $v1, $num) { $result = array(); for ($i = 0; $i < count($v1); ++$i) { $result[] = $v1[$i] * $num; } return $result; } function score(array $input) { return mulVectorNumber(array(1, 2), 1); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { return softmax(array(2.0, 3.0)); } function softmax(array $x) { $size = count($x); $result = array(); $m = max($x); $sum = 0.0; for ($i = 0; $i < $size; ++$i) { $result[$i] = exp($x[$i] - $m); $sum += $result[$i]; } for ($i = 0; $i < $size; ++$i) { $result[$i] /= $sum; } return $result; } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def __init__(self, model): self.model_name = "model" self.model = model self.interpreter = PhpInterpreter() assembler_cls = get_assembler_cls(model) self.model_ast = assembler_cls(model).assemble() self.executor_name = "score" self.script_path = None
def test_log1p_expr(): expr = ast.Log1pExpr(ast.NumVal(2.0)) expected_code = """ <?php function score(array $input) { return log1p(2.0); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { return pow(2.0, 3.0); } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_abs_expr(): expr = ast.AbsExpr(ast.NumVal(-1.0)) expected_code = """ <?php function score(array $input) { return abs(-1.0); } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_raw_array(): expr = ast.VectorVal([ast.NumVal(3), ast.NumVal(4)]) expected_code = """ <?php function score(array $input) { return array(3, 4); } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_atan_expr(): expr = ast.AtanExpr(ast.NumVal(2.0)) expected_code = """ <?php function score(array $input) { return atan(2.0); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { $var0 = null; $var0 = exp(1.0); return ($var0) / ($var0); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { return (($input[0]) / (-2)) * (2); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { $var0 = null; $var1 = null; if ((1) === (1)) { $var1 = 1; } else { $var1 = 2; } if ((1) === (($var1) + (2))) { $var2 = null; if ((1) === (1)) { $var2 = 1; } else { $var2 = 2; } if ((1) === (($var2) + (2))) { $var0 = $input[2]; } else { $var0 = 2; } } else { $var0 = 2; } return $var0; } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
def test_sigmoid_expr(): expr = ast.SigmoidExpr(ast.NumVal(2.0)) expected_code = """ <?php function score(array $input) { return sigmoid(2.0); } function sigmoid($x) { if ($x < 0.0) { $z = exp($x); return $z / (1.0 + $z); } return 1.0 / (1.0 + exp(-$x)); } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { $var0 = null; if ((1) === ($input[0])) { $var0 = 2; } else { $var0 = 3; } return $var0; } """ interpreter = PhpInterpreter() 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 = """ <?php function score(array $input) { $var0 = array(); if ((1.0) === (1.0)) { $var0 = array(1.0, 2.0); } else { $var0 = array(3.0, 4.0); } return $var0; } """ interpreter = PhpInterpreter() utils.assert_code_equal(interpreter.interpret(expr), expected_code)
class PhpExecutor(BaseExecutor): def __init__(self, model): self.model_name = "model" self.model = model self.interpreter = PhpInterpreter() assembler_cls = get_assembler_cls(model) self.model_ast = assembler_cls(model).assemble() self.executor_name = "score" self.script_path = None def predict(self, X): exec_args = [ "php", "-f", str(self.script_path), "--", *map(utils.format_arg, X) ] return utils.predict_from_commandline(exec_args) def prepare(self): if self.model_ast.output_size > 1: print_code = PRINT_VECTOR else: print_code = PRINT_SCALAR executor_code = EXECUTOR_CODE_TPL.format( model_file=self.model_name, print_code=print_code) self.script_path = self._resource_tmp_dir / f"{self.executor_name}.php" utils.write_content_to_file(executor_code, self.script_path) model_code = self.interpreter.interpret(self.model_ast) model_file_name = self._resource_tmp_dir / f"{self.model_name}.php" utils.write_content_to_file(model_code, model_file_name)