CF based type inference
Hi! Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it. It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry: a = 1 b = a a = "str" a is python object and b is integer. Here are testcases that show some new cases it can solve: https://github.com/vitek/cython /blob/_type_inference_new/tests/run/type_inference_new.pyx Here is branch for it https://github.com/vitek/cython /tree/_type_inference_new -- vitja.
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve: https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja, Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in: x = 0 for i in range(N): x += 0.2 * i print typeof(x)
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve:
https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja,
Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in:
x = 0 for i in range(N): x += 0.2 * i print typeof(x)
Hi Mark, Nothing changed in your example old algorithm was able to handle this "simple" kind of cycles as well as new one: def foo(int N): x = 0 for i in range(N): x += 0.2 * i print typeof(x) So this function (not that N is an integer here) will print 'dobule'. With new algorithm we can go further: def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y) Here both x and y will be inferred as double -- vitja.
On 21 May 2013 14:14, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve:
https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja,
Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in:
x = 0 for i in range(N): x += 0.2 * i print typeof(x)
Hi Mark,
Nothing changed in your example old algorithm was able to handle this "simple" kind of cycles as well as new one:
def foo(int N): x = 0 for i in range(N): x += 0.2 * i print typeof(x)
So this function (not that N is an integer here) will print 'dobule'.
With new algorithm we can go further:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double. What happens when the reaching types cannot be promoted together? Do you fall back to object?
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 14:14, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's
almost
ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve:
https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja,
Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in:
x = 0 for i in range(N): x += 0.2 * i print typeof(x)
Hi Mark,
Nothing changed in your example old algorithm was able to handle this "simple" kind of cycles as well as new one:
def foo(int N): x = 0 for i in range(N): x += 0.2 * i print typeof(x)
So this function (not that N is an integer here) will print 'dobule'.
With new algorithm we can go further:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double. What happens when the reaching types cannot be promoted together? Do you fall back to object?
Can you provide example please? And yes if type cannot be inferred it fallback to object. -- vitja.
On 21 May 2013 14:41, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 14:14, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve:
https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja,
Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in:
x = 0 for i in range(N): x += 0.2 * i print typeof(x)
Hi Mark,
Nothing changed in your example old algorithm was able to handle this "simple" kind of cycles as well as new one:
def foo(int N): x = 0 for i in range(N): x += 0.2 * i print typeof(x)
So this function (not that N is an integer here) will print 'dobule'.
With new algorithm we can go further:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double. What happens when the reaching types cannot be promoted together? Do you fall back to object?
Can you provide example please? And yes if type cannot be inferred it fallback to object.
Sure, e.g. if cond: x = 2 else: x = "hello" use(x) A tricky one is this: try: x = f() # let's say 'double' x = g() # let's say 'string' finally: print typeof(x) # what does this print if 'f' can raise an exception?
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 14:41, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 14:14, Vitja Makarov <vitja.makarov@gmail.com> wrote:
2013/5/21 mark florisson <markflorisson88@gmail.com>
On 21 May 2013 11:26, Vitja Makarov <vitja.makarov@gmail.com> wrote:
Hi!
Recently I've started work on new type inference engine. Now it's almost ready and I want to discuss it.
It works like this: first infer type for each assignment then for whole entry. It has some advantages over previous algorithm: - it handles assignment cycles, see test_swap() for example - it can infer type using info about assignments on the whole
entry:
a = 1 b = a a = "str"
a is python object and b is integer.
Here are testcases that show some new cases it can solve:
https://github.com/vitek/cython/blob/_type_inference_new/tests/run/type_infe...
Here is branch for it https://github.com/vitek/cython/tree/_type_inference_new
-- vitja.
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Hey Vitja,
Cool! How do you want to handle variable merge at control flow joins? Would you promote (backwards incompatible), use a union type, or object? E.g. what does this result in:
x = 0 for i in range(N): x += 0.2 * i print typeof(x)
Hi Mark,
Nothing changed in your example old algorithm was able to handle this "simple" kind of cycles as well as new one:
def foo(int N): x = 0 for i in range(N): x += 0.2 * i print typeof(x)
So this function (not that N is an integer here) will print 'dobule'.
With new algorithm we can go further:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double. What happens when the reaching types cannot be promoted together? Do you fall back to object?
Can you provide example please? And yes if type cannot be inferred it fallback to object.
Sure, e.g.
if cond: x = 2 else: x = "hello" use(x)
x will be of object type here.
A tricky one is this:
try: x = f() # let's say 'double' x = g() # let's say 'string' finally: print typeof(x) # what does this print if 'f' can raise an exception?
As well as here. Can it raise exception or not doesn't matter here since typeof() returns type of entry and it's calculated at compile time. -- vitja.
mark florisson, 21.05.2013 15:32:
On 21 May 2013 14:14, Vitja Makarov wrote:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double.
I'm not sure what you mean here. I certainly don't think the inferred type of x and y should depend on the value of N. It should always be a double, because that's the spanning type for all paths. In the very unlikely case that that's not what the user wants, explicit typing will easily fix it for them. Stefan
On Sun, Jun 2, 2013 at 7:22 AM, Stefan Behnel <stefan_ml@behnel.de> wrote:
mark florisson, 21.05.2013 15:32:
On 21 May 2013 14:14, Vitja Makarov wrote:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double.
I'm not sure what you mean here. I certainly don't think the inferred type of x and y should depend on the value of N. It should always be a double, because that's the spanning type for all paths. In the very unlikely case that that's not what the user wants, explicit typing will easily fix it for them.
But 'double' does not actually span 'int', floats and integers are different in all kinds of corner cases. Both have values that are unrepresentable in the other, etc. So this optimization as stated is... not an optimization, it's just wrong. I mean obviously in this example double would be fine, but how do you decide when it's okay to randomly reinterpret users' code as meaning something different than what they wrote, and when it isn't? It's not that I think the Python rules here are particularly awesome, or that I on purpose write code that sometimes returns ints and sometimes doubles. But at least I know what the Python rules are, which means I can always look at a chunk of code and figure out what the interpreter will do. This is why people writing serious C compilers are so anal about obscure problems like aliasing and guaranteeing that you get segfaults at the right time, and generally insisting that optimizations must *exactly* preserve semantics. I'm worried from this discussion that in Cython, the rule for how variables are typed will become "well, you get whatever types our type inference engine guessed; dropping ordinary Python code into Cython might change the outputs or might not; if you want to know 100% what your code will do then your only option is to either put explicit types on every single variable or else go read the source code for the inference engine in the specific version of Cython you're using". -n
On 2 June 2013 07:22, Stefan Behnel <stefan_ml@behnel.de> wrote:
mark florisson, 21.05.2013 15:32:
On 21 May 2013 14:14, Vitja Makarov wrote:
def foo(int N): x = 1 y = 0 for i in range(N): x = x * 0.1 + y * 0.2 y = x * 0.3 + y * 0.4 print typeof(x), typeof(y)
Here both x and y will be inferred as double
Ok, so I assume it promotes the incoming types (all reaching definitions)? If N == 0, then when using objects you get an int, otherwise a double.
I'm not sure what you mean here. I certainly don't think the inferred type of x and y should depend on the value of N. It should always be a double, because that's the spanning type for all paths. In the very unlikely case that that's not what the user wants, explicit typing will easily fix it for them.
Right, my point is that taking the spanning type of all paths is different from python semantics. But if you can prove something about the value of N (e.g. N <= 0, or N > 0), you should certainly exploit this information.
Stefan
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
participants (4)
-
mark florisson -
Nathaniel Smith -
Stefan Behnel -
Vitja Makarov