<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aniruddha Karajgi</title>
    <description>The latest articles on DEV Community by Aniruddha Karajgi (@polaris000).</description>
    <link>https://dev.to/polaris000</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F318402%2F9ed4e36c-d03d-41dc-903f-e51db05943d6.jpeg</url>
      <title>DEV Community: Aniruddha Karajgi</title>
      <link>https://dev.to/polaris000</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/polaris000"/>
    <language>en</language>
    <item>
      <title>Python: Decorators in OOP</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Wed, 27 Jan 2021 13:14:53 +0000</pubDate>
      <link>https://dev.to/polaris000/python-decorators-in-oop-175</link>
      <guid>https://dev.to/polaris000/python-decorators-in-oop-175</guid>
      <description>&lt;h4&gt;
  
  
  A guide on classmethods, staticmethods and the property decorator
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sg-UKVa4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AG6JSLU01uhka9uJ2okEcgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sg-UKVa4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AG6JSLU01uhka9uJ2okEcgg.png" alt=""&gt;&lt;/a&gt;Image by author&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Object Oriented Programming paradigm&lt;/strong&gt; became popular in the ’60s and ‘70s, in languages like Lisp and Smalltalk. Such features were also added to existing languages like Ada, Fortran and Pascal.&lt;/p&gt;

&lt;p&gt;Python is an object oriented programming language, though it doesn’t support strong encapsulation.&lt;/p&gt;

&lt;p&gt;Introductory topics in object-oriented programming in Python — and more generally — include things like defining classes, creating objects, instance variables, the basics of inheritance, and maybe even some special methods like __str__. But when we have an advanced look, we could talk about things like the use of decorators, or writing a custom new method, metaclasses, and Multiple Inheritance.&lt;/p&gt;

&lt;p&gt;In this post, we’ll first discuss what decorators are, followed by a discussion on classmethods and staticmethods along with the property decorator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Classmethods, staticmethods and property are examples of what are called descriptors. These are objects which implement the __get__ , __set__ or __delete__ methods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, that’s a topic for another post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;p&gt;We’ll talk about the following in this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**- what are decorators?  
- classmethods  
- staticmethods  
- @property**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  An example
&lt;/h3&gt;

&lt;p&gt;Let’s work on a simple example: a Student class.&lt;/p&gt;

&lt;p&gt;For now, this class has two variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name&lt;/li&gt;
&lt;li&gt;age&lt;/li&gt;
&lt;li&gt;score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll add a simple __init__ method to instantiate an object when these two attributes are provided.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We’ll modify this as we go throughout the post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decorators
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Decorators are functions (or classes) that provide enhanced functionality to the original function (or class) without the programmer having to modify their structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A simple example?&lt;/p&gt;

&lt;p&gt;Suppose we want to add a method to our Student class that takes a student’s score and total marks and then returns a percentage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---PXCkPHu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AjpUxr9kXGK0nnHcUMFkVMQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---PXCkPHu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AjpUxr9kXGK0nnHcUMFkVMQ.png" alt=""&gt;&lt;/a&gt;The get_percent function — Image by author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our percent function can be defined like so:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s define our decorator, creatively named record_decorator. It takes a function as input and outputs another function ( wrapper , in this case).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PVF2O-a9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkX0alKprN_8ICsC-hrQfEw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PVF2O-a9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkX0alKprN_8ICsC-hrQfEw.png" alt=""&gt;&lt;/a&gt;Our decorator — Image by author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The wrapper function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;takes our two arguments score and total&lt;/li&gt;
&lt;li&gt;calls the function object passed to the grade_decorator&lt;/li&gt;
&lt;li&gt;then calculates the grade that corresponding to the percent scored.&lt;/li&gt;
&lt;li&gt;Finally, it returns the calculated percentage along with the grade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tZCLXO6H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_0KivLuoTGOw2_YQyX3EUw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tZCLXO6H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_0KivLuoTGOw2_YQyX3EUw.png" alt=""&gt;&lt;/a&gt;How applying the decorator works — Image by author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can implement our decorator like so.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, to improve the get_percent function, just use the @ symbol with the decorator name above our function, which has exactly the same definition as before.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To use this, we don’t need to modify our call statement. Executing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**get\_percent(25, 100)**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;returns&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**25.0, D**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What basically happens is that the function get_percent is replaced by wrapper when we apply the decorator.&lt;/p&gt;

&lt;p&gt;We’ll place the get_percent method inside the Student class, and place our decorator outside the class. Since get_percent is an instance method, we add a self argument to it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;How are decorators used in classes?&lt;/p&gt;

&lt;p&gt;We’ll see three popular decorators used in classes and their use-cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mYJELp0C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATaqEDwhHTSZS9-DrLXe8uA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mYJELp0C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATaqEDwhHTSZS9-DrLXe8uA.png" alt=""&gt;&lt;/a&gt;The kinds of methods in our class A — Image by author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  classmethod
&lt;/h3&gt;

&lt;p&gt;Let’s first talk about instance methods. Instance methods are those methods that are called by an object, and hence are passed information about that object. This is done through the self argument as a convention, and when that method is called, the object’s information is passed implicitly through self.&lt;/p&gt;

&lt;p&gt;For example, we could add a method to our class that calculates a student’s grade and percentage (using the get_percent method) and generates a report as a string with the student’s name, percentage, and grade.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Coming to a class method&lt;/strong&gt; , this type of function is called on a class, and hence, it requires a class to be passed to it. This is done with the cls argument by convention. And we also add the @classmethod decorator to our class method.&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class A:
    def instance_method(self):
        return self

 **@classmethod  
 def class\_method(cls):  
 return cls**  

A.class_method()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  use-cases for class-methods
&lt;/h4&gt;

&lt;p&gt;Since class-methods work with a class, and not an instance, they can be used as part of a &lt;strong&gt;factory pattern,&lt;/strong&gt; where objects are returned based on certain parameters.&lt;/p&gt;

&lt;p&gt;For example, there are multiple ways to create a Dataframe in pandas. There are methods like: from_records() , from_dict() , etc. which all return a dataframe object. Though their actual implementation is pretty complex, they basically take something like a dictionary, manipulate that and then return a dataframe object after parsing that data.&lt;/p&gt;

&lt;p&gt;Coming back to our example, let's define a few ways to create instances of our Student class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;by two separate arguments: for example, , 20 and 85&lt;/li&gt;
&lt;li&gt;by a comma-separated string: for example, “, 20, 85”.&lt;/li&gt;
&lt;li&gt;by a tuple: for example, (, 20, 85)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accomplish this in Java, we could simply overload our constructor:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In python, a clean way to do it would be through classmethods:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We also define the __str__ method, so we can directly print a Student object to see if it has been instantiated properly. Our class now looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, to test this, let’s create three Student objects, each from a different kind of data.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The output is exactly as expected from the definition of the __str__ method above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name: John Score: 25 Total : 100
Name: Jack Score: 60 Total : 100
Name: Jill Score: 125 Total : 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  staticmethod
&lt;/h3&gt;

&lt;p&gt;A static method doesn’t care about an instance, like an instance method. It doesn’t require a class being passed to it implicitly.&lt;/p&gt;

&lt;p&gt;A static method is a regular method, placed inside a class. It can be called using both a class and an object. We use the @staticmethod decorator for these kinds of methods.&lt;/p&gt;

&lt;p&gt;A simple example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class A:
    def instance_method(self):
        return self

    @classmethod
    def class_method(cls):
        return cls

 **@staticmethod  
 def static\_method():  
 return**  

a = A()

a.static_method()
A.static_method()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  use-cases for the staticmethod
&lt;/h4&gt;

&lt;p&gt;Why would this be useful? Why not just place such functions outside the class?&lt;/p&gt;

&lt;p&gt;Static methods are used instead of regular functions when it makes more sense to place the function inside the class. For example, placing utility methods that deal solely with a class or its objects is a good idea, since those methods won’t be used by anyone else.&lt;/p&gt;

&lt;p&gt;Coming to our example, we can make our get_percent method static, since it serves a general purpose and need not be bound to our objects. To do this, we can simply add @staticmethod above the get_percent method.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h3&gt;
  
  
  property
&lt;/h3&gt;

&lt;p&gt;The property decorator provides methods for accessing (&lt;em&gt;getter&lt;/em&gt;), modifying (&lt;em&gt;setter&lt;/em&gt;), and deleting (&lt;em&gt;deleter&lt;/em&gt;) the attributes of an object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S1150VzN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A9oOfB4c_Wqvnde8SOgdiqQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S1150VzN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A9oOfB4c_Wqvnde8SOgdiqQ.png" alt=""&gt;&lt;/a&gt;The property decorator — Image by author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The getter and setter methods
&lt;/h4&gt;

&lt;p&gt;Let’s start with getter and setter methods. These methods are used to access and modify (respectively) a private instance. In Java, we would do something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, anytime you access or modify this value, you would use these methods. Since the variable x is private, it can’t be accessed outside JavaClass .&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;In python, there is no private keyword. We prepend a variable by a dunder(__ ) to show that it is private and shouldn’t be accessed or modified directly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adding a __ before a variable name modifies that variable’s name from varname to _Classname__varname , so direct access and modification like print(obj.varname) and obj.varname = 5 won’t work. Still, this isn’t very strong since you could directly replace varname with the modified form to get a direct modification to work.&lt;/p&gt;

&lt;p&gt;Let’s take the following example to understand this:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Adding getter and setter methods&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Taking our Student class example, let’s make the score attribute “private” by adding a __ before the variable name.&lt;/p&gt;

&lt;p&gt;If we directly went ahead and added get_score and set_score like Java, the main issue is that if we wanted to do this to existing code, we’d have to change every access from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**print("Score: " + str(student1.score))**
 **student1.score = 100**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**print(student1.get\_score())  
student1.set\_score(100)**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here’s where the @property decorator comes in. You can simply define getter, setter and deleter methods using this feature.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Our class now looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;To make the attribute&lt;/strong&gt;  &lt;strong&gt;score read-only,&lt;/strong&gt; just remove the setter method.&lt;/p&gt;

&lt;p&gt;Then, when we update score, we get the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "main.py", line 16, in &amp;lt;module&amp;gt;
    student.score = 10
**AttributeError: can't set attribute**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The deleter method&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The deleter method lets you delete a protected or private attribute using the del function. Using the same example as before, if we directly try and delete the score attribute, we get the following error:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;student = Student("Tom", 50, 100)
del student.score

This gives:
Traceback (most recent call last):
  File "&amp;lt;string&amp;gt;", line 17, in &amp;lt;module&amp;gt;
**AttributeError: can't delete attribute**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But when we add a deleter method, we can delete our private variable score .&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The attribute has been successfully removed now. Printing out the value of score gives “object has no attribute…”, since we deleted it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "&amp;lt;string&amp;gt;", line 23, in &amp;lt;module&amp;gt;
File "&amp;lt;string&amp;gt;", line 9, in x
**AttributeError: 'PythonClass' object has no attribute '\_\_score'**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  use-cases for the property decorator
&lt;/h4&gt;

&lt;p&gt;The property decorator is very useful &lt;strong&gt;when defining methods for data validation&lt;/strong&gt; , like when deciding if a value to be assigned is valid and won’t lead to issues later in the code.&lt;/p&gt;

&lt;p&gt;Another use-case would be when &lt;strong&gt;wanting to display information in a specific way&lt;/strong&gt;. Coming back to our example, if we wanted to display a student’s name as “Student Name: ” , instead of just  , we could return the first string from a property getter on the name attribute:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now, any time we access name, we get a formatted result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;student = Student("Bob", 350, 500)
**print(student.name)**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Student Name: Bob**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The&lt;/strong&gt;  &lt;strong&gt;property decorator can also be used for logging changes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, in a setter method, you could add code to log the updating of a variable.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now, whenever the setter is called, which is when the variable is modified, the change is logged. Let’s say there was a totaling error in Bob’s math exam and he ends up getting 50 more marks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;student = Student("Bob", 350, 500)
print(student.score)  
**student.score = 400** print(student.score)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above gives the following output, with the logged change visible:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;70.0 %
**INFO:root:Setting new value...**
80.0 %
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, our class looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h4&gt;
  
  
  Note#1: Where should you define a decorator wrt a class?
&lt;/h4&gt;

&lt;p&gt;There are many places you could define a decorator: outside the class, in a separate class, or maybe even in an inner class (with respect to the class we are using the decorator in). In this example, we simply defined grade_decorator outside the Student class. Though this works, the decorator now has nothing to do with our class, which we may not prefer.&lt;/p&gt;

&lt;p&gt;For a more detailed discussion on this, check out this post:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@vadimpushtaev/decorator-inside-python-class-1e74d23107f6"&gt;Decorator inside Python class&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Note#2: Are there options other than constructor overloading in Java to simulate the methods we discussed (like, from_str or from_tuple)?
&lt;/h4&gt;

&lt;p&gt;Apart from overloading the constructor, we could make use of &lt;strong&gt;static factory methods in java&lt;/strong&gt;. We could define a static method like from_str that would extract key information from the string passed to it and then return an object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Object-oriented programming is a very important paradigm to learn and use. Regardless of whether you’ll ever need to use the topics discussed here in your next project, it’s necessary to know the basics really well. Topics like the ones in this post aren’t used all that often compared to more basic concepts — like inheritance or the basic implementation of classes and objects — on which they are built. In any case, I hope this post gave you an idea of the other kinds of methods in Python OOP (apart from instance methods) and the property decorator.&lt;/p&gt;




</description>
      <category>programming</category>
      <category>java</category>
      <category>objectoriented</category>
      <category>python</category>
    </item>
    <item>
      <title>How Neural Networks Solve the XOR Problem</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Wed, 04 Nov 2020 17:56:49 +0000</pubDate>
      <link>https://dev.to/polaris000/how-neural-networks-solve-the-xor-problem-3mm1</link>
      <guid>https://dev.to/polaris000/how-neural-networks-solve-the-xor-problem-3mm1</guid>
      <description>&lt;h4&gt;
  
  
  And why hidden layers are so important
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wnKAip8i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A7YhLRr9Xz4wFECQ-0Q3Spg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wnKAip8i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A7YhLRr9Xz4wFECQ-0Q3Spg.png" alt=""&gt;&lt;/a&gt;Image by Author&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The perceptron&lt;/strong&gt; is a classification algorithm. Specifically, it works as a linear binary classifier. It was invented in the late 1950s by Frank Rosenblatt.&lt;/p&gt;

&lt;p&gt;The perceptron basically works as a threshold function — non-negative outputs are put into one class while negative ones are put into the other class.&lt;/p&gt;

&lt;p&gt;Though there’s a lot to talk about when it comes to neural networks and their variants, we’ll be discussing a specific problem that highlights the major differences between a single layer perceptron and one that has a few more layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**The Perceptron**
   Structure and Properties
   Evalutation
   Training algorithm

**2d Xor problem**   
   The XOR function

**Attempt #1: The Single Layer Perceptron**   
Implementing the Perceptron algorithm
   Results
   The need for non-linearity

**Attempt #2: Multiple Decision Boundaries**  
   Intuition
   Implementing the OR and NAND parts

**The Multi-layered Perceptron**  
   Structure and Properties
   Training algorithm

**Attempt #3: The Multi-layered Perceptron**  
   Implementing the MLP
   Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Structure and Properties&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A perceptron has the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input nodes&lt;/li&gt;
&lt;li&gt;Output node&lt;/li&gt;
&lt;li&gt;An activation function&lt;/li&gt;
&lt;li&gt;Weights and biases&lt;/li&gt;
&lt;li&gt;Error function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MxwRlWZg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATzjf5GuL-1xu2tMb2Rsg1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MxwRlWZg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATzjf5GuL-1xu2tMb2Rsg1g.png" alt=""&gt;&lt;/a&gt;A representation of a single-layer perceptron with 2 input nodes — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Input Nodes
&lt;/h4&gt;

&lt;p&gt;These nodes contain the input to the network. In any iteration — whether testing or training — these nodes are passed the input from our data.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Weights and Biases&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;These parameters are what we update when we talk about “training” a model. They are initialized to some random value or set to 0 and updated as the training progresses. The bias is analogous to a weight independent of any input node. Basically, it makes the model more flexible, since you can “move” the activation function around.&lt;/p&gt;
&lt;h4&gt;
  
  
  Evaluation
&lt;/h4&gt;

&lt;p&gt;The output calculation is straightforward.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compute the dot product of the input and weight vector&lt;/li&gt;
&lt;li&gt;Add the bias&lt;/li&gt;
&lt;li&gt;Apply the activation function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can be expressed like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AY1RE8TX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/753/1%2AkgmKKBVoFIXJC0qiqpC50A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AY1RE8TX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/753/1%2AkgmKKBVoFIXJC0qiqpC50A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is often simplified and written as a dot- product of the weight and input vectors plus the bias.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KsvsFEDP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/958/1%2A0GjDWpgA_x2a4QbjNh6HKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KsvsFEDP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/958/1%2A0GjDWpgA_x2a4QbjNh6HKQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Activation Function
&lt;/h4&gt;

&lt;p&gt;This function allows us to fit the output in a way that makes more sense. For example, in the case of a simple classifier, an output of say -2.5 or 8 doesn’t make much sense with regards to classification. If we use something called a sigmoidal activation function, we can fit that within a range of 0 to 1, which can be interpreted directly as a probability of a datapoint belonging to a particular class.&lt;/p&gt;

&lt;p&gt;Though there are many kinds of activation functions, we’ll be using a simple linear activation function for our perceptron. The linear activation function has no effect on its input and outputs it as is.&lt;/p&gt;
&lt;h4&gt;
  
  
  Classification
&lt;/h4&gt;

&lt;p&gt;How does a perceptron assign a class to a datapoint?&lt;/p&gt;

&lt;p&gt;We know that a datapoint’s evaluation is expressed by the relation wX + b . We define a threshold ( &lt;strong&gt;θ&lt;/strong&gt; ) which classifies our data. Generally, this threshold is set to 0 for a perceptron.&lt;/p&gt;

&lt;p&gt;So points for which wX + b is greater than or equal to 0 will belong to one class while the rest (wX + b is negative) are classified as belonging to the other class. We can express this as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--06KJKepg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ApzNeD1NCpKEpOWUMI_-xiQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--06KJKepg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ApzNeD1NCpKEpOWUMI_-xiQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Training algorithm
&lt;/h4&gt;

&lt;p&gt;To train our perceptron, we must ensure that we correctly classify all of our train data. Note that this is different from how you would train a neural network, where you wouldn’t try and correctly classify your entire training data. That would lead to something called overfitting in most cases.&lt;/p&gt;

&lt;p&gt;We start the training algorithm by calculating the &lt;strong&gt;gradient&lt;/strong&gt; , or Δw. Its the product of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the value of the input node corresponding to that weight&lt;/li&gt;
&lt;li&gt;The difference between the actual value and the computed value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qVEoM4QQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYoaCWleG8stS4AobGX_H_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qVEoM4QQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYoaCWleG8stS4AobGX_H_w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We get our new weights by simply incrementing our original weights with the computed gradients multiplied by the learning rate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZwcPig8h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/943/1%2A7h2ZWZXOr_Ae5ZERGRpLLg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZwcPig8h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/943/1%2A7h2ZWZXOr_Ae5ZERGRpLLg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple intuition for how this works: if our perceptron correctly classifies an input data point, actual_value — computed_value would be 0 , and there wouldn’t be any change in our weights since the gradient is now 0.&lt;/p&gt;
&lt;h3&gt;
  
  
  The 2D XOR problem
&lt;/h3&gt;

&lt;p&gt;In the XOR problem, we are trying to train a model to mimic a 2D XOR function.&lt;/p&gt;
&lt;h4&gt;
  
  
  The XOR function
&lt;/h4&gt;

&lt;p&gt;The function is defined like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bmsNy7Sa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/496/1%2Abpc3E6NlkPQpyGtL-azRsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bmsNy7Sa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/496/1%2Abpc3E6NlkPQpyGtL-azRsw.png" alt=""&gt;&lt;/a&gt;The XOR Truth table — Image by Author&lt;/p&gt;

&lt;p&gt;If we plot it, we get the following chart. This is what we’re trying to classify. The ⊕ (“o-plus”) symbol you see in the legend is conventionally used to represent the XOR boolean operator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LBltDpBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AaN7_uKSN8iWUktGOKa1Vgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LBltDpBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AaN7_uKSN8iWUktGOKa1Vgg.png" alt=""&gt;&lt;/a&gt;The XOR output plot — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our algorithm —regardless of how it works — must correctly output the XOR value for each of the 4 points. We’ll be modelling this as a classification problem, so Class 1 would represent an XOR value of 1, while Class 0 would represent a value of 0.&lt;/p&gt;
&lt;h3&gt;
  
  
  Attempt #1: The Single Layer Perceptron
&lt;/h3&gt;

&lt;p&gt;Let's model the problem using a single layer perceptron.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Input data&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The data we’ll train our model on is the table we saw for the XOR function.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Data Target  
[0, 0] 0  
[0, 1] 1  
[1, 0] 1  
[1, 1] 0**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Imports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apart from the usual visualization ( matplotliband seaborn) and numerical libraries (numpy), we’ll use cycle from itertools . This is done since our algorithm cycles through our data indefinitely until it manages to correctly classify the entire training data without any mistakes in the middle.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We next create our training data. This data is the same for each kind of logic gate, since they all take in two boolean variables as input.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The training function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, we cycle through the data indefinitely, keeping track of how many consecutive datapoints we correctly classified. If we manage to classify everything in one stretch, we terminate our algorithm.&lt;/p&gt;

&lt;p&gt;If not, we reset our counter, update our weights and continue the algorithm.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To visualize how our model performs, we create a mesh of datapoints, or a grid, and evaluate our model at each point in that grid. Finally, we colour each point based on how our model classifies it. So the Class 0 region would be filled with the colour assigned to points belonging to that class.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The Perceptron class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To bring everything together, we create a simple Perceptron class with the functions we just discussed. We have some instance variables like the training data, the target, the number of input nodes and the learning rate.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Results
&lt;/h4&gt;

&lt;p&gt;Let’s create a perceptron object and train it on the XOR data.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You’ll notice that the training loop never terminates, since a perceptron can only converge on linearly separable data. Linearly separable data basically means that you can separate data with a point in 1D, a line in 2D, a plane in 3D and so on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A perceptron can only converge on linearly separable data. Therefore, it isn’t capable of imitating the XOR function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remember that a perceptron must correctly classify the entire training data in one go. If we keep track of how many points it correctly classified consecutively, we get something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--en6rJa8c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AylW5N5ObDpDf6TxzCeJDXw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--en6rJa8c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AylW5N5ObDpDf6TxzCeJDXw.png" alt=""&gt;&lt;/a&gt;The value of correct_counter over 100 cycles of training — Image by Author&lt;/p&gt;

&lt;p&gt;The algorithm only terminates when correct_counter hits 4 — which is the size of the training set — so this will go on indefinitely.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Need for Non-Linearity
&lt;/h4&gt;

&lt;p&gt;It is clear that a single perceptron will not serve our purpose: the classes aren’t linearly separable. This boils down to the fact that a single linear decision boundary isn’t going to work.&lt;/p&gt;

&lt;p&gt;Non-linearity allows for more complex decision boundaries. One potential decision boundary for our XOR data could look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d1vXvi9M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AfgcoOFn-gfKnA_U5BOw-XA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d1vXvi9M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AfgcoOFn-gfKnA_U5BOw-XA.png" alt=""&gt;&lt;/a&gt;A potential non-linear decision boundary for our XOR model — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The 2d XOR problem — Attempt #2
&lt;/h3&gt;

&lt;p&gt;We know that the imitating the XOR function would require a non-linear decision boundary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But why do we have to stick with a single decision boundary?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  The Intuition
&lt;/h4&gt;

&lt;p&gt;Let’s first break down the XOR function into its AND and OR counterparts.&lt;/p&gt;

&lt;p&gt;The XOR function on two boolean variables A and B is defined as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wh2C9xB7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/811/1%2ALuINCL4Tf_yDGUlMD44T4A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wh2C9xB7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/811/1%2ALuINCL4Tf_yDGUlMD44T4A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s add A.~A and B.~B to the equation. Since they both equate to 0, the equation remains valid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I-cZDs7V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AvRRn_PvwGlMego2Xxe_LIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I-cZDs7V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AvRRn_PvwGlMego2Xxe_LIg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s rearrange the terms so that we can pull out A from the first part and B from the second.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XtZIOhtb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJMB4L2oK5PJVYqGQrm5y0A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XtZIOhtb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJMB4L2oK5PJVYqGQrm5y0A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simplifying it further, we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7UVx7QsD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/890/1%2AM9nguc5_2v1A1ABR-IUF0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7UVx7QsD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/890/1%2AM9nguc5_2v1A1ABR-IUF0g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using DeMorgan’s laws for boolean algebra:~A + ~B = ~(AB) , we can replace the second term in the above equation like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BfmBPhkB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/755/1%2AJBrvvYfm-jVFmgtGW-LiIw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BfmBPhkB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/755/1%2AJBrvvYfm-jVFmgtGW-LiIw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s replace A and B with x_1 and x_2 respectively since that’s the convention we’re using in our data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TlN2Xbr5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/819/1%2AHutPiBbJJ2iafsRo_g0O2Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TlN2Xbr5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/819/1%2AHutPiBbJJ2iafsRo_g0O2Q.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The XOR function can be condensed into two parts: &lt;strong&gt;a NAND and an OR&lt;/strong&gt;. If we can calculate these separately, we can just combine the results, using &lt;strong&gt;an AND gate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s call the OR section of the formula part I, and the NAND section as part II.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Modelling the OR part&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We’ll use the same Perceptron class as before, only that we’ll train it on OR training data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jSy4YUhF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/492/1%2AroabWS1sgBDoqKHtCde0oQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jSy4YUhF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/492/1%2AroabWS1sgBDoqKHtCde0oQ.png" alt=""&gt;&lt;/a&gt;The OR truth table — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This converges, since the data for the OR function is linearly separable. If we plot the number of correctly classified consecutive datapoints as we did in our first attempt, we get this plot. It’s clear that around iteration 50, it hits the value 4, meaning that it classified the entire dataset correctly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;correct_counter measures the number of consecutive datapoints correctly classified by our Perceptron&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s38-xT3z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIybVY22exz_e-AoTJeIF9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s38-xT3z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIybVY22exz_e-AoTJeIF9g.png" alt=""&gt;&lt;/a&gt;The correct_counter plot for our OR perceptron — Image by Author&lt;/p&gt;

&lt;p&gt;The decision boundary plot looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jWu-tWKb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AG7r0FU4_2YZJzPixFXExcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jWu-tWKb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AG7r0FU4_2YZJzPixFXExcA.png" alt=""&gt;&lt;/a&gt;The Output plot of our OR perceptron — Image by Author&lt;/p&gt;

&lt;h4&gt;
  
  
  Modelling the NAND part
&lt;/h4&gt;

&lt;p&gt;Let’s move on to the second part. We need to model a NAND gate. Just like the OR part, we’ll use the same code, but train the model on the NAND data. So our input data would be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L2pOT8rm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/492/1%2A0J2g4A35NfCUT82y3GZcVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L2pOT8rm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/492/1%2A0J2g4A35NfCUT82y3GZcVQ.png" alt=""&gt;&lt;/a&gt;The NAND Truth table — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After training, the following plots show that our model converged on the NAND data and mimics the NAND gate perfectly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0A39a74b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_FSuCnOqRtg1uXYSgnD9KQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0A39a74b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_FSuCnOqRtg1uXYSgnD9KQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IWaqHU98--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Aq4H9dJUjyDkAcUO72R3Nkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IWaqHU98--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Aq4H9dJUjyDkAcUO72R3Nkg.png" alt=""&gt;&lt;/a&gt;Decision boundary and correct_counter plots for the NAND perceptron — Image by Author&lt;/p&gt;

&lt;h4&gt;
  
  
  Bringing everything together
&lt;/h4&gt;

&lt;p&gt;Two things are clear from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we are performing a logical AND on the outputs of two logic gates (where the first one is an OR and the second one a NAND)&lt;/li&gt;
&lt;li&gt;and that both functions are being passed the same input (x1 and x2).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s model this into our network. First, let’s consider our two perceptrons as black boxes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_IYvRMSN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6E1lvXJv9phURco9mBr08A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_IYvRMSN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6E1lvXJv9phURco9mBr08A.png" alt=""&gt;&lt;/a&gt;The plan for our model — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding our input nodes x_1 and x_2, we can finally implement this through a simple function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9mvbIajq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AtTBFlBgXysCfR2OHXKWP_A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9mvbIajq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AtTBFlBgXysCfR2OHXKWP_A.png" alt=""&gt;&lt;/a&gt;Adding input nodes — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we need an AND gate, which we’ll train just we have been.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HgOh8BEl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Apc4V2KACa6MBjHdI5Y3bAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HgOh8BEl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Apc4V2KACa6MBjHdI5Y3bAg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fKH1gres--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AZ5FCj0Nhk31n3XDX9SZWdA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fKH1gres--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AZ5FCj0Nhk31n3XDX9SZWdA.png" alt=""&gt;&lt;/a&gt;The correct_count and output plots of our AND perceptron. — Image by Author&lt;/p&gt;

&lt;p&gt;What we now have is a model that mimics the XOR function.&lt;/p&gt;

&lt;p&gt;If we were to implement our XOR model, it would look something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If we plot the decision boundaries from our model, — which is basically an AND of our OR and NAND models — we get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j16LlGC---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A5yVX7bID4pp0svaEOAPuZw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j16LlGC---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A5yVX7bID4pp0svaEOAPuZw.png" alt=""&gt;&lt;/a&gt;The Output plot of our 2nd Attempt, showing a correct classification on our XOR data— Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Out of all the 2 input logic gates, the XOR and XNOR gates are the only ones that are not linearly-separable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Though our model works, it doesn’t seem like a viable solution to most non-linear classification or regression tasks. It’s really specific to this case, and most problems can’t be split into just simple intermediate problems that can be individually solved and then combined. For something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NzQm2ALJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A--0y9w95J7lZAUqjGetHVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NzQm2ALJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A--0y9w95J7lZAUqjGetHVQ.png" alt=""&gt;&lt;/a&gt;A binary classification problem in two dimensions — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A potential decision boundary could be something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k7-PqLdS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AC0fYqaCJIGZLsoiKGZgP7Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k7-PqLdS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AC0fYqaCJIGZLsoiKGZgP7Q.png" alt=""&gt;&lt;/a&gt;A potential decision boundary that fits our example — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to look for a more general model, which would allow for non-linear decision boundaries, like a curve, as is the case above. Let’s see how an MLP solves this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Multi-layered Perceptron
&lt;/h3&gt;

&lt;p&gt;The overall components of an MLP like input and output nodes, activation function and weights and biases are the same as those we just discussed in a perceptron.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The biggest difference? An MLP can have hidden layers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Hidden layers
&lt;/h4&gt;

&lt;p&gt;Hidden layers are those layers with nodes other than the input and output nodes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An MLP is generally restricted to having a single hidden layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The hidden layer allows for non-linearity.&lt;/strong&gt; A node in the hidden layer isn’t too different to an output node: nodes in the previous layers connect to it with their own weights and biases, and an output is computed, generally with an activation function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qTXbNzSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AiB0NCmG2OFUGI-DCokHT2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qTXbNzSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AiB0NCmG2OFUGI-DCokHT2g.png" alt=""&gt;&lt;/a&gt;The general structure of a multi-layered perceptron — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Activation Function
&lt;/h4&gt;

&lt;p&gt;Remember the linear activation function we used on the output node of our perceptron model? There are several more complex activation functions. You may have heard of the sigmoid and the tanh functions, which are some of the most popular non-linear activation functions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Activation functions should be differentiable, so that a network’s parameters can be updated using backpropagation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Training algorithm
&lt;/h4&gt;

&lt;p&gt;Though the output generation process is a direct extension of that of the perceptron, updating weights isn’t so straightforward. Here’s where backpropagation comes into the picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backpropagation&lt;/strong&gt; is a way to update the weights and biases of a model starting from the output layer all the way to the beginning. The main principle behind it is that each parameter changes in proportion to how much it affects the network’s output. A weight that has barely any effect on the output of the model will show a very small change, while one that has a large negative impact will change drastically to improve the model’s prediction power.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Backpropagation&lt;/strong&gt; is an algorithm for update the weights and biases of a model based on their gradients with respect to the error function, starting from the output layer all the way to the first layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The method of updating weights directly follows from derivation and the chain rule.&lt;/p&gt;

&lt;p&gt;There’s a lot to cover when talking about backpropagation. It warrants its own article. So if you want to find out more, have a look at this excellent article by &lt;a href="https://medium.com/@simonnoff?source=post_page-----7bb3aa2f95fd--------------------------------"&gt;Simeon Kostadinov&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/understanding-backpropagation-algorithm-7bb3aa2f95fd"&gt;Understanding Backpropagation Algorithm&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt #3: the Multi-layered Perceptron
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The architecture
&lt;/h4&gt;

&lt;p&gt;There are no fixed rules on the number of hidden layers or the number of nodes in each layer of a network. The best performing models are obtained through trial and error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The architecture of a network refers to its general structure — the number of hidden layers, the number of nodes in each layer and how these nodes are inter-connected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Let’s go with a single hidden layer with two nodes in it.&lt;/strong&gt; We’ll be using the sigmoid function in each of our hidden layer nodes and of course, our output node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5ER11UqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkAZGp-basYjFSHexmQteUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5ER11UqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkAZGp-basYjFSHexmQteUA.png" alt=""&gt;&lt;/a&gt;The final architecture of our MLP — Image by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;p&gt;The libraries used here like NumPy and pyplot are the same as those used in the Perceptron class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The training algorithm&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The algorithm here is slightly different: we iterate through the training data a fixed number of times — num_epochs to be precise. In each iteration, we do a forward pass, followed by a backward pass where we update the weights and biases as necessary. This is called backpropagation.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The sigmoid activation function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, we define a sigmoid function. As discussed, it’s applied to the output of each hidden layer node and the output node. Its differentiable, so it allows us to comfortably perform backpropagation to improve our model.&lt;/p&gt;

&lt;p&gt;Its derivate its also implemented through the _delsigmoid function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The forward and backward pass&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the forward pass, we apply the wX + b relation multiple times, and applying a sigmoid function after each call.&lt;/p&gt;

&lt;p&gt;In the backward pass, implemented as the update_weights function, we calculate the gradients of each of our 6 weights and 3 biases with respect to the error function and update them by the factor learning rate * gradient.&lt;/p&gt;

&lt;p&gt;Finally, the classify function works as expected: Since a sigmoid function outputs values between 0 and 1, we simply interpret them as probabilities of belonging to a particular class. Hence, outputs greater than or equal to 0.5 are classified as belonging to Class 1 while those outputs that are less than 0.5 are said to belong to Class 0 .&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The MLP class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s bring everything together by creating an MLP class. All the functions we just discussed are placed in it. The plot function is exactly the same as the one in the Perceptron class.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Results
&lt;/h4&gt;

&lt;p&gt;Let’s train our MLP with a learning rate of 0.2 over 5000 epochs.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If we plot the values of our loss function, we get the following plot after about 5000 iterations, showing that our model has indeed converged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A2rpTE5H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AXDHpv6hzQ7Mo17auo5G3VQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A2rpTE5H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AXDHpv6hzQ7Mo17auo5G3VQ.png" alt=""&gt;&lt;/a&gt;The Loss Plot over 5000 epochs of our MLP — Image by Author&lt;/p&gt;

&lt;p&gt;A clear non-linear decision boundary is created here with our generalized neural network, or MLP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CKTBzTvw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATrja6lUuVl71Xn1w27XRSQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CKTBzTvw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ATrja6lUuVl71Xn1w27XRSQ.png" alt=""&gt;&lt;/a&gt;The Decision Boundary plot, showing the decision boundary and the classes — Image by Author&lt;/p&gt;

&lt;h4&gt;
  
  
  Note #1: Adding more layers or nodes
&lt;/h4&gt;

&lt;p&gt;Adding more layers or nodes gives increasingly complex decision boundaries. But this could also lead to something called overfitting — where a model achieves very high accuracies on the training data, but fails to generalize.&lt;/p&gt;

&lt;p&gt;A good resource is the Tensorflow Neural Net playground, where you can try out different network architectures and view the results.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://playground.tensorflow.org/#activation=sigmoid&amp;amp;batchSize=30&amp;amp;dataset=xor&amp;amp;regDataset=reg-plane&amp;amp;learningRate=0.1&amp;amp;regularizationRate=0&amp;amp;noise=0&amp;amp;networkShape=2&amp;amp;seed=0.21709&amp;amp;showTestData=false&amp;amp;discretize=true&amp;amp;percTrainData=70&amp;amp;x=true&amp;amp;y=true&amp;amp;xTimesY=false&amp;amp;xSquared=false&amp;amp;ySquared=false&amp;amp;cosX=false&amp;amp;sinX=false&amp;amp;cosY=false&amp;amp;sinY=false&amp;amp;collectStats=false&amp;amp;problem=classification&amp;amp;initZero=false&amp;amp;hideText=false&amp;amp;batchSize_hide=false"&gt;Tensorflow - Neural Network Playground&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Note #2: Choosing a loss function
&lt;/h4&gt;

&lt;p&gt;The loss function we used in our MLP model is the Mean Squared loss function. Though this is a very popular loss function, it makes some assumptions on the data (like it being gaussian) and isn’t always convex when it comes to a classification problem. It was used here to make it easier to understand how a perceptron works, but for classification tasks, there are better alternatives, like &lt;strong&gt;binary cross-entropy loss.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://machinelearningmastery.com/how-to-choose-loss-functions-when-training-deep-learning-neural-networks/"&gt;How to Choose Loss Functions When Training Deep Learning Neural Networks - Machine Learning Mastery&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Neural nets used in production or research are never this simple, but they almost always build on the basics outlined here. Hopefully, this post gave you some idea on how to build and train perceptrons and vanilla networks.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;




</description>
      <category>perceptron</category>
      <category>datascience</category>
      <category>algorithms</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Understanding Dynamic Programming</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Sun, 04 Oct 2020 17:02:41 +0000</pubDate>
      <link>https://dev.to/polaris000/understanding-dynamic-programming-46h3</link>
      <guid>https://dev.to/polaris000/understanding-dynamic-programming-46h3</guid>
      <description>&lt;h4&gt;
  
  
  An intuitive guide to the popular optimization technique.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0IHMLjyZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyEugK-e5TyuSMPsjLDpb1Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0IHMLjyZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyEugK-e5TyuSMPsjLDpb1Q.png" alt=""&gt;&lt;/a&gt;Image by author&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic programming&lt;/strong&gt; , or DP, is an optimization technique. It is used in several fields, though this article focuses on its applications in the field of algorithms and computer programming. Its a topic often asked in algorithmic interviews.&lt;/p&gt;

&lt;p&gt;Since DP isn’t very intuitive, most people (myself included!) often find it tricky to model a problem as a dynamic programming model. In this post, we’ll discuss when we use DP, followed by its types and then finally work through an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  When is DP used?
&lt;/h3&gt;

&lt;p&gt;There are two necessary conditions a problem must satisfy for DP to work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overlapping Sub-problems&lt;/li&gt;
&lt;li&gt;Optimal substructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go over these in a little more detail.&lt;/p&gt;

&lt;h4&gt;
  
  
  Overlapping Sub-Problems
&lt;/h4&gt;

&lt;p&gt;This property is exactly what it sounds like: repeating sub-problems. But for this to make sense, we need to know what a sub-problem is.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;sub-problem&lt;/strong&gt; is simply a smaller version of the problem at hand. In most cases, this would mean smaller parameter values which you would pass to your recursive function.&lt;/p&gt;

&lt;p&gt;If you’re looking for a particular page in a book, what would you do? You’d open the book to a particular page and compare the page number you’re on with the page number you’re looking for.&lt;/p&gt;

&lt;p&gt;If the current page is smaller than the required page, you’d start looking in between the current page and the last page. On the other hand, if the current page number is greater, you’d start searching between the start of the book and the current page.&lt;/p&gt;

&lt;p&gt;You’d continue this until you found the page.&lt;/p&gt;

&lt;p&gt;If you had to model this as a recursive function, what would that look like? Maybe something like this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;The following snippets have been written in a form of pseudocode to improve readability&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pretty straightforward. There’s a &lt;strong&gt;&lt;em&gt;getpage&lt;/em&gt;&lt;/strong&gt; function which returns the page ( &lt;strong&gt;&lt;em&gt;target_page&lt;/em&gt;&lt;/strong&gt; , here) we’re looking for. The function looks at the middle page between &lt;strong&gt;&lt;em&gt;from_page&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;to_page&lt;/em&gt;&lt;/strong&gt; and checks if we have a match.&lt;/p&gt;

&lt;p&gt;If not, the function looks at either the left half or the right half of the section we are looking at.&lt;/p&gt;

&lt;p&gt;But what do those two recursive calls to &lt;strong&gt;&lt;em&gt;getpage&lt;/em&gt;&lt;/strong&gt; represent? You’ll notice that at each recursive call, we are reducing our search space by half. What we’re doing is solving the same problem, that is, looking for a specific page, in a smaller space. We’re solving sub-problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Divide and Conquer,&lt;/strong&gt; or &lt;strong&gt;DAC&lt;/strong&gt; algorithms work through the principle of sub-problems. The “divide” part refers to splitting a problem into sub-problems. Sorting algorithms like mergesort and quicksort are great examples. Note that binary search isn’t exactly a DAC algorithm for the simple reason that it doesn’t have a “combine” step, whereas an actual divide and conquer algorithm would combine the results of its sub-problems to get the final solution.&lt;/p&gt;

&lt;p&gt;Now that we have answered the question of what a sub-problem is, we move on to the other word: “ &lt;strong&gt;overlapping&lt;/strong&gt; ”.&lt;/p&gt;

&lt;p&gt;When these sub-problems have to be solved more than once, they are said to be overlapping. Look at the call graph for computing the value of the nth Fibonacci term.&lt;/p&gt;

&lt;p&gt;The recurrence relation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the relation  
**f(n) = f(n - 1) + f(n-2)**  

the base case
**f(0) = 0  
f(1) = 1**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ubxmpDsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AN-g5eJ6XhOVp0cm0EdE-Ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ubxmpDsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AN-g5eJ6XhOVp0cm0EdE-Ag.png" alt=""&gt;&lt;/a&gt;The recursive Fibonacci call tree. f(n) is the nth Fibonacci number — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The calls have been shaded to represent overlapping subproblems. Compare this with something like binary search, where the subproblems aren’t overlapping.&lt;/p&gt;
&lt;h4&gt;
  
  
  The optimal substructure property
&lt;/h4&gt;

&lt;p&gt;The optimal substructure property is slightly more intricate: it refers to the scenario where optimal solutions to sub-problems can directly be considered when computed the overall optimal solution.&lt;/p&gt;

&lt;p&gt;A quick example? Say you want to find the shortest path from &lt;strong&gt;&lt;em&gt;A&lt;/em&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;B&lt;/em&gt;&lt;/strong&gt;. Let &lt;strong&gt;&lt;em&gt;X&lt;/em&gt;&lt;/strong&gt; be an intermediate point between &lt;strong&gt;&lt;em&gt;A&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;B&lt;/em&gt;&lt;/strong&gt; with a &lt;strong&gt;single edge&lt;/strong&gt; connecting it to  &lt;strong&gt;&lt;em&gt;A&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XR0uTX7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AefUCb45YaKrBQR9XBF0qOg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XR0uTX7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AefUCb45YaKrBQR9XBF0qOg.png" alt=""&gt;&lt;/a&gt;Finding the shortest path using intermediate nodes — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To solve this, we can find the shortest path from all intermediate nodes ( &lt;strong&gt;&lt;em&gt;X&lt;/em&gt;&lt;/strong&gt; ) to B, and then find the path from A to X plus the shortest path from X to B which is shortest for all X.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shortest(A, B) = min(AX + shortest(X, B)) for all intermediate nodes X.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What we’re doing here is using an optimal intermediate solution (&lt;strong&gt;&lt;em&gt;shortest(X, B)&lt;/em&gt;&lt;/strong&gt;) and use that (as opposed to considering every solution for a sub-problem) to find the final optimal answer.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;The two kinds of DP&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  The top-down (memoization) approach
&lt;/h4&gt;

&lt;p&gt;In a top-down approach, we start from the highest level of our problem. In this approach, we initially check if have already solved the current sub-problem. If we have, we just return that value. If not, we solve that sub-problem. We use recursive calls to solve our sub-problem.&lt;/p&gt;

&lt;p&gt;Since those calls require solving smaller sub-problems which we haven’t seen before, we continue this way, until we encounter a sub-problem we have either solved or know the answer to trivially.&lt;/p&gt;
&lt;h4&gt;
  
  
  The bottom-up (tabulation) approach
&lt;/h4&gt;

&lt;p&gt;In this approach, we start at the very bottom and then work our way to the top. Since we start from the “base case”, and use our recurrence relation, we don’t really need recursion, and so, this approach is iterative.&lt;/p&gt;

&lt;p&gt;The main difference between the two approaches is that bottom-up calculates all solutions, while top-down computes only those that are required. For example, to find the shortest path between source and destination, using the top-down approach, we only compute the distances with intermediate points near the shortest path, choosing the minimum at each stage.&lt;/p&gt;

&lt;p&gt;On the other hand, in a bottom-up approach, we end up calculating the shortest distance between each point on the grid and the destination, finally returning the shortest distance from the start to the end.&lt;/p&gt;

&lt;p&gt;As a comparison, let's look at a possible top-down and bottom-up function that returns the nth Fibonacci term.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;While both approaches have the same asymptotic time complexities, the recursive calls in a top-down implementation may lead to a stack overflow, which is a non-issue owing to the iterative nature of the bottom-up approach.&lt;/p&gt;

&lt;p&gt;Remember that though we implement the latter iteratively, your logic would still use the recurrence relation from the very basic recursive approach, as we shall see in this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;An example&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's go over a problem which we’ll solve using both approaches to dynamic programming.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Problem
&lt;/h4&gt;

&lt;p&gt;Find the maximum sum of elements in an array ensuring that no adjacent elements are included. Let’s assume that no elements are negative.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**example 1:  
[1, 2, 3] =&amp;gt; 1 + 3 = 4**  

**example 2:  
[1, 1, 1, 1] =&amp;gt; 1 + 1 = 2**  

**example 3:  
[2, 5, 2] =&amp;gt; 5 = 5**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;First, let's try a &lt;strong&gt;greedy approach.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since our goal is to maximize the sum of the elements we choose, we could hope to accomplish this by choosing the biggest elements, ignoring its neighbours, and then continuing this way. Here, we’re ensuring that at each step of the way, we have a maximum sum. But this would be correct only in a local context, while we are, of course, looking for a global solution.&lt;/p&gt;

&lt;p&gt;This approach could work in certain cases.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**[1, 9, 1, 10, 1, 9, 1]**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, we first choose 10, since its the biggest element. We then ignore its neighbours, so that we don’t violate the condition that we aren’t allowed to choose adjacent elements.&lt;/p&gt;

&lt;p&gt;Next, we choose both the 5’s, since they’re the next biggest elements, and then ignore their neighbours. Our algorithm ends here since there aren’t any elements left. The result we get — 10 + 5 + 5 — is in fact, the right answer.&lt;/p&gt;

&lt;p&gt;But this won’t always work. Take the following example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**[1, 1, 9, 10, 9, 1, 1]**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At every step, if you chose the maximum element, ignored its neighbours and continued that way, you’d end up choosing 10, then 1 and then 1 again after ignoring both the 9's, which would add up to 12, but the right answer would be 1 + 9 + 9 + 1, which is 20.&lt;/p&gt;

&lt;p&gt;Its clear this approach isn’t the right one. Let’s start from a basic recursive solution and work up to one that uses dynamic programming one.&lt;/p&gt;

&lt;p&gt;This is the difference between the greedy and dynamic programming approaches. While a greedy approach focuses on doing its best to reach the goal at every step, DP looks at the overall picture. With a greedy approach, there’s no guarantee you’ll even end up with an optimal solution, unlike DP. Greedy algorithms often get trapped in local maxima, leading to sub-optimal solutions.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;The recursive solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;After thinking for a bit, you can probably see that we have a condition to keep in mind: &lt;strong&gt;no adjacent elements&lt;/strong&gt;. You can probably figure out that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we can choose to either consider an element in our sum or ignore it&lt;/li&gt;
&lt;li&gt;if we consider it, we will have to ignore its adjacent element&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the sake of brevity, let &lt;strong&gt;&lt;em&gt;f(a..b)&lt;/em&gt;&lt;/strong&gt; represent a call to &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; our array from index &lt;strong&gt;&lt;em&gt;a&lt;/em&gt;&lt;/strong&gt; to index &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt; (both inclusive). That function &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; would represent our recursive function which would solve the problem.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;&lt;em&gt;f(0..4)&lt;/em&gt;&lt;/strong&gt; would mean running the function from index 0 to index 4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fETKvUC4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/524/1%2AY8zXc6mPImLyFPeB2Ae_8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fETKvUC4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/524/1%2AY8zXc6mPImLyFPeB2Ae_8g.png" alt=""&gt;&lt;/a&gt;Our function call representation — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The two arrows pointing from a cell represent our choices of subsequent function calls. Since this is a maximization problem, we’d have to choose the maximum out of these options.&lt;/p&gt;

&lt;p&gt;Let’s come back to our array.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**[5, 10, 100, 10, 5]**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Keeping the conditions discussed above in mind let’s actually write down what we would be doing.&lt;/p&gt;

&lt;p&gt;Our first call would be on the entire array, which is of length 5 as can be seen above.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(0..4)**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the element at index 0 (which happens to be 5 here), we can either choose to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;include it in our sum:&lt;/strong&gt; our current sum would then be 5 + the maximum sum of the rest of the array, but excluding the next element (index 1). Thus, our sum becomes &lt;strong&gt;&lt;em&gt;5 + f(2..4)&lt;/em&gt;&lt;/strong&gt;. Or to generalize it, &lt;strong&gt;&lt;em&gt;arr[0] + f(2..4)&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;exclude it:&lt;/strong&gt; our current sum would then just be equal to the maximum sum of the remaining array. This can be written as: &lt;strong&gt;&lt;em&gt;0 + f(1..4)&lt;/em&gt;&lt;/strong&gt;. Notice that our next call is from index 1 and not 2 as in the previous case. Since we aren’t considering the element at index 0, we are free to consider the element at index 1 — we aren’t forced to ignore it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AFdFFX8p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/908/1%2A16XvPir53Yo38Kd1r1wz6Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AFdFFX8p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/908/1%2A16XvPir53Yo38Kd1r1wz6Q.png" alt=""&gt;&lt;/a&gt;The few first calls of our function — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The graph here visually explains this. As mentioned earlier, all arrows at a given level represent our choices, from which we choose the greatest one.&lt;/p&gt;

&lt;p&gt;So our final answer would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(0..4) = max(arr[0] + f(2..4), f(1..4))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s expand this for the next iteration.&lt;/p&gt;

&lt;p&gt;First, we’ll do it for the left tree, which is &lt;strong&gt;&lt;em&gt;f(2..4)&lt;/em&gt;&lt;/strong&gt;. This is just like what we did for the first call to f. Remember that the &lt;strong&gt;&lt;em&gt;arr[0] +&lt;/em&gt;&lt;/strong&gt; part is still there. It will be added to the value of &lt;strong&gt;&lt;em&gt;f(2..4)&lt;/em&gt;&lt;/strong&gt; on our way back up the call tree.&lt;/p&gt;

&lt;p&gt;Our choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;consider &lt;em&gt;arr[2]&lt;/em&gt; in our sum:&lt;/strong&gt; our sum at this stage becomes &lt;strong&gt;&lt;em&gt;arr[2] + f(4..4)&lt;/em&gt;&lt;/strong&gt;. Remember that since we’re considering the element at index 2, we would have to ignore the next element — index 3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ignore &lt;em&gt;arr[2]&lt;/em&gt;:&lt;/strong&gt; our sum here is the same as the maximum result of the remaining array without having to ignore the adjacent element. So, that's &lt;strong&gt;&lt;em&gt;f(3..4)&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gbyvkZxQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AuLrX5BoNJSRF_ZR3P1sbow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gbyvkZxQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AuLrX5BoNJSRF_ZR3P1sbow.png" alt=""&gt;&lt;/a&gt;The third level of our call tree — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just like before, the value of &lt;strong&gt;&lt;em&gt;f(2..4)&lt;/em&gt;&lt;/strong&gt; would be the maximum of our two choices.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(2..4) = max(arr[2] + f(4..4), f(3..4))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The base case&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;What do you think &lt;strong&gt;&lt;em&gt;f(4..4)&lt;/em&gt;&lt;/strong&gt; would evaluate to? Following our notation, it is the result of our function call on the array from index 4 to … well, index 4. That means that we are calling the function on a single element. The maximum sum of a single element is itself.&lt;/p&gt;

&lt;p&gt;Another thing to keep in mind: in &lt;strong&gt;&lt;em&gt;f(a..b)&lt;/em&gt;&lt;/strong&gt;, a should never be greater than b. Since this call represents starting from index a and going up to index b, we would have to return 0 if &lt;strong&gt;&lt;em&gt;a&lt;/em&gt;&lt;/strong&gt; ever gets bigger than &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt;. There is no maximum sum if there are no elements.&lt;/p&gt;

&lt;p&gt;We have our base case here. Our function &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; , when called on a single element, would return that element directly and returns 0 if we are not in a valid range. There are no further recursive calls. That’s why its called the base case.&lt;/p&gt;

&lt;p&gt;In our case, our call to &lt;strong&gt;&lt;em&gt;f(3..4)&lt;/em&gt;&lt;/strong&gt; leads to an invalid call to &lt;strong&gt;&lt;em&gt;f(5..4)&lt;/em&gt;&lt;/strong&gt;, which we handle by returning 0. We’ll generalize this later.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(4..4) = arr[4]  
f(5..4) = 0**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The recurrence relation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let’s have another look at our results.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;first call:  
**f(0..4) = max(arr[0] + f(2..4), f(1..4))**  

second call:
**f(2..4) = max(arr[2] + f(4..4), f(3..4))**

the base case:
**f(4..4) = arr[4]  
f(5..4) = 0**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice a pattern in the first two results? If we generalize these, we get:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(a..b) = max(arr[a] + f(a+2 .. b), f(a+1, b))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This still isn’t the most simplified version of our relation. Notice the occurrences of &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt; here. In fact, go back and look at our specific calls in the previous block.&lt;/p&gt;

&lt;p&gt;They don’t change. There’s no &lt;strong&gt;&lt;em&gt;b + 1&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;b + 2&lt;/em&gt;&lt;/strong&gt;. It’s always &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt;. And what’s the value of &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt; in our first call? The last index. Since &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt; is constant throughout our algorithm, we can remove it.&lt;/p&gt;

&lt;p&gt;Our recurrence relation becomes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(a) = max(arr[a] + f(a+2), f(a+1))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;where &lt;strong&gt;&lt;em&gt;f(a)&lt;/em&gt;&lt;/strong&gt; is a call on the array from index &lt;strong&gt;&lt;em&gt;a&lt;/em&gt;&lt;/strong&gt;  onwards.&lt;/p&gt;

&lt;p&gt;Another thing to realize is that similar to how we removed &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt; since it was always equal to the last index in the array, the base case, which refers to a single element, would only happen if that element was the last in the array.&lt;/p&gt;

&lt;p&gt;A generalized version of our base case is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(n-1) = arr[n-1]** where **n** is the size of the array
**f(a) = 0** if **a** &amp;gt;= **n** where **n** is the size of the array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Thus, we have our relation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**f(a) = max(arr[a] + f(a+2), f(a+1))  
f(n-1) = arr[n-1] **where** n** is the size of the array
**f(a) = 0** if **a** &amp;gt;= **n** where **n** is the size of the array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s implement the recursive approach based on this relation.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This function would be called like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**array := [1, 5, 2, 4, ...]  
return f(array, 0)**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What would be the complexity of this?&lt;/p&gt;

&lt;p&gt;If we were to approximate the complexity based on the size of the array ( &lt;strong&gt;&lt;em&gt;n&lt;/em&gt;&lt;/strong&gt; ) we are operating on, we get something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**T(n) = T(n-2) + T(n-1) + O(1)**

**T(0) = O(1)**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Intuitively, every call to f on an array of size n — represented as &lt;strong&gt;&lt;em&gt;T(n)&lt;/em&gt;&lt;/strong&gt; — leads to two calls on f on arrays of size &lt;strong&gt;&lt;em&gt;n-2&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;n-1&lt;/em&gt;&lt;/strong&gt;. That is, at each stage, we’re doubling the number of calls to  &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The asymptotic time complexity is exponential. With the above reasoning, we get &lt;strong&gt;&lt;em&gt;O(2^n).&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a loose estimate on the upper bound, since the &lt;strong&gt;&lt;em&gt;n-2&lt;/em&gt;&lt;/strong&gt; tree is bound to end before the &lt;strong&gt;&lt;em&gt;n-1&lt;/em&gt;&lt;/strong&gt; tree, and so we are doing slightly less than doubling the calls. The actual complexity is &lt;strong&gt;&lt;em&gt;O(phi^n) — phi&lt;/em&gt;&lt;/strong&gt; is the golden ratio — or &lt;strong&gt;&lt;em&gt;O(1.618^n),&lt;/em&gt;&lt;/strong&gt; which is slightly lesser than our original estimate, but let's stick to &lt;strong&gt;O(2^n)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another thing to notice is that the recurrence relation above is similar to that of the nth Fibonacci term, which would hence give a similar complexity.&lt;/p&gt;
&lt;h4&gt;
  
  
  A dynamic programming approach
&lt;/h4&gt;

&lt;p&gt;Here’s where dynamic programming comes into the picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A3-Dbwx0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyH_GlIjc8O1Ehy7LvU4Stg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A3-Dbwx0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyH_GlIjc8O1Ehy7LvU4Stg.png" alt=""&gt;&lt;/a&gt;Notice the repeating sub-problems in the call graph — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you look closely, you’ll see the overlapping sub-problems we were talking about earlier.&lt;/p&gt;

&lt;p&gt;Now comes the important part — converting this recursive implementation to a dynamic programming approach. What if we stored the values of the function calls that are being repeated?&lt;/p&gt;

&lt;p&gt;Let’s maintain an array where the ith element is the value of &lt;strong&gt;&lt;em&gt;f(i)&lt;/em&gt;&lt;/strong&gt;, which in turn, is the maximum sum of the array from index &lt;strong&gt;&lt;em&gt;i&lt;/em&gt;&lt;/strong&gt; to the end.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] = f(i..n) = f(i)**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And since we already have a result for f(i),&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] = max(arr[i] + f(i + 2), f(i + 1))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that we have this relation, we can go two different ways. Either we go the top-down route, where our function is still recursive, like our result above, or we remove all recursive calls and go the bottom-up route.&lt;/p&gt;

&lt;p&gt;We’ll focus on the bottom-up route, but let's discuss the top-down approach.&lt;/p&gt;
&lt;h4&gt;
  
  
  - The Top-down approach
&lt;/h4&gt;

&lt;p&gt;Look at our previous result.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] = max(arr[i] + f(i + 2), f(i + 1))**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That’s all we need to implement the top-down approach. For any call to &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; , we’ll first check in our array &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt; if we have already made that call earlier, and if we have, we use the pre-calculated value directly.&lt;/p&gt;

&lt;p&gt;On the other hand, if the call we are making has never been done before, we have to compute the entire thing. In that case, once we arrive at a value, we make sure to store it in our array &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt; so that we won’t have to repeat the whole process.&lt;/p&gt;

&lt;p&gt;The call tree should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MTN0Nu9p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A8EpjkUlVOchxAy9F4G8_7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MTN0Nu9p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A8EpjkUlVOchxAy9F4G8_7g.png" alt=""&gt;&lt;/a&gt;The call tree in the top-down dynamic programming approach — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s implement this algorithm.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The additional space required to store the results of our sub-problems grows linearly with the size of the input array. Hence, apart from the &lt;strong&gt;&lt;em&gt;O(n)&lt;/em&gt;&lt;/strong&gt; space required due to the recursive stack, we have an &lt;strong&gt;&lt;em&gt;O(n)&lt;/em&gt;&lt;/strong&gt; space for the &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt; array, n being the size of the input array.&lt;/p&gt;

&lt;p&gt;The time complexity, though harder to compute, is linear to the input size. This is because we are storing the answers to the sub-problems we have already solved, and so, we have &lt;strong&gt;&lt;em&gt;O(n)&lt;/em&gt;&lt;/strong&gt; unique sub-problems that we have to solve. This result can also be verified with the complexity we get using the bottom-up approach.&lt;/p&gt;

&lt;h4&gt;
  
  
  - The Bottom-up approach
&lt;/h4&gt;

&lt;p&gt;Recall that in this approach, we seek to eliminate all recursive calls by following an iterative approach, where we start from the base case, or the “bottom” and make our way up.&lt;/p&gt;

&lt;p&gt;Let’s replace the other calls to &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; with accessing elements of  &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] = max(arr[i] + dp[i + 2], dp[i + 1])**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What about the base case, &lt;strong&gt;&lt;em&gt;f(n-1) = arr[n-1]&lt;/em&gt;&lt;/strong&gt;? This would be the last element of the array  &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[n-1] = arr[n-1]**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And just like that, we have our solution for a bottom-up &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt; approach!&lt;/p&gt;

&lt;p&gt;Let’s implement this, just like we did for the recursive approach.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This function would be called like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**array := [1, 5, 2, 4, ...]  
output(f(array))**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The complexity here would be linear in both space and time.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;We are running a single for-loop &lt;strong&gt;&lt;em&gt;n-1&lt;/em&gt;&lt;/strong&gt; times, and in each iteration, we are performing constant time operations — a linear time complexity.&lt;/p&gt;

&lt;p&gt;Since the size of the array &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt; depends on the size of the input array — which, of course, is variable — our space complexity is also linear.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Improving the algorithm&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;But can we do better? Let’s see.&lt;/p&gt;

&lt;p&gt;In terms of asymptotic time complexity, we can’t do better. To find the answer, we have to check every element of the array. So we can’t do better than linear time.&lt;/p&gt;

&lt;p&gt;But what about space complexity? Do we need to maintain an array of size &lt;strong&gt;&lt;em&gt;n&lt;/em&gt;&lt;/strong&gt; to solve the problem?&lt;/p&gt;

&lt;p&gt;Look closely at the line inside the for-loop:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] = max(arr[i] + dp[i + 2], dp[i + 1])**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At any point of time, all we need to populate &lt;strong&gt;&lt;em&gt;dp[i]&lt;/em&gt;&lt;/strong&gt; is the next two elements in &lt;strong&gt;&lt;em&gt;dp&lt;/em&gt;&lt;/strong&gt;  — at indices &lt;strong&gt;&lt;em&gt;i +1&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;i + 2&lt;/em&gt;&lt;/strong&gt;. There’s no reason to maintain all of our results. We just need to keep track of the last two iterations.&lt;/p&gt;

&lt;p&gt;Let’s use three variables here. Let’s name them &lt;strong&gt;&lt;em&gt;i_0&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;i_1&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;i_2&lt;/em&gt;&lt;/strong&gt; for make it easier to relate between them.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[i] --&amp;gt; i\_0  
dp[i+1] --&amp;gt; i\_1  
dp[i+2] --&amp;gt; i\_2**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice that in the next iteration of our loop, our loop counter &lt;strong&gt;i&lt;/strong&gt; &lt;em&gt;,&lt;/em&gt; becomes &lt;strong&gt;&lt;em&gt;i + 1&lt;/em&gt;&lt;/strong&gt; , since we’re decrementing &lt;strong&gt;&lt;em&gt;i&lt;/em&gt;&lt;/strong&gt; in each iteration. &lt;strong&gt;&lt;em&gt;dp[i +1]&lt;/em&gt;&lt;/strong&gt; would be the next &lt;strong&gt;&lt;em&gt;dp[i +2]&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;dp[i]&lt;/em&gt;&lt;/strong&gt; would be the next &lt;strong&gt;&lt;em&gt;dp[i +1]&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;dp[i+2]&lt;/em&gt;&lt;/strong&gt; — which we wouldn’t need since &lt;strong&gt;&lt;em&gt;dp[i +3]&lt;/em&gt;&lt;/strong&gt; isn’t required — can be reused as the next &lt;strong&gt;&lt;em&gt;dp[i]&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Replacing this with our three new variables, the code inside our loop becomes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**i\_0 := max(arr[i] + i\_2, i\_1)  
i\_2 := i\_1  
i\_1 := i\_0**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We initialize these variables just like our array implementation.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**dp[n-1] = arr[n-1] --&amp;gt; i\_1 = arr[n-1]  
dp[n] = 2 --&amp;gt; i\_2 = 0**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One last thing to keep in mind: what if the input array has only a single element? Our loop, which runs from &lt;strong&gt;&lt;em&gt;n-2&lt;/em&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;0&lt;/em&gt;&lt;/strong&gt; , wouldn’t run even once.&lt;/p&gt;

&lt;p&gt;Hence, we initialize &lt;strong&gt;&lt;em&gt;i_0&lt;/em&gt;&lt;/strong&gt; with the value of &lt;strong&gt;&lt;em&gt;i_1&lt;/em&gt;&lt;/strong&gt;. So if the loop never runs — the input array has only one element — returning &lt;strong&gt;&lt;em&gt;i_0&lt;/em&gt;&lt;/strong&gt; would return the value of &lt;strong&gt;&lt;em&gt;i_1&lt;/em&gt;&lt;/strong&gt; , which is the arrays only element.&lt;/p&gt;

&lt;p&gt;Finally, we return &lt;strong&gt;&lt;em&gt;i_0&lt;/em&gt;&lt;/strong&gt; instead of &lt;strong&gt;&lt;em&gt;dp[0]&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**return dp[0] --&amp;gt; return i\_0**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Thus, our final algorithm would look something like this.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Just like the previous dynamic programming approach, this function would be called by simply passing in an array or a reference to one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**array := [1, 5, 2, 4, ...]  
return f(array)**  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For an array of any length, all we need is three variables. Thus, the space complexity of our algorithm is now &lt;strong&gt;&lt;em&gt;O(1)&lt;/em&gt;&lt;/strong&gt; — constant.&lt;/p&gt;

&lt;p&gt;Summarizing our results,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cfpqiqYY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AM4M0loVZVUoAhWTCKb-KAw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cfpqiqYY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AM4M0loVZVUoAhWTCKb-KAw.png" alt=""&gt;&lt;/a&gt;A summary of our implementations — image created by Author using &lt;a href="https://app.diagrams.net/"&gt;draw.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Comparing the recursive approach with our top-down approach, it's clear that &lt;strong&gt;we are trading space complexity for better time complexity&lt;/strong&gt;. Of course, since both are recursive, they have the additional space required for the recursive call stack.&lt;/p&gt;

&lt;p&gt;In a similar vein, the lowest two rows are the results of our bottom-up approaches. They are iterative, so they don’t require storing function records recursively on the stack. And since they’re essentially the same algorithm as the top-down approach, they have the same linear time complexity.&lt;/p&gt;

&lt;p&gt;The best case is the &lt;strong&gt;bottom up approach requiring O(1) space &lt;/strong&gt;— meaning that the space our dp algorithm is using doesn’t change with the input size n.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;The code&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let's implement our final algorithm of &lt;strong&gt;constant space bottom-up dynamic programming&lt;/strong&gt; in C++. The variable and function names are the same as before.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the final space complexity optimization step is slightly harder to look for, but drastically improves your space usage as we just saw. See if you can spot a similar relation for the bottom-up approach for the nth Fibonacci term.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Dynamic Programming is not often very intuitive or straightforward. Then again, most complex things aren’t. But things do get easier with practice. There are tonnes of dynamic programming practise problems online, which should help you get better at knowing when to apply dynamic programming, and how to apply it better. Hopefully, this post served as a good starting point.&lt;/p&gt;




</description>
      <category>algorithms</category>
      <category>editorspick</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Understanding Maximum Likelihood Estimation</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Mon, 10 Aug 2020 02:59:30 +0000</pubDate>
      <link>https://dev.to/polaris000/understanding-maximum-likelihood-estimation-3pg2</link>
      <guid>https://dev.to/polaris000/understanding-maximum-likelihood-estimation-3pg2</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EXSKX7Lc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2APFPNg3jngAjU8j_RQnO9aw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EXSKX7Lc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2APFPNg3jngAjU8j_RQnO9aw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maximum Likelihood Estimation&lt;/strong&gt; , or MLE, for short, is the process of estimating the parameters of a distribution that maximize the likelihood of the observed data belonging to that distribution.&lt;/p&gt;

&lt;p&gt;Simply put, when we perform MLE, we are trying to &lt;strong&gt;find the distribution that best fits our data.&lt;/strong&gt; The resulting value of the distribution’s parameter is called the &lt;strong&gt;maximum likelihood estimate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MLE is a very prominent frequentist technique. Many conventional machine learning algorithms work with the principles of MLE. For example, the best-fit line in linear regression calculated using least squares is identical to the result of MLE.&lt;/p&gt;

&lt;h3&gt;
  
  
  The likelihood function
&lt;/h3&gt;

&lt;p&gt;Before we move forward, we need to understand the likelihood function.&lt;/p&gt;

&lt;p&gt;The likelihood function helps us find the best parameters for our distribution. It can be defined as shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dQutipSB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/598/1%2Ar90eozWc7pjdxOhjgH52mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dQutipSB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/598/1%2Ar90eozWc7pjdxOhjgH52mw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;where &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;&lt;/strong&gt; is the parameter to maximize, &lt;strong&gt;&lt;em&gt;x_1, x_2, … x_n&lt;/em&gt;&lt;/strong&gt; are observations for &lt;strong&gt;n&lt;/strong&gt; random variables from a distribution and &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt; is the joint density function of our distribution with the parameter &lt;em&gt;θ&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The pipe (“ | “) is often replaced by a semi-colon, since &lt;em&gt;θ&lt;/em&gt; isn’t a random variable, but an unknown parameter.&lt;/p&gt;

&lt;p&gt;Of course, &lt;em&gt;θ&lt;/em&gt; could also be a set of parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DtoribRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/481/1%2AZ7D0XQ0L7N0NYZa_hswerg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DtoribRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/481/1%2AZ7D0XQ0L7N0NYZa_hswerg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, in the case of a normal distribution, we would have&lt;br&gt;&lt;br&gt;
&lt;em&gt;θ = (μ,σ)&lt;/em&gt;, with μ and σ representing the two parameters of our distribution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intuition
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Likelihood&lt;/strong&gt; is often interchangeably used with probability, but they are not the same. Likelihood is not a probability density function, meaning that integrating over a specific interval would not result in a “probability” over that interval. Rather, it talks about how likely a distribution with certain values for its parameters fits our data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gXSHrHp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AOfxcaYeexRFT9SiOSoeB4Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gXSHrHp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AOfxcaYeexRFT9SiOSoeB4Q.jpeg" alt=""&gt;&lt;/a&gt;&lt;em&gt;θ_MLE is the value that maximizes the likelihood of our data x&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Looking at it this way, we can say that likelihood is how likely the distribution fits of given data for variable values of its parameters. So, if &lt;em&gt;L(θ_1|x)&lt;/em&gt; is greater than &lt;em&gt;L(θ_2|x)&lt;/em&gt;, the distribution with parameter value as &lt;em&gt;θ_1&lt;/em&gt; fits our data better than the one with a parameter value of &lt;em&gt;θ_2.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Process
&lt;/h3&gt;

&lt;p&gt;To re-iterate, we’re looking for the parameter (or parameters, as the case may be) that maximize our likelihood function. How do we do that?&lt;/p&gt;

&lt;p&gt;To simplify our calculations, lets assume that our data is &lt;strong&gt;independently and identically distributed&lt;/strong&gt; , or i.i.d, for short, meaning that observations are independent of each other and that they can be quantified in the same way, which basically means that all points are from the same distribution.&lt;/p&gt;

&lt;p&gt;The i.i.d assumption allows us to easily calculate the cumulative likelihood considering all data points as a product of individual likelihoods.&lt;/p&gt;

&lt;p&gt;Also, most likelihood functions have a single maxima, allowing us to simply equate the derivate to 0 to get the value of our parameter. If multiple maxima exist, we would need to look at the global maxima to get our answer.&lt;/p&gt;

&lt;p&gt;In general, more complex numerical methods would be required to find the maximum likelihood estimate.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Example
&lt;/h3&gt;

&lt;p&gt;To understand the math behind MLE, let’s try a simple example. We’ll derive the value of the &lt;strong&gt;exponential distribution&lt;/strong&gt; ’s parameter corresponding to the maximum likelihood value.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Exponential Distribution
&lt;/h4&gt;

&lt;p&gt;The exponential distribution is a continuous probability distribution used to measure inter-event time.&lt;/p&gt;

&lt;p&gt;It has a single parameter, called &lt;strong&gt;λ&lt;/strong&gt; by convention. λ is called  &lt;strong&gt;rate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Its &lt;strong&gt;mean&lt;/strong&gt; and &lt;strong&gt;variance&lt;/strong&gt; is &lt;em&gt;1/ λ&lt;/em&gt; and &lt;em&gt;1 / λ²,&lt;/em&gt; respectively.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;probability density function&lt;/strong&gt; for the exponential distribution is as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SIOlYai4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/639/0%2APSmW16GwuFfn2-Tf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SIOlYai4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/639/0%2APSmW16GwuFfn2-Tf.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RBz8jOxh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/382/1%2Ai74ZYpgdxhwFed5eH9_DKw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RBz8jOxh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/382/1%2Ai74ZYpgdxhwFed5eH9_DKw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8KiDdFs0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/752/1%2Av4F-0RLZGil-do2IiXxSwA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8KiDdFs0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/752/1%2Av4F-0RLZGil-do2IiXxSwA.png" alt=""&gt;&lt;/a&gt;PDF plots with variable λ&lt;/p&gt;

&lt;p&gt;There’s a single parameter &lt;em&gt;λ&lt;/em&gt;. Let’s calculate its value, given n random points x_1 to x_n.&lt;/p&gt;

&lt;p&gt;As discussed earlier, we know that the &lt;strong&gt;likelihood&lt;/strong&gt; for a given point xi is given by the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v-vc7RMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/592/1%2A2qEje_VyqWgYBmNxj-v5XA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v-vc7RMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/592/1%2A2qEje_VyqWgYBmNxj-v5XA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We calculate the likelihood for each of our n points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kCgdCcCe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/327/1%2AKNphGWrNpSNGBk0cnbkzhA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kCgdCcCe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/327/1%2AKNphGWrNpSNGBk0cnbkzhA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The combined likelihood for all n points would just be the product of their individual likelihoods, since we are considering independent and identically distributed points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zxSBfI9---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/789/1%2AAMda9GmZskFl9tMD-_6_uQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zxSBfI9---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/789/1%2AAMda9GmZskFl9tMD-_6_uQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The log-likelihood
&lt;/h4&gt;

&lt;p&gt;Our next step would be to find the derivative of our likelihood function and set it to 0, since we want to find the value of our distribution parameter (in this case, &lt;em&gt;λ&lt;/em&gt;) which gives the maximum likelihood.&lt;/p&gt;

&lt;p&gt;Since the derivatives of both functions and those of their logarithms have the same &lt;strong&gt;stationary points&lt;/strong&gt; (derivative equates to 0), we can simplify our calculations by considering the logarithm of our likelihood function.&lt;/p&gt;

&lt;p&gt;Lets plot a simple graph that represents the following equations when a and b are both set to 1. The rate parameter, &lt;em&gt;λ,&lt;/em&gt; has been replaced by x.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f_9pOKb6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/541/1%2ALcfDP_g3D-E6kipohOH3WQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f_9pOKb6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/541/1%2ALcfDP_g3D-E6kipohOH3WQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The terms a and b represent two datapoints, say, x_1 and x_2. Our likelihood function is represented by the orange curve. It is the product of likelihoods of the two individual datapoints.&lt;/p&gt;

&lt;p&gt;The logarithm of the likelihood function, or the &lt;strong&gt;log-likelihood&lt;/strong&gt; , is represented by the pink curve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--quRY0BLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/968/1%2ALhrfOJtNI-OQbhj3195XgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--quRY0BLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/968/1%2ALhrfOJtNI-OQbhj3195XgA.png" alt=""&gt;&lt;/a&gt;The likelihood and the log-likelihood function for our points x_1 and x_2.&lt;/p&gt;

&lt;p&gt;The blue-dotted line will be covered later.&lt;/p&gt;

&lt;p&gt;Two things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both the likelihood function (orange) and its logarithm (pink) have the same stationary point (the derivative is 0).&lt;/li&gt;
&lt;li&gt;That common stationary point occurs at the x=1 (blue curve), which may not make much sense at the moment, is basically a simple proof of our result. We’ll revisit this point after obtaining our result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iQqv98cZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/767/1%2A8-YAJaYLrDbeYkd-VmIj0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQqv98cZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/767/1%2A8-YAJaYLrDbeYkd-VmIj0w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The product of small probabilities, as is the case in calculating the likelihood over several data points, can also lead to numerical underflow due to very small probabilities, giving us another reason to prefer working with the “sum of logs” rather than “products”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--id3tzCfh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/869/1%2Av6qJVLQl2YiJ5Ub3g9d_Dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--id3tzCfh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/869/1%2Av6qJVLQl2YiJ5Ub3g9d_Dw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simplifying our result, we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qqrd34fV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/419/1%2A8G_2Lq3hteWzvbkXlZ-t5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qqrd34fV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/419/1%2A8G_2Lq3hteWzvbkXlZ-t5g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the log-likelihood for the exponential distribution.&lt;/p&gt;

&lt;h4&gt;
  
  
  The derivative
&lt;/h4&gt;

&lt;p&gt;Now that we have our log-likelihood function, lets find its maxima. To do this, we simply find its first derivative with respect to λ.&lt;/p&gt;

&lt;p&gt;Differentiating &lt;em&gt;log (L(λ)),&lt;/em&gt; we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sUIAnQxA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/536/1%2AiEIaN1h6An6NwYnirF13nA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUIAnQxA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/536/1%2AiEIaN1h6An6NwYnirF13nA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following that, we end up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K73dvvtF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/344/1%2A46ZwD4CG9u_jC5v53KoWeA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K73dvvtF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/344/1%2A46ZwD4CG9u_jC5v53KoWeA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simplying this further, we get the following relation for λ:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L2zYe8-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/494/1%2Ap8qUyW83UdUgXpgKUCuJmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L2zYe8-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/494/1%2Ap8qUyW83UdUgXpgKUCuJmw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the value of λ that maximizes likelihood can be calculated using the above relation. Similar calculations can be done for other continuous and even discrete distributions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--quRY0BLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/968/1%2ALhrfOJtNI-OQbhj3195XgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--quRY0BLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/968/1%2ALhrfOJtNI-OQbhj3195XgA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, coming back to our graph example, the blue dotted line, with the equation: &lt;em&gt;x = 2 / (a + b),&lt;/em&gt; is our value for λ when n is 2.&lt;/p&gt;

&lt;p&gt;Remember, the value of λ we obtained represents the maximum value of likelihood function (orange curve). For a = 1 and b = 1, we get x = 1 and hence λ = 1, which is shown in the graph as the maxima of the orange curve.&lt;/p&gt;

&lt;p&gt;In distributions with multiple parameters, like the normal distribution, we consider each one in turn, keeping the others constant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;MLE isn’t the only technique which helps us do this. Other techniques include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maximum A Priori Estimation (MAP),&lt;/strong&gt; which uses prior data as well, unlike MLE, which considers a uniform prior; and&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expectation Maximization,&lt;/strong&gt; which handles latent variables (those unobservable variables which have an effect on present variables), something that MLE struggles with.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s a lot more to Maximum Likelihood Estimation — and for that matter, other parameter estimation techniques. This post focuses more on the underlying math behind MLE using the exponential distribution as an example.&lt;/p&gt;

&lt;p&gt;Hopefully, this article gets you started with other, more complex techniques!&lt;/p&gt;

&lt;p&gt;Of course, please let me know in the comments if anything’s unclear and I’ll update the post. Thanks for reading!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>statistics</category>
      <category>maximumlikelihood</category>
      <category>mathematics</category>
    </item>
    <item>
      <title>Visualizing the Defective Chessboard problem</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Sat, 11 Jan 2020 02:59:30 +0000</pubDate>
      <link>https://dev.to/polaris000/visualizing-the-defective-chessboard-problem-4n0e</link>
      <guid>https://dev.to/polaris000/visualizing-the-defective-chessboard-problem-4n0e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V-vyaiop--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/542/1%2AjMx7jrHOg4qngBL6pBp9hQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V-vyaiop--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/542/1%2AjMx7jrHOg4qngBL6pBp9hQ.png" alt=""&gt;&lt;/a&gt;A tiled chessboard&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Defective Chessboard problem,&lt;/strong&gt; also known as the &lt;strong&gt;Tiling Problem&lt;/strong&gt; is an interesting problem. It is typically solved with a “divide and conquer” approach. The algorithm has a time complexity of &lt;strong&gt;&lt;em&gt;O(n²)&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Given a &lt;em&gt;n&lt;/em&gt; by &lt;em&gt;n&lt;/em&gt; board where &lt;em&gt;n&lt;/em&gt; is of form 2^k where k &amp;gt;= 1 (Basically, n is a power of 2 with minimum value as 2). The board has one missing square). Fill the board using trionimos. A trionimo is an L-shaped tile is a 2 × 2 block with one cell of size 1×1 missing.&lt;/p&gt;

&lt;p&gt;Solving the problem efficiently isn’t the goal of this post. Visualizing the board as the algorithm runs is much more interesting in my opinion, though. Lets discuss the algorithm first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dqeGM-Zw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/528/0%2AadonlEHar0FeZ3XM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dqeGM-Zw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/528/0%2AadonlEHar0FeZ3XM.png" alt=""&gt;&lt;/a&gt;The board with no defects added&lt;/p&gt;

&lt;h3&gt;
  
  
  The Algorithm
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, a divide-and-conquer (DAC) technique is used to solve the problem. DAC entails splitting a larger problem into sub-problems, ensuring that each sub-problem is an exact copy of the larger one, albeit smaller. You may see where we are going with this, but lets do it explicitly.&lt;/p&gt;

&lt;p&gt;The question we must ask before writing the algorithm is: is this even possible? Well, yes. The total number of squares on our board is &lt;em&gt;n&lt;/em&gt;², or 4^&lt;em&gt;k&lt;/em&gt;. Removing the defect, we would have 4^&lt;em&gt;k&lt;/em&gt; — 1, which is always a multiple of three. This can be proved with mathematical induction pretty easily, so I won’t be discussing it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VyUnjl2u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/527/0%2AzOyl7BWBT9R4Csjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VyUnjl2u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/527/0%2AzOyl7BWBT9R4Csjd.png" alt=""&gt;&lt;/a&gt;The board in the initial state (with an added defect)&lt;/p&gt;

&lt;h3&gt;
  
  
  The base case
&lt;/h3&gt;

&lt;p&gt;Every recursive algorithm must have a base case, to ensure that it terminates. For us, lets consider the case when &lt;em&gt;n&lt;/em&gt;, 2^&lt;em&gt;k&lt;/em&gt; is 2. We thus have a 2×2 block with a single defect. Solving this is trivial: the remaining 3 squares naturally form a trionimo.&lt;/p&gt;

&lt;h3&gt;
  
  
  The recursive step
&lt;/h3&gt;

&lt;p&gt;To make every sub-problem a smaller version of our original problem, all we have to do is add our own defects, but in a very specific way. If you take a closer look, adding a “defect” trionimo at the center, with one square in each of the four quadrants of our board, except for the one with our original defect would allow use to make four proper sub-problems, at the same time ensuring that we can solve the complete problem by adding a last trionimo to cover up the three pseudo-defective squares we added.&lt;/p&gt;

&lt;p&gt;Once we are done adding the “defects”, recursively solving each of the four sub-problems takes us to our last step, which was already discussed in the previous paragraph.&lt;/p&gt;

&lt;h3&gt;
  
  
  The combine step
&lt;/h3&gt;

&lt;p&gt;After solving each of the four sub-problems and putting them together to form a complete board, we have 4 defects in our board: the original one will lie in one of the quadrants, while the other three were those we had intentionally added to solved the problem using &lt;strong&gt;DAC&lt;/strong&gt;. All we have to do is add a final trionimo to cover up those three ‘defects’ and we are done.&lt;/p&gt;

&lt;p&gt;Thus, the recursive equation for time complexity becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;T(n) = 4T(n/2)+c&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;4&lt;/strong&gt; comes from the fact that to solve each problem of input n, we divide it into 4 sub-problems of input size &lt;em&gt;n/2&lt;/em&gt; (half the length of the original board). Once we are done solving those sub-problems, all that’s left to be done is to combine them: this is done by adding the last trionimo to cover up the pseudo-defects we added. This, of course, is done in constant time.&lt;/p&gt;

&lt;p&gt;If you are interested in finding the asymptotic time complexity of the recurrence relation, you could try the &lt;strong&gt;recursion tree method&lt;/strong&gt; or the &lt;strong&gt;substitution method&lt;/strong&gt;. For now, lets just use the &lt;strong&gt;Master theorem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The master theorem says that for a recurrence relation of the form:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;T(n) = aT(n/b) + f(n)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the complexity depends on the complexities of &lt;em&gt;f(n)&lt;/em&gt; and &lt;em&gt;n ^ log_b(a)&lt;/em&gt; (the log is to the base &lt;em&gt;b&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;The cases in the image below tell us which case we need to use here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ulUf3J2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AfPnVzEh00aTSG3PCX2MnXQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ulUf3J2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AfPnVzEh00aTSG3PCX2MnXQ.png" alt=""&gt;&lt;/a&gt;The Master Theorem. From &lt;a href="https://brilliant.org/wiki/master-theorem/"&gt;brilliant.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the value of n ^ log(a) base b is &lt;em&gt;n&lt;/em&gt;², while the term &lt;em&gt;f(n)&lt;/em&gt; is of constant complexity, we use &lt;strong&gt;Case 1,&lt;/strong&gt; which ultimately tells us that our algorithm has an order of &lt;strong&gt;&lt;em&gt;n&lt;/em&gt;²&lt;/strong&gt;. In other words, the time complexity of our algorithm is &lt;strong&gt;O(&lt;em&gt;n&lt;/em&gt;²).&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;Initially, each square is represented by a 0. A ‘-1’ represents a defective square, and would appear black in the plots. Each trionimo would be displayed with a unique number, which would be incremented as more trionimos are added.&lt;/p&gt;

&lt;p&gt;Again, the goal of the code is not optimization — its to do as much from scratch (in plain python) as possible.&lt;/p&gt;

&lt;p&gt;I have commented the code below, so it should be pretty straight-forward.&lt;/p&gt;

&lt;h4&gt;
  
  
  Importing required libraries
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The random library is used to randomly pick a square to be defective, just for starting the problem, and seaborn is, of course, for the visualization.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating the board
&lt;/h4&gt;

&lt;p&gt;Nothing too crazy: just creating a two dimensional Python list. The algorithm can be optimized by using structures like numpy arrays instead of vanilla Python lists. The list is initialized with 0's.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Adding a defect randomly
&lt;/h4&gt;

&lt;p&gt;Here we are randomly choosing an element using randint() and making it the defective tile. We will represent defects with a  &lt;strong&gt;-1.&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Locating the defect when solving each sub-problem
&lt;/h4&gt;

&lt;p&gt;We are doing two things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;locating the row and column of the defect&lt;/li&gt;
&lt;li&gt;determining which quadrant of the board the defect lies in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step can be optimized by using numpy functions instead of the ‘from-scratch’ approach below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Adding trionimos
&lt;/h4&gt;

&lt;p&gt;This function adds a trionimo to a 2 x 2 section of the board. Here, the quadrant of the defect comes in handy as we can simply define a dictionary to decide how to add our trionimo.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Recursive Tiling Function
&lt;/h4&gt;

&lt;p&gt;This is a divide-and-conquer implementation of our tiling algorithm. The function accomplishes the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;determining the location of the defect in the given section of the board (the rows r1 and r2 and the columns c1 and c2 allow the function to focus on a particular section of the board).&lt;/li&gt;
&lt;li&gt;adding a trionimo if we are dealing with a 2 x 2 section of the board&lt;/li&gt;
&lt;li&gt;otherwise, adding three defects to the center&lt;/li&gt;
&lt;li&gt;recursively solving each quadrant of the board&lt;/li&gt;
&lt;li&gt;adding a final trionimo to cover up the three defects we added at the center.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  The Parent Tiling Function
&lt;/h4&gt;

&lt;p&gt;This just makes the interface cleaner since we technically have only two independent arguments: the board and the parameter k (well, k can be calculated or used as a global variable, but that’s up to the programmer).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Visualizing
&lt;/h3&gt;

&lt;p&gt;I made use of a simple &lt;strong&gt;seaborn heat-map&lt;/strong&gt; to display the board. The drawboard() method creates the heat-map.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The two heat-map calls are to more easily distinguish between defective and non-defective squares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the first one creates the heat-map without any labels or masks.&lt;/li&gt;
&lt;li&gt;the second heat-map has a mask which hides the defective squares, but annotates the rest, allowing us to distinguish each trionimo by number while leaving defective squares blank.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;I’ve dragged the post long enough. The snippet below calls relevant functions, allowing us to view each of the board’s states.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Su-m5OcZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/765/0%2AMxZqUAWFbqnmn4Ja.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Su-m5OcZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/765/0%2AMxZqUAWFbqnmn4Ja.gif" alt=""&gt;&lt;/a&gt;A GIF of the board as the algorithm runs on it&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://polaris000.github.io/blog/defective_chessboard"&gt;&lt;em&gt;https://polaris000.github.io&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on January 11, 2020.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>A Guide to the Google Summer of Code</title>
      <dc:creator>Aniruddha Karajgi</dc:creator>
      <pubDate>Fri, 03 Jan 2020 02:59:30 +0000</pubDate>
      <link>https://dev.to/polaris000/a-guide-to-the-google-summer-of-code-2334</link>
      <guid>https://dev.to/polaris000/a-guide-to-the-google-summer-of-code-2334</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dM14JS7M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAZ9DtM3WofuoNXNoiKP8kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dM14JS7M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAZ9DtM3WofuoNXNoiKP8kw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the last few days, I’ve received several messages and emails on the subject and after responding to some, I decided to compile everything into a single post.&lt;/p&gt;

&lt;h3&gt;
  
  
  A short note on the program
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://summerofcode.withgoogle.com/"&gt;Google Summer of Code&lt;/a&gt; (GSoC, for short) is a program whose primary goal is to boost interest in open-source. The program targets college and university students and gives them the opportunity to contribute to open-source organizations of their choice over the summer. Potential candidates are required to write a proposal detailing the work they would be doing along with a timeline with specific deadlines for each sub-task. The coding period is the main part of the program and is when you work with your mentors. It is divided into three sections by periods of evaluation. This is where your mentor provides feedback and evaluates your work in that period.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1hS1K_BJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/379/1%2AMgmLnxx7ZgrMxF4klbHLqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1hS1K_BJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/379/1%2AMgmLnxx7ZgrMxF4klbHLqw.png" alt="The GSoC 2020 TimeLine"&gt;&lt;/a&gt;The GSoC 2020 timeline&lt;/p&gt;

&lt;h3&gt;
  
  
  The myth of the ideal candidate
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Goals
&lt;/h4&gt;

&lt;p&gt;The first thing I would like to say is that GSoC is not a competitive examination. It is an opportunity for you to play a role in open-source software development, implying that you would benefit a lot more from this program if you are actually keen on contributing.&lt;/p&gt;

&lt;p&gt;That’s why it is often said that choosing a project that you actually use in your life is a pretty good idea. It would be much harder and oftentimes less rewarding to finish the Summer of Code program successfully if you are just doing it to be more “successful”. For me personally, did finishing the program open more opportunities for me? Probably. Would I have been less ‘successful’ if I hadn’t participated in the program? Maybe not.&lt;/p&gt;

&lt;h4&gt;
  
  
  Skills
&lt;/h4&gt;

&lt;p&gt;A common question I get asked is: &lt;em&gt;Am I good enough?&lt;/em&gt;. Though skills are an important part of your program, I would say that having less than stellar skills is not deal breakers. If you know how to code in the language your project uses, or if you have a decent idea of a particular framework, you should not have any difficultly getting selected. Of course, it is imperative that you spend a little more time honing your skills than someone with “ideal” skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shortlisting organizations
&lt;/h3&gt;

&lt;p&gt;This is an important step of the process. It is necessary to be realistic but at the same time, a little optimistic. It would probably be a little too hard trying as a candidate for, say, the Git project, if you have no idea how version control works or have no knowledge of the C programming language. That’s not to say that it’s impossible, just that most people would be doing it alongside their regular course loads and it would certainly be more difficult to balance both.&lt;/p&gt;

&lt;p&gt;One often gets the advice: “&lt;em&gt;Just pick an organization and start contributing…&lt;/em&gt;”, It’s apparent from the vague nature of this response that starting out with GSoC isn’t that simple. I suggest going through previous years’ projects and organizations (present in the &lt;a href="https://summerofcode.withgoogle.com/archive/"&gt;archives&lt;/a&gt;) and focusing on the ones who use the languages and frameworks of that you are interested in. Probably short list about 2–3 or even 4 organizations that interest you — they may seem like a cool project to work on and your skills align to a greater degree when compared to other organizations.&lt;/p&gt;

&lt;p&gt;Make sure that your selected organizations have participated in the at least the past year. Though it is very rare for a regularly participating organization to not be selected for the next year’s program, it is still possible. Unfortunately, not much can be done about this, except to keep your options open: hence, the advice of shortlisting multiple organizations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;Once you are done with the shortlisting step, you should ideally end up with a set of organizations that you are happy to work with. Now, I’d suggest introducing yourself on their communication channels (generally mailing lists or slack), talking about who you are, why you are interested, which particular area of the project you are interested, your skills, etc.. Make sure to go through any contribution and new comer guidelines prior to this. It does not look to good if you ask them where to start, and there is an entire section with the exact same title on their website.&lt;/p&gt;

&lt;p&gt;Don’t be afraid to ask if you’re unsure of how to start (but only if it is not clearly mentioned anywhere, though it usually is) — you’ll save everyone some time. And time is likely the most important factor in your selection. If there is no obvious place to start contributing (again, there usually is), just ask. They’ll like your enthusiasm. You could also suggest adding some contributing or new-comer guidelines to the maintainers. Maybe this could be your first issue.&lt;/p&gt;

&lt;p&gt;Communication is an important aspect of your journey — you’ll spend hours in contact with your mentor(s). Being polite, enthusiastic and giving prompt replies to emails or messages gets you closer to being the ideal candidate.&lt;/p&gt;

&lt;p&gt;Around February, start thinking about which organizations you are going to move forward with. And that’s it: just stay active, show your skills and enthusiasm and with a little luck, you should see yourself as a participant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Announcing the Participating Organizations
&lt;/h3&gt;

&lt;p&gt;Though the GSoC time line varies a little (have a look at the &lt;a href="https://summerofcode.withgoogle.com/how-it-works/#timeline"&gt;timeline&lt;/a&gt; on the official website), you should expect participating organizations to be announced in the second half of February. As mentioned earlier, almost every organization continues participating year after year. This is probably a good time to finalize which organization you’ll actually move forward with, so that you have enough time to dedicate your complete attention to it and more importantly, your potential mentors notice your enthusiasm.&lt;/p&gt;

&lt;h3&gt;
  
  
  The proposal
&lt;/h3&gt;

&lt;p&gt;It was the most daunting part of my journey, and I’m sure some would agree. The scary part is probably the fact that you have to come up with it all by yourself and it is impossible to get help (not a 100% true). Till now, your journey was a little more mechanical — you went with the flow. Personally, I feel that the difference between a good proposal and a great one is the deeper understanding of a project and ones own abilities.&lt;/p&gt;

&lt;p&gt;For the uninitiated, your proposal is basically your ticket to the program. If you ace this part, your chances of selection are greatly increased. Your proposal basically outlines what you, as a candidate, will do and when. This means that you should have a timeline in mind along with clear cut goals. Ideally, there should be some big goals, which should be divided into a per-week basis. Each coding period (there are three) can have its own goal.&lt;/p&gt;

&lt;p&gt;This is of course, not the only way. There are several excellent posts out there that you could have a look at to fine tune your proposal. Just make sure that you follow your organization’s proposal guidelines (formatting, structure, etc), deadlines and most importantly, ask your future mentors for tips if they are willing (they most likely will).&lt;/p&gt;

&lt;h3&gt;
  
  
  The last stretch
&lt;/h3&gt;

&lt;p&gt;There are a few weeks between submitting your proposal and the announcement of the selected candidates. Use this time to focus on the areas you’ll be working over the summer. Make sure you are comfortable with stuff like virtual environments, git, GitHub, docker, the command line — whatever your project uses. Continue to contribute, all the while increasing the significance of your contributions. When the day arrives, you thank yourself for your efforts.&lt;/p&gt;

&lt;h3&gt;
  
  
  In conclusion
&lt;/h3&gt;

&lt;p&gt;Just remember that even if you are not chosen, it may not be only about you. As a mentor, you’d definitely want to go with the ‘best fit’, and that may not always be the ‘most skilled’. Many people don’t get into the program in their first attempt but are much stronger candidates in subsequent years. Be sure to ask for some feedback as to where you can improve the next year. Then again, there are bound to be some candidates who end up failing due to missed deadlines, so make sure you are organized and have everything on your calendar (I hope you use a calendar :)).&lt;/p&gt;

&lt;h3&gt;
  
  
  F.A.Q. ‘s
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Am I skilled enough?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans&lt;/strong&gt;. Yes. (addressed in this post)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. Which year in my undergraduate is the best time to participate in the program?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans.&lt;/strong&gt; That depends on commitments and responsibilities. With respect to that metric, the general order of years from best to worst is: 1 &amp;gt; 2 &amp;gt; 3 ~ 4. The obvious problem with this is that your experience and skills growth follow the opposite trend. The happy medium is probably the second year, but if you are skilled/interested enough you could potentially do it in the first summer. Make sure you have enough time during the summer. In my opinion, the only thing worse that not getting selected is failing the program because you have too many things on your plate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;3. I have done the Andrew Ng machine learning course on Coursera. What else should I do to improve my chances of getting selected for GSoC?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans.&lt;/strong&gt; If you want to pursue a ML project for GSoC, please work on as many personal projects as possible. Almost everyone has done that course, so you’ll need to build experience.Your projects portfolio will show your potential mentors your style, skills and approach to problem solving.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4. Do I need to know Linux?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans.&lt;/strong&gt; A vast majority of open source projects use Linux. Its hard to give a definite answer since the choice of operating system you will be using the one your project’s development happens in. I’d recommend learning to use Linux — at least the basics like the terminal, the directory structure, creating and using virtual environments and installing packages and tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;5. Will I be able to get into the program if I start now?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans&lt;/strong&gt;. Yes. But the earlier you start, the better (in my opinion).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;6. How do I start contributing?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ans.&lt;/strong&gt; Most organizations have some issues reserved for beginners and new-comers. They are usually labeled “easy”, “beginner”, “low-hanging fruit”, or something like that.&lt;/p&gt;

&lt;p&gt;Remember that your first contribution need be world-changing. It can be as simple as a typo in their documentation. As you get comfortable with the project, you’ll naturally be able to solve more complex issues and bugs. Use the fact that you are new and let the maintainers know if the “Getting Started” section needs any improvements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Though I have attempted to make this guide thorough but generic enough to apply to everyone, it may not be as exhaustive as you may like. Please put any suggestions and queries in the comments and I’ll add them to the article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As I get more questions, they will be added to this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Good luck!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://polaris000.github.io"&gt;&lt;em&gt;polaris000.github.io&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on January 3, 2020.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>gsoc</category>
      <category>google</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
