So in this video, we're going to find the center of mass of a semicircle of radius r. Notice that this is a semicircle. If I was looking for a circle, it'd be a much easier problem, but we're going to focus on the semicircle here. So we've learned previously that we can find the center of mass by the following formulas, x bar and y bar look like the following. x bar is one over the area times the integral from a to b, x f of x dx and then y bar is equal to one over the area, the integral from a to b of one half f of x squared dx. Now here the area is the area of the region, which that can typically be found by taking the integral from a to b of f of x dx. As this is a semicircle, I'm just going to use the formula one half pi r squared. The radius is r, so therefore this actually gives us the area here. I don't need integration to do that. I mean, because integration is a very powerful tool, but remember like any tool, we only want to use it if it's the best tool for the problem. And oftentimes that is the case, but in the case of a semicircle, we can find the area much simpler from just standard formulas we're aware of. And so if we apply this to x bar, x bar is going to be one over one half pi r squared. We get that. We get the integral. In this case, we're going to integrate from the left side to the right side. That's where the x ranges. So we get from negative r to r. We're going to get x times our function. Well, since this is a semicircle, we can represent the semicircle by the formula y equals the square root of r squared minus x squared. We plug that in for f of x right here. Like so. And so this is the integral that we want to compute at this moment. Now, I noticed that there are, that we're over a symmetric interval. This is negative r to r. So I'm going to want to be looking for, do I have a function that is even or odd? Well, this semicircular function here, the square root of r squared minus x squared, if I replace negative, if I replace x with negative x, we'll see that that part's even, but this part's odd. And when you combine those together, the total is an odd function. What this tells me is that this will equate to be zero. And so I don't actually want to go find an anti-driven. We're going to see this as zero just by using the symmetry here. And that kind of makes sense that given the semicircle we see over here, it does have a line of symmetry, which is the y-axis. And one thing that you should know is that centroids always lie on lines of symmetry. If a region has a line of symmetry, that means the mass on one side is equal to the mass on the other side. And therefore, the axis of symmetry will contain the centroid there. So because the y-axis was a line of symmetry, I actually didn't have to do any calculation whatsoever. I would have known from using the line of symmetry that x bar was equal to zero. And that was a consequence of this thing being an odd function. y bar, on the other hand, is a little bit more complicated because we don't know, we don't know, we don't have a horizontal line of symmetry. That's what I'm trying to say here. So we have the one over the area, which is going to be two over pi r squared. We're going to go from negative r to r. And then we have one half f of x squared. So our function y equals r squared of r squared minus x squared. We're going to square that, which is actually quite fortunate for the situation dx right here. There's a nice cancellation here. The one half here cancels with the two right there. And the square cancels with the square root. So we end up with, with those simplifications, one over pi r squared, the integral from negative r to r of r squared minus x squared dx. So that's a pretty good place to be. Also, symmetry does apply here that this time we have an even function that as you integrate from negative r to r, r squared minus x squared, there's the same amount to the left as this to the right. And I'm not referring to this picture over here. I'm referring to this function specifically. If you replace x with a negative x, you'll get the exact same function here. And so by symmetry, we can simplify this integral to look like two over pi r squared integral from zero to r of r squared minus x squared dx. So integrating our antiderivatives, we're going to get r squared x minus x cubed over three as you go from zero to r. Plug it in zero makes just everything disappear, which is really nice. Plug in an r cubed. So we get two over pi r squared. We're going to have an r cubed here. Sorry, we're not, we're not plugging in an r cube. We're plugging in an r, but some r cubes will emerge. You'll get an r cubed minus an r cubed over three. If you factor out the r cubed, we're going to get two r cubed over pi r squared, which is nice. And then one minus a third. There are square of the bottom will cancel with most of the r's right there. And then if you take one minus a third, that's a two thirds. So we get two over pi, sorry, two r over pi times two thirds. And so in the end, the y-coordinate y bar of the center mass should be four r over three pi, which we can write that as a percentage of the radius r. We found it as a formula. And if we come back up here, this diagram here is drawn on the scale, which whatever the radius turns out to be, the center mass would be this location right here.


So, welcome to my talk. It's about ScytheN, as the title suggests. Thing is, I regularly speak at Python conferences here and there, and tell people about ScytheN, teach them a bit here and there. I had a tutorial on Tuesday here, don't know if anyone attended it, yeah, still a couple people, cool. So, question now to the audience, I can present a couple of different things depending on what you want. Who's interested in a general introduction to ScytheN, understanding what it is, who's never used it and wants to know what it is? That is quite a number of people. So, the actual topic that I proposed for today was more like, I have some Python code and I want to optimize it without losing the ability to run it in Python, so compile it, speed it up. That's a bit of a less general topic who's interested in that, who came from that. That's about the same number of people. Wonderful. Okay, so I'll just jump back and forth between whatever I can tell you. So, yeah, hi, I'm Stefan Biene, quick intro about myself. I'm a software or data engineer if you want. I'm also a trainer, so I'm given ScytheN trainings here and there. If you want me in-house, just talk to me and I'll come over and teach your people there. I'm using Python since 2002. I'm a ScytheN call developer ever since we forked the project from an existing project at the time. Who knows Pyrex, heard of the name before? Yeah, about a dozen people, yeah, wonderful. That's what we forked and Pyrex has basically not been updated much since then. So, we've pretty much taken over the project and everyone's using ScytheN these days. But thanks, Greg, for writing Pyrex because it was a wonderful tool to build ScytheN on. So, I do trainings, I do consulting and actually joined TrustU, spawned at this conference last year. And as a motivating example, I'll tell you what we do. So, if you look for a hotel in Google, you'll see something like this. You'll get a lot of information about the hotel. And if you click around a bit, you'll also see that some of this information would actually be provided by TrustU. So, we know what a hotel is and how good a hotel is. How do we do that? Well, we crawl the web and we have partners and we read hotel reviews by actual people all around the world, collect them at a rate of about three million hotel reviews every week and then we do text analysis on them, we do data processing on them and we do that in lots of different languages including Spanish, Thai, Mandarin, Japanese, lots of languages and build this kind of information from it. So, we summarize all this. This is a meta review, so just a summarization of everything that 45,000 people have been saying about hotel in this case and we can tell you what's special about the hotel, what people like, what people dislike, all of these things. You can actually go to trustu.com, enter a hotel name there and see this information about any hotel you want pretty much all over the world. So, TrustU, NuzPython, NuzData, we all do all of the data processing in Python and we use the kind of the usual tools you would expect. We use NumPy, we use SciPy, Scikit-learn, Pandas, we use Basitool to a certain extent, LXML for the data extraction from the web and many of these tools actually use Scython, are implemented in Scython, some of them completely, others mostly and they're part of the Python data ecosystem. So, why is that an ecosystem? Well, it's an ecosystem because it's integrated. Everything works nicely together, it chains together and a big part of that came from the fact that people develop NumPy as basically a data integration layer that all of these tools could use, could put their data into, could use to share their data across some different libraries, even pass the data on into C libraries, into native code to processes data. So, NumPy integrates the data layer and you can say that Scython is the way to integrate the code layer because what does Scython give you? It allows you to talk to native code, it allows you to use all these tons of native libraries, C libraries, FORTRON libraries out there, connect them to Python, use them from Python, integrate these libraries from your Python runtime. So, when NumPy integrates data, Scython integrates code. So, what is Scython good for? Well, it integrates native code into Python, that's one use case. Many people use it to speed up Python code by compiling it, compiling it into native code and surprisingly, many people actually use it to write C code without having to write C code, okay? Because, you know, writing C code is actually hard. Writing Python code is much more fun and Scython allows you to write Python code that translates to C. So, writing C without writing C. So, we write the C code so you don't have to. Our topic for today is speeding up Python code. So, I'll kind of focus on that. While you use Scython in general, it's a very pragmatic programming language. It's actually a programming language, so it extends Python. But it is Python, you can take arbitrary Python code, drop it into Scython, compile it. It usually runs faster. But you can also use extended syntax or type annotations in there to speed up your code, to tell the compiler how to optimize your code beyond what the Python language allows. So, it's an optimizing compiler. It's actually very production proven. It's used to run, I mean, it showed you a couple of tools that uses. It's used to process, I don't know, like terabytes, maybe petabytes of data out there in all sorts of Python libraries. It is really widely used. And the cool thing about the language is that it's really about getting things done. In the same way that Python is. It keeps your focus on the functionality rather than having to look into all the boilerplate that you would need to talk to a C library or to speed up your code, to optimize it. If you optimize your code by rewriting it in a native language in C or C++, it gets really messy. It's way more difficult than taking your existing Python code, you tested Python code and just making it faster rather than rewriting it. So, the main property of the language is actually that it allows you to freely move between Python and C or C++. It takes Python code, but it allows you to mix in C data types or C++ data types right in your Python code.  Native data types, be fast. I don't care about object operations anywhere. I don't want to pass around stuff through Python and so just make it fast, compute it as fast as you can. And the language makes it very easy. So it allows you to write code that's as Pythonic as you want but as low level as you need. Okay, first demo. Does everyone know the Jupyter notebook? Who does not know it? Nice. It's just, you know, Jupyter is just wonderful. It's a wonderful piece of software. It's a very interactive way to do programming, even data analysis. Lots of people use it to play around with data, visualize it in their browser. And one cool thing of Jupyter is that it does not only support Python, it supports lots of languages. Last time I checked which was years ago and there was already a dozen languages more. It's probably way more now. And one of those languages is Python. All I have to do in Jupyter to make it support Python is load ex-Sython. And I should restart my kernel to show you that it actually works properly. And there you go. Okay, and then just a quick overview of what I'm using here. Latest Python release, latest unreleased Sython. Yeah, I'm a core developer. I can take the risk of using an unreleased Sython version in the talk. Some NumPy version, GC7.  In Sython, it's an alpha version. Oh, you mean 029? Yeah, it's 029. Well, it's production proven, but we still say it's 0. something so at some point, ages ago, we said that version 1.0 should be the version that runs arbitrary Python code. And we still have one or two bucks in there that where we have to say, well, we have to fix those first before we can say that we can compile any Python code out there. And so it's still at 0. something and we haven't reconsidered the goal for 1.0. I think we should, because no one cares about full Python compatibility, actually, it's, you know, it works, it's perfect, it's wonderful, and it's just, yeah, it's 0. something. Okay, I consider doing like Chrome and Firefox and just say, you know, this is actually not 0.29, it's 29. something. There you go. Okay, anyway. Quick intro. So, here's a bit of Python code. I say from math import sign, so I'm using the sign function from the Python math module, I calculated sign 5 and says, well, that's about minus 1, more or less. So it works. Now, in order to do that with Python, I can just add these, this line here, which instructs Jupyter to compile this cell in Python instead of just pushing it into Python right there, compile it in Python and it builds an extension module from that that it then imports. Okay, so it builds a shared library and that is also something to keep in mind to do with Python. You step away from the simple write code import try to write code compile import try. So there's a build step involved from that point on. It's usually worth it. Okay, so run it. It's actually pretty quick apparently. I think it was pre-compiled before. So Jupyter caches these cells if it knows that they didn't change. You see a little change in here. What I did before up there is I just said sign 5 and for Jupyter, what Jupyter does is it takes the last expression, the last value that fell out of your cell and displays it. For a Python compiled cell that does not work, why? It's an extension module. It's native code. It's external. Jupyter can't look into it. It doesn't know anything that falls out of it. There's actually nothing falling out of it. It gets executed. It gets imported. And it's imported as a module. There's no value that comes out of it at one time. So if it just ran this, it would display nothing. But I have to be explicit then and say print this. Okay. One difference. This is still, you know, it's a bit boring, right? I'm doing the same thing. I'm taking the Python function, calling it. It doesn't make a difference if I call Python function in compiled code or in imperfective code. It's pretty much the same thing. The nice thing about Python now is I'm not limited to using Python things. Python takes my code, takes my Python code, compiles it to C. Okay. So what I can do now is I can start using C things because, you know, my code ends up in C anyway. And doing C stuff is a totally natural thing to do from C. So instead of importing the math sign function, this static import, and this syntax extension here in Python code. So this is no longer Python code, it's Python code now. I say C import libc math. And that gives me the math header file from libc. Okay. And now I can use the C sign function here. Okay. What I'm doing here is I'm assigning it to a Python variable in my module, compiling that, executing it and question now is what happens when I assign a C function to a Python variable? It becomes callable, right? Python callable. Because it's kind of obvious what this should do, right? I mean, I have a function here. So I can see the function signature and I want it to be a Python thing. So the most obvious thing to do is convert it into a Python callable. What Python does is it generates code for me that wraps the C callable in a Python callable object. I can now call it directly. You'll see that in a minute. Okay. So I have a Python callable now and when I call it from Jupyter, it outputs the same thing as before. There's kind of the quickest way to wrap a C function that has a Python-like signature. Sign symbol just gets a double in, a double out, C double in, double C double out. That means from the Python side you can pass in any float object and get a float object to pick out. Okay. What this basically does internally is this spelled out. So this is a long version of this, right? I'm writing a Python function which says it's called C sign takes a C double, another extension that they can use in the Python now. I can type my arguments. I could just write this. Fine. I would do that in Python. In Python, I can be explicit here and say what I actually want there is a C double. Okay. Whatever you put in as an argument should be converted into a C double and Python will generate the conversion code for me. So what I'll get here is a Python callable function which takes an argument, converts it into a C double. I could type error if that's not possible. So if I put it in string, we get a type error, obviously. And then inside of my function I just call the C sign function. That's what you ask for, right? And I can do that from Jupyter again, call my Python function and it runs the sign function internally. Okay. Nice feature of Cython. When I say Cython minus A what it generates, it generates a C code for me but it additionally generates a little HTML snippet for me that shows me how the compiler understood my code. So this is a copy of my code and it has information that I can use to understand what became of my code. It helps me in optimizing my code. And when I click on one of these lines I can actually see what C code is generated for this line. This is the function signature. It's pretty involved because it has to do error checking. It has to do argument conversion. It has to do lots of things here and there. It has to register a function at a callable in the module argument and all that. So this is what comes out of this line and this line is actually, the second line is actually more interesting. I can see that there's an X argument going in. So we are just, you know, the argument names when we generate C code to avoid naming collisions. This is basically variable X that I put in. I call the C sign function on it and you can see that it's really straight. C call to C sign. And then since this is a Python function the end result has to be passed back into Python, to my Python caller and for that it converts it from a C double to a Python float. And this is what this C API call is doing here. Okay? So this is a nice way for me to, you know, for me as a, as a Python user to understand what Python is doing with my code, how it's interpreting it, what becomes of my code. You can see that there are a couple of yellow lines in here and those yellow lines give me additional information that tell me how much object or operations there are in each of these lines. Which is interesting when I want to start optimizing my code, when I want to, you know, drop it into C and make it faster there because every yellow line tells me there's some object operation going on, there's some exception handling going on, some error checking and that's anything that uses interaction with the C Python runtime. And if my goal is to convert my code into fast C, not using objects, but using native data types than any yellow line is probably worth looking at. And the darker the yellow, the more object operations, the object interaction there is going on. Which is kind of obvious in this case, I mean there's a signature, so like type conversions, error checking, exception handling, stuff like that, lots of interaction going on there and this line is really just converting the end result of a C call back into a Python object, so there's less operations going on here. Okay. Now what makes, I mean this is just a different way basically of spelling the initial example that I had, right? Wrapping a C function, that's it. What makes it more interesting then is in Cython, once I have these, I have a wrapper function here, I can move more code below the Python level, I can take functionality from Python, right, and make my wrapper thicker. I can put functionality into the wrapper between the C library that I'm talking to and the Python API that I'm providing to Python users. So I can make my wrapper more intelligent, smarter, better looking, you know, more Pythonic for a Python user, I put in more functionality at the lower level and hiding all the little dirty quirks in the C API that this Python user shouldn't have to bother with. Okay. Simple example here. Instead of calculating just, you know, just calling the sign function, I call sign of X squared, right? I could do that in Python. I could use my wrapped sign function and do, you know, X squared passing into the sign function and then would call, would calculate the sign of that. But doing that in C is just much faster, right? I pushed down the X, it calculates X squared sign of X squared and then passes back that result much faster than doing half of that in Python. I can do that here. And it runs. Okay. Just two little things. Since we're in C now, I can use manual memory handling in C. This is how that would look like. I have Melloc and Free so I can allocate some memory. I mean, in Python, memory handling is completely automatic, right? You have objects, you have references to them and when the last reference to an object goes away, then the object just dies and gets collected. That is not the case in C. Like, totally not. C is completely manual. And so in C, I would say, you know, allocate some memory here. If that fails, I can now point it back and I just say, raise memory error. You wouldn't really do that in C, right? What would you do in C? You would return some error code, right? Say you return minus one or return something that tells the caller something went wrong and you have to handle it. In Python, well, Python is Python, right? It integrates with Python so you can just say, raise memory error, raise an exception from your Python code. Totally normal. And this is totally what you would do. Well, if the allocation worked, then I can use my memory for something and we have a couple of nice features in the language that make array operations, pointer operations a bit more handy and pythonic than they would be in C. No, since, so question was, are those bound checked? No, because C is just a memory pointer. This is one place in memory and here I'm actually explicitly telling Python to assign something to the first two entries, which is still much nicer than in C, but pointers are just pointers. They're not arrays. Arrays are actually bound checked. Okay, so I can do this and do a couple of nice things. You can also say just print. If anything goes wrong here, then I definitely want to clean up my allocated memory. So I want to free the memory and I do that with try finally, as I would in Python. So if print, for example, raises an exception, can print, send it out anymore, for example, close already, anything can go wrong here. I'm doing a Python thing. So this can raise an exception and if that happens, I say finally, still make sure you free my memory.  Nice feature. Okay, quick example for calling external code. You've seen Lipsy sign function that I called. Here's an example for calling external library that is not just there, like Lipsy, but really an external library. Who knows what Lua is? Who's used to before? Yeah, okay, cool. So Lua is really a small language. It's a language that people use for embedding, commonly in C++ projects, but you can obviously also embed them in C++. Why not? So here's a little embedding for Lua in Python. First thing I have to do is I have to tell what the C API that I'm using here, the Lua C API looks like. Previously, you may remember that I said C import LipsyMath. What that does is it looks up an external declaration file and finds the LipsyMath declarations in there. Here, I'm doing that inline in a module, and this is a syntax for it. I'm basically just saying, you know, this is an external declaration. It describes external code which comes from the Lua.h file. So that's the header file that describes the Lua API. And it has a couple of things in there. There's a function for creating a Lua runtime for cleaning things up, for loading code into the Lua runtime, and it's on fourth, a couple of functions. And note that I did not copy the complete vast Lua C API in there. I just copied the functions that I need. Because that is all I need in my code. Remember that Python translates my code to C, right? And then there's a C compiler afterwards that compiles that to a shared library. And the C compiler obviously sees the whole thing, right? But Scythe doesn't need to know about the whole thing. It just needs to know what I'm using. In order to generate proper C code that the C compiler can compile and understand. Okay? It's also very nice. It's really just a dozen functions here, so that allow me to execute Lua code from Python. So what's my interface? I'm defining a Python function that takes a code, Lua code as a string. And I'm doing a couple of things. Blah, blah, here. It might be a Unicode string. In Python 3, it's quite likely going to be a Unicode string. In that case, I have to convert it because C doesn't know Unicode. It only knows bytes in strings. And that's how the Lua API works also. So I convert it into A to be able to execute it there. Then I create a new Lua runtime. If that fails, I just say raise memory error because that's what the documentation tells me. If the creation of the Lua runtime fails, documentation says it. Well, it's probably a memory problem, right? It couldn't be allocated. So raise memory error is the right thing.  This is what I'm doing down here in my finally. So I'm cleaning up the Lua stack and closing the Lua runtime to clean everything up. To release the memory. And then I have a function to pass in the Lua code into Lua. If that fails, I raise the syntax error. Well, probably the wrong syntax. Then I can execute my code using the C API function and I get some result back.  I'm just expecting some number back. I could look at what the result is and properly convert it to some corresponding Python type, but here I'm only expecting numbers. One number result and that's it. There's a function to converting it to a C number. And then when I return that from a Python function, Scythe will see okay, there's a C number and you want to return it from Python functions or return it as a Python object. So I compile this. Here's a couple of lines of Lua code.  And when I runtime it on that, it's going to tell me that Fibonacci of 24 could be calculated in 2 milliseconds a bit more. Okay? This is how you use C libraries from Python. Okay. So of 10 minutes. So I'll get back here. Second example. Optimizing Python code. I chose DiffLip. Who knows DiffLip? From the standard library. Not so many people. You should look through the standard library documentation. There's lots of nice goodies in there. So what DiffLip does is you can pass two sequences in there and it's going to compare them and tell you where the difference is. It's just like the Unix diff but at an API level. You can use it directly from Python. It's been there for a long time. Most things in the standard library have been there for a long time. So I'm going to optimize DiffLip a bit. Okay. As a benchmark, I'm using a tool called FuzzyWuzzy which comes with a little benchmark. That's why I'm using it. FuzzyWuzzy basically just does fuzzy comparison between text. So it passes into text and I try to match the parts. And it's not really relevant. I'm just using it as a benchmark here. I'm using Cprofile for profiling to see how fast my program is running and where I get. Okay. Let's look at DiffLip. Let's run it first. I'll just clean up my stuff and then run a benchmark. Let's take a couple seconds. It's running multiple examples. The time it takes to run the whole benchmark for FuzzyWuzzy. You'll see in a minute that it's dominated by the time it takes DiffLip to do the comparisons. Takes a bit of time. One thing you shouldn't forget when running benchmarks is some switch of energy handling of your laptop. Okay. In this case because it's been doing computations before and so I'm probably not slowed down much. It's about what I expected. So 46 seconds for the whole runtime. Okay. Now, next thing I'm going to do is I'm running Cprofile on the benchmark to see where time goes. So I'm going to run it again. It's going to take a bit longer but who does not know Cprofile? Okay, couple of people. So Cprofile, what Cprofile does is basically it traces your code. On each function call it's going to tell you functions we called, functions been exited and then afterwards it's going to present you know, it's going to dump the profile somewhere and it's going to tell you what were the functions in there that took most of the time and where was most of the time spent and was less relevant. So it's a very quick way of assessing the runtime profile of your code and like finger point and point that you want to optimize first. Okay, again it takes a while. Obviously it takes longer now because as I said it instruments your code. So it's really doing stuff where your code is running. There are profiles out there that slow down your code much less and it's really worth looking into them. One is the Perf tool in Linux. So if you have Linux look at the Perf, definitely. But it operates, most of these tools operate at a much lower level so they give you C-level information rather than Python-level information and Cprofile just really gives you Python-level information. So I've executed lots of function calls. How many are there? 153 million function calls along the way. It took 78 seconds to run now and the most costly function here is FindLongestMatch in Deflip and it took 25 seconds of our runtime all by itself plus it took an accumulated 34 seconds if you add the its own function calls internal function calls to it. So the whole time spent in that function was 34 seconds and its own code that it uses and 25 seconds only directly in the function itself. So that's a lot of processing time. So I'll look into that function and I have it somewhere here. Can you read this large enough? Larger? Like this? Better? So this is the FindLongestMatch function. It's actually a method which makes it a bit more difficult to optimize but I'll just do a couple of quick speedups here. And it basically starts here. You can see someone's already tried to optimize this function quite a while ago apparently. This is one of the standard tricks that you would pull in Python.  Normally what you would say is A and B and what they do here is they take the bound method of Bs and B contains A. So they replace the operator by function call and apparently that was faster at the time. I actually tested it and it's still a bit faster in 307 but it's something that you don't need in Python because operators in Python are actually much faster. One thing I would do is remove that but they're actually quicker gains to make here and I'll start with those. When you look at the code it has a nested loop and runs over a couple of data structures. You don't need to understand what those data structures actually do.  A nested loop always means that there's a lot of work going into looping and to do and stuff there and loops are very easy to speed up in Python because you can replace them by C loops and do stuff that you can see rather than run through Python's iteration protocol. I'll do that first. How do I do that? This is using a loop over a range so I know that these are actually integers and I can replace them by C integers. Most obvious change first. When I look into the usage of I then I can see that it's used to index into a data structure. It's used as key in the dict and it's also used as index somewhere and that means that a difference between C integers and Python integers is that Python integers are unbounded. They can have arbitrary they have an arbitrary value range that can be as large as your memory allows. C integers are not. C integers are always range bounded so this is 32-bit integer which can take numbers up to 2 to 31 and stuff like that. If it's signed and when you're converting Python code to Python now to faster C code you have to take care of that. So I'm replacing Python integers, save Python integers which can go out to large and have to make sure that I'm not restricting the value range in a valid way because C integers wrap around the weird stuff when they go out of bounds but there is a C integer type that I can use here and that is it's called PySizeT which is defined to be large enough to fit the size of the memory so it's a 32-bit system 64-bit system and so on and forth and I'll type all variables in here using that type I'll actually use a different type it's called PySizeT but that's just a different name for it that's used in the Python world I'll use that for my integer variables and I'll type them in in Python so I have an i I have a j as an index I have what else do I have a low a high so there are all index variables here and there is b low and b high when I look through my code those are all the index variables that are being used here and that's also best size just an index best i and best j all of them best i and best j yep, I'm through with my 40 minutes I'll just go a bit into the question time and then run this there so I'll first compile it I'm using Cythonize here so I've compiled my deflip what it does is it just generated a c file for me now it's called in the c compiler so Cythonize is a nice tool for doing like all of them I just say Cythonize my code Cythonize minus i is we built it in place compiles it generates the shared library for me and we can just import it and now when I run my benchmark again it'll take a while it's going to be a lot faster already and while it's running I can just tell you there are a couple of more things that we can do one I already mentioned is I can replace this Python hack here by just the expected operator so undo a Python optimization that is you know that you can do but that is not beautiful and a couple of other things are I'm using dicts here for example dicts and lists here I'm calling the get method of a dict which in Python is looked up every time in Cython that's actually very fast if Cython knows that B2J is a dict and so if I type B2J as dict which is the next thing I can do this is probably an argument so B2J is a dict Python dicts then that's also going to be sped up and you can see we're down from 46 seconds to 35 seconds just by typing the integers and one thing that did is it allowed Cython to replace this integer range loop by a C for loop because all the index variables type so it knows that there's nothing that can wrong I'm actually asking for C for loop here and I'll try the dict optimization next and then I'm already through with my talk and there should be time for one or two questions afterwards so it's compiling and the benchmark again and this is the usual way to go about optimizing code in Cython to take Python code you start typing variables replace them by C data types here and there you use static typing for instructing Cython to opt out of general this is some kind of object semantics into this is a specific data type please optimize it optimize the code for it that is usually faster and definitely more adapted to what you're doing in the code that gives another 5 seconds runtime so we're down from 46 seconds to 30 seconds just by typing a couple of variables here that's it time for a few questions just a couple of questions the first one is like we have seen that you can call random I mean custom C libraries from Python just by defining the interface for them is it possible to do the opposite I mean call Python code from C with using Cython yes so you can generate so-called C def functions in Cython which are just C functions with the expected C signature and you can drop any and you can call the C function from C and then you can execute any Python code in there oh cool and the second question is like whether Cython benefits in some way from using typing hints like in new Python we have the function type hints and so on I've used the syntax for this it does not really benefit all that much from normal typing because there's not so much to gain from them for optimization they are for code checking they're not for optimizing code one last question so we use Cython a lot these are really great tool and one of the things we miss in the Cython ecosystem is a linter some kind of like Flakey or Pepe or whatever we use some subset of what Flakey does like basically for in syntax errors but we wonder if there is any project or idea of maybe exposing the abstract syntax tree or something so we can hook into existing linten tool okay so tool support you can do two things one is as long as you're really just optimizing Python code you can use Python syntax for it and that keeps your code, your optimized code your compilable code in Python syntax and you can use all your Python tools you can start calling to see using native code you lose that ability because it can't be mapped to Python that code cannot run in Python anymore so you use Cython syntax for that in which case there are a couple of well there's at least PyCharm definitely which supports Cython you can use that there probably also other ideas kind of having some basic support but I'm not aware of many many tools for code analysis and this kind of stuff on Cython code specifically is Cython syntax alright, don't forget to rate the talk and let's give Stefan one round of applause


This video is voted on by patrons. They got to choose my final review of Cobra Convergence 7. I like to give them what they want. And this time since we're looking at a Cobra Wilderness Survival Specialist, I'm testing my own survival skills. I'm out here far from civilization, and I must survive only on what I can find in the wild. I hope I can survive to the end of the video. It's important to stay hydrated. Hello everybody, hooded Cobra Commander 788 here. It's my final review of Cobra Convergence 7, and some of you watching this help me choose what to review. Thank you to everyone who supports the channel on Patreon. You make these reviews possible. This time I am risking my life by surviving in the wilderness until the end of this video. It will not be easy. It's very hot out here. I could die.  I'll get a lot of views out of it. The Range Viper is a unique and popular figure, and he has a horror theme, which is why he's usually reviewed around Halloween.  The Range Viper is also known for his skill at surviving in the wild. He can live off of wildlife, build his own shelters, and even steal ammunition from the enemy. If he can do it, I can do it. It's hot out here. HCC 788 presents the Range Viper. This is the Range Viper, Cobra's wilderness trooper from 1990. This action figure was introduced in 1990 and was only available in 1990. It was discontinued for 1991. This is the only vintage version of the Range Viper. The figure was revisited several times after the vintage era, including the modern GI Joe classified series of 6-inch action figures. It's unclear who the designer is. Mark Pennington did some presentation artwork, but he had left Hasbro at the time and was working as a freelancer. The design has some of the organic elements we see in other Mark Pennington designs, but have not been able to confirm that he created the Range Viper. Range Viper's specialty is similar to GI Joe's Outback. They live in the wilderness, they live off the land, and they fight in harsh conditions. Prototype code names for the Range Viper included bush vipers, badgers, snake eaters, and dingoes, all of which sound vaguely sexual. The name Range Viper is probably a reference to U.S. Army Rangers. Army Rangers receive survival training in several environments, but they also have leadership training that the Cobra Range Viper seemed to lack. 1990 was a great year for Cobra specialized vipers. There was the Laser Viper, the Rock Viper, the Saw Viper, and also the Night Creeper who worked with Cobra. There was also Undertow, but he worked with Destro. 1987 Outback may have been the closest GI Joe counterpart to the Range Viper, but the 1990 GI Joe character that most closely matched the Range Viper was the concealment expert Ambush. Ambush had a personal connection with one specific Range Viper, which we will talk about later. Let's look at the Range Viper's accessories, of which he has many, and let's start with his primary weapon, this grenade launcher. It is in black plastic. It has a stock and a foregrip that is small enough to actually use. It has this large drum magazine on top, and you can see the grenades loaded into it. That is a separate piece which can be removed. This drum grenade magazine has a notch where it connects to the grenade launcher, and on the back it has a gear and chain detail that hints at how it's supposed to work. The drum loader just snaps onto the top of the launcher like so. It doesn't rotate or anything like that, but when it's all together, it looks like a very fearsome weapon. The next accessory I'm going to look at is the knife. I have the knife wedged in the backpack. We will need to take a look at the backpack at length later, but let's look at this knife first. This knife is in black plastic. The blade is wider at the end than it is on the base, and it has some spikes on the hilt and a black handle. The knife will fit in the action figure's hand, and it looks really wicked. I like it. The next accessory looks like another grenade launcher or a missile launcher, but it is neither. According to the card contents, this is a mortar, which it doesn't look like at all. This mortar is in gray plastic. It has some detail along the barrel, and it has a grip that is pretty thin and fits easily in the action figure's hand. It also has these two knobs that don't really connect to anything. It also includes a removable gray missile, the same color as the tube itself, or a mortar, whatever this is supposed to be. This is not one of these spring-loaded missile launchers we got in the later 90s. I played around with this to figure out how it worked, and I originally had the missile going in this end, the smaller end, with the grip toward the front. But I don't think that's actually how it's supposed to go. I think it's supposed to go in the wider end and slide all the way through the back, and it protrudes out the back. I think this is an FFT, or Finger Flick Technology missile launcher, which we did see in the early 90s.  It's a low-tech way to get a firing missile launcher before the days of spring-loaded missile launchers. It's pretty weak, but it does kind of work. If this is, in fact, an FFT missile launcher, I don't think it's advertised on the packaging anywhere, which means it's a bonus feature. The next accessory is this black plastic hose connector. One end of it connects to a peg on the backpack. The other end connects to a peg on the back of the action figure's head. And that can be removed. This is a standard black, flexible plastic hose. Many G.I. Joe action figures came with black hoses like this. In this case, I'm not sure exactly what it does. It connects the action figure to the backpack, but what exactly is it feeding into the helmet? There is this tank on the top of the backpack, so maybe that's some kind of air tank, but it's not clear. Finally, we get to the backpack. This backpack is large. It is in gray plastic. It has a lot of detail, and it has some features you might not expect. It is surprisingly intricate. It has this tank at the top who knows what's supposed to be in that, and the peg for the connector. It has four antennae, two on each side, on the top and on the bottom, and they connect to these devices on the side. So this must be some kind of communication backpack. Do be cautious. Those antennae can break off. I have another backpack with the top antennae broken, and if you didn't know they were supposed to be there, you might not realize it's broken. There are two rows of replacement grenades for the grenade launcher, and I like that coordination between accessories. There is some electronic detail at the bottom, and then there's this slot which cuts from one side to the other. What is that for? I'll tell you what it can be used for. It can hold his other accessories. As earlier, I had the knife wedged in that slot, and you can hold the grenade launcher by pressing the foregrip into the slot, and he can hold two of his other accessories, which is possible, but that looks really awkward, doesn't it? This is often what collectors use it for, but the accessories fit in there so awkwardly, I can't say that's what it's intended for. But if it's not intended for that, what is its purpose? In case you're wondering if the mortar fits, first let's take a note of what a nice color match it is with the backpack, but it doesn't work on mine.  Whether it's intended or not, this backpack does mean he can hold all of his accessories at the same time, despite coming with a lot of them. With the accessories out of the way, let's take a look at the articulation on the range viper. He had the articulation that was standard for GI Joe figures well before 1990, so he could turn his head from left to right and look up and down. He could swing his arm up at the shoulder and swivel at the shoulder all the way around. He had a hinge at the elbow that allowed him to bend his arm at the elbow about 90 degrees. He had a swivel at the bicep, so he could swivel his arm all the way around. This was an O-ring figure, meaning the figure was held together with a rubber O-ring around the inside. That allowed him to move at the torso a bit. He could move his legs apart about so far. He could bend his leg at the hip about 90 degrees and bend at the knee about 90 degrees. Let's take a look at the sculpt design and color of the range viper. The range viper is supposed to be in the wilderness all the time. He is not camouflaged for it. Despite this, the colors are attractive and well-balanced. It's a good-looking action figure, even if he isn't well camouflaged for his job. I have to point out that on his head, he has a dark greenish-blue skull-like mask with red eyes very spooky looking. He has a band that's the same color that goes over the top of the mask to the peg connector in the back. The rest of the helmet is gray and it has this texture pattern on it that looks like brain. It looks like he has an exposed brain, but that goes all over the helmet down the back and the sides as well. This helmet is intentionally scary. It looks like something out of a horror movie and it's intended to evoke a fear reaction in any enemy that sees it. Moving on to his chest, he has a dark greenish-blue uniform with a dark blue undershirt. He has yellow rings around his arms. He has a gray strap over the left shoulder for the backpack. And that gray strap is a nice color match for the backpack. That looks really good. There's presumably another strap on the right side, but it is covered by these ammunition belts. These ammunition belts are highly detailed and painted gold. There's one that goes over the right shoulder across the body and under the left arm. There's also one that goes around the right arm. What is this ammunition for? It doesn't fit any weapon included with the figure. It's a great detail, but it should match an accessory. Otherwise, it's just decoration. Moving on to the arms. The upper arms are in that greenish-blue color. The lower arms are in the dark-blue color and he has gray gloves. With just the gloves painted, we have three colors on these arms. That is judicious use of paint and it's a lot of color variety. I think it looks good. On the waist, he has a black uniform and a yellow belt. The belt has three pouches in the front. There's another smaller belt under that that's gray. The gray belt has a pouch or something on the right hip and a black detail on the left hip. On the legs, he has a black uniform and I think black was an excellent color choice. I think it adds even more depth to the colors on this figure. There are no sculpted pockets or weapons on the upper legs, but on the lower legs, we have some gray knee pads and shin guards that continue over the top of the boots that has a slight texture pattern on those. There are short dark blue straps that connect the shin guards to the boots and we finish up with some black boots. Despite the oddities, this figure looks great. It's one of the favorites from 1990 and it's easy to see why. It isn't camouflage, but Cobra didn't do camouflage very often. The colors work really well together. The skull helmet is intentionally scary. The biggest oddity is the ammunition belt. It looks great, but why is it there? What weapon does it feed? There's also no Cobra emblem anywhere on this figure. Is Cobra trying to disown them? Are they really deploying them or are they just driving them out to the woods and leaving them like your grandpa did with his old dog?  Let's take a look at the Range Viper's file card. The file card has his faction as Cobra. There's a portrait of the Range Viper wearing his mean face mask. He is the Range Viper's plural and they are the Cobra Wilderness Troopers. This paragraph says, Range Viper's are usually committed to long-term operations deep within unfriendly territory completely cut off from communications or supplies, but he comes with a communications backpack. They have an unusually high tolerance for discomfort and can survive on a diet of snakes, grubs, roots, berries, nuts, and whatever slow rodents they can catch and your grandpa's old dog. They are expected to build their shelters out of indigenous materials, usually rocks and mud, and procure their own ammunition by way of hit and run raids on enemy ammo depots. This bottom paragraph has a quote. It says, Range Viper's are favorites of Cobra High Command since they're so inexpensive to sustain. Once they're in the field, they don't cost anything to feed, clothe, and arm. Range Viper's don't care who they shoot as long as they shoot at someone or something. That's why the Cobra High Command makes sure they stay out in the bush. Cobra just throws them out there and they fend for themselves. Cobra takes advantage of their wilderness survival skills to cut their own budget. They would be formidable enemies for GI Joe. They are resourceful and determined. Luckily I found this natural pond to cool myself off on this very hot day. Surviving in the wild sure is tough. Larry Hama was the writer of the GI Joe comic book series and the action figure file cards. On three separate occasions, Hasbro tried to remove that responsibility from him and do it in-house, and each time they discovered it's not as easy as it looks. On the Hasbro written file cards, they're filled with just fluff and promotional copy. File cards written by Larry Hama tended to be more colorful and imaginative. You can kind of tell which file cards were written by Larry Hama by which ones sound good. The Range Viper file card is definitely a Larry Hama file card. Looking at how the Range Viper was used in GI Joe media, they appeared in the Dieck era in the animated series. The first appearance was barely in the episode United We Stand. Range Viper appeared more prominently in the episode Pig Skin Commandos. That's the episode where they played a football game with tanks. Range Viper had the most screen time in the episode An Officer and a Viperman. Range Viper is a trooper, not a named individual character, so he was treated the same way as other Viper's were. They appeared when it was convenient, but they took a back seat to the main characters. But there is one named Range Viper known to her comrades as Range Viper 3, but her name was Evie. In the episode I Found You Evie, a female Range Viper named Evie was a friend of GI Joe's ambush. Their relationship was one of the most interesting and complex in the Dieck series and proves the Dieck GI Joe animation team was capable of good writing. I mean, it's no Pig Skin Commandos, but it's not bad. Because of Evie, the Range Viper had a more important role in the series than most other Viper's. The Range Viper appeared in a video game, but I don't usually cover the video game, so I will leave that to the experts. In the comic book series published by Marvel Comics, the Range Viper first appeared in issue number 113. That was an issue known for the death of GI Joe team members. The comic book series depicted death much more often than the animated series. Death is a consequence of war and that consequence was addressed head on. The most deadly Viper was the saw Viper, but the Range Viper had a notable kill of his own. In issue number 113 during the Benzene War, a frag Viper tossed a child into the middle of a firefight. Sneak Peek tried to protect the child, but a Range Viper shot him down. That was the death of Sneak Peek. In that issue, the Range Viper's grenade launcher is treated like a machine gun. It even still has the drum grenade magazine, but it shoots bullets. That's the same issue where most of Battle Force 2000 was killed. The Benzene War story arc resulted in more GI Joe deaths than any other, and it showed there are real stakes in these battles. The characters were not invulnerable. The Range Viper has it all, or almost. The figure is highly detailed. It's sharply sculpted. The plastic and paint color is excellent. There's so much to it, you just want to keep looking at it. The Range Viper is most famous for the Skull Mask, which is unusual even for Cobra. The Mask isn't for concealing his identity, or even for some tactical function. It's to inspire fear in his enemies. What the figure doesn't have is anything that indicates he is Cobra. Obviously, he looks like a bad guy, but there's not a small Cobra patch on the figure. The accessories are also unique and interesting, and he has a lot of them. He has two weapons for firing explosive projectiles. The Mortar looks more like a missile launcher to me, and it comes with a removable missile. Add to that the knife, the hose, and the backpack. It's a lot. Despite including a lot of accessories, he can hold all of them. Sort of. The knife and the grenade launcher can be wedged in the slot on the backpack, but it's an odd way to carry them. I'm not even sure that's what the slot is for. What he doesn't have is a weapon that would use the bullets sculpted on the figure. The role the Range Viper plays in Cobra has a lot of play potential. Cobra tosses them out in the jungle and forgets about them, and when G.I. Joe least expects it, they attack. The Range Viper is a fan favorite, which is why he was chosen by patrons for this review. In this case, I have to agree. Surviving in the wild sure does wear you out. This is my final review for Cobra Convergence 7, but the event is not quite over. We still have a couple presenters. We have podcasts from the pit and Agent Chuckles, and there's still time to get involved in the band video every week. There's one more to go. Check the website, ACC788.com to find out how.  And the website in Cobra


Marines learned principles of underwater evacuation during a helicopter-dunker exercise aboard Camp Pendleton, November 4th. More than 20 Marines with 2nd Battalion, 5th Marine Regiment, conducted the training as preparation for their deployment with the 31st Marine Expeditionary Unit in Okinawa, Japan. They put their survival skills to the test when instructors put them inside of a modular, amphibious egress trainer and completely submerged them underwater. The Marines trained to escape from a helicopter that has flipped upside down at sea and learned to use reference points to quickly find an exit. You learn, no matter how confident you are in the water, it does take a technique. I came from a recon background. I was pretty much a drown poof when I got here, but I first tried to get out that exit. It wasn't working for me, so the techniques we teach here, they work. We don't just make these things up as you get here. The Marines went through the dunker several times, increasing the amount of equipment worn as they progressed. From the initial dunk, the gear increased to include a rifle, flak jacket, blacked-out goggles, and an emergency breathing device, which allowed them to develop survival skills that could save their lives. Before doing this, if you had asked me, is it possible to survive an egress from a helicopter that crashed in the ocean, I always said you're out of your mind. But after doing this training, although I'm sure it's still a lot more difficult than a real-life scenario, have a lot more confidence manipulating the gear, finding reference points and finding an egress point on that aircraft that I can get myself out of if it goes in the water. With the training, the Marines can effectively operate as an amphibious task force and safely conduct heliborne ship-to-shore movements. Reporting from Camp Pendleton, California, I'm Lance Corporal, Christopher Moore.


What's up everyone, takedown here, welcome back to another video. Today we're going to be talking about if winter wiper blades are worth buying. Let's get right into this. So as you guys might know, I did use to work a few years ago at Canadian Tire in the automotive parts and service departments, and there was a lot of confusion whenever it came to wiper blades and which you should buy at which time of the year. So we're going to be talking about that in today's video. Now whenever it comes to summer wiper blades, those are the ones that look like they're a metal frame. They're extremely light and they're only intended to remove rain off of your windshield and perform terribly in the winter. I recommend to never use summer wiper blades in the winter, since it is a metal frame that is prone to have ice and snow build up in between each part of the frame and can actually break as you're driving down the road, which is extremely dangerous. Now winter wiper blades do cost more, but in the winter weather they are proven to perform better with heavy snow and ice. Regardless of if there's snow or ice on your windshield, you should be scraping your windshield prior to you starting your drive because even if there's ice on your windshield, if it's frozen on your windshield, your wipers are not going to be able to remove that. It's literally a thin wiper blade. It's not something that can scrape off ice on your windshield, but with that being said, any snow or ice that's accumulated on your windshield while you're driving, the winter wipers should have no problem removing that snow while you are driving. Now whenever it comes to the cost, the summer blades, which are the metal framed blades, usually cost around $5 each wiper, while the winter blades cost around $25 each wiper or more depending on the brand that you choose. But there also is another option, which is the all season wiper blades. The main difference between the winter wipers and the all season wipers is that the winter wipers are a little bit bulkier, which means they can remove the heavy snow a lot easier than the all seasons. Personally, I use all season wipers all year round and only replace them whenever I need it. The all season wipers are a better option for me. I find that they work better for me because I always end up clearing off my windshield anyways prior to my drive, so I have no issue just running with all season wipers all year round. All season wipers can start around $10 each and the more expensive ones are $27 each and up. The ones that I use and recommend are called Reflex Gold, which used to be called Reflex All Seasons and they're exclusively sold at Canadian Tire. It costs around $20 each and they include a one year warranty, which is something that usually wipers do not include, so if you have a problem whether or not it's just not clearing the windshield, it's just streaking or they break. If it happens in that one year, you can get a free replacement. But with these ones here, if they're taken care of, they can last a minimum of two years or more before you need to go and replace them. In my opinion, with these all season wipers compared to winter wipers, there's not really a big difference in performance or design, which is why I decided to go with the all season wipers and I've been using them for years and that's the brand that I'm honestly going to stick with. So are winter wipers worth it? In my opinion, no. You can get a mid-range or mid-priced all season wiper that is going to last, in my opinion, a lot longer than a winter wiper and you can use it in the winter and it will perform just as good as an actual winter wiper, regardless of what they claim it will do. Now winter wipers can be used all year round. Winter tires should only be used in the winter months, whereas winter wipers can be used all year, but they are bulkier and at $25 a piece compared to $20 a piece for my all season wipers, it's not really worth it, considering the all season wipers will do just as good a job. So in my opinion, simply get a mid-priced and a good rated all season wiper and that will do great for you in the winter. The winter wipers aren't completely necessary in my opinion, but hopefully this has helped you guys understand a little bit more about the difference between the summer blades, which are the metal framed blades, which perform terribly, terribly in the winter and I highly recommend not using them and the all season and the winter blades as well. I'll see you guys in the next video. Please take care.