From 757585d85157e807b27c07283edcce6ad91f3659 Mon Sep 17 00:00:00 2001 From: Nikita Titov Date: Wed, 20 May 2020 19:49:50 +0300 Subject: [PATCH 1/2] Migrate from string.Template to string.format (#213) --- m2cgen/interpreters/c/code_generator.py | 4 +-- m2cgen/interpreters/code_generator.py | 27 ++++++++++--------- m2cgen/interpreters/go/code_generator.py | 18 ++++++------- m2cgen/interpreters/haskell/code_generator.py | 6 ++--- m2cgen/interpreters/php/code_generator.py | 2 +- .../interpreters/powershell/code_generator.py | 8 +++--- m2cgen/interpreters/python/code_generator.py | 14 +++++----- m2cgen/interpreters/r/code_generator.py | 4 +-- m2cgen/interpreters/ruby/code_generator.py | 10 +++---- .../visual_basic/code_generator.py | 20 +++++++------- 10 files changed, 58 insertions(+), 55 deletions(-) diff --git a/m2cgen/interpreters/c/code_generator.py b/m2cgen/interpreters/c/code_generator.py index 5e99bf40..38f44fa3 100644 --- a/m2cgen/interpreters/c/code_generator.py +++ b/m2cgen/interpreters/c/code_generator.py @@ -6,8 +6,8 @@ class CCodeGenerator(CLikeCodeGenerator): - tpl_scalar_var_declare = CT("double ${var_name};") - tpl_vector_var_declare = CT("double ${var_name}[${size}];") + tpl_scalar_var_declare = CT("double {var_name};") + tpl_vector_var_declare = CT("double {var_name}[{size}];") scalar_type = "double" vector_type = "double *" diff --git a/m2cgen/interpreters/code_generator.py b/m2cgen/interpreters/code_generator.py index dc5dc523..94ebac38 100644 --- a/m2cgen/interpreters/code_generator.py +++ b/m2cgen/interpreters/code_generator.py @@ -1,19 +1,22 @@ from io import StringIO -from string import Template from weakref import finalize class CodeTemplate: def __init__(self, template): - self.template = Template(template) self.str_template = template def __str__(self): return self.str_template def __call__(self, *args, **kwargs): - return self.template.substitute(*args, **kwargs) + # Force calling str() representation + # because without it numpy gives the same output + # for different float types + return self.str_template.format( + *[str(i) for i in args], + **{k: str(v) for k, v in kwargs.items()}) class BaseCodeGenerator: @@ -187,12 +190,12 @@ class CLikeCodeGenerator(ImperativeCodeGenerator): have to provide logic for wrapping expressions into functions/classes/etc. """ - tpl_num_value = CodeTemplate("${value}") - tpl_infix_expression = CodeTemplate("(${left}) ${op} (${right})") - tpl_var_declaration = CodeTemplate("${var_type} ${var_name};") - tpl_return_statement = CodeTemplate("return ${value};") - tpl_array_index_access = CodeTemplate("${array_name}[${index}]") - tpl_if_statement = CodeTemplate("if (${if_def}) {") - tpl_else_statement = CodeTemplate("} else {") - tpl_block_termination = CodeTemplate("}") - tpl_var_assignment = CodeTemplate("${var_name} = ${value};") + tpl_num_value = CodeTemplate("{value}") + tpl_infix_expression = CodeTemplate("({left}) {op} ({right})") + tpl_var_declaration = CodeTemplate("{var_type} {var_name};") + tpl_return_statement = CodeTemplate("return {value};") + tpl_array_index_access = CodeTemplate("{array_name}[{index}]") + tpl_if_statement = CodeTemplate("if ({if_def}) {{") + tpl_else_statement = CodeTemplate("}} else {{") + tpl_block_termination = CodeTemplate("}}") + tpl_var_assignment = CodeTemplate("{var_name} = {value};") diff --git a/m2cgen/interpreters/go/code_generator.py b/m2cgen/interpreters/go/code_generator.py index 9f1782b0..16917d31 100644 --- a/m2cgen/interpreters/go/code_generator.py +++ b/m2cgen/interpreters/go/code_generator.py @@ -5,15 +5,15 @@ class GoCodeGenerator(ImperativeCodeGenerator): - tpl_num_value = CodeTemplate("${value}") - tpl_infix_expression = CodeTemplate("(${left}) ${op} (${right})") - tpl_array_index_access = CodeTemplate("${array_name}[${index}]") - tpl_else_statement = CodeTemplate("} else {") - tpl_block_termination = CodeTemplate("}") - tpl_var_declaration = CodeTemplate("var ${var_name} ${var_type}") - tpl_return_statement = CodeTemplate("return ${value}") - tpl_if_statement = CodeTemplate("if ${if_def} {") - tpl_var_assignment = CodeTemplate("${var_name} = ${value}") + tpl_num_value = CodeTemplate("{value}") + tpl_infix_expression = CodeTemplate("({left}) {op} ({right})") + tpl_array_index_access = CodeTemplate("{array_name}[{index}]") + tpl_else_statement = CodeTemplate("}} else {{") + tpl_block_termination = CodeTemplate("}}") + tpl_var_declaration = CodeTemplate("var {var_name} {var_type}") + tpl_return_statement = CodeTemplate("return {value}") + tpl_if_statement = CodeTemplate("if {if_def} {{") + tpl_var_assignment = CodeTemplate("{var_name} = {value}") scalar_type = "float64" vector_type = "[]float64" diff --git a/m2cgen/interpreters/haskell/code_generator.py b/m2cgen/interpreters/haskell/code_generator.py index 5b7a9312..26a34ec0 100644 --- a/m2cgen/interpreters/haskell/code_generator.py +++ b/m2cgen/interpreters/haskell/code_generator.py @@ -5,9 +5,9 @@ class HaskellCodeGenerator(BaseCodeGenerator): - tpl_num_value = CodeTemplate("${value}") - tpl_infix_expression = CodeTemplate("(${left}) ${op} (${right})") - tpl_module_definition = CodeTemplate("module ${module_name} where") + tpl_num_value = CodeTemplate("{value}") + tpl_infix_expression = CodeTemplate("({left}) {op} ({right})") + tpl_module_definition = CodeTemplate("module {module_name} where") def __init__(self, *args, **kwargs): self._func_idx = 0 diff --git a/m2cgen/interpreters/php/code_generator.py b/m2cgen/interpreters/php/code_generator.py index ffc70028..c75649bd 100644 --- a/m2cgen/interpreters/php/code_generator.py +++ b/m2cgen/interpreters/php/code_generator.py @@ -7,7 +7,7 @@ class PhpCodeGenerator(CLikeCodeGenerator): - tpl_array_index_access = CodeTemplate("$$${array_name}[${index}]") + tpl_array_index_access = CodeTemplate("${array_name}[{index}]") def __init__(self, *args, **kwargs): super(PhpCodeGenerator, self).__init__(*args, **kwargs) diff --git a/m2cgen/interpreters/powershell/code_generator.py b/m2cgen/interpreters/powershell/code_generator.py index 8aee4565..e6577ba0 100644 --- a/m2cgen/interpreters/powershell/code_generator.py +++ b/m2cgen/interpreters/powershell/code_generator.py @@ -7,10 +7,10 @@ class PowershellCodeGenerator(CLikeCodeGenerator): - tpl_var_declare = CT("${var_type}${var_name} = ${init_val}") - tpl_var_assignment = CT("${var_name} = ${value}") - tpl_array_index_access = CT("$$${array_name}[${index}]") - tpl_return_statement = CT("return ${value}") + tpl_var_declare = CT("{var_type}{var_name} = {init_val}") + tpl_var_assignment = CT("{var_name} = {value}") + tpl_array_index_access = CT("${array_name}[{index}]") + tpl_return_statement = CT("return {value}") scalar_type = "[double]" vector_type = "[double[]]" diff --git a/m2cgen/interpreters/python/code_generator.py b/m2cgen/interpreters/python/code_generator.py index 9c27ddd3..1e42a547 100644 --- a/m2cgen/interpreters/python/code_generator.py +++ b/m2cgen/interpreters/python/code_generator.py @@ -6,14 +6,14 @@ class PythonCodeGenerator(ImperativeCodeGenerator): - tpl_num_value = CT("${value}") - tpl_infix_expression = CT("(${left}) ${op} (${right})") - tpl_return_statement = CT("return ${value}") - tpl_array_index_access = CT("${array_name}[${index}]") - tpl_array_convert_to_numpy = CT("np.asarray(${value})") - tpl_if_statement = CT("if ${if_def}:") + tpl_num_value = CT("{value}") + tpl_infix_expression = CT("({left}) {op} ({right})") + tpl_return_statement = CT("return {value}") + tpl_array_index_access = CT("{array_name}[{index}]") + tpl_array_convert_to_numpy = CT("np.asarray({value})") + tpl_if_statement = CT("if {if_def}:") tpl_else_statement = CT("else:") - tpl_var_assignment = CT("${var_name} = ${value}") + tpl_var_assignment = CT("{var_name} = {value}") tpl_var_declaration = CT("") tpl_block_termination = CT("") diff --git a/m2cgen/interpreters/r/code_generator.py b/m2cgen/interpreters/r/code_generator.py index 0e5ec3b9..29f89d29 100644 --- a/m2cgen/interpreters/r/code_generator.py +++ b/m2cgen/interpreters/r/code_generator.py @@ -6,8 +6,8 @@ class RCodeGenerator(CLikeCodeGenerator): - tpl_return_statement = CodeTemplate("return(${value})") - tpl_var_assignment = CodeTemplate("${var_name} <- ${value}") + tpl_return_statement = CodeTemplate("return({value})") + tpl_var_assignment = CodeTemplate("{var_name} <- {value}") def __init__(self, *args, **kwargs): super(RCodeGenerator, self).__init__(*args, **kwargs) diff --git a/m2cgen/interpreters/ruby/code_generator.py b/m2cgen/interpreters/ruby/code_generator.py index 1cc54db7..98cb0e6e 100644 --- a/m2cgen/interpreters/ruby/code_generator.py +++ b/m2cgen/interpreters/ruby/code_generator.py @@ -7,14 +7,14 @@ class RubyCodeGenerator(ImperativeCodeGenerator): tpl_var_declaration = CT("") - tpl_num_value = CT("${value}") - tpl_infix_expression = CT("(${left}) ${op} (${right})") + tpl_num_value = CT("{value}") + tpl_infix_expression = CT("({left}) {op} ({right})") tpl_return_statement = tpl_num_value - tpl_array_index_access = CT("${array_name}[${index}]") - tpl_if_statement = CT("if ${if_def}") + tpl_array_index_access = CT("{array_name}[{index}]") + tpl_if_statement = CT("if {if_def}") tpl_else_statement = CT("else") tpl_block_termination = CT("end") - tpl_var_assignment = CT("${var_name} = ${value}") + tpl_var_assignment = CT("{var_name} = {value}") def add_function_def(self, name, args): func_def = "def " + name + "(" diff --git a/m2cgen/interpreters/visual_basic/code_generator.py b/m2cgen/interpreters/visual_basic/code_generator.py index 539c4b9e..57f63633 100644 --- a/m2cgen/interpreters/visual_basic/code_generator.py +++ b/m2cgen/interpreters/visual_basic/code_generator.py @@ -6,18 +6,18 @@ class VisualBasicCodeGenerator(ImperativeCodeGenerator): - tpl_num_value = CodeTemplate("${value}") - tpl_infix_expression = CodeTemplate("(${left}) ${op} (${right})") + tpl_num_value = CodeTemplate("{value}") + tpl_infix_expression = CodeTemplate("({left}) {op} ({right})") tpl_var_declaration = \ - CodeTemplate("Dim ${var_name}${type_modifier} As ${var_type}") - tpl_return_statement = CodeTemplate("${func_name} = ${value}") - tpl_if_statement = CodeTemplate("If ${if_def} Then") + CodeTemplate("Dim {var_name}{type_modifier} As {var_type}") + tpl_return_statement = CodeTemplate("{func_name} = {value}") + tpl_if_statement = CodeTemplate("If {if_def} Then") tpl_else_statement = CodeTemplate("Else") - tpl_block_termination = CodeTemplate("End ${block_name}") - tpl_array_index_access = CodeTemplate("${array_name}(${index})") - tpl_array_set_by_index = CodeTemplate("${array_name}(${index}) = ${value}") - tpl_var_assignment = CodeTemplate("${var_name} = ${value}") - tpl_module_definition = CodeTemplate("Module ${module_name}") + tpl_block_termination = CodeTemplate("End {block_name}") + tpl_array_index_access = CodeTemplate("{array_name}({index})") + tpl_array_set_by_index = CodeTemplate("{array_name}({index}) = {value}") + tpl_var_assignment = CodeTemplate("{var_name} = {value}") + tpl_module_definition = CodeTemplate("Module {module_name}") scalar_type = "Double" From 4869e002373fa53f96b62f92eee13b914586fc13 Mon Sep 17 00:00:00 2001 From: Nikita Titov Date: Wed, 20 May 2020 20:01:03 +0300 Subject: [PATCH 2/2] Add support for multiclass XGBoost RF (#217) --- README.md | 2 +- m2cgen/assemblers/boosting.py | 23 +++++++++++++++-------- tests/e2e/test_e2e.py | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 55fd0014..4f0b7618 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ pip install m2cgen | **Linear** | | | | **SVM** | | | | **Tree** | | | -| **Random Forest** | | | +| **Random Forest** | | | | **Boosting** |