Hi everyone, welcome. My name is Martin and this is my collaborator, Riccardo, and we're going to be talking about Solo 5, which is something we're calling a retargetable sandbox execution environment for Unikernels. That's a lot of words, so we'll go and try and explain some of the concepts if I can switch to the next slide. So, actually Riccardo told me that in the Unicraft talk, which was just before a bunch of people were asking what is a Unikernel, so it's good that we have some background to this. There are two separate terms that people use here. There are two separate terms that people use that are kind of similar related to each other, but I think it's important to show some distinction between them. So, a library operating system, these are things that have been around since the early 90s. They actually come from even older technologies, Butler-Lampson had some papers I think in the 70s that were kind of using similar concepts. A library operating system is essentially just a collection of libraries, except those libraries do traditional OSC kind of things that you'd normally expect to have in your monolithic kernel. It's in the sacred kernel space and you have file systems, TCP stacks and so on. With micro kernels that's a bit different, but it's still part of the micro kernel component, whereas here it really is just a collection of libraries. Generally, there is no concept of process isolation with the Libos, that's not really its job. And they also use cooperative scheduling. For the non OSC people in the room, that basically means applications are more like event loops, rather than getting preempted internally. So, you take this collection of libraries and then you combine it at compile time and out pops a unikernel. That's the distinction I'd like to make between these terms. The unikernel is the art effect, which is made up of your library operating system and your application code. Unikernels, then due to this process of being built out of this collection of libraries, we can minimize the code that goes into them. So, you have minimal code size, which implies a minimal kind of horizontal attack surface. There's not very much stuff that goes into this thing. You can think of them as single purpose application operating systems, though then people tend to think, oh, it's actually a kernel, it has to run in kernel space. That's not true. Conceptually, I would, my favorite way of looking at it is it's just a process that does more. So, it does more operating system-type things. So, what is Solo 5? This is the shape of Solo 5. And the top bit, so is where your unikernel and library OS go. And the bottom triangle pointing up, which is much bigger in this case, is some host thing. And Solo 5 occupies the space that's the blue circle in the middle. Okay, what is this then? So, it's, there are three important parts to it. One is a minimalist legacy-free interface. So, really, really small.  Then we have some bindings, which are the implementation of that interface. And in this picture here, the bindings would be roughly the top bits, the top part of the intersection of the circle with the triangle. And we have bindings for micro kernels, for separation kernels, and so for a vertio-based hypervisors, so cloud hypervisors basically, and existing monolithic kernels. Additionally, on a monolithic kernel, we have a third concept, which is a component we call a tender. And that's used to strongly sandbox the unicernel further away from this big bad monolithic kernel with its huge interfaces, as I'll go to show in a bit. And we have two tenders. There's a hardware-virtualized tender and a sandbox-processed tender. From the library operating system and all the application and library operating system developers point of view, Solo 5 is just middleware. So, ideally, it's integrated directly into the Libos build system, and you don't actually interact with it directly. An example for Mirage OS is it is just a different parameter to Mirage Configure, where you can say which of these targets I want and out pops a unicernel. That's the way it should be. Other Libo OSes are not quite up to that state yet, but hopefully we'll get there. So, comparing the Solo 5 shape to other common isolation interfaces and some units of execution. Again, the bottom side is always some host, and the top part is the units of execution that we're comparing Solo 5 against. Now, what I want to show here is both horizontally in the middle where they meet at this line, there is something that represents relative width of these interfaces. Also, vertically, I'm very roughly not entirely to scale, comparing that unicernels are small, containers are generally larger, and the VM, well, a traditional VM can just be as big as your host, or bigger. So, the width of this interface in the container case, I'm actually showing that the interface is the entire host interface. Now, people may say, well, okay, but it's names-based and we have C groups and whatever. Actually, it's just adding more logic to this interface, which is just as wide as it was before. You can switch bits of it off, which some people do with SetConf. We'll talk about that in a bit. But most of the time in your general container case, you still have access to 350 calls. In the case with the traditional VM talking to some kind of host, host or hypervisor, the entire interface between the VM and the host is actually quite big. So, you've got tons of stuff in here. You've got ACPI, device discovery, vertio, PCI, whatever. All of these things are in themselves quite wide and complicated and stateful. So, the guiding philosophy of Solo5 is that the interface must be minimal. That, I think, is a fairly straightforward term. States list, which is something I've appropriated for this purpose and I'll go on to explain what that means. And it should also be portable. And then the implementation should be clearly layered. It should do one thing and do it well. It should be an engine for running unicernals, other things like orchestration, configuration management, monitoring, whatever. Those are done by layers higher up the stack. So, we're at the lowest layer. We try to integrate or we don't get in the way of other people integrating us into higher layers, but that's not our job. So, in terms of minimalism, we want to provide the simplest useful abstraction. Importantly, that means we're not trying to be Linux. So, this is not an exercise in re-implementing Linux or POSIX. Let's try the smallest thing which is actually useful and still lets us get some work done. One thing that pops out of minimalism is also that we don't do any kind of device discovery. This leads to a very small implementation size. A typical configuration, by that I mean Solr5 compiled into one target that has a tender and some bindings, some of which go in your unicernal, some of which live on the host, is about 3,000 lines of C. 12,000 lines of C is in total the whole code base with all the different combinations of tenders and bindings that we have. Minimalism also gives us clarity of implementation. So, we don't try to do very much and we prefer to do what we do correctly rather than add more features. And it gives us very fast startup time, comparable to what a normal user process would have. So, with Solr5 HVT or SPT we get something of less than 50 milliseconds. QMU, a traditional QMU will typically take when starting a Linux VM up to a second before you get, say, to a first network packet. A lot of that time is spent precisely doing things like device discovery and then actually bootstrapping the kernel. But, yeah. And then for cloud managed VMs with traditional hypervisors, so things like Google computer and general, it takes seconds. So, stateless. Minimalism by itself or a minimal interface by itself, that's just saying, okay, we don't do very much. But, that is not necessarily all we want. By stateless, I mean that there's very little state inside this interface. So, that means both, there's very little state transferred in any of the calls. You could think of them as as idempotent as possible, I suppose. And the guest, the unicernal cannot change host state. So, there is no dynamic resource allocation. Conversely, the host cannot change guest state. So, there are no interrupts going across this interface. This gives us a system that's very deterministic and easy to reason about. And it's also essentially a static system. So, you get some resources, some things from the host up front, memory, access to devices, so on. And that's it. You can never get more. And I think that the stateless property is also what very much helps us to actually strongly isolate this interface and do that both on existing monolithic kernels and on component-based and high assurance microkernels. So, it's this way of thinking about what the interface should do that helps us to get to strong isolation. So, and the third part of the philosophy is that we want to be portable. That includes easily porting existing library OSs to cell F5. And we currently have MirageOS, which was the original library OS that, where cell F5 got started as a standard way of getting MirageOS to run on other things. And Riccardo here has also done support for IncludeOS, which is a C++ based library operating system. And Rump Run, which is a POSIXE-like thing using NetBSD Rump kernels. So, conversely, it should be easy to port cell F5 to new targets. And interestingly, since the project started, we've had OpenBSD VMM support contributed, which I'll show by a guy who's basically an OpenBSD user, definitely not a cell F5 expert. Adrian from the Moon Separation Kernel contributed a port to targets Moon native subjects as a cell F5 target. And Emery, who's here in this room, just last year contributed a port to run or implement the cell F5 interface, so bindings to the cell F5 interface as a genode component. So, let's be honest, there are some limitations. Or you might want to call this slide non-goals. I mean, these are kind of the inherent limitations. As I already said, it's not Linux. We don't intend to become Linux. If you want Linux, you know where to find it. But there are library OSs that let you get quite a lot of the way there. So, Rump Run LKL is something called, I think, the Linux kernel library, which is running a similar project trying to do what Rump kernels did for NetBSD, but with Linux. So, if you want, you can build your POSIX application against a libOS. Semantically, it might be a bit different. You've got to be a bit careful, but generally it'll work. So, keeping the interface stateless, well, no interrupts implies it's a single core, no SMP, no library. The answer to that is run more than one instance of your thing and parallelize your work and pass messages around. It's not intended for interfacing to hardware. That is possibly a bigger limitation, but then we see cell F5 as something which is components as part of a wider disaggregated system and then drivers become some other components problem. So, you can do that both in the microkernel case where you have other microkernel components providing access to hardware, or in the monolithic kernel case, you have monolithic kernel itself in a type 2 hypervisor approach providing access to the hardware, then it's not isolated. Or you have a disaggregated system like cubes or something based on passing hardware directly to isolated components. Portability implies that we have some copying semantics in the interface, and also we have things like one core per packet. That's not very nice, but, well, actually we found it's pretty good. But the main thing I'd point out there is it's not intended for scenarios where you're trying to do high performance computing or pass millions of packets per second. If you're doing that, generally you will want hardware pass through anyway, and trying to implement an interface alongside of these goals for something like hardware pass through is, I think, just a fool's errand. You will end up with bits of the interface, take a typical hardware interface, rip a line down the middle and you'll have bits kind of sticking out. So, having shown the philosophy, I'd like to show the actual interface, and I'll leave this up on here for you for a bit to read through it. Originally I had one slide with all of the interface because I thought it would be cool to just fit the whole interface in one slide, but then maybe that's too much text to read in one go. So, I've split it up into two groups. Top call you can see is basically an entry point into the Unikernel Guest. This also shows that the fact that there is a static system. So, you get given some heap memory with some size and that's it. And you get told here it is, go for your life. There is an exit and an abort call. Those are separate calls. The abort call is something that's intended to say, oh, I'm giving up. Could the host thing, whatever it is, if it's configured to do things like call dumps or page someone or whatever. Something abnormal happened. If you care about that, then treat it differently. I don't like overloading exit and status codes for something which I think is conceptually slightly different. So, that's why there are two. There's a console. The console is intended mainly for debugging-y type stuff or some simple logging, but generally you'd want to do that over protocols and networks or somewhere else. So, it's a console. Nothing particularly interesting about that. We have monotonic time. We have wall clock time. Those are 64-bit types. They are nanoseconds. They'll run out in 500 something years from now. Too bad. Then there is a yield function. So, what this does is it essentially says please yield to the host until some deadline comes. And then, I'll show the second part where I'll repeat the yield. So, we actually want to talk to some devices. So, what we have here is we have a network API which is a very simple layer two network with layer two semantics. So, you push it back it. Packets can get dropped. Read is always non-blocking. So, it will return again if there isn't anything to read. And this ties into cello five yield which will give you back a bool that says do I have work to do or is there nothing to do and it's just the fact that the deadline was reached. Then we have a block interface which is basically block IO again. Calls are idempotent in themselves. So, there is always an offset and a buffer together. The interface is intended to read and write only at some minimum block size that you get out of block info. And it's yeah. So, you will either get back an okay and what you asked to write was written or not. So, there are a couple of things missing here. Which I saw observant people will be asking themselves right now which is where we do you say which of these devices you want to talk to. And also more obviously in the block API there is no flush that is just missing that is something that we need to add. So, there will likely be a flush and a discard. So, the multiple devices thing at the moment the implementation is rather naive and you can only have one or zero or one of these. This is something that we want to change. I'll go into a bit more detail later about why it hasn't happened yet. But fundamentally this interface will not change hugely even in the presence of multiple devices. The difference will probably be that block info and net info will give you back some kind of handle. So, you will pass in an identifier, some name of the device you'll get a handle out and then read and write except a handle. Yield interestingly will not change much. It might give you back a mask of bits saying which of the handles have worked for them. But I don't expect to have again with the not changing host state. You will always ask for is there any work at all? So, you don't go saying oh I'm no longer interested in net zero. Well, no you asked for it in the first place in the beginning. So, if there's any work then I'll tell you there's work on it. So, going to hijack the presentation for a couple of minutes. Concrete view. I need to give you a mic. Well, but no one will hear you on the stream. So, I can just kind of hold it like this. I can do it. Before that I just wanted to add something to what Maito was saying which is that even though the interface looks very, very minimalistic it's surprisingly enough to run a lot of stuff. For example, with RampRam we can run Python node, a lot of things which at least to me it's pretty amazing that such a simple interface it's able to do. So, now again. Can I make the font size smaller? Sure. There you go. That's probably just about right there. Okay. So, let's say you have a, actually let me show you. Let's say you want to implement a small web server as a unique kernel that just returns something like a pretty camel and it stores, of course it comes, and it stores a counter in persistent storage just to count the number of requests. So, you need storage, you need a file system with a key value store, and you need an HTTP server basically. So, one way of implementing this would be to use something like Mirage and because you want to, you want to print my camel so you would use something like a camel, right? Makes sense. So, you would go into Mirage and you would write a bit of a camel and you would use an HTTP library and also a networks like library and also something like a key value store as a library and then you would tell the Mirage build system that you want to construct a unique kernel using some target. Let's say a Sol of 5 target and more specifically, let's say a Sol of 5 micro BMM target. So, in that case, you would do that, you will make and you will get something like this. You would build and you will get the unique kernel which will be this one dot HVT which is, actually it's not that small as I thought, and also the tender which will be the equivalent of QMU for example if you were running a typical VM. And now the way you would run this is just like with QMU you would say HVT. Now because we need a disk to store the key value store information we need to specify the disk and we would say disk image net tap and HTTP HVT. Yeah, well it's huge. Okay. And then just to show you that actually works. So we go. Cool. Another possible target is the process one which is called SPT and so you would again tell the Mirage build system to build another unique kernel you will tell it now I want SPT and it will output something like this SPT SPT which is also pretty large. Yeah, makes a lot of sense. Really size will give a different number. Yeah, still pretty large. Anyway. Yeah, so you would use the SPT one something like this. Exactly the same. Just to show you as well that it works. Ta-da. 195 camel. So the counter is working. And now to give you a more in-depth view of what this thing is doing let's take a look at the as the S-trace. So for example for the HVT one the HVT tender is kind of implementing the solo5 interface by using Cisco. So we would map a solo5 API call for example I yield into a poll into a specific file descriptor into the host. True. Okay, sorry. Sorry, sorry. Okay, so let's do an S-trace. Yeah, well just boot it. And now it's just polling is just an event loop and it will take a look at what happens when we actually curl. We see a bunch of KVM stuff read into the this is the tap and polls. I mean it's really very very minimal. It's basically reads and writes into the this file descriptor and reads and writes into the into the the tap file descriptor. And now to compare against the the SPT one let's do the same on SPT. Yeah, that's booting don't worry. So that's pretty much exactly the same except that it doesn't have the KVM iactals. Yeah. And again that's just to give you a rough idea of the minimalism and also that we have a even more minimal interface which is called SPT that is pretty much like the KVM one but without doing all the KVM stuff. And now back to Maito to get to tell you more about how these works. So Riccardo showed a couple of the cellophane targets that use tenders to run on monolithic kernels. What do these actually do? So there's the HVT which is the hardware virtualized tender which uses hardware virtualization. Obviously and from the name it runs on KVM on Linux on FreeBSD on Beehive and on OpenBSD on the VMM APIs. So this is this is not a traditional VMM not even close. It has about 10 hypercalls. It self the code base is not modular. Again a typical configuration so a solo 5 HVT on Linux on x8664 would be about one and a half thousand lines of code. So again right we're talking about the tender which is this part it's the bottom intersection of the bottom triangle with the blue circle. Comparing to something like QMU well QMU I tried to be nice to them so I ignored the one and a half million lines of code that was just random blobs of firmware and stuff and that still leaves another roughly million lines of code. Something like cross VMM this may be a little bit unfair but I didn't S-Lock count doesn't understand rust so but I came up with some figure which looks like it's it's an order of magnitude smaller. HVT is also something that we've was the first tender that we implemented so it's been around since 2015 it works then got FreeBSD added into it and then OpenBSD contributed later as well. It's was formerly known as UKVM which some people here may be familiar with that name. So what is the tender responsible for? Well it loads the unicolonial artifact into the VCPU's memory it sets up access to the host resources that the unicolonial is asking for so the the network tap device or the disk block device. Does some VCPU set up sets up page tables for the guest which are very simple just one-to-one page tables so there's no no virtual memory is being used at the at the guest level and then it needs to hang around to handle guest hypercalls which or handle VM exits to actually perform some IO. So hypercalls what do they actually look like? What we do is we transfer a 32-bit pointer to a struct which contains the hypercalls parameters. The reason there is this hybrid approach is we actually want to run on existing deployed KVM systems so I think Martin Dedzky I don't know if he's here mentioned VM funk there is also an instruction called VM call which you could use on x86 for this except that KVM steals that for its own purposes so too bad. So we figured out this approach which on x86 basically does an out to some port which causes the VM exit and on arm64 we do an MMIO to some region which also causes a VM exit. At that point the tender just fishes the data out of the guest's memory and operates on it directly. So the HVT bindings then implement the cell F5 interface on using these hypercalls to talk to the tender. Apart from that they don't do very much so there's some handling of vcpu trap vectors which basically just say oh we got a trap abort sorry and the only other thing they do is provide monotonic time using a timestamp counter or an equivalent mechanism. So you can see an entire implementation of cell F5 net write for HVT which is basically just putting stuff into a structure and then invoking the hypercall. The mucking about with return codes here is because these two interfaces actually need to be aligned but we haven't done that yet. So Ricardo showed you HVT but we also have something called SPT which we're calling a sandbox process tender. The interesting thing about this notice that the blue circle suddenly got much much smaller. So what SPT does is instead of using hyper virtualization which is great if you have it but you don't always have access to that but just for example you might be running in a clouds where you're already virtualized while nested virtualization exists it's not something I would actually use to isolate things with. So instead we had this realization that oh we could just we already know exactly the calls we need to implement this interface. So why not just use a system call filter use a strict system call filter and turn off all the APIs that the host kernel is providing and it turns out that this is exactly what SPT does. Currently we only have this implemented for Linux using Seccom BPF but it should be possible to port to free BSD and open BSD. There's also a link to our paper from last year which talks a bit more about quantifying the the difference in the TCB where we actually make some claims where we say they're using something like HVT which touches hyper virtualization and KVM and actually ends up using more of the host kernel code than the approach where we switch off all but these seven system calls. So similarly to HVT SPT loads the unicolonal into its process address space sets up access to the host resources applies the sandbox and then basically gets out of the way. So the blue circle should actually disappear at this point but I don't have animations in there. So what this does is you've now taken the your unicolonal recompiled the same code against a different target and you're now running as essentially a user processor that's coming back to the original slide where I say just unicolonals are just like processes that do more and here we're basically treating the monolithic kernel as kind of as a hypervisor. So switch off everything. So some more about the the bindings side. Those are interested so the bindings basically end up directly invoking system calls but they are now inside the sandbox which they cannot change. There's no libc involves in there. Yep we have it for x86 64 and now 64 it's for SPT it's pretty trivial to add basically anything that the host supports. For HVT I'm not sure if I mentioned that we also have these two architectures it's a little bit more work but yeah so possible. What just happened hmm? Oh I clicked on something and so as I mentioned we have targets for micro kernels as well. So moon is a rather interesting it's actually technically called a separation kernel so for people that are not familiar with the distinction a separation kernel gives you much simplified way gives you much stronger guarantees about how your components can communicate so about the data flow between the things in the system. It's also I mean the original term is used as a way of saying that the componentized system should look exactly like as if it were a distributed system. You can look up the term and there's some more discussion about it there. So moon provides isolation using hardware virtualization it's implemented in Ada Spark and it's formally proven to contain no runtime errors at the source code level. The shape is now a bit different so the blue circle has moved more or less into the unicernel and moon is much much smaller. There aren't any hypercalls communication is done via shared memory. Verti was the first solo 5 implementation shape doesn't really match up we still have it there because well people find it useful I mean it runs on Google compute engine that's great but yeah it's doing like two and a half thousand lines of code in there just to do virtio stuff. Does anyone want to implement virtio scuzzy? Not really. Debugging this is the special slides. There is this myth that unicernels are undebuggable just use GDB and you can do it with a unicernel hidden inside an HVTVM or with SPT as well. Some lessons learned okay this is a bit complicated I have only five minutes but originally we with UKVM we wanted to specialize the tender to the unicernel it turns out that and we did that at compile time that's not practical the supply chain doesn't make sense you're not going to be supplying the tender and the unicernel at the same time it's now gone but we still want to it's gone for SPT we still haven't removed it for HVTV but it needs to go we still want to enforce a contract between the tender and the unicernel so the unicernel wants some resources tender should match those and not accidentally provide something else possible solution is to embed a manifest into the unicernel art effects but can we still specialize the tender some plans and challenges security we gradually implementing more best practices like ASLR, stack smashing protection, write or execute but again stack smashing protection the compiler ABI's are completely undocumented you have to go and read the compiler source to find out what it's doing that oh on x86 it always wants percent FS colon 0x28 yeah why isn't that specified somewhere for so there's some hypervisor support lacking on free BSD and open BSD where if you do an M protects on memory that's owned by the guest by the hypervisor that does not update the EPT tables it's just a knob KVM actually does this right and some defense defense in depth portability can we do dynamic linking safely and get a tender independent unicernel binary so none of this ahead of time choosing of do I want this or that isolation mechanism that's a very good question can we define an interface that allows asynchronicity but is consistent with our philosophy if someone can define one for me on a back of a bare mat and this later this evening then you are definitely God please contribute we would like more languages and libo s is ported also more targets HVT should run on macOS you should be able to build an SGX enclave out of this using keeping the same interface web assembly okay related work how much time do I have two minutes this should be on a spectrum solo five is somewhere here like the most radical thing QMU is somewhere here drawbridge is somewhere here cross VM firecracker the air there the sort of going towards the right G visor is just weird that's up there that's trying to re-implement the linux is called to face it go I mean yeah it's strange so we can do a lot with minimalism we have a tiny API it's legacy free it's IC licensed you can run 1500 HVT things on your three-year-old laptop we want to apply you the kernels everywhere both on monolithic systems because there are a lot of them around but you should trivially move to recompile your code and run it and genoed run it on new end and at the same time no compromises so you still get strong isolation across the spectrum of targets any questions okay so what you're saying is should we sandbox HVT even more I mean so one of the things that we we will do is but extend the set comp sandbox to the HVT tender itself right so I think that's that's kind of what you what you're touching on no we haven't we haven't thought about that yeah it's not recursive sorry any other questions yes yes that was that was the that was the real code you will get so there's some nope there's no reason you should get intra E inter because there aren't any signals being handled in especially not in the in the second case because you we don't even have sig return in the second filter so if you get a signal then you can't handle it sorry your process just dies I haven't actually seen so I haven't really seen E inter happen in any other case in practice I mean if you're not handling signals then why would why should you get that but good point yeah any other questions you're not you're not you're not the first person that's asked about so can can this be used for the sandboxing desktop applications with actual UI the question is what would that interface be because then then you run into the problem of well if you want performance you want at least some kind of at least a frame buffer but then that's very low level so it's like where how do you decide that abstraction right I mean how would this run across this interface I mean protect you could of course certainly run like an x11 client inside this thing right and have that talking to an X server somewhere else right so so that'd be one way of accomplishing that but yeah I mean possibly not the not the cleanest approach I'm not sure I know that there are people that did things with I mean even the even the genoed folks have been doing things with virtualizing graphics hardware but it's really quite a different area which I don't know that much about but yeah you could do the x11 thing or yeah


Well, thanks everybody for being here. The paper I'm about to present is called Motherhood and Flexible Jobs, Evidence from Latin American Countries. This is joint work with a lot of colleagues from Argentina. Inez Berniela, Mariana Marchioni from Sedlas, Universidad de la Plata, and Lucila Berniela and Dolores de la Mata from CAF. And I am Maria from Universidad de San Andres in Buenos Aires. Let me give you some motivation. I think nobody needs motivation in this room, but just in case. We're all very well aware of the great convergence in terms of gender roles for men and women during the last century. Yet we also know that very large gender gaps exist, especially in the labor market. And we know that these gaps are particularly large in Latin America. And the literature recently has identified motherhood as a key factor here. And basically, motherhood is identified as the last hurdle to be overcome if we are to finally achieve gender equality. And so basically, there has been a lot of papers that have been able to identify the causal effect of the arrival of the first child. And there are a lot of nice papers, but basically these papers are focused on developed countries. So we get a lot of information about the effect in labor market outcomes for developed countries in the country for Latin American countries or for developing countries in general. We have very little information. And the question is, does it matter? Should we care that we just have information for developed countries? And we think this is important. We think that extrapolating these results from developed countries to developing regions might be misleading. Why? Because as we discussed today, we have very different cultural and institutional backgrounds. And so it is important that we provide specific evidence for developing countries. OK, so this is what we tried to do in this paper. We tried to do three different things. First, we provide evidence of the causal effect of the arrival of the first child with comparable data for four countries in the region. These countries are Chile, Mexico, Peru, and Uruguay. And we assess this effect on a variety of labor market outcomes. We assess this effect on employment, also on changes in the occupational structure, so part-time employment, self-employment, and informal jobs. And lastly, we try to provide some suggestive, descriptive evidence on the role that social norms and family policies may have in these motherhood effects that we are estimating. So let me give you a glimpse of the methodology and data we are basing our analysis on. We are using an event study approach around the birth of the first child. This is the standard methodology that's been used in these developed countries I mentioned before, basically led by the first paper by Cleven and Coethers. And this event study approach requires panel data. We need to follow men and women across time. We need to follow their labor market trajectories. And we need to know the exact date of the birth of the first child. So we need all of this information to be able to estimate the causal effect of the arrival of the first child. And it's important to know that we need people to become parents at some point. So our sample is composed of men and women that become parents at some point. And another thing that's important to bear in mind is that we are only capturing post-birth effects. What this means is that maybe there may be some anticipation effects. Women may be making different choices anticipating the fact that at some point they will become mothers. We are not going to be able to capture these effects with this methodology. And of course, we have this to rely on an identification assumption. And this identification assumption is that the timing of the event is not correlated with the labor outcome we are looking at, conditional on having a child in the sample period, and on the included controls. OK, so this is the equation we are estimating. Let me walk you through a little bit. On the left-hand side, we have our outcomes of interest. So y is our outcome of interest for individual i in time t. y are going to be four different labor market outcomes. It's going to be employment, self-employment, part-time employment, and informality. And then on the right-hand side, the first term is the most important. Here we have a set of dummy variables that what they're doing is that they're indicating the relative distance to the birth of the first child. So basically, this beta tau that's there, this parameter here is our parameter of interest. And this tau, this sub-index tau, is measuring the time relative to birth. So whenever tau is zero, we are identifying the time of the birth of the first child. Whenever tau is positive, we are identifying periods after the birth of the first child. And whenever tau is negative, we are capturing pre-trans. And we are including a set of controls, age, and calendar months, and year-fixed effects. Data sources. As I said before, we require panel data, very intensive panel data. And this is a very unimportant limitation to try to explore this issue in Latin America because there are very few surveys that account for this. So we are able to do this for these four countries. I mentioned Chile, Mexico, Peru, and Uruguay. These are the sources we use. And all of these surveys are nationally representative. And they have the information we need. That is the exact date of the birth of the first child and the labor trajectory of men and women before and after the child is born. And these are the results we get. I am going to present all results in the forms of graphs, what is typically done in this literature. So let me walk you through the first graph. Let's concentrate in Chile here, so that you get an idea of what we're looking at. And then I will repeat this for the other results. So we are focusing on employment. This is the first labor market outcome we are looking at. And basically what you have on the x-axis here, you have tau. So you can see very well, but here tau is equal to zero. So basically here, we are looking at the birth of the first child. Everything that is to the right of tau equal to zero are all periods after the birth of the first child. And whatever is to the left of tau equal to zero is a region. And what we have on the y-axis here, we are plotting the pedas. So each of these dots here in green, we are plotting pedas for women. And in orange, we have men. So basically what these pedas are capturing is the difference in the outcome of interest, in this case, employment. And sorry, I forgot to say that we are using as an omitted category tau equal to minus 12. So we are looking at one year before the child is born. We are comparing the outcome of interest in each period to what happened one year before the child is born. So basically, we are measuring here the change in employment relative to the employment one year before the child is born. And so what we see for Chile, and then this is repeated for countries, is that as a child is born, we find a very large drop in employment rates for women. Nothing much seems to be happening to the fathers. And the same is repeated for Mexico, for Peru and for Uruguay. I didn't mention also that here for Peru and Uruguay, we have yearly data. Instead for Chile and Mexico, we have monthly data. That is why you're looking at graphs that look a little bit different. But basically in all cases, we see this sharp drop. For women, nothing much seems to be happening to fathers. And we see that this persists over time. On average, the magnitude of the effect is very similar across countries, between 17 and 20 percent. Yes? These are the veras, the change, the difference between the period, like that equal to like two years after the birth of the first child, compared as the employment one year before. Sorry? And yes, we're including age as a control. Yes, in Mexico, right? Yes, yes. Yes, yes. In the present, here in the present, right? Or after the child is born? Yes, okay, okay. That's before, do you mean this, right? Yes, we're focusing on this large drop that's happening here. Like after the birth, what I meant is after the birth, but actually in Mexico, we are seeing something. But we're concentrating. Sorry? Okay. Yes? Okay. Okay, so this is employment. Then we go to part-time employment and we find a similar pattern. You won't find Mexico here because Mexico does not provide hours of work. So for Mexico, we cannot try this analysis. And we see here that part-time employment is increasing for women, but it's decreasing actually for men. And this is significant for Chile and for Peru. We don't find significant results for Uruguay. Then we have self-employment. And here again, women seem to be taking up self-employment in Chile and in Mexico. For Peru and for Uruguay, we do not have the results are not significant. But in the case of Chile and Mexico, they're taking up, they seem to be taking up self-employment after the child is born, first child is born. And then we have labor informality, which is an aspect that maybe it's not so much considering the developed countries literature. And basically we find here that labor informality for women is also increasing after the birth of the first child. And this is significant for all countries. For Chile and Peru, the effect is around 16, 17%. And for Mexico and Uruguay, the effect is of the order of magnitude of 50%. It's very large. So basically what I've shown you is that we find a significant impact of motherhood on labor market outcomes of women. Many women job out of the labor force when the first child is born. And for those that remain in the labor market, many change their occupational structure towards self-employment, but time employment and informal jobs. This comes at a very high cost for women. For women, of course, they are giving up economic independence, they're giving up social security, they're giving up future career prospects. And of course these choices have also a positive side. They're offering flexibility to women. And so the question is, why are women willing to trade these present and future benefits for time flexibility? And so what we do in the last part of the paper is to try to explore, to provide very suggestive descriptive evidence of the possible drivers behind these choices or at least two possible drivers that are gender norms and family policies. And of course we know that this is very difficult to do. We have a lot of endogeneity issues here and so they are very difficult to overcome. And even further on we have very strict data restrictions for the Latin American region. And so we decide to go on a descriptive route and that's okay, but even if we stick to a descriptive analysis we find further challenges because ideally what we would like to have is to have these causal effects for all Latin American countries and make some correlations with gender norms and family policies for the whole set of Latin American countries. But of course as I told you, we are only able to produce these causal effects for four countries in the region. And we think that it would be a little bit misleading to base our correlational analysis only on four countries. So what we do for this, the exercise we do is to rely on an approximation of this causal motherhood effect. And we are not looking here at causal effects but rather we are computing the gaps between mothers and non-mothers in labor market outcomes. So the difference between mothers and non-mothers in employment, in self-employment, part-time employment and so on and so forth. And we use this as an approximation of the motherhood effect. We call this the motherhood gap to make a difference. And we correlate these gaps through the deep prevailing gender norms and family policies in the region. We take the data from SEDLAC, the database from SEDLAS. So what we do here is this is just a set of, as I said, very suggestive and descriptive evidence. We have made no claims of causality here. We're just connecting these two different issues. And again, I'm going to present this in the form of graphs. So let me walk you through them. So you get an idea of what you're looking at. We are here, we are relating gender norms to this motherhood gap. Remember the difference between mothers and non-mothers. And basically what we are looking at is one gender norm, which we elicited from the Latino barometer. And the gender norms is the level of disagreement with the statement women should work only if the partner does not earn enough. So what you see here is basically that in all countries, for all results, we find that the more conservative use the country held, the larger the gap between mothers and non-mothers is. So the more conservative a country, mothers are making choices that are really different from non-mothers. And the less conservative, they make similar choices. Then we do the same for childcare availability. And here we plot this motherhood gaps for the four outcomes of interest to preschool enrollment rates for younger children, children three to five years old. And once again, what we see is that it comes as no surprise, of course, that when enrollment rates grow up, we just saw it with Veronica. Basically mothers tend to make much more similar choices than non-mothers in terms of labor market decisions. And finally, we do the same kind of analysis for maternity leave. Basically we are correlating here the number of weeks of protected maternal leave with this motherhood gap. And once again, we find that the more generous a countries in terms of this maternal leave, the way women with children and without children make decisions in the labor market regards to this, regarding this four labor market outcomes is more similar. So just to sum up if you got lost a little bit in the presentation, basically what we try to do here is to estimate the causal effects of motherhood on four countries in the region. And we find significant reduction in employment and a significant change in the occupation of structure. This is per instant over time. Women seem to be moving on to less quality jobs. And basically we try to answer the question of why they're doing this. And we just provide some suggestive and descriptive evidence regarding gender norms and family policies that may be to some extent shaping the decisions of women. And let me conclude by saying we're pretty sure that there's a lot of room for designing better policies. We know that these policies are really tricky to design, but of course we need to design better and more policies for alleviating time constraints for family if we want to achieve gender equality in the region. Thank you very much.


My name is Samuel Odiambo, o Tieno. I come from Kenya and currently I am doing my thesis. My area of study is urban water and sanitation, masters of science. I am specializing in water supply engineering. I think the one thing that really got to me when I came to this environment is the ability to discuss water challenges with people from different backgrounds. You see that the challenges of water are similar in a particular way but also different in a particular way from different parts of the world. Also just being able to interact with people from different countries of the world. I think this is the most multicultural environment that I have ever been. In our classroom only we were 40 students from 20 different countries. During the modules there are field trips that we went to just to ignite or to trigger the knowledge that you've learnt in class and to show you the real environment how the water treatment plans for example are working. But also we did an international field trip where we went to Spain. The trip to Spain was a three-week trip. We went to Madrid and then we went to Catahena. So in these two towns there are two things that we were looking at. We were looking at the technologies that are being implemented in water treatment and also the challenges that these two places are facing in terms of water distribution, in terms of waste management, wastewater management, water treatment, desalination plans. My thesis is quite relevant and that is for me why I chose the topic because I have a job back home as a civil engineer in charge of design and supervision of construction for water and wastewater infrastructure. So one of my topic, I'm doing a topic in hydraulic modelling of intermittent water supplies and that is one of the challenges that we are facing back home. There is no water system that is continuous. That is a water system that supplies water 24 hours a day. So basically what I'm doing right now is I'm trying to model this, to find a way of modelling this system in such a way that there is some level of equity in the system. How can we ensure that everyone has, we could call it not really equal but the amount of water that they need. The challenges of water are global. So that's one thing that I have appreciated and different people are facing different challenges and one thing I have appreciated of land is that research is very important to solving the water issues that are around the world. But that is on the technical aspect of it. On the social part of it is basically just humility. I mean, I have seen people interacting with the professors and the professors are quite helpful. And time keeping, very important. I have learnt how to keep time perfectly. That's one of the biggest lessons I have learnt in the Netherlands. The Netherlands people keep time and it has gone a long way into ensuring that things are done when they are supposed to be done.


Today on another Pop Review, we're going to be taking a look at the Pop Movies National Lampoon's Christmas Vacation. Number 242, this is Clark Griswold. Hey guys, welcome back to Comic Gettin TV, the only place on YouTube where all geek culture collides. If you're new to the channel, make sure you hit that subscribe button so you don't miss out on future videos. As I said today on the show, we're taking a look at the Pop Movies National Lampoon's Christmas Vacation 242. This is Clark Griswold.  Nice little window side there.  And then we have the display side here which has the house all lit up ready for Christmas and Clark getting electrocuted up top there. We also have the Cousin Eddie's mobile home or RV, whatever you want to call it, and the Griswold's car with the tree tied to the roof. Now let's go ahead and open this box up and take a look at Clark Griswold. As you guys can see, old Sparky here does not need his display stand. He does stand quite well on his own. Nice, very nice pop. However there is quite a bit of paint bleeding, some paint error. Quality control wasn't, kind of fell asleep on the job with this one.  But overall still not a bad figure. Here he is with his moose mug made out of a clear plastic with his spiked egg nog, Santa jacket, and then his dress clothes. Very nice, very movie accurate. His head does spin all the way around, does not get hindered at all. I kind of wish it would have maybe included the squirrel, maybe on the back of his jacket or off to the side or something. That would have been pretty nice. As you can see inside the mug, you can make out the yellow. They should have maybe made it more of a cream color though, because eggnog is a cream color, but still not bad. And then you got, I think that's his membership to the Jelly of the Month Club in his pocket. And again you got some red paint in between his fingers there, but overall not a bad pop. I really, I really like it. I do plan on getting cousin Eddie, however this will be the last Funko Pop Review for the year of 2018. And also the last regular Pop Review, as we will no longer be doing Pop Reviews every Tuesday. My collection is just getting too big guys. I apologize and since I'm doing this on my own now, I can't really count on others to provide the Pop Reviews either. Billy's pretty busy. Him and John are working on their channel, The Logic, which I'll link in the description below, which is more of a R rated version of Comic-Gaden. They talk more about wrestling and stuff like that, a few tour reviews. Not really much with comics though, which I'm kind of surprised about, but it's their channel. They do what they want to do.  I hope you enjoyed these Pop Reviews. I will occasionally be doing other Pop Reviews as I get new pops, just not on a regular basis like I've done these past few years. So again Merry Christmas my friends, have a Happy New Year and I'll see you next time. Hey guys if you enjoyed this video make sure you hit that subscribe button right there so you can stay up to date on all things geek culture. Also you can check out one of these two playlists right here on the side for more videos just like the one you just watched.


Hey guys, welcome back skidstone series episode 19 Topic today is a filler topic. I'll be honest least squares regression basically polynomial fits for data and our goal today is to make plots like this one and like this one where we basically fit a polynomial to data and As usual, we'll first talk about the theory pretty quickly and then we'll talk about the implementation in assembly And again, there's no libraries of any kind in the skidstone series so dog asks what is least squares and the cat responds very verbose Lee basically least squares is an approach well, I'll summarize here Basically, you have data points in this case six of them that you want to fit with a line a line can only pass through Guaranteed to data points. And so how do you pick the line that best approximates the other four? Or I should say all six. So how can you do that? And I'm sure there are other applications of this methodology that I couldn't care less about So what's the approach? How do you fit a line to data? Here's the math that you would do by hand. So let's say you have these data points x and y Which by the way are the data points from the plots. I just showed you a Line has the equation for y equals mx plus b where m is the slope and b is the y intercept And if you just plug the values for x and y Into that equation you unless the lines unless the points are already online You won't be able to pick a line or a combination of m and b values that would hit all those points And so you're gonna have an error term on most if not all of these equations And so this error term are called residuals sometimes the idea is if you solve this equation for the error term And you take the square of those terms and sum them up and you you basically get a Quantification of how bad your line was right? If I pick a line I pick values for m and b To create a line and I get error terms for every single point. I was off by this much every single point I can quantify how bad my approximation was by squaring all those terms and adding them up and the idea is The best line it would be if you were to take all of these squared error terms and add them up That error would be the least the lowest error That's why it's called least squares because you're taking up the error terms squaring them adding them up and Picking the values for b and m that minimize that error And so if you do that if you take these equations solve for e Square them and add them up you'll get this which if you spend five minutes You can reduce down to this expression down here and the question is still what values for slope and intercept would minimize That expression remember that expression quantifies how bad my line was So how do you minimize an expression or an equation or whatever? Let's say you have a single variable function like this one here The minimum would be where the slope is zero obviously you can't get any better So your slope has to be zero at the minimum and also the maximum But in our case we don't care about maximum because I can always pick a worse line I mean this line is good I can pick a million worse lines than this and I can always pick a worse line And so maximums are not of any consequence for this question today wherever the slope of the error sum Square would be zero that would be the minimum and so If you take that expression to be let's say s and Then take the partial derivatives of s with respect to those two coefficients b and m slope and intercept You would and make the equal to zero you can find these equations here So you'd say now zero equals this equation Derivative with respect to be that would be 12b plus 44 and minus 200 Similarly, you can take dsdm and get 44b plus 200m minus 1000 and you can solve this linear System in whatever way you want. I like matrices But you can do whatever you'd like and if you solve for b and m in this system You'll find that b is negative 2 and m is 6 and so you can plug those values back into your line And say y equals 6x minus 2 and that is in fact this line that you see here And so that was very arithmetically expensive and took a lot of time for me to write out But of course there is always an easier way in this case the easier way involved matrices And so the idea is if you take your data Your safe for example your y data is this you can keep that the way it is for a vector y For your x matrix what you do is you construct this here This would be a n by 2 matrix n is the number of data points you have And so the first column of that is just once and the second column is the x values Now if you take those two You know matrices you can equate them in this fashion with what I'm calling a q here You can call whatever you want. That's just the coefficients that we're trying to solve for And this is your equation for a line essentially y equals you know mx plus b least squares here and so To square something which you do is take the transpose times the values itself But so how does that work? So what we can do is to solve for q in this equation We can pre multiply both sides by x transpose And then invert x transpose x And multiply both sides by that in that in that case you'll solve for q equals x transpose x inverse times x transpose y So a lot of manipulations here, but You've taken out all this math all this squaring all this derivatives And you've encompassed that same exact math in these matrix equations here and the idea is If you can just generate these matrices From the input data You can solve this expression to find for your coefficients of interest And there's two notes. I have the first tip would be for linear Lines, you know that you're trying to fit data with I'd say two by two matrix inverse and for parabolas It would be a three by three. We don't usually like to take inverses of matrices, but for small ones like Two by two and three by three. We can get away with that pretty easily The next tip is you actually don't need to generate These intermediate matrices x and x transpose and whatever because you can just Compute x transpose x on the fly as well as x transpose y on the fly Completely from the input data alone. Why is that because it's such a simple You know matrix x is just ones and x values y is just y values I don't have to waste memory space with x transpose x or sorry with x transpose and with x I can develop these Terms directly And so our approach to solve for this in assembly. It's going to basically be constructing x transpose x In memory directly from x x values Then we're going to be constructing x transpose y directly in memory from the values of x and y Then we're going to be inverting x transpose x Multiplying it by x transpose y And that is our answer Now that's for lines. How does it extend to higher order polynomial fits? Well, the number of rows obviously is the number of data points you have we have six points So we have six rows the number of columns is the number of unknowns in the polynomial lines have two unknowns slope intercept and so we've had we had two columns But if you had a parabola you'd have to add another column and how do the columns look? Basically the first column is just well I should say the zeroth column is just the x values to the power of zero which is just ones Second column or the first column. I should say is the x values to the power of one And then you have to the power of two and three and four etc And so if you had a parabola fit your x would actually be of the form ones x values x values squared So yeah, that's how that would work Lastly, how do you invert these small matrices two by two and three by three? I'm very simple two by two matrix.  It's just ad minus bc. So this diagonal minus this diagonal That's a two by two. How about three by three? Well Terminant of a three by three matrix is basically The way you compute it is you compute it a couple different ways in this case. What we're doing is taking the first row Multiplying that by the determinant of these smaller Submatrices, so you have a times determinant of this sub matrix minus b times This sub matrix determinant plus c etc. This follow the equation. No big deal What you do is you take that one over that value and you multiply that by this matrix Which is just the determinants of two by two matrices out of the big one So follow along at home solve this yourself. It's not a hard thing to implement at all all the code for today is in the lib math Lin algebra directory of this soy hub suppository pick a look if you're curious Here are the four functions that we're going to use most in this video Uh these first two to take the inverse of matrix So what you do is you pass in address rdi Or register. Sorry you pass in register rsi the address of your matrix of interest that you want to invert and um You pass in register rdi the destination address for the inverted matrix For straight forward and then you have these two functions here Which are function of the same thing in terms of how you call them, but they do different things. So linearly squares computes the linear line of best fit and Quadratically squares computes the parabola of best fit And what you do is you pass in register RSI and rdx the addresses of your input data for x and for y And register rcx you pass in the number of data points you have And then lastly you put in a register rdi the address of your Answer where do you want the answer to be placed? Where do you want the? B and m values the coefficient values to be placed that would be in register rdi And so with that out of the way Let's look at the code So here is examples 19 Directory and there are again two examples in here, which I showed you at the beginning of the video First let's take a look at the actual Functions that we're going to be calling. So here are three of those four functions The first one I want to talk about is the inverse two by two matrix function And uh, so how does this work? Well, we just covered how this works All we're doing here is we're computing the determinants of a Two by two matrix, which is the first element Times the fourth element minus the second element times the third element One over that is what we're going to be pre multiplying our matrix by essentially. So how did that work in assembly? Well First you can see I Saved my registers because again in our schizone series None of our registers are ever affected by function calls unless they are return values So we save those registers and we restore them at the very end. You can see down here Now how does the rest of the of the code work? So first thing was to compute that determinant So how did this work? Well, you can see here what we're doing is we're moving so rsi remember pointed to the rsi points in memory to the matrix of interest and so rsi Plus zero that Offset of zero is the first element as you can see here I've pulled the first element or what was called element a In this expression into x of m zero Then I multiplied that by element four element four is three bytes offset from element one You can see I have multiplied this by the previous value. So now I have basically a times d in x of m zero then In x and m one a different register. I have pulled in The value b And I multiply that by the value c So now x of m zero contains ad x of m one contains bc and so we have this term and this term This term and this term Now we subtract the two how does that work? Well, I subtract x of m one from x and m zero Then you can see I've put the value one which I've defined here in memory Into x and m one and divided x and m one by zero at this point x and m one contains one over The determinant. So I basically have Sorry, this whole thing is now in x and m one at this point. All I have to do is to basically Grab elements out of the original matrix Multiply them by this And then negate some of them and I can then construct the resultant in inverted matrix so Let's see how that looked for element one one. Basically, you can see here. I'm grabbing The fourth element of the original matrix that would be Three bytes offset from the first element which would be at rsi And that's now in x and m zero. So this is basically element d element d is now in x and m zero that I'm multiplying element d by One over the determinant value and putting that value in the destination element one. So is that correct? Yes, we take element d multiply it by this one over value And put that in the first element's location I'll give one more example element one two. So this is the element to the right of that one I here you can see I've I've set x and m zero equal to zero and I've subtracted off Element b From the original matrix. So now I have negative b in x and m zero Then I'm multiplying element negative b times one over the determinant And I'm dropping that into the second slot in the matrix That's here. Is that correct negative b times one over that number? Yes, that's where it should be And similarly you can you could do the last row as well. That's how we've inverted two by two matrix in assembly similarly A three by three is just much of the same but a little bit more arithmetic I won't get into it, but I'll just summarize how this works We've started off computing the determinant of that three by three matrix like this That's this value here We then took one over that value as this value here Then for each element we are pulling out of the input matrix Values and making the determinant calculation for each two by two sub matrix Multiplying that by this one over determinant value and dropping that in the destination Of uh of interest So again, yeah, we could compute determinants of any matrix like this realistically speaking But it gets more and more mathematically expensive to do so for higher and higher dimension matrices Okay That's this one. Now. How did the linearly squares function leverage this I mentioned before that our procedure was basically To take the input data directly and compute X transpose X and X transpose Y without any intermediates of any kind Then invert X transpose X Multiply by X transpose Y And that's our answer. So those steps are our operating procedure here Is that what I did? So first thing I saved my registers And at the end I obviously restore the registers But so here let's talk about how does X transpose X and X transpose Y work So first you can see I have space at the bottom of my Function here to drop in X transpose X and X transpose Y now How bigger these spaces will think about it X that matrix X Is an n by two matrix n is the number of data points we have So it's n by two So X transpose X Is two by n Well X transpose is two by n X transpose X is a two by two matrix So we only need space for four double numbers Eight bytes each for X transpose X. Do we have that? Yes, 32 bytes all set to zero to begin What about X transpose Y? Well, that is just a two by n matrix multiplied by a n by one Matrix so this is a two by one matrix. So yeah, we have two Doubles worth of space here or 16 bytes all set to zero to begin Now let's talk about how does X transpose X even look Right. This is X. What is X transpose X? Well If you think about it The way it will look is basically you'll have n here, right X transpose X is basically this row this column Dot it with itself, right? What is what is once? Dot it with itself. Well, it's just the number of things you have. So we'll have an n in the first element What about the diagonals here? Well, this is basically this row Dot it with or this column dotted with this column. What is that? That's just the sum of the X values Sum of the X values And then what is the last one? What is what is the second column times the second column? Well, that is just the sum of the X value squared And of course you could argue that this is not n. It's it's the sum of the X values to the zero, right? And this is to the one and this is to the one That's how X transpose X looks It's a very simple matrix to construct without having to go through the any intermediates like this matrix here So I can directly compute the sum of the inputs And put it in this slot I can just put The number of elements in this slot and I could put the Square of the inputs in this slot and of course this one and this one are the same value What about X transpose Y? How does that look? Well X transpose Y is just basically Think about it. What's the what's this column? Dot it with this column Well, it's the sum of the Y value So this is how X transpose Y would look it would be the sum of the Y values And then you'd have the sum of the X times Y values And of course this is probably Y values times X to the zero This is times X to the one and then if you had more you'd have X squared Y Etc etc etc That's the form of X transpose Y. It's a very simple thing to construct So how do we do that? Here you can see for the first element that was just the sum Of X to the zero that's just the number of elements again. We passed that as an input that was in rcx That's the number of data points we have so we can just convert Rcx into a float And drop that Into the first slot in X transpose X Then you can see here. I've set some summing Variables equal to zero So i'm saving some spot in memory or in my registers for the values of X transpose X components and Y transpose Y components. So I have saved four You know floating point registers to do that So how did this work? Well, obviously I loop through the input data I decrement in this loop by One in rcx every time and every time I iterate through The input data which we've passed in the address for that in rsi and rdx And so what I do is basically I pull the X value The current X value into X of m4 I pull the current Y value into X and m5 And then I add those to the running sums in X and m0 and X and m2 again Those were just the sum of the X values and the Y values respectively That's these two lines here. Then what I'm doing is I'm I guess I'm multiplying both those X and Y values by the X value. So now I have X squared In X mm Four and I have X times Y and X and m5 Then I've added those values to the running sums X and m1 X and m3 and those were the components 2 2 of X transpose X and component 2 of X transpose Y Basically, I'm just populating those two matrices As we go I'm computing all these terms sum of Y times X to the zero sum of Y times X to the one as well as the ones for the X transpose X That I discussed before Once that loop is completed We now have basically dropped in to our memory locations X transpose Y And X transpose X the correct terms. So that's what we've done here. Once we compute in X and m0 through 3 all of the Elements we then drop them. You can see down here These five lines are populating those matrices with the running sums that we just computed And then I have another workspace here where I'm basically inverting that X transpose X into by calling Inverse 2 by 2. So if I look down here, we have a workspace Of 32 bytes. So that's four 8 byte floating point numbers worth of space So we've entered that now our dot workspace memory location contains the inverse of X transpose X Which was the next step, right? That was That was this here We now have this in that dot workspace memory address and we have this in the X transpose Y memory address What's the next step? Well, obviously it's to multiply and so you can see here. I then I multiplied this Workspace so the inverse of X transpose X by X transpose Y. I passed in the dimensions Call multiply and then of course Um What what is this here? What's this move rdi rsp plus 120 that is where we saved the original rdi value So I don't have to do that because we didn't touch rdi, but just to be safe. We saved our rdi in On the stack and it happens to be 120 bytes off the stack right now And so I can grab that I didn't have to do this because we didn't affect rdi But let's say we did in some case I can grab the value of rdi And put it back in its proper location for this function call rdi again contains the address of our answer Where should we put the answer? And so I can comment this out and it would still work all the same But I'm gonna leave it just just uh, actually no, I can't because look right here Here we we destroyed rdi. So that's why I've done this I've pulled rdi back off the stack because I destroyed it in the previous function call So that's true. I did mess it up. Sorry At the end. I just returned everything back off the stack to its register and Return so that's the entire process of linearly squares Implement in assembly as you've seen. So does this work? Well, let me look at the code that we have here. So We have our two examples Example a was a linear fit if we look at the code Here's the code. So we have a lot of stuff to talk about here The first thing I want to talk about is the includes So Because we're plotting stuff we have to have the includes required for plotting And so for that we have to be able to open and close files make a scatter plot Etc etc in addition because I plot a line. I also have the stuff required for plotting Evaluating expressions plotting a plotting a curve that we that we have So I have this evaluate parameters linear space again for lines You don't have to worry about this because it's whatever but for more advanced Curves we want to be able to like for quadratic. We want to be able to plot You know the entire curve without just having two points And so how does this work? Well, first thing that I've done is I've defined a line fit function So this what this does is basically it computes uh, the line if you give it the coefficients, so the B and the m for y was mx plus b This will compute if you give it an x value the corresponding y value And so you can see here it has a 16 byte worth of space for Though those two coefficients The slope and the intercept would be in this memory location So how are we doing this? Well, you can see first thing Um, very simple this these five lines here. This is the entire video. This is what I just talked about for half an hour Um, this is the linearly squares function. So what we're doing is we're passing in to rsi and rdx Our data point values. So I have those in memory at locations Determines with the label dot x values and dot y values Those are probably down here somewhere. You can see here here the x values and y values that we're calling Then I put into rcx the number of data points six and lastly I put the Location where I want the answer to be put. You can see here. I moved into rdi Line fit function dot regression coefficients. What that does is basically I'm going to compute least squares on the x values and y values. I'm going to put the answers up here This basically means the sub label regression coefficients under the label line fit function. That means basically put the answer In these 16 bytes here So at this point when the when the program gets to this line Because you know, it's skipped over all this it doesn't start until the start label Why is that? Well, because if you look up here in the elf header, we said start at the entry point start So it will jump all the way down to start And then immediately compute the linearly squares of those data points and put the answer right here And then I'm printing it out We covered that in a previous video. I'm printing out those answers those coefficients And uh, yeah, then what I'm doing is I'm basically plotting everything in a way that you've been familiar with from previous videos So I won't cover all that here But if I run this you'll see that well first off it printed out those answers This this is the um y intercept and the slope of that linearly squares So everything worked as expected and in fact these values happen to match Uh these values Exactly It also created for us this line fit dot svg This scatter plot which I already showed you that's this one here. I can refresh and it's it's all the same So, yeah, that's it. We did it. We plotted the line of best fit for this data great And it's much the same process for the quadratic one. Let's show that really quick Example b I can run that very much the same process In this case, I have three coefficients I have basically an x to the zero term and x to the one term x to the two term Here here in here and again, it also created this svg Which I can open up in firefox It's this one here and you can see this is that parabola defined by those coefficients and it it pretty closely approximates those points With that the video is over. We effectively have implemented in assembly A least squares regression algorithm for lines and parabolas And if you wanted to you could extend this to higher order systems I didn't want to because I don't see any value to higher order polynomials, but maybe you do If you want to make a cubic You know Best fit program It's fine. The only difference you have to do is you have to make a larger x matrix.  Thanks for watching. We do have a discord server If you want to hang out last link in the description Thanks for watching. See you