Scientific computing using Cython: Best of both Worlds!
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Mourya, Simmi
Scientific computing using Cython: Best of both Worlds! Cython is not only an excellent and widely used tool to speed up computational Python code, it’s also a very smart way to talk to native code and libraries. The Cython compiler translates Python code to C or C++ code, and supports static type annotations to allow direct use of C/C++ data types and functions. You get the best of both worlds while working with Cython: Python like syntax with blazing fast C speed. This talk/tutorial by a Python/Cython developer introduces Cython programming language and leads the participants all the way from their first Python extension to an efficient integration with native C. Topics covered will be: 1. Using the Cython compiler to build a native extension module 2. Cython development from Jupyter notebook 3. Mixing Python with static C types in the Cython language 4. Calling into native code from Cython code (Brief introduction) 5. Wrap up: A brief case study Cyvlfeat: A Cython/Python wrapper for Computer Vision library, VLFeat. Participants are expected to have a good understanding of the Python language, some basic knowledge about C or C++. No deep C programming knowledge is required, nor is any prior knowledge needed about writing extension modules for the CPython runtime
 So, let's hope it's like this is my first Europiping presentation. Let's hope I do good. So this talk is about scientific computing using Scython. So I'm going to go around some basic overview of what Scython is, how can you use it, and how can you specifically use it in the scientific computing world? So I am Simi Moria. I work at Credible Health. So it's a startup in India. So we work on like cancer reporting. So basically we work on like cancer detection and brain, liver, and lung. So the idea is to connect deep learning with cloud computing so you can actually get all the matrices and dashboard directly through your web browser. So you can't hear me? Okay. I'll be just near to the mic. Am I audible now? Okay. Perfect. So what this talk is about, so we'll just go through step by step. What is Scython? How like we'll unleash the Scython superpowers and we'll try to build our first Scython module and we'll see how Scython provides like support for NumPy and we'll unleash more superpowers and there's a project demo at the end, CYVL feed. So I worked on this project last summer for Portland State University. I actually wrote a wrapper for VL feed. It's a library for computer vision. So it has like all the major vision algorithms like SIFT and yeah, similar to that. So okay. So what is Scython? Like it's actually a static compiler for both Python programming language and extended Scython programming language. So it makes writing C extension for Python as easy as Python itself. So we'll unleash the superpowers now. So okay, the first super power is you can, the when you use Scython, your Python code will actually be able to like call cc++ code back and forth. It talks to it like natively. You can easily tune like Python code into like you can optimize the performance by adding static type declarations. Let's see how we do that. Yeah. So this is up your Python code. It's a simple integration function. So yeah, it's pretty easy. So now you have to spot the differences here. So what do we have added? We have added a type to I, S and DX. So we have pre-declared the types and we have done that by using Cdef and not simple def. So Cdef is basically you use there actually three like, like yours. Similar, you know, so there is a def, there is a Cdef and there is a Cpdef. So I'll explain it to them. I'll explain them later. Let's look at just Cdef. So in a nutshell, Cdef is basically when you're dealing with C stuff and there is no, you don't have to deal with Python objects. So yeah, then that's when you use Cdef and you'll be able to actually harness the actual performance of C Python runtime when you use Cdef. So you have declared, no, so you have defined the type of I, S and DX and how does it help? So, so whenever there is a like performance critical code, you have to like, you have lots of loops and lots of computation. So you add static types, declarations, it actually allows to actually, Scython just bypasses the C Python API calls and it just runs everything in C. So the code that Scython generates now, it's more, you know, more optimized and has better performance. So typically how Scython works is it's basically you write everything in Python, you write everything in.py file, in Scython, you write it in.py X. So you can just copy paste pure Python code into a Scython file that is.py X and it would run. So this won't like give you like really good speed up, but you can do that. Like it's, if you want more optimization, you can actually include types just as we did here. So just copying this particular code in.py X gives like 35% speed improvement. So and yeah, by adding some static types, it's actually like speed is like four times than the, as compared to the core Python. So yeah, I talked about def, C def and Cp def. Let's look at them in detail. Def is basically, yeah, it's Python. So it is called directly from Python and it takes Python objects arguments and it returns a Python object. So there is no, you don't have to deal with C anywhere. So yeah. And C def, it's basically C. So where Scython functions, like you intend them to be like pure C functions, you want actual C performance, you use C def, but you have to be very careful. You cannot like at that, when you are using C def, you should like that particular patch should not deal with any Python object. So that you might run into a problem if you do that. So the generated code, like so when you compile.py, like Scython file, it generates a.C and then you can, like it gets converted to.so, which is a shared object. So in Linux, you, and then you can directly import that so in the Python session by doing an import, simple import. We'll come to that too. So Cp def, it's basically both def and C def. So there is a trick here. It actually recognizes both Python and C code. So when there is a C code, it recognizes, okay, it's C code, it can actually do some early binding. And when you are dealing with Python objects, so it uses dynamic binding and it kind of gets slow. So it's like Python then too. So yeah. It can directly import CC plus plus libraries using C import. So you can just to see import, see something, you can directly import. We'll show, I'll show you an example later. So yeah, you can actually integrate with existing CC plus plus code. So you have, say you have a library in C and you want to use it, like you want to create a Python interface with that library. You can do that by using Scython. We'll look into that too. I'm just, you know, unleashing all the superpowers. So yeah. Okay. So where is the magic? How does Scython do what's so special about it? So the main feature in Scython is the optional static type declarations. You don't have to declare them every time. They are optional. So the source code gets converted into optimized CC plus plus code. And this allows very fast program execution with, you know, programmer productivity since you are using a Python likes syntax. So what's the motivation behind using Scython? So this is a really cool diagram I borrowed from advanced Python summer school. It happened in 2012. So there's ease of use and by access and there's a speed on X axis. So speed, you're just using like low level languages like, you know, Fortran or something. So they give you speed and with Python you get ease of use. You want to find somewhere like a middle way out. So that's where Scython is. Scython exists. So okay. Let's get to the code directly. So first one is Python core. Second one is CC plus plus. So third one is, yeah, Scython version. So there's just few differences when you compare the Python and Scython code. There's one C def. This gives, you know, 80% speed X and when you compare it to Python, like native Python code. So this is like a really sloppy function that I wrote. You can add a few more optimizations. We'll come to that slowly. So Scython, where is it used? So there are many big, big projects which use Scython. One is NumPy. You might have heard of NumPy. There's an AstroPy as well. It's not an example. But yeah, it does. And yeah, it's like coding and C and Python at the same time. Okay. We'll come to the use cases slowly. Am I going too fast? Just let me know if I am. Yeah. Okay. Thank you so much. So library wrapping. I have, like, said enough, like, again and again that you can wrap libraries. So for example, I'll give you an example. So in C, when you're writing something in C, you have, like, the structure is like you have a dot C and dot H. In Scython, you have dot pyx and dot pxt, the knowledge files for those. And let's see how we can do that. Okay. So the second use case is when you have performance critical code. I have explained this already again and again. So the common procedure is when you really need speed, just, you know, you can use a compile language like C, C++ and then wrap the whole code in Scython. Instead of, like, directly doing it in Scython, like, it'll give you, like, really good speed. And yes. The third use case is, okay, use case one, I'm sorry. So who knows about the Jill? I think everybody does. Okay. That's great. So Jill is basically it's a global interpreter lock. So it's what it does, it's kind of like when the lock is acquired, it limits the threat performance. You won't be actually, even if you're running your program on, like, a multi-core CPU, it won't be able to, like, harness the total power. So yeah. So there's a solution that Scython provides to break out of the Jill wherever required. So let's see. So these are the unwritten rules of Python. You don't talk about Jill. You actually, you do not. And seriously, you don't even mention the Jill. So let's get into an example. So this is a really, this is a small function which actually keeps a CPU busy. So it does a lot of computation again and again. So it takes 6.7 seconds to run on, like, my laptop. Now, see, this is a sequential one. There are no threads involved. This is a really simple function. Now let's consider the threaded version. And yeah, there are two threads. And it takes 11.1 seconds. And this should not, this is not what you expect, right? So what happened? What happened here? Okay. So it actually, what happens is when you run it on a multi-core CPU and multi-core processor, you actually expect to, like, the script to run, like, nearly half time. But or at least in equal, at least in the equal time as of the sequential version. But it's not happening. Because the threaded version suffers from a very bad behavior where the OS tries, the operating system tries to desperately schedule the two threads on different cores. But because of the jail, the lock, only one runs at a time and whereas the other is moved, like, across the cores endlessly, it keeps, you know, it tries to allocate it to any core, but it just can't. So that's how it takes so much time. So what's the solution? Scython provides a really good context manager. It's known as with no jail. So the catch is, like, you can use it when it does not touch any Python object. So let's see how we can use it. So this is the implementation of the same function. It has different computation. It's, like, a bit more time-taking. So yeah, so you have this with no jail and you can see in the busy underscore sleep underscore no jail. So we use this context manager with no jail. So now this, you can see underscore the last function. It's implemented in pure C because you're using Cdef everywhere. You're declaring all the types. So it's not Python. It's like, yeah, it's almost C. So the performance has actually increased so much, a lot. So let's see. Yeah, this is, you can actually, you can use Jupyter notebooks to get these yellow. This is actually when you compile it using a minus a flag, it creates, like, this is like yellow yellow lines. The more yellow it is, the more Python interaction is happening. So you can see in line number 10, there is almost no Python interaction because, yeah, you have declared everything. So this is, like, super fast. And there are the number one and number two are equally yellow. So they're dealing with Python objects somewhere. Yeah, actually they are. That's why. So one tip that you can take is you can decrease the yellowness of these lines if you want to optimize your code. So that's one of your, like, if you want to optimize, just use the minus a flag and get these results and see where you can actually use, actually, there is a need for optimization. So yeah, we'll build, or build site, like, a really small program. So I have, yeah, there's a lot, I have told you, like, there's a PyX file and it gets converted to.c. And then.c is converted to.so or.pyd on Windows. And if you can import it directly into a Python session, let's see. You can import it, like, you can build using different methods. You can use just tutorials. You can use PyX import. It's a really cool tool, but you don't want to use it on production. I don't know. We don't use it. Third is Jupyter Notebook. Yeah, it's the most common way. That's the way I use it. So yeah. This is a simple hello world script. So you have a simple, this is actually Python. You can, as I told you, you can copy paste into a Python file and you can, it will run. So this is, there's a line from.sython.bill import. It does all the work for you. It's, like, like, if you can, if you want to import it into the Python session, the Sythonize does all the work for you. So you use, like, extension module is equal to Sythonize and that's where you're using your Sython file,.pyx. So yeah. And when you use this minus, minus in place, what it does, it creates a.so file in your current directory. So you can directly import it from there and it would work. So yeah. Congratulations. You have built your first Sython, you know, module. Yeah. Next. Yeah. You can use PIX import as well if you don't want to go through all that procedure of, like, writing a distu-tiles and everything. You can just have.pyx file somewhere and you can just use PIX import and import hello and it would work. So it's a really easy way to do that. So what are the conclusions that we drive? Naive Sython means when you just paste the Python code into the Sython file. So it does speed up things but it's not, you know, you probably don't just, you don't opt, you didn't opt for a Sython to just get a, like, 1.8x increase. And so you probably might want to tweak it more. So you can optimize Sython is where you have type declarations where you are actually dealing with CDF and other modifications. So CP def gives a really good improvement over def but CDF is where actual power is. So it's really valuable but you have to be very careful when you're using it. So Sython CDF is almost, yeah, it's almost equal to the C version of that Python code. It's the best attempt to actually increase the performance but, yeah. Okay. Now let's move slowly, slowly to the scientific computing world. So NumPy and Sython. Actually Sython provides really fast access to NumPy arrays. So it has a C-level type which is known as type to memory view. You might have how many of you know memory? What's memory view? Okay. Just two. Okay. Anybody else? Okay. Great. So memory view is just, okay. It's like similar to buffer protocol. You don't have to, like, you can actually read and get the contents of particular, say, memory without, like, you know, memory view is just like an interface. You don't need to copy it somewhere or you can just access it. You can read it. So the type memory view is kind of similar to the NumPy array buffer support. And, yeah, Sython actually allows you to work with buffers without even knowing, like, without even getting into the details of it. So yeah, that's pretty cool. And a type, okay, so because a type memory view is actually designed to work with a buffer protocol, it kind of supports every buffer producing object efficiently. And, yeah, so it allows sharing a buffer data without copying. So, okay. So we will go, these are like, okay. So now when you have type memory views, the cat gets a unicycle. Let's see how we improve this unicycle, this motor transport. So, okay. So let's suppose we want to work with, like, a one-dimensional buffer in Sython. So we do not care, like, how data is created at the Python level. We just want to access it in an efficient way. So let's create a def function in Sython that has a type memory view argument. There we go. So this double parentheses and a colon denotes a memory, typed memory view. So you have actually, you're actually passing a memory view as an argument to a function. So, okay. So, yeah. And you might want to, so you can see there are a few optimizations, like static type declarations. You are actually defining the types of I and total. Why do we do that? So I is actually the loop variable. So you probably want to, like, you know, we'll come to that later. Okay. I have full explanation of that. So we are, okay. So yeah. So, yeah. Here the memory view actually attempts to access the objects underlying data buffer. So if the past object cannot provide a buffer, that is, like, it's, it probably might not, it doesn't support the protocol, then a value error would be raised. And if it does, then it means it supports the protocol. So this was, this is actually, the next one is actually the same code, but with few more optimizations, you have to tweak more. So when you are iterating through a type memory view, it treats it as a general Python iterator. So it actually calls Python's API for every single access. So we can do better. So we were doing it here. We were actually, it's considered as a Python iterator. We are calling the API every time. So how can we do better here? So the type memory views are designed in such a way that you don't have Python overhead every time. So it's like, yeah, it's C style, it's C style way of accessing things. So this version has a much better performance. Probably if you make one, an array with like a million numbers, and if you want to add them and like, like by doing iteration. And if you use this function for that, it's actually sums the argument. So if foo is an array of like a thousand objects, a thousand numbers, and this, if say it takes say two milliseconds, this will take one less. I tried it. So I didn't include the examples, so I thought I would explain it like this. There's one more thing. The Python, actually in this case, it generates a code that bypasses the Python API, calls and like indexes into the underlying buffer directly. So this is the source of our large speed up, but we can still do better always. So optimization never stops. It's a never ending process. I learned it from Andrew. I attended his workshop yesterday. So no, day before yesterday. So yeah. Okay. So now when you have this kind of speed up, our cat gets a good bicycle and it can do gymnastics. So yeah. It's a bit better improvement now. You can do a lot. You can actually increase the performance by, but you have to trade the safety. Let's see how. So every time we access our memory view, Scython checks that like the index is in bounds. So if it's out of bounds, Scython raises an index error. Also like the Scython allows us to index into memory views with negative indices. So just like the Python list, the index wrap around. So in our full function here, yeah, we trade through a memory view once and we do not do anything fancy. It's just a rather simple thing. So we know here we know ahead of time that we never going to index, like we never index within out of bounds or negative index condition. So we can actually instruct Scython to turn off these bounds check for better performance. So to do so, we use the Scython special module with the bounds check and wrap around compiler detectives. So we have modified the code here. So it's the same full function. And now we have like original, we have the original definition, but we have a new block or context manager here, which actually turns off the bounds and wrap around checking when we are accessing our memory view. The result is like really small performance improvement, but more better efficient code generation. It is up to us that we ensure that index doesn't go out of bounds if it does. If you use like negative indexes, so you could lead into a segmentation fault. So we can, okay, there are actually a lot of ways to turn off the bounds checking. So one way is this. You can use a context manager if you just want to use it. See it's the width bounds check, false, wrap around false. This is just above the loop. It means that you want to turn off the bounds check for the next loop. So if you want to do it for the whole function, so you can, okay, no, sorry. Okay. Yeah, this was it. If you want to do it for the whole function, you can use another, actually, you can use a decorator. So it's another form of directive that removes the context manager. So there's one more way if you want to remove the bounds check globally across the program. So you can use another compiler directive. You can actually add, it's a comment line where bounds check is equal to false and same for the wrap around. So actually now the size one provides different scope levels for these directives. One was context manager, second was decorator. This is like global module level. So you can actually have really precise control over where these directives are in effect. So they can be easily disabled for debugging and enabled for the production runs. So now your cat can do this. It has big rocket and laser beams in the eyes. And it can also do this. It's up to you how much you want to optimize. So I promise that I'll show you a project demo. So let's just wrap up like what have we learned. So we saw how to declare like a simple type memory view. We saw how like indexing a type memory view within, you know, integral argument can efficiently access the memory views underlaying buffer. We saw how to use the bounds check and the wrap around directive and we saw like three different ways. So when do we optimize? Like we just don't go and optimize everything. So I, yeah, so I borrowed this from Andrew's tutorial again. So, so you first see like you have to actually profile and you have to set benchmarks. Like, okay, where do you want to optimize? You just have, so there are some, if you want to like write a really small program, you probably don't need optimization. You have to like know beforehand whether you need it or not. Now you know it. You can use the minus a tool that I told you earlier. So now you know where the optimization is needed. So you can go ahead and like add static type declarations or any of the other previous methods that I told. Yeah. Next. Okay. So this is the project demo. Last year I worked for Portland State University for Google Summer of Code program. So the project is CYVL feed. It's actually a wrapper for library named VL feed. So VL feed is actually, so what is VL feed? So, VL feed is actually popular computer vision algorithms library. It actually specialize in image understanding and local feature extraction and matching. So we have like couple of algorithms. You might know the SIFT scale invariant feature transform. K-means, hierarchical K-means and slick super pixels and quick shift super pixels. These are like very famous image algorithms. So yeah, these are the algorithms that it has. So I work for a company in like India. So they needed to, they were working on a video platform. So what they were trying to do, they was actually, so if you see a video and say someone is driving a car and you love that car and you want to know what model is that are like probably the video is really short and you're not able to get, spot the like you know brand of that car. So they were actually trying to make video advertising platform. So where you can, it provides you, you know, an interface to run the video where you can actually click on any pixel. So if that pixel belongs to a car, that clicks, got saved somewhere and you can see it when the video finishes or probably in the middle. So it saves, actually each and every pixel was labeled and it was mapped to the advertisement info. So if that car was like Ford Figo, you can actually see it and that you can directly go to the advertisement, advertiser website or something. So there was a lot of object detection involved in that project. So I had to use real feet. So it was like written in MATLAB and so like, you know, they don't, companies don't prefer MATLAB so they asked me to like, whether you can write few functions like you can wrap few functions for Siphon, so for iPhone. So I proposed this project for Google summer of code last year and it got accepted and I, so, so project was already in, I didn't realize this, but the project was already in progress by like five researchers of Imperial College of London. They were already working on it. So I contributed along them, along with them. So I, like, we worked on like 14, 15 features and they got completed. So yeah, yay. So you can find it here. It's CYVL feet is a part of Menpo project and Menpo was actually in the demo section of last year's CVPR, the computer vision pattern recognition workshop last year. So you can check it. It's a small part of the Menpo project. So yeah, contributions are welcome for CYVL feet. You can actually fork it and create a new feature branch. So I'll also tell you a few limitations of Siphon that I faced when I was working on the project. So yeah, these, by the way, yeah, these are the two modules that need more work and these branches are like still really active. You can go through, have a look or something. So I was actually working when I was wrapping this particular library VL feet. So there's actually the bin some module that you can see. It has, so it has like, we were actually taking reference from the corresponding MATLAB interface. They had a MATLAB interface. So there was like, so in MATLAB the structure is quite simple. So there's when you have a.h file and a mix which actually provides, there's a mix file which actually provides the interface between MATLAB or Octave and the functions in MATLAB and C, the mix files do that. And so the corresponding Siphon implementation would have been.h translate to.pxt and the C mix translates to.pyx. So that's the analogous. So there were no deviations until we finished like 12, 13 features. But when we came to bin some, there was a file.def which is the module definition file. So like, so I'll give you a brief introduction what def is. Does anybody know here what def is? Okay. So in Windows, like,.def describes what functions are going to be exported from the DLL. So unlike like in GCC Linux where every symbol gets exported by default. So you have to tell in Windows, you have to like tell the compiler what functions to export. So the standard way of doing it is to write.def files. So at that time I didn't know how to like wrap this def file in Siphon, how to watch the analogous. It wasn't documented anywhere. So yeah, I asked, it's on Stack-O-Flow, that's the normal way of doing it. So yeah, I still can't figure it out if somebody knows. You can just talk to me later. So this is the one limitation that I faced with Siphon. And the recent, there's one more limitation in Python 3, like they have removed the nested tuple argument and packing. So yeah, Siphon also doesn't support that. So it's a recent removal. The slides are here if you want to download it or something. Thank you. Yeah, I finished it really early. Okay. So any questions or something? We have time for a lot of questions. Thank you so much. It's a great talk and personally I'm going to rate it highly. I have a question. Do you have any examples of importing or referencing external libraries from Siphon? Yes. Here we have. So you see this one, can you see it? See import libc.mass. So you can directly import the library and see, okay, there's an example of minus a as well. So here it generates, okay, you can actually click on it. So this is the C code that it generates. So yeah, you should be able to read it if you want to optimize it. So yeah, it takes some time. So it's number four is less yellow since it deals with the library that is imported directly from C. So yeah, it's really small. And number three, it deals with Python, the def. So here it's a bit longer. Is it clear? Any more questions? Anything else? Okay. Thank you so much. You're a behind. You have? You have? You have? You have?
 So, let's hope it's like this is my first Europiping presentation.  Let's hope I do good.  So this talk is about scientific computing using Scython.  So I'm going to go around some basic overview of what Scython is, how can you use it, and  how can you specifically use it in the scientific computing world?  So I am Simi Moria.  I work at Credible Health.  So it's a startup in India.  So we work on like cancer reporting.  So basically we work on like cancer detection and brain, liver, and lung.  So the idea is to connect deep learning with cloud computing so you can actually get all  the matrices and dashboard directly through your web browser.  So you can't hear me?  Okay.  I'll be just near to the mic.  Am I audible now?  Okay.  Perfect.  So what this talk is about, so we'll just go through step by step.  What is Scython?  How like we'll unleash the Scython superpowers and we'll try to build our first Scython module  and we'll see how Scython provides like support for NumPy and we'll unleash more superpowers  and there's a project demo at the end, CYVL feed.  So I worked on this project last summer for Portland State University.  I actually wrote a wrapper for VL feed.  It's a library for computer vision.  So it has like all the major vision algorithms like SIFT and yeah, similar to that.  So okay.  So what is Scython?  Like it's actually a static compiler for both Python programming language and extended  Scython programming language.  So it makes writing C extension for Python as easy as Python itself.  So we'll unleash the superpowers now.  So okay, the first super power is you can, the when you use Scython, your Python code  will actually be able to like call cc++ code back and forth.  It talks to it like natively.  You can easily tune like Python code into like you can optimize the performance by adding  static type declarations.  Let's see how we do that.  Yeah.  So this is up your Python code.  It's a simple integration function.  So yeah, it's pretty easy.  So now you have to spot the differences here.  So what do we have added?  We have added a type to I, S and DX.  So we have pre-declared the types and we have done that by using Cdef and not simple def.  So Cdef is basically you use there actually three like, like yours.  Similar, you know, so there is a def, there is a Cdef and there is a Cpdef.  So I'll explain it to them.  I'll explain them later.  Let's look at just Cdef.  So in a nutshell, Cdef is basically when you're dealing with C stuff and there is no, you  don't have to deal with Python objects.  So yeah, then that's when you use Cdef and you'll be able to actually harness the actual  performance of C Python runtime when you use Cdef.  So you have declared, no, so you have defined the type of I, S and DX and how does it help?  So, so whenever there is a like performance critical code, you have to like, you have  lots of loops and lots of computation.  So you add static types, declarations, it actually allows to actually, Scython just bypasses  the C Python API calls and it just runs everything in C. So the code that Scython generates now,  it's more, you know, more optimized and has better performance.  So typically how Scython works is it's basically you write everything in Python, you write everything  in.py file, in Scython, you write it in.py X. So you can just copy paste pure Python code  into a Scython file that is.py X and it would run.  So this won't like give you like really good speed up, but you can do that.  Like it's, if you want more optimization, you can actually include types just as we did  here.  So just copying this particular code in.py X gives like 35% speed improvement.  So and yeah, by adding some static types, it's actually like speed is like four times  than the, as compared to the core Python.  So yeah, I talked about def, C def and Cp def.  Let's look at them in detail.  Def is basically, yeah, it's Python.  So it is called directly from Python and it takes Python objects arguments and it returns  a Python object.  So there is no, you don't have to deal with C anywhere.  So yeah.  And C def, it's basically C. So where Scython functions, like you intend them to be like  pure C functions, you want actual C performance, you use C def, but you have to be very careful.  You cannot like at that, when you are using C def, you should like that particular patch  should not deal with any Python object.  So that you might run into a problem if you do that.  So the generated code, like so when you compile.py, like Scython file, it generates a.C  and then you can, like it gets converted to.so, which is a shared object.  So in Linux, you, and then you can directly import that so in the Python session by doing  an import, simple import.  We'll come to that too.  So Cp def, it's basically both def and C def.  So there is a trick here.  It actually recognizes both Python and C code.  So when there is a C code, it recognizes, okay, it's C code, it can actually do some  early binding.  And when you are dealing with Python objects, so it uses dynamic binding and it kind of  gets slow.  So it's like Python then too.  So yeah.  It can directly import CC plus plus libraries using C import.  So you can just to see import, see something, you can directly import.  We'll show, I'll show you an example later.  So yeah, you can actually integrate with existing CC plus plus code.  So you have, say you have a library in C and you want to use it, like you want to create  a Python interface with that library.  You can do that by using Scython.  We'll look into that too.  I'm just, you know, unleashing all the superpowers.  So yeah.  Okay.  So where is the magic?  How does Scython do what's so special about it?  So the main feature in Scython is the optional static type declarations.  You don't have to declare them every time.  They are optional.  So the source code gets converted into optimized CC plus plus code.  And this allows very fast program execution with, you know, programmer productivity since  you are using a Python likes syntax.  So what's the motivation behind using Scython?  So this is a really cool diagram I borrowed from advanced Python summer school.  It happened in 2012.  So there's ease of use and by access and there's a speed on X axis.  So speed, you're just using like low level languages like, you know, Fortran or something.  So they give you speed and with Python you get ease of use.  You want to find somewhere like a middle way out.  So that's where Scython is.  Scython exists.  So okay.  Let's get to the code directly.  So first one is Python core.  Second one is CC plus plus.  So third one is, yeah, Scython version.  So there's just few differences when you compare the Python and Scython code.  There's one C def.  This gives, you know, 80% speed X and when you compare it to Python, like native Python  code.  So this is like a really sloppy function that I wrote.  You can add a few more optimizations.  We'll come to that slowly.  So Scython, where is it used?  So there are many big, big projects which use Scython.  One is NumPy.  You might have heard of NumPy.  There's an AstroPy as well.  It's not an example.  But yeah, it does.  And yeah, it's like coding and C and Python at the same time.  Okay.  We'll come to the use cases slowly.  Am I going too fast?  Just let me know if I am.  Yeah.  Okay.  Thank you so much.  So library wrapping.  I have, like, said enough, like, again and again that you can wrap libraries.  So for example, I'll give you an example.  So in C, when you're writing something in C, you have, like, the structure is like you  have a dot C and dot H. In Scython, you have dot pyx and dot pxt, the knowledge files for  those.  And let's see how we can do that.  Okay.  So the second use case is when you have performance critical code.  I have explained this already again and again.  So the common procedure is when you really need speed, just, you know, you can use a  compile language like C, C++ and then wrap the whole code in Scython.  Instead of, like, directly doing it in Scython, like, it'll give you, like, really good speed.  And yes.  The third use case is, okay, use case one, I'm sorry.  So who knows about the Jill?  I think everybody does.  Okay.  That's great.  So Jill is basically it's a global interpreter lock.  So it's what it does, it's kind of like when the lock is acquired, it limits the threat  performance.  You won't be actually, even if you're running your program on, like, a multi-core CPU, it  won't be able to, like, harness the total power.  So yeah.  So there's a solution that Scython provides to break out of the Jill wherever required.  So let's see.  So these are the unwritten rules of Python.  You don't talk about Jill.  You actually, you do not.  And seriously, you don't even mention the Jill.  So let's get into an example.  So this is a really, this is a small function which actually keeps a CPU busy.  So it does a lot of computation again and again.  So it takes 6.7 seconds to run on, like, my laptop.  Now, see, this is a sequential one.  There are no threads involved.  This is a really simple function.  Now let's consider the threaded version.  And yeah, there are two threads.  And it takes 11.1 seconds.  And this should not, this is not what you expect, right?  So what happened?  What happened here?  Okay.  So it actually, what happens is when you run it on a multi-core CPU and multi-core processor,  you actually expect to, like, the script to run, like, nearly half time.  But or at least in equal, at least in the equal time as of the sequential version.  But it's not happening.  Because the threaded version suffers from a very bad behavior where the OS tries, the  operating system tries to desperately schedule the two threads on different cores.  But because of the jail, the lock, only one runs at a time and whereas the other is moved,  like, across the cores endlessly, it keeps, you know, it tries to allocate it to any core,  but it just can't.  So that's how it takes so much time.  So what's the solution?  Scython provides a really good context manager.  It's known as with no jail.  So the catch is, like, you can use it when it does not touch any Python object.  So let's see how we can use it.  So this is the implementation of the same function.  It has different computation.  It's, like, a bit more time-taking.  So yeah, so you have this with no jail and you can see in the busy underscore sleep underscore  no jail.  So we use this context manager with no jail.  So now this, you can see underscore the last function.  It's implemented in pure C because you're using Cdef everywhere.  You're declaring all the types.  So it's not Python.  It's like, yeah, it's almost C.  So the performance has actually increased so much, a lot.  So let's see.  Yeah, this is, you can actually, you can use Jupyter notebooks to get these yellow.  This is actually when you compile it using a minus a flag, it creates, like, this is  like yellow yellow lines.  The more yellow it is, the more Python interaction is happening.  So you can see in line number 10, there is almost no Python interaction because, yeah,  you have declared everything.  So this is, like, super fast.  And there are the number one and number two are equally yellow.  So they're dealing with Python objects somewhere.  Yeah, actually they are.  That's why.  So one tip that you can take is you can decrease the yellowness of these lines if you want  to optimize your code.  So that's one of your, like, if you want to optimize, just use the minus a flag and get  these results and see where you can actually use, actually, there is a need for optimization.  So yeah, we'll build, or build site, like, a really small program.  So I have, yeah, there's a lot, I have told you, like, there's a PyX file and it gets  converted to.c.  And then.c is converted to.so or.pyd on Windows.  And if you can import it directly into a Python session, let's see.  You can import it, like, you can build using different methods.  You can use just tutorials.  You can use PyX import.  It's a really cool tool, but you don't want to use it on production.  I don't know.  We don't use it.  Third is Jupyter Notebook.  Yeah, it's the most common way.  That's the way I use it.  So yeah.  This is a simple hello world script.  So you have a simple, this is actually Python.  You can, as I told you, you can copy paste into a Python file and you can, it will run.  So this is, there's a line from.sython.bill import.  It does all the work for you.  It's, like, like, if you can, if you want to import it into the Python session, the  Sythonize does all the work for you.  So you use, like, extension module is equal to Sythonize and that's where you're using  your Sython file,.pyx.  So yeah.  And when you use this minus, minus in place, what it does, it creates a.so file in your  current directory.  So you can directly import it from there and it would work.  So yeah.  Congratulations.  You have built your first Sython, you know, module.  Yeah.  Next.  Yeah.  You can use PIX import as well if you don't want to go through all that procedure of, like,  writing a distu-tiles and everything.  You can just have.pyx file somewhere and you can just use PIX import and import hello  and it would work.  So it's a really easy way to do that.  So what are the conclusions that we drive?  Naive Sython means when you just paste the Python code into the Sython file.  So it does speed up things but it's not, you know, you probably don't just, you don't opt,  you didn't opt for a Sython to just get a, like, 1.8x increase.  And so you probably might want to tweak it more.  So you can optimize Sython is where you have type declarations where you are actually dealing  with CDF and other modifications.  So CP def gives a really good improvement over def but CDF is where actual power is.  So it's really valuable but you have to be very careful when you're using it.  So Sython CDF is almost, yeah, it's almost equal to the C version of that Python code.  It's the best attempt to actually increase the performance but, yeah.  Okay.  Now let's move slowly, slowly to the scientific computing world.  So NumPy and Sython.  Actually Sython provides really fast access to NumPy arrays.  So it has a C-level type which is known as type to memory view.  You might have how many of you know memory?  What's memory view?  Okay.  Just two.  Okay.  Anybody else?  Okay.  Great.  So memory view is just, okay.  It's like similar to buffer protocol.  You don't have to, like, you can actually read and get the contents of particular, say,  memory without, like, you know, memory view is just like an interface.  You don't need to copy it somewhere or you can just access it.  You can read it.  So the type memory view is kind of similar to the NumPy array buffer support.  And, yeah, Sython actually allows you to work with buffers without even knowing, like,  without even getting into the details of it.  So yeah, that's pretty cool.  And a type, okay, so because a type memory view is actually designed to work with a buffer  protocol, it kind of supports every buffer producing object efficiently.  And, yeah, so it allows sharing a buffer data without copying.  So, okay.  So we will go, these are like, okay.  So now when you have type memory views, the cat gets a unicycle.  Let's see how we improve this unicycle, this motor transport.  So, okay.  So let's suppose we want to work with, like, a one-dimensional buffer in Sython.  So we do not care, like, how data is created at the Python level.  We just want to access it in an efficient way.  So let's create a def function in Sython that has a type memory view argument.  There we go.  So this double parentheses and a colon denotes a memory, typed memory view.  So you have actually, you're actually passing a memory view as an argument to a function.  So, okay.  So, yeah.  And you might want to, so you can see there are a few optimizations, like static type  declarations.  You are actually defining the types of I and total.  Why do we do that?  So I is actually the loop variable.  So you probably want to, like, you know, we'll come to that later.  Okay.  I have full explanation of that.  So we are, okay.  So yeah.  So, yeah.  Here the memory view actually attempts to access the objects underlying data buffer.  So if the past object cannot provide a buffer, that is, like, it's, it probably might not,  it doesn't support the protocol, then a value error would be raised.  And if it does, then it means it supports the protocol.  So this was, this is actually, the next one is actually the same code, but with few more  optimizations, you have to tweak more.  So when you are iterating through a type memory view, it treats it as a general Python  iterator.  So it actually calls Python's API for every single access.  So we can do better.  So we were doing it here.  We were actually, it's considered as a Python iterator.  We are calling the API every time.  So how can we do better here?  So the type memory views are designed in such a way that you don't have Python overhead  every time.  So it's like, yeah, it's C style, it's C style way of accessing things.  So this version has a much better performance.  Probably if you make one, an array with like a million numbers, and if you want to add them  and like, like by doing iteration.  And if you use this function for that, it's actually sums the argument.  So if foo is an array of like a thousand objects, a thousand numbers, and this, if say it takes  say two milliseconds, this will take one less.  I tried it.  So I didn't include the examples, so I thought I would explain it like this.  There's one more thing.  The Python, actually in this case, it generates a code that bypasses the Python API, calls  and like indexes into the underlying buffer directly.  So this is the source of our large speed up, but we can still do better always.  So optimization never stops.  It's a never ending process.  I learned it from Andrew.  I attended his workshop yesterday.  So no, day before yesterday.  So yeah.  Okay.  So now when you have this kind of speed up, our cat gets a good bicycle and it can do gymnastics.  So yeah.  It's a bit better improvement now.  You can do a lot.  You can actually increase the performance by, but you have to trade the safety.  Let's see how.  So every time we access our memory view, Scython checks that like the index is in bounds.  So if it's out of bounds, Scython raises an index error.  Also like the Scython allows us to index into memory views with negative indices.  So just like the Python list, the index wrap around.  So in our full function here, yeah, we trade through a memory view once and we do not do  anything fancy.  It's just a rather simple thing.  So we know here we know ahead of time that we never going to index, like we never index  within out of bounds or negative index condition.  So we can actually instruct Scython to turn off these bounds check for better performance.  So to do so, we use the Scython special module with the bounds check and wrap around compiler  detectives.  So we have modified the code here.  So it's the same full function.  And now we have like original, we have the original definition, but we have a new block  or context manager here, which actually turns off the bounds and wrap around checking when  we are accessing our memory view.  The result is like really small performance improvement, but more better efficient code  generation.  It is up to us that we ensure that index doesn't go out of bounds if it does.  If you use like negative indexes, so you could lead into a segmentation fault.  So we can, okay, there are actually a lot of ways to turn off the bounds checking.  So one way is this.  You can use a context manager if you just want to use it.  See it's the width bounds check, false, wrap around false.  This is just above the loop.  It means that you want to turn off the bounds check for the next loop.  So if you want to do it for the whole function, so you can, okay, no, sorry.  Okay.  Yeah, this was it.  If you want to do it for the whole function, you can use another, actually, you can use  a decorator.  So it's another form of directive that removes the context manager.  So there's one more way if you want to remove the bounds check globally across the program.  So you can use another compiler directive.  You can actually add, it's a comment line where bounds check is equal to false and same  for the wrap around.  So actually now the size one provides different scope levels for these directives.  One was context manager, second was decorator.  This is like global module level.  So you can actually have really precise control over where these directives are in effect.  So they can be easily disabled for debugging and enabled for the production runs.  So now your cat can do this.  It has big rocket and laser beams in the eyes.  And it can also do this.  It's up to you how much you want to optimize.  So I promise that I'll show you a project demo.  So let's just wrap up like what have we learned.  So we saw how to declare like a simple type memory view.  We saw how like indexing a type memory view within, you know, integral argument can efficiently  access the memory views underlaying buffer.  We saw how to use the bounds check and the wrap around directive and we saw like three  different ways.  So when do we optimize?  Like we just don't go and optimize everything.  So I, yeah, so I borrowed this from Andrew's tutorial again.  So, so you first see like you have to actually profile and you have to set benchmarks.  Like, okay, where do you want to optimize?  You just have, so there are some, if you want to like write a really small program, you  probably don't need optimization.  You have to like know beforehand whether you need it or not.  Now you know it.  You can use the minus a tool that I told you earlier.  So now you know where the optimization is needed.  So you can go ahead and like add static type declarations or any of the other previous  methods that I told.  Yeah.  Next.  Okay.  So this is the project demo.  Last year I worked for Portland State University for Google Summer of Code program.  So the project is CYVL feed.  It's actually a wrapper for library named VL feed.  So VL feed is actually, so what is VL feed?  So, VL feed is actually popular computer vision algorithms library.  It actually specialize in image understanding and local feature extraction and matching.  So we have like couple of algorithms.  You might know the SIFT scale invariant feature transform.  K-means, hierarchical K-means and slick super pixels and quick shift super pixels.  These are like very famous image algorithms.  So yeah, these are the algorithms that it has.  So I work for a company in like India.  So they needed to, they were working on a video platform.  So what they were trying to do, they was actually, so if you see a video and say someone is driving  a car and you love that car and you want to know what model is that are like probably  the video is really short and you're not able to get, spot the like you know brand of that  car.  So they were actually trying to make video advertising platform.  So where you can, it provides you, you know, an interface to run the video where you can  actually click on any pixel.  So if that pixel belongs to a car, that clicks, got saved somewhere and you can see it when  the video finishes or probably in the middle.  So it saves, actually each and every pixel was labeled and it was mapped to the advertisement  info.  So if that car was like Ford Figo, you can actually see it and that you can directly  go to the advertisement, advertiser website or something.  So there was a lot of object detection involved in that project.  So I had to use real feet.  So it was like written in MATLAB and so like, you know, they don't, companies don't prefer  MATLAB so they asked me to like, whether you can write few functions like you can wrap  few functions for Siphon, so for iPhone.  So I proposed this project for Google summer of code last year and it got accepted and  I, so, so project was already in, I didn't realize this, but the project was already  in progress by like five researchers of Imperial College of London.  They were already working on it.  So I contributed along them, along with them.  So I, like, we worked on like 14, 15 features and they got completed.  So yeah, yay.  So you can find it here.  It's CYVL feet is a part of Menpo project and Menpo was actually in the demo section  of last year's CVPR, the computer vision pattern recognition workshop last year.  So you can check it.  It's a small part of the Menpo project.  So yeah, contributions are welcome for CYVL feet.  You can actually fork it and create a new feature branch.  So I'll also tell you a few limitations of Siphon that I faced when I was working on  the project.  So yeah, these, by the way, yeah, these are the two modules that need more work and these  branches are like still really active.  You can go through, have a look or something.  So I was actually working when I was wrapping this particular library VL feet.  So there's actually the bin some module that you can see.  It has, so it has like, we were actually taking reference from the corresponding MATLAB interface.  They had a MATLAB interface.  So there was like, so in MATLAB the structure is quite simple.  So there's when you have a.h file and a mix which actually provides, there's a mix file  which actually provides the interface between MATLAB or Octave and the functions in MATLAB  and C, the mix files do that.  And so the corresponding Siphon implementation would have been.h translate to.pxt and the  C mix translates to.pyx.  So that's the analogous.  So there were no deviations until we finished like 12, 13 features.  But when we came to bin some, there was a file.def which is the module definition file.  So like, so I'll give you a brief introduction what def is.  Does anybody know here what def is?  Okay.  So in Windows, like,.def describes what functions are going to be exported from the  DLL.  So unlike like in GCC Linux where every symbol gets exported by default.  So you have to tell in Windows, you have to like tell the compiler what functions to export.  So the standard way of doing it is to write.def files.  So at that time I didn't know how to like wrap this def file in Siphon, how to watch  the analogous.  It wasn't documented anywhere.  So yeah, I asked, it's on Stack-O-Flow, that's the normal way of doing it.  So yeah, I still can't figure it out if somebody knows.  You can just talk to me later.  So this is the one limitation that I faced with Siphon.  And the recent, there's one more limitation in Python 3, like they have removed the nested  tuple argument and packing.  So yeah, Siphon also doesn't support that.  So it's a recent removal.  The slides are here if you want to download it or something.  Thank you.  Yeah, I finished it really early.  Okay.  So any questions or something?  We have time for a lot of questions.  Thank you so much.  It's a great talk and personally I'm going to rate it highly.  I have a question.  Do you have any examples of importing or referencing external libraries from Siphon?  Yes.  Here we have.  So you see this one, can you see it?  See import libc.mass.  So you can directly import the library and see, okay, there's an example of minus a as  well.  So here it generates, okay, you can actually click on it.  So this is the C code that it generates.  So yeah, you should be able to read it if you want to optimize it.  So yeah, it takes some time.  So it's number four is less yellow since it deals with the library that is imported directly  from C. So yeah, it's really small.  And number three, it deals with Python, the def.  So here it's a bit longer.  Is it clear?  Any more questions?  Anything else?  Okay.  Thank you so much.  You're a behind.  You have?  You have?  You have?  You have?
Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_0_215.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_216_599.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_600_875.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_876_1259.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_1260_3491.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_3492_3683.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_3684_5399.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_5400_5471.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_5472_11159.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_11160_12803.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_12804_16463.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_16464_20147.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_20148_24179.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24180_24323.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24324_24407.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24408_24479.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24480_24527.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24528_24623.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_24624_26147.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_26148_28499.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_28500_33695.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_33696_33887.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_33888_34043.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_34044_34859.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_34860_35651.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_35652_38891.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_38892_39371.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_39372_42503.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_42504_46499.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_46500_48935.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_48936_49475.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_49476_50483.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_50484_50579.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_50580_50795.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_50796_50939.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_50940_51083.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_51084_51311.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_51312_51359.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_51360_51899.png Simmi_Mourya_-_Scientific_computing_using_Cython__Best_of_both_Worlds__ZSHL5rkFDQQ_51900_52953.png