WordPress, one of the most powerful open source blogging and content management systems, is being used to power a major chunk of the interwebs.

Unlike many other CMSes, WordPress is loved by many for its flexibility and customizability. Taxonomies, one of the core features of WordPress, allows you to organize content just the way you need to. Although it comes built-in with a few default taxonomies, WordPress lets you add as many custom taxonomies as you please.

However, getting taxonomies to behave exactly the way you want them to may require you to fiddle with some undocumented approaches.

In this article, you will learn how you can define exclusive custom taxonomies in WordPress that behave much more like categories than tags, allowing you to categorize your posts much more strictly than you can out of the box.

According to the WordPress codex:

A taxonomy is a way to group things together.

For example, a bunch of different types of fruits can be grouped together according to various characteristics and then those groups can be assigned names.

In WordPress, taxonomies are used to group posts, pages, and even custom post types under different groups.

The names for the different groupings in a taxonomy are called **terms**. Take fruits, for example, and how they can be grouped based on their colors. In this case, the names of different colors would be the terms.

By default, WordPress comes built in with four taxonomies: **category**, **tag**, **link category**, and **post format**. You can learn more about these default taxonomies here.

Among these built-in taxonomies, categories and tags are very similar but have one important difference: Categories are exclusive taxonomies (i.e., for each post, you may select at most one category) whereas each post can be assigned multiple tags.

Moreover, categories are usually predefined, while tags may be defined as you go.

You can define a custom taxonomy using the `register_taxonomy()`

function. You can learn more about the function here.

To see how this function works, let us define a custom taxonomy for posts with photos of scenery.

```
function view_init() {
register_taxonomy(
'view',
'post',
array(
'label' => __( 'View' ),
'capabilities' => array(
'assign_terms' => 'edit_guides',
'edit_terms' => 'publish_guides'
)
)
);
}
add_action( 'init', 'view_init' );
```

In the above snippet, we are defining a new taxonomy for posts called **view**.

You can think of this taxonomy being used to categorize photos based on the kind or nature of views that are present in the photos (e.g., mountain, lake, or forest).

As always, posts that belong to specific terms of this category will appear under **/view/{view_name}**.

The capabilities line in the snippet above is optional. Without it, WordPress will default capabilities to the same users as posts. As shown above, this will allow any user with the custom “edit_guides” capability to assign the taxonomy to a post and any user with the custom “publish_guides” capability to create new taxonomy items.

According to the official documentation, there are four capabilities that may be defined:

Taxonomy capabilities include`assign_terms`

,`edit_terms`

,`manage_terms`

(displays the taxonomy in the admin navigation) and`delete_terms`

.

Within your code, you can use the `wp_set_object_terms()`

function to add terms to objects using the taxonomy. You can list existing terms using the `the_terms()`

function. Furthermore, you can use the `wp_tag_cloud()`

function to generate a cloud of terms for your custom taxonomy. You can learn more about these functions here.

On the UI side, WordPress creates a new meta box on posts for every taxonomy. The meta box is similar to the Tags meta box which lets you link one or more terms to your post. This is what WordPress does by default, and this is what we can change by making a taxonomy exclusive: Make the custom taxonomy behave like the category taxonomy.

When we create a custom taxonomy with the `register_taxonomy()`

method, WordPress adds a meta box with multiple item selection to the post editing page:

Using this meta box, a user can choose any number of existing (already used) terms and also can add new terms using the text box.

To create a category-like taxonomy, where each post belongs to at most one category from a set of predefined categories, you can do so by tweaking WordPress a little:

- Hide the default meta box created by WordPress.
- Create a custom meta box on post editing page which will provide controls for single item selection.
- Save the taxonomy value when the post is saved.

Let’s take a look at each of the steps.

For this, we need to set `show_in_quick_edit`

and `meta_box_cb`

options to `false`

when calling `register_taxonomy`

.

The first option hides the taxonomy in the quick/bulk edit panel and the second option hides it in the post edit page:

```
register_taxonomy( 'custom_taxonomy', 'post', array(
'labels' => array(
'name' => 'Custom Exclusive Taxonomy'
),
'show_in_quick_edit' => false,
'meta_box_cb' => false
));
```

When the default meta box is hidden, items can be added to the set of available terms of the taxonomy via the taxonomy management page:

To create a custom meta box, we can use the `add_meta_boxes`

WordPress hook. You can learn more about the hook here.

```
add_action('add_meta_boxes', 'add_custom_meta_box');
function add_custom_meta_box(){
add_meta_box( 'taxonomy_box', __('Custom Exclusive Taxonomy'), 'fill_custom_meta_box_content', 'post' ,'side');
}
```

We call the `add_meta_box`

method with the following arguments:

`taxonomy_box`

– The ID of the meta box`__('Custom Exclusive Taxonomy')`

– The title of the meta box`fill_custom_meta_box_content`

– A function that is used to fill the contents of the meta box`post`

– This indicates that the meta box should appear on the post editing page.`side`

– This indicates the place where the meta box should be inserted.

Notice how we specified `taxonomy_box`

as the ID. However, it is the function in the third parameter that will let us define what will go into the box.

We will now implement the `fill_custom_meta_box_content`

function:

```
<?php
function fill_custom_meta_box_content( $post ) {
$terms = get_terms( array(
'taxonomy' => 'custom_taxonomy',
'hide_empty' => false // Retrieve all terms
));
// We assume that there is a single category
$currentTaxonomyValue = get_the_terms($post->ID, 'custom_taxonomy')[0];
?>
<p>Choose taxonomy value</p>
<p>
<?php foreach($terms as $term): ?>
<input type="radio" name="custom_taxonomy" id="taxonomy_term_<?php echo $term->term_id;?>" value="<?php echo $term->term_id;?>"<?php if($term->term_id==$currentTaxonomyValue->term_id) echo "checked"; ?>>
<label for="taxonomy_term_<?php echo $term->term_id;?>"><?php echo $term->name; ?></label>
</input><br/>
<?php endforeach; ?>
</p>
<?php
}
```

Here, we are first retrieving all of the terms (i.e., existing values) of the taxonomy. We will use these to show a list of radio button controls.

Next, we retrieve the currently selected taxonomy term using `get_the_terms()`

function—we need it to make the respective radio button selected.

Notice that this function returns an array. This is because, by default, the post can have any number of terms associated with it. By our assumption, the post has at most one term, so we access the first array element. (It is ok if the array is empty; we’ll get `null`

as the current value and no radio button will be selected.)

The HTML emitting code uses `custom_taxonomy`

as the name of radio buttons and corresponding term IDs as their values; radio button ID attributes are just used for connecting to label tags. As a result, we get the following custom meta box:

Finally, we need to persist the taxonomy value when the post is saved. For this, we can use the `save_post`

hook:

```
add_action('save_post', 'save_custom_taxonomy');
function save_custom_taxonomy($post_id){
if ( isset( $_REQUEST['custom_taxonomy'] ) )
wp_set_object_terms($post_id, (int)sanitize_text_field( $_POST['custom_taxonomy'] ), 'custom_taxonomy');
}
```

And that’s it! We are done.

You now know how to define a custom taxonomy that will behave like the built-in category taxonomy.

*Note: WordPress has accepted a feature request to make it easier to toggle exclusivity for custom taxonomies. However, the ticket has not seen much activity for a while.*

Taxonomies are a very powerful and useful feature in WordPress. Out of the box, they lack the ability to make strict categorization of posts, but as with nearly anything in WordPress, taxonomies and related functionality are extremely customizable. This allows us to add this often necessary ability in a few steps.

The approach introduced here can also be used to create even more customized UI on post editing pages for the taxonomy term selection.

I hope you have found this quick tutorial on defining exclusive custom taxonomies useful!

in collaboration with Toptal and post by Narek Malkhasyan

]]>Have you ever wondered: What exactly is the device that you are reading this article on? What is a computer?

Computational science dates back to a time long before these modern computing devices were even imagined. In an industry where the more frequently asked questions revolve around programming languages, frameworks, and libraries, we often taken for granted the fundamental concepts that make a computer tick.

But these computers, which seem to possess endless potential—do they have any limitations? Are there problems that computers cannot be used to solve?

In this article, we will address these questions by stepping away from the particulars of programming languages and computer architectures. By understanding the power and limitations of computers and algorithms, we can improve the way we think and better reason about different strategies.

The abstract view of computing produces results that have stood the test of time, being as valuable to us today as they were when initially developed in the 1970s.

In school, we are often taught a mental model of problems and functions that goes something like this:

A function is a procedure you apply to an input x in order to find an output f(x).

Turns out the mathematical definition is different:

A function is a set of ordered pairs such that the first element of each pair is from a set X (called the domain), the second element of each pair is from a set Y (called the codomain or range), and each element of the domain is paired with exactly one element of the range.

That was quite the mouthful. But, what exactly does that mean?

This definition tells us that a computer is a machine for computing functions.

Why?

Because computers transform arbitrary input to some output. In other words, they solve problems. The two definitions of functions, the one we are so familiar with and the formal one, coincide for many practical purposes.

However, the mathematical definition allows us to reach interesting conclusions such as the existence of uncomputable functions (i.e., unsolvable problems):

Because, not every function can be described as an algorithm.

To help make our arguments, let us imagine computers as machines taking some input, performing a sequence of operations, and after some time, giving some output.

We will call the input the machine’s alphabet; that is, a set of strings of characters from some finite set. For example, the machine’s alphabet may be binary (0s and 1s) or it might be the ASCII character set. Any finite sequence of characters is a string—for example, “0110.”

Furthermore, we will represent a machine’s output as a binary accept-reject decision, delivered once the machine (hopefully) finishes its computation. This abstraction fits well with the mathematical definition of functions from earlier.

Given these parameters, it is important to characterize one more type: a collection of strings. Maybe we care about the set of strings that some machine accepts, or maybe we are building a machine that accepts strings in a certain set and no others, or maybe we’re asking if it’s even possible to design a machine that accepts everything in some particular set and no others.

In all these cases, a set of strings is called a language—for example, the set of all binary strings that represent even numbers or the set of strings that have an even number of characters. It turns out that languages, like numbers, may be operated on with operators such as concatenation, union, intersection, and the like.

One important operator is the Kleene star operator that’s also used with regular expressions. This can be thought of as the union of all possible powers of the language. For example, if our language **A** is the set of strings { ‘01’, ‘1’ }, then one member of **A*** is the string ‘0101111’.

The last piece of the puzzle before we prove our claim that not all functions are computable is the concept of countability. Intuitively, our proof will show that there are more languages; that is, more problems than there are possible programs to solve them. This works because the question of whether a string belongs in a language (Yes/No) is itself a problem.

More precisely, our proof claims that the set of possible programs is countably infinite while the set of languages over an alphabet is uncountably infinite.

At this point, you may be thinking, “Infinity is a strange enough idea by itself; now I have to deal with two of them!”

Well, it’s not that bad. A countably infinite set is one that can be enumerated. It’s possible to say this is the first element, this is the second element, and so forth, eventually assigning a number to every element of the set. Take the set of even numbers, for example. We can say that 2 is the first one, 4 the second, 6 the third, and so forth. Such sets are countably infinite or countable.

With some sets though, like the real numbers, it doesn’t matter how clever you are; there simply is no enumeration. These sets are uncountably infinite or uncountable.

First, we want to show that the set of computer programs is countable. For our purposes, we do this by observing that the set of all strings over a finite alphabet is countable. This works because computer programs are finite strings themselves.

The proof is straightforward, and we don’t cover the details here. The key takeaway is that there are just as many computer programs out there as there are, say, natural numbers.

To reiterate:

The set of all strings over any alphabet (e.g., set of all computer programs) is countable.

Given this conclusion, what about the subsets of these strings? Asked another way, what about the set of all languages? It turns out that this set is uncountable.

The set of all languages over any alphabet is uncountable.

Once again, we don’t cover the proof here.

Although they may not be immediately apparent, the consequences of the uncountability of languages and the countability of the set of all computer programs are profound.

Why?

Suppose **A** is the set of ASCII characters; ASCII characters are just those needed to compose a computer program. We can see that the set of strings that represent, say, JavaScript programs, is a subset of **A*** (here, * is the Kleene star operator). The choice of JavaScript is arbitrary. Since this set of programs is a subset of a countable set, we have that the set of JavaScript programs is countable.

In addition, let us consider that for any language **L**, we can define some function **f**that evaluates to 1 if some string **x** is in **L** and 0 otherwise. All such functions are distinct. Because there is a 1:1 correspondence with the set of all languages and because the set of all languages is uncountable, we have that the set of all such functions is uncountable.

Here is the profound point:

Since the set of all valid programs is countable but the set of functions is not, then there must be some functions for which we simply cannot write programs.

We don’t yet know what these functions or problems look like, but we know they exist. This is a humbling realization, because there are some problems out there for which there is no solution. We consider computers to be extremely powerful and capable, yet some things are out of even their reach.

Now the question becomes, “What do these problems look like?” Before we continue describing such problems, we have to first model computation in a generalized way.

One of the very first mathematical models of a computer was developed by Alan Turing. This model, called the Turing machine, is an extremely simple device that completely captures our notion of computability.

The input to the machine is a tape onto which the input has been written. Using a read/write head, the machine turns input into output through a series of steps. At each step, a decision is made about whether and what to write to the tape and whether to move it right or left. This decision is based on exactly two things:

- The current symbol under the head, and
- The machine’s internal state, which is also updated as the symbol is written

That’s it.

In 1926, Alan Turing not only developed the Turing machine but also had a number of other major insights into the nature of computation when he wrote his famous paper, “On Computable Numbers.” He realized that a computer program itself could be considered input to a computer. With this point of view, he had the beautiful idea that a Turing machine could simulate or execute that input.

While we take these ideas for granted today, back in Turing’s day, the idea of such a universal machine was the major breakthrough that allowed Turing to develop unsolvable problems.

Before we continue, let’s examine an important point: We know the Turing machine is a model of computation, but is it general enough? To answer this question, we turn to the Church-Turing Thesis, which gives credence to the following statement:

Everything computable is computable by a Turing machine.

While Turing developed the Turing machine as a model of computation, Alonzo Church also developed a model of computation known as lambda-calculus. These models are powerful, because they both describe computation and do so in a way equal to any of today’s computers or for that matter any computer ever. This means we can use a Turing machine to describe the unsolvable problems we seek, knowing that our findings would apply to all possible computers past, present, and beyond.

We have to cover just a bit more background before we concretely describe an unsolvable problem, namely the concepts of language recognizers and language deciders.

A language isrecognizableif there is a Turing machine that recognizes it.and

A language isdecidableif there is a Turing machine that decides it.

To be a recognizer of a language, a Turing machine must accept every string in the language and it must not accept anything not in the language. It may reject or loop on such strings. To be a decider, a Turing machine must always halt on its input either by accepting or by rejecting.

Here, the idea of halting on input is critical. In fact, we see that deciders are more powerful than recognizers. Furthermore, a problem is solvable, or put another way, a function is decidable only if there exists a Turing machine that decides the language described by the function.

If you’ve ever written a computer program, surely you must know the feeling of sitting there just watching the computer spin its wheels when the program is executed. You don’t know whether the program is just taking a long time or if there is some mistake in the code causing an infinite loop. You may have even wondered why the compiler doesn’t check the code to see if it would stop or loop forever when run.

The compiler doesn’t have such a check because it simply can’t be done. It’s not that compiler engineers aren’t smart enough or lack the resources; it is simply impossible to check an arbitrary computer program to determine whether it halts.

We can prove this using the Turing machine. Turing machines can be described as strings, so there are a countable number of them. Suppose M_{1}, M_{2}, and so on make up the set of all Turing machines. Let us define the following function:

f(i, j) = 1 if M_{i} accepts <M_{j}>, 0 otherwise

Here, <M> is the syntax for “string encoding of M,” and this function represents the problem of outputting 1 if M_{i} halts by accepting M_{j} as input and outputting 0 otherwise. Note that M_{i} must halt (i.e., be a decider). This is required since we wish to describe an undecidable function (i.e., unsolvable problem).

Now, let us also define a language **L** that consists of string encodings of Turing machines that do NOT accept their own descriptions:

L = { <M> | M does not accept <M> }

For example, some machine M_{1} may output 0 on the input <M_{1}> while another machine M_{2} may output 1 on the input <M_{2}>. To prove this language is undecidable, we ask what M_{L}, the machine that decides the language L, does when it is given its own description <M_{L}> as input. There are two possibilities:

M

_{L}accepts <M_{L}>or

M

_{L}rejects <M_{L}>

If M_{L} accepts its own encoding, then that means <M_{L}> is not in the language L; however, if that were the case, then M_{L} should not have accepted its encoding in the first place. On the other hand, if M_{L} does not accept its own encoding, then <M_{L}> is in the language L, so M_{L} should have accepted its string encoding.

In both cases, we have a paradox, or in mathematical terms, a contradiction, proving that the language L is undecidable; thus, we’ve described our first unsolvable problem.

While the problem we just described may not seem relevant, it can be reduced to additional unsolvable problems of practical importance, most notably the halting problem:

The language of encodings of Turing machines that halt on the empty string.

The halting problem applies to the question of why compilers cannot detect infinite loops from earlier. If we cannot determine whether a program terminates on the empty string, then how could we possibly determine if its execution would result in an infinite loop?

At this point, it might seem like we just waved our hands around to reach some simple conclusion; however, we actually realized that no Turing machine can tell whether a computer program will halt or remain in a loop forever. This is an important problem with practical applications, and it can’t be solved on a Turing machine or any other kind of computer. An iPhone cannot solve this problem. A desktop with many cores cannot solve this problem. The cloud cannot solve this problem. Even if someone were to invent a quantum computer, it still wouldn’t be able to solve the halting problem.

In our examination of computability theory, we have seen how there are many functions that are not computable in any ordinary sense of the word by a counting argument. We precisely defined what we mean by computation, going all the way back to Turing’s inspiration from his own experience with pen and paper to formalize the Turing machine. We have seen how this model can compute anything that any computer today or envisioned for tomorrow can, and we realized a class of problems that are not computable at all.

Still, computability has a downside. Just because we can solve a problem doesn’t mean we can solve it quickly. After all, what good is a computer if its computation isn’t going to finish before the sun goes nova on us tens of millions of years in the future?

Leaving computable functions and languages behind, we now discuss computation complexity, surveying efficient computation and the famous P vs. NP problem.

Computer scientists recognize a variety of classes of problems, and two classes that we care about include problems that computers can solve quickly or efficiently known as **P** and problems whose solutions can be verified quickly but cannot be obtained quickly known as **NP**.

For example, suppose you are responsible for developing algorithms for an online dating service and someone poses the question, “Can everyone get a date?” The answer boils down to pairing compatible individuals such that everyone is paired. Turns out there are efficient algorithms for solving this problem. This problem is in the set **P**.

Well, what if we wanted to identify the largest clique among our users? By clique, we mean the largest network of individuals that are all compatible with one another. When the user count is low, this problem can be solved quickly. We can easily identify, say, a clique with 3 users. As we start to look for larger cliques, however, the problem becomes harder and harder to solve. This problem is in the set **NP**.

**P** is the set of problems that are solvable in polynomial time. That is, the number of computational steps is bounded by a polynomial function with respect to the problem size. We know that the “Can everyone get a date?” question, also known as bipartite matching problem, is in **P**.

**NP** is the set of problems that are verifiable in polynomial time. This includes every problem in P, of course; however, we don’t know whether this containment is strict. We know of problems that are efficiently verifiable but not efficiently solvable, but we don’t know if the problem is truly intractable. The clique problem is one such problem. We know we can verify the solution efficiently, but we don’t know for sure if we can solve the problem efficiently.

Lastly, **NP-complete** is the set of problems that are the hardest problems in **NP**. They are referred to as the hardest because any problem in **NP** can efficiently be transformed into **NPC**. As a result, if someone were to identify an efficient solution to a problem in **NPC**, then the entire class of **NP** would be absorbed by **P**. The clique problem is also in **NPC**.

Thus, we arrive at the problem of **P** vs. **NP**. Many computer scientists and mathematicians strongly believe that **P** and **NP** are not equal. If they were, the implications would be beyond profound. Much of today’s digital infrastructure relies on the fact that there are problems in **NP** that are not in **P**. If that were not the case, then cryptographic methods, for example, would collapse overnight, allowing a person possessing an efficient solution to an **NPC** problem to subvert even the tightest security protocols.

To computer science novices, the difference between the matching and clique problems might not seem like a big deal. In fact, the difference between a problem in **P** and a problem in **NP** can be very subtle. Being able to tell the difference is important for anyone designing algorithms in the real world.

Consider the shortest path problem. Given two locations, the objective is to identify the shortest path between them. An iPhone computes this in a matter of milliseconds. This is a computationally tractable problem.

On the other hand, consider the traveling salesman problem, where the objective is to visit a subset of possible destinations ending at the origin while traveling the shortest possible distance. This problem is similar to the shortest path problem but is NP-complete; it also explains why supply chain logistics is a billion dollar industry.

We can actually be even subtler. Instead of asking for the shortest path (P), we can ask for the longest path without cycles. Turns out longest path problem is also NP-complete.

There are many more examples of this subtle distinction, including identification of vertex covers in bipartite vs. general graphs or satisfaction of boolean formulas with two vs. three literals per clause. The point is that it is not immediately obvious whether a problem is in P or NP, and this is why running time analysis is a critical skill. If the algorithm one must design is for a problem in P, then we know there is an efficient solution. If on the other hand the problem is in NP, then we have a strong case to argue against pursuing a solution, because the algorithm, generally, would simply take too long to solve the problem.

In this examination of complexity, we defined the classes of problems P and NP. P informally represents problems that can be efficiently solved by a computer while NP represents those that are efficiently verifiable.

No one has been able to prove that P is not equal to NP. Whether these two classes of problems are equivalent is the known as the P vs. NP problem, and it is the most important open problem in theoretical computer science today if not in all of mathematics. In fact, in the year 2000, the Clay Math Institute named the P vs. NP problem as one of the seven most important open questions in mathematics and has offered a million-dollar bounty for a proof that determines the solution to this problem.

In this article, we delved into the realms of computability and complexity, answering big questions such as, “What is a computer?” While the details can be overwhelming, there are a number of profound takeaways worth remembering:

- There are some things that simply cannot be computed, like the halting problem.
- There are some things that cannot be computed efficiently, like the problems in NPC.

More important than the details are the ways to think about computation and computational problems. In our professional lives and even in our day to day, we may come across problems never seen before, and we can use tried and true tools and techniques to determine the best course of action.

in collaboration with Toptal and post by Mehmet Bajin

]]>Testing is an essential part of any mobile app development process. Whether you are automating such tests or not, no sane developer considers their work to be done unless they have tested their app.

A well-tested app usually goes through multiple steps of testing: Unit testing, integration testing, acceptance testing, and so on. As your app grows, the importance of testing increases and automation in testing becomes a necessity.

While other platforms, such as the web, have advanced significantly in terms of testing mechanisms and frameworks, the mobile realm is not lagging behind. In this article, you will learn how you can use Calabash to automate the UI for your Android and iOS apps using plain English instructions and make acceptance testing them as painless as possible.

If you have been testing your apps manually, you are probably wasting a big chunk of your time performing the same tasks over and over again. You make some changes to the code, build the app, run it in a device or an emulator, and fiddle with the app to figure out if it works as expected.

By automating UI testing, you can perform those same manual steps automatically. If your app is of a decent size, this can save a lot of your time and also save your app from being riddled with embarrassing bugs, especially the regression ones.

“That sounds awesome,” you say, but how do you do it for your Android or iOS app?

If you read the official documentation for Android and iOS, they suggest you write and run UI tests in their official IDEs. For Android, it’s Android Studio, and for iOS, it’s Xcode.

The official documentation goes as far as to recommend specific frameworks for testing. The official Android documentation covers some topics about Espresso, the Android UI testing framework. Similarly, Apple suggests using the XCTest framework.

And if you are going to work seriously on UI tests, you may be following these suggestions, which makes sense since Espresso is maintained by Google and is a part of Android Support Repository. It is very likely that Espresso will support all the new features that Google will introduce for Android in the future. You could say the same about XCTest framework for iOS.

However, it is worth keeping in mind that despite the numerous benefits of automated testing, many developers simply don’t write them at all.

Every developer that is aware of test automations, deep inside, knows it is a great idea. But, when it comes to sitting down and writing these tests, many developers start questioning if it is worth their time, because “touch the button” manually turns out to be a much faster operation than writing a code that will “touch this button” automatically. Sometimes, clients and managers, eagerly waiting to try the app, don’t help either.

Many developers, at that point, decide that it is better to continue working on new features of the application rather than write automated UI tests for the existing ones.

When the application grows, it becomes more and more time consuming to “touch these buttons” manually every time you’re updating the application.

But what if there was a framework that made UI testing easier, and didn’t give you any excuse to not write UI tests for your apps?

Meet Calabash.

About a year ago, I started searching for a testing framework that will be easy to use for the people who are not software developers. And, that is when I found Calabash.

This open source testing framework, developed and maintained by the Xamarin team, works for both Android and iOS. It lets you write and execute automated acceptance tests for mobile applications.

Acceptance tests are generally what comes after system tests that determine if your app satisfies the business requirements. Given that it operates on the UI level, this works well as our choice of UI testing automation framework.

Calabash can interact with your app like Espresso or XCTest does. However, what makes Calabash an excellent choice here is its support for Cucumber.

Cucumber is a tool that can run automated tests written in plain English (if you want you can adjust it to use any other plain language). So to write automated tests on Cucumber, the tester doesn’t need to know Java, Objective-C, or any other programming language.

Calabash framework consists of libraries that can interact with the Android and iOS apps. It can be run on real devices. So it can do things that the tester is doing manually.

There are two different projects on GitHub that make Calabash possible:

- calabash-android – for Android
- calabash-ios – for iOS

Calabash can work with any Ruby-based test framework. In this article, we will cover Cucumber – the most popular and convenient way of writing tests for Calabash.

Before continuing, if you want to try Calabash as you follow the rest of the article, be sure you have Ruby installed on your machine. You can find detailed instructions of installation here.

Next, install Calabash for your favorite platform by following the GitHub links above.

Writing tests on Calabash is quite easy. Let’s see how a simple test for an iOS app looks:

```
Feature: User Login
Scenario: Unsuccessful user login
Given the app has launched
Then I wait for the "Login" button to appear
When I enter "tstuser" into the "Username" field
And I enter "qwerty" into the "Password" field
And I touch "Login"
Then I should see "Username you entered is incorrect"
Scenario: Successful user login
Given the app has launched
Then I wait for the "Login" button to appear
When I enter "testeruser" into the "Username" field
And I enter "qwerty" into the "Password" field
And I touch "Login"
Then I should see "Hey testeruser!"
```

Here, an app is being tested with incorrect username and password, and then is being tested with correct username and password. The test expects the app to fail login for the first scenario, but succeed in the second one.

You can create as many scenarios as need, and all you need to do that is break down the steps/instructions into simple English sentences. Just like you would write a story!

Anyone who knows about behavior-driven development (BDD) will already find themselves familiar with this.

To see what goes on behind the steps that tester is using, you can open the project on GitHub and check the following file:

```
calabash-cucumber/features/step_definitions/calabash_steps.rb
```

Let’s see a definition of the following step:

```
When I enter "testeruser" into the "Username" field
```

```
Then /^I enter "([^"]*)" into the "([^"]*)" field$/ do |text_to_type, field_name|
touch("textField marked: '#{field_name}'")
wait_for_keyboard
keyboard_enter_text text_to_type
sleep(STEP_PAUSE)
end
```

This small snippet of Ruby code looks for a specific field, touches it, waits for keyboard to appear, types the text from the `text_to_type`

variable, and waits for a bit before switching to the next step.

The first word of the step can be “Given,” “When,” “Then,” “And,” or “But.” It does not matter what keyword you will use. You can use any of them to make the story clearer.

If you need a step that is not implemented in Calabash yet, you can write it by yourself. The syntax is exactly the same as it is in already predefined steps.

For example, if a tester needs to access the input field by placeholder, instead of field name:

```
Then /^I enter "([^"]*)" into the field with placeholder "([^"]*)"$/ do |text_to_type, placeholder|
touch("textField placeholder:'#{placeholder}'")
wait_for_keyboard()
keyboard_enter_text text_to_type
sleep(STEP_PAUSE)
end
```

This step definition is much the same as it was the previous one, but you’re accessing the field by placeholder instead of the field name. Given how your app looks, this may make things even easier for the tester.

And it’s easy for the developer, too. The developer is implementing the step once, and then the tester is using it whenever they need it. Moreover, you don’t need to know a lot of Ruby to implement your own custom steps.

You can find the Ruby functions you can use, here:

http://www.rubydoc.info/gems/calabash-cucumber/Calabash/Cucumber

There is one more challenge when testing mobile applications. You should test them on as many devices as possible, because there are so many devices and so many OS versions.

This is where Xamarin Test Cloud helps a lot. There are about 2,000 real devices in the cloud and the good news is that it supports Calabash tests.

The same Calabash tests that helped you save time by saving you from doing repetitive work can now be used to test your application on many real devices.

Whether Calabash is the testing solution your app needs, with the advantages it brings, it leaves no room for excuses when it comes to writing automated UI tests for your mobile apps. Calabash may fall short if your app heavily relies on certain device features (e.g., the camera), but it still makes writing tests for a majority of the apps a much easier feat.

Post by collobaration with Toptal. Author of this post Alexander Gedevanishvili

Always be happy and make the crazy effort for what you do in life.

Jay Ambe, Namaste (greeting we Hindu people follow same like “bye” in English)

]]>Here’s a problem: Your business assigns contractors to fulfill contracts. You look through your rosters and decide which contractors are available for a one month engagement and you look through your available contracts to see which of them are for one month long tasks. Given that you know how effectively each contractor can fulfill each contract, how do you assign contractors to maximize the overall effectiveness for that month?

This is an example of the assignment problem, and the problem can be solved with the classical Hungarian algorithm.

The Hungarian algorithm (also known as the Kuhn-Munkres algorithm) is a polynomial time algorithm that maximizes the weight matching in a weighted bipartite graph. Here, the contractors and the contracts can be modeled as a bipartite graph, with their effectiveness as the weights of the edges between the contractor and the contract nodes.

In this article, you will learn about an implementation of the Hungarian algorithm that uses the Edmonds-Karp algorithm to solve the linear assignment problem. You will also learn how the Edmonds-Karp algorithm is a slight modification of the Ford-Fulkerson method and how this modification is important.

The maximum flow problem itself can be described informally as the problem of moving some fluid or gas through a network of pipes from a single source to a single terminal. This is done with an assumption that the pressure in the network is sufficient to ensure that the fluid or gas cannot linger in any length of pipe or pipe fitting (those places where different lengths of pipe meet).

By making certain changes to the graph, the assignment problem can be turned into a maximum flow problem.

The ideas needed to solve these problems arise in many mathematical and engineering disciplines, often similar concepts are known by different names and expressed in different ways (e.g., adjacency matrices and adjacency lists). Since these ideas are quite esoteric, choices are made regarding how generally these concepts will be defined for any given setting.

This article will not assume any prior knowledge beyond a little introductory set theory.

The implementations in this post represent the problems as directed graphs (digraph).

A **digraph** has two attributes, **setOfNodes** and **setOfArcs**. Both of these attributes are sets (unordered collections). In the code blocks on this post, I’m actually using Python’s frozenset, but that detail isn’t particularly important.

```
DiGraph = namedtuple('DiGraph', ['setOfNodes','setOfArcs'])
```

(Note: This, and all other code in this article, are written in Python 3.6.)

A **node** `n`

is composed of two attributes:

`n.uid`

: A unique identifier.This means that for any two nodes`x`

and`y`

,

```
x.uid != y.uid
```

`n.datum`

: This represents any data object.

```
Node = namedtuple('Node', ['uid','datum'])
```

An **arc** `a`

is composed of three attributes:

`a.fromNode`

: This is a**node**, as defined above.`a.toNode`

: This is a**node**, as defined above.`a.datum`

: This represents any data object.

```
Arc = namedtuple('Arc', ['fromNode','toNode','datum'])
```

The set of **arcs** in the **digraph** represents a binary relation on the **nodes** in the **digraph**. The existence of **arc** `a`

implies that a relationship exists between `a.fromNode`

and `a.toNode`

.

In a directed graph (as opposed to an undirected graph), the existence of a relationship between `a.fromNode`

and `a.toNode`

does **not** imply that a similar relationship between `a.toNode`

and `a.fromNode`

exists.

This is because in an undirected graph, the relationship being expressed is not necessarily symmetric.

**Nodes** and **arcs** can be used to define a **digraph**, but for convenience, in the algorithms below, a **digraph** will be represented using as a dictionary.

Here’s a method that can convert the graph representation above into a dictionary representation similar to this one:

```
def digraph_to_dict(G):
G_as_dict = dict([])
for a in G.setOfArcs:
if(a.fromNode not in G.setOfNodes):
err_msg = 'There is no Node {a.fromNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
pdg(G)
raise KeyError(err_msg)
if(a.toNode not in G.setOfNodes):
err_msg = 'There is no Node {a.toNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
pdg(G)
raise KeyError(err_msg)
G_as_dict[a.fromNode] = (G_as_dict[a.fromNode].union(frozenset([a]))) if (a.fromNode in G_as_dict) else frozenset([a])
for a in G.setOfArcs:
if(a.fromNode not in G.setOfNodes):
err_msg = 'There is no Node {a.fromNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
if a.toNode not in G_as_dict:
G_as_dict[a.toNode] = frozenset([])
return G_as_dict
```

And here’s another one that converts it into a dictionary of dictionaries, another operation that will be useful:

```
def digraph_to_double_dict(G):
G_as_dict = dict([])
for a in G.setOfArcs:
if(a.fromNode not in G.setOfNodes):
err_msg = 'There is no Node {a.fromNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
if(a.toNode not in G.setOfNodes):
err_msg = 'There is no Node {a.toNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
if(a.fromNode not in G_as_dict):
G_as_dict[a.fromNode] = dict({a.toNode : frozenset([a])})
else:
if(a.toNode not in G_as_dict[a.fromNode]):
G_as_dict[a.fromNode][a.toNode] = frozenset([a])
else:
G_as_dict[a.fromNode][a.toNode] = G_as_dict[a.fromNode][a.toNode].union(frozenset([a]))
for a in G.setOfArcs:
if(a.fromNode not in G.setOfNodes):
err_msg = 'There is no Node {a.fromNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
if a.toNode not in G_as_dict:
G_as_dict[a.toNode] = dict({})
return G_as_dict
```

When the article talks about a **digraph** as represented by a dictionary, it will mention `G_as_dict`

to refer to it.

Sometimes it’s helpful to fetch a **node** from a **digraph** `G`

by it up through its `uid`

(unique identifier):

```
def find_node_by_uid(find_uid, G):
nodes = {n for n in G.setOfNodes if n.uid == find_uid}
if(len(nodes) != 1):
err_msg = 'Node with uid {find_uid!s} is not unique.'.format(**locals())
raise KeyError(err_msg)
return nodes.pop()
```

In defining graphs, people sometimes use the terms **node** and vertex to refer to the same concept; the same is true of the terms **arc** and edge.

Two popular graph representations in Python are this one which uses dictionaries and another which uses objects to represent graphs. The representation in this post is somewhere in between these two commonly used representations.

This is my **digraph** representation. There are many like it, but this one is mine.

Let `S_Arcs`

be a finite sequence (ordered collection) of **arcs** in a **digraph** `G`

such that if `a`

is any **arc** in `S_Arcs`

except for the last, and `b`

follows `a`

in the sequence, then there must be a **node** `n = a.fromNode`

in `G.setOfNodes`

such that `a.toNode = b.fromNode`

.

Starting from the first **arc** in `S_Arcs`

, and continuing until the last **arc** in `S_Arcs`

, collect (in the order encountered) all **nodes** `n`

as defined above between each two consecutive **arcs** in `S_Arcs`

. Label the ordered collection of **nodes** collected during this operation `S_{Nodes}`

.

```
def path_arcs_to_nodes(s_arcs):
s_nodes = list([])
arc_it = iter(s_arcs)
step_count = 0
last = None
try:
at_end = False
last = a1 = next(arc_it)
while (not at_end):
s_nodes = [a1.fromNode]
last = a2 = next(arc_it)
step_count = 1
if(a1.toNode != a2.fromNode):
err_msg = "Error at index {step_count!s} of Arc sequence.".format(**locals())
raise ValueError(err_msg)
a1 = a2
except StopIteration as e:
at_end = True
if(last is not None):
s_nodes = [last.toNode]
return s_nodes
```

- If any
**node**appears more than once in the sequence`S_Nodes`

then call`S_Arcs`

a Walk on**digraph**`G`

. - Otherwise, call
`S_Arcs`

a path from`list(S_Nodes)[0]`

to`list(S_Nodes)[-1]`

on**digraph**`G`

.

Call **node** `s`

a **source node** in **digraph** `G`

if `s`

is in `G.setOfNodes`

and `G.setOfArcs`

contains no **arc** `a`

such that `a.toNode = s`

.

```
def source_nodes(G):
to_nodes = frozenset({a.toNode for a in G.setOfArcs})
sources = G.setOfNodes.difference(to_nodes)
return sources
```

Call **node** `t`

a **terminal node** in **digraph** `G`

if `t`

is in `G.setOfNodes`

and `G.setOfArcs`

contains no **arc** `a`

such that `a.fromNode = t`

.

```
def terminal_nodes(G):
from_nodes = frozenset({a.fromNode for a in G.setOfArcs})
terminals = G.setOfNodes.difference(from_nodes)
return terminals
```

A cut `cut`

of a connected **digraph** `G`

is a subset of **arcs** from `G.setOfArcs`

which partitions the set of **nodes** `G.setOfNodes`

in `G`

. `G`

is connected if every **node** `n`

in `G.setOfNodes`

and has at least one **arc** `a`

in `G.setOfArcs`

such that either `n = a.fromNode`

or `n = a.toNode`

, but `a.fromNode != a.toNode`

.

```
Cut = namedtuple('Cut', ['setOfCutArcs'])
```

The definition above refers to a subset of **arcs**, but it can also define a partition of the **nodes** of `G.setOfNodes`

.

For the functions `predecessors_of`

and `successors_of`

, `n`

is a **node** in set **G.setOfNodes** of **digraph** `G`

, and `cut`

is a **cut** of `G`

:

```
def cut_predecessors_of(n, cut, G):
allowed_arcs = G.setOfArcs.difference(frozenset(cut.setOfCutArcs))
predecessors = frozenset({})
previous_count = len(predecessors)
reach_fringe = frozenset({n})
keep_going = True
while( keep_going ):
reachable_from = frozenset({a.fromNode for a in allowed_arcs if (a.toNode in reach_fringe)})
reach_fringe = reachable_from
predecessors = predecessors.union(reach_fringe)
current_count = len(predecessors)
keep_going = current_count - previous_count > 0
previous_count = current_count
return predecessors
def cut_successors_of(n, cut, G):
allowed_arcs = G.setOfArcs.difference(frozenset(cut.setOfCutArcs))
successors = frozenset({})
previous_count = len(successors)
reach_fringe = frozenset({n})
keep_going = True
while( keep_going ):
reachable_from = frozenset({a.toNode for a in allowed_arcs if (a.fromNode in reach_fringe)})
reach_fringe = reachable_from
successors = successors.union(reach_fringe)
current_count = len(successors)
keep_going = current_count - previous_count > 0
previous_count = current_count
return successors
```

Let `cut`

be a **cut** of **digraph** `G`

.

```
def get_first_part(cut, G):
firstPartFringe = frozenset({a.fromNode for a in cut.setOfCutArcs})
firstPart = firstPartFringe
for n in firstPart:
preds = cut_predecessors_of(n,cut,G)
firstPart = firstPart.union(preds)
return firstPart
def get_second_part(cut, G):
secondPartFringe = frozenset({a.toNode for a in cut.setOfCutArcs})
secondPart = secondPartFringe
for n in secondPart:
succs= cut_successors_of(n,cut,G)
secondPart = secondPart.union(succs)
return secondPart
```

`cut`

is a **cut** of **digraph** `G`

if: `(get_first_part(cut, G).union(get_second_part(cut, G)) == G.setOfNodes) and (len(get_first_part(cut, G).intersect(get_second_part(cut, G))) == 0)`

`cut`

is called an **x-y cut** if `(x in get_first_part(cut, G)) and (y in get_second_part(cut, G) ) and (x != y)`

. When the **node** `x`

in a **x-y cut** `cut`

is a **source node** and **node** `y`

in the **x-y cut** is a **terminal node**, then this **cut** is called a **s-t cut**.

```
STCut = namedtuple('STCut', ['s','t','cut'])
```

You can use a **digraph** `G`

to represent a flow network.

Assign each **node** `n`

, where `n`

is in `G.setOfNodes`

an `n.datum`

that is a `FlowNodeDatum`

:

```
FlowNodeDatum = namedtuple('FlowNodeDatum', ['flowIn','flowOut'])
```

Assign each **arc** `a`

, where `a`

is in `G.setOfArcs`

and `a.datum`

that is a `FlowArcDatum`

.

```
FlowArcDatum = namedtuple('FlowArcDatum', ['capacity','flow'])
```

`flowNodeDatum.flowIn`

and `flowNodeDatum.flowOut`

are positive real numbers.

`flowArcDatum.capacity`

and `flowArcDatum.flow`

are also positive real numbers.

For every node **node** `n`

in `G.setOfNodes`

:

```
n.datum.flowIn = sum({a.datum.flow for a in G.Arcs if a.toNode == n})
n.datum.flowOut = sum({a.datum.flow for a in G.Arcs if a.fromNode == n})
```

**Digraph** `G`

now represents a **flow network**.

The **flow** of `G`

refers to the `a.flow`

for all **arcs** `a`

in `G`

.

Let **digraph** `G`

represent a **flow network**.

The **flow network** represented by `G`

has **feasible flows** if:

- For every
**node**`n`

in`G.setOfNodes`

except for**source nodes**and**terminal nodes**:`n.datum.flowIn = n.datum.flowOut`

. - For every
**arc**`a`

in`G.setOfNodes`

:`a.datum.capacity <= a.datum.flow`

.

Condition 1 is called a conservation constraint.

Condition 2 is called a capacity constraint.

The **cut capacity** of an **s-t cut** `stCut`

with **source node** `s`

and **terminal node** `t`

of a **flow network**represented by a **digraph** `G`

is:

```
def cut_capacity(stCut, G):
part_1 = get_first_part(stCut.cut,G)
part_2 = get_second_part(stCut.cut,G)
s_part = part_1 if stCut.s in part_1 else part_2
t_part = part_1 if stCut.t in part_1 else part_2
cut_capacity = sum({a.datum.capacity for a in stCut.cut.setOfCutArcs if ( (a.fromNode in s_part) and (a.toNode in t_part) )})
return cut_capacity
```

Let `stCut = stCut(s,t,cut)`

be an **s-t cut** of a **flow network** represented by a **digraph** `G`

.

`stCut`

is the **minimum capacity cut** of the **flow network** represented by `G`

if there is no other **s-t cut** `stCutCompetitor`

in this **flow network** such that:

```
cut_capacity(stCut, G) < cut_capacity(stCutCompetitor, G)
```

I would like to refer to the **digraph** that would be the result of taking a **digraph** `G`

and stripping away all the flow data from all the **nodes** in `G.setOfNodes`

and also all the **arcs** in `G.setOfArcs`

.

```
def strip_flows(G):
new_nodes= frozenset( (Node(n.uid, FlowNodeDatum(0.0,0.0)) for n in G.setOfNodes) )
new_arcs = frozenset([])
for a in G.setOfArcs:
new_fromNode = Node(a.fromNode.uid, FlowNodeDatum(0.0,0.0))
new_toNode = Node(a.toNode.uid, FlowNodeDatum(0.0,0.0))
new_arc = Arc(new_fromNode, new_toNode, FlowArcDatum(a.datum.capacity, 0.0))
new_arcs = new_arcs.union(frozenset([new_arc]))
return DiGraph(new_nodes, new_arcs)
```

A **flow network** represented as a **digraph** `G`

, a **source node** `s`

in `G.setOfNodes`

and a **terminal node** `t`

in `G.setOfNodes`

, `G`

can represent a **maximum flow problem** if:

```
(len(list(source_nodes(G))) == 1) and (next(iter(source_nodes(G))) == s) and (len(list(terminal_nodes(G))) == 1) and (next(iter(terminal_nodes(G))) == t)
```

Label this representation:

```
MaxFlowProblemState = namedtuple('MaxFlowProblemState', ['G','sourceNodeUid','terminalNodeUid','maxFlowProblemStateUid'])
```

Where `sourceNodeUid = s.uid`

, `terminalNodeUid = t.uid`

, and `maxFlowProblemStateUid`

is an identifier for the problem instance.

Let `maxFlowProblem`

represent a **maximum flow problem**. The solution to `maxFlowProblem`

can be represented by a **flow network** represented as a **digraph** `H`

.

**Digraph** `H`

is a **feasible** solution to the **maximum flow problem** on input `python maxFlowProblem`

if:

`strip_flows(maxFlowProblem.G) == strip_flows(H)`

.`H`

is a**flow network**and has**feasible flows**.

If in addition to 1 and 2:

- There can be no other
**flow network**represented by**digraph**`K`

such that`strip_flows(G) == strip_flows(K)`

and`find_node_by_uid(t.uid,G).flowIn < find_node_by_uid(t.uid,K).flowIn`

.

Then `H`

is also an **optimal** solution to `maxFlowProblem`

.

In other words a **feasible maximum flow solution** can be represented by a **digraph**, which:

- Is identical to
**digraph**`G`

of the corresponding**maximum flow problem**with the exception that the`n.datum.flowIn`

,`n.datum.flowOut`

and the`a.datum.flow`

of any of the**nodes**and**arcs**may be different. - Represents a
**flow network**that has**feasible flows**.

And, it can represent an **optimal maximum flow solution** if additionally:

- The
`flowIn`

for the**node**corresponding to the**terminal node**in the**maximum flow problem**is as large as possible (when conditions 1 and 2 are still satisfied).

If **digraph** `H`

represents a **feasible maximum flow solution** : `find_node_by_uid(s.uid,H).flowOut = find_node_by_uid(t.uid,H).flowIn`

this follows from the **max flow, min cut theorem** (discussed below). Informally, since `H`

is assumed to have **feasible flows** this means that **flow** can neither be ‘created’ (except at **source node** `s`

) nor ‘destroyed’ (except at **terminal node** `t`

) while crossing any (other) **node** (**conservation constraints**).

Since a **maximum flow problem** contains only a single **source node** `s`

and a single **terminal node** `t`

, all flow ‘created’ at `s`

must be ‘destroyed’ at `t`

or the **flow network** does **not** have **feasible flows** (the **conservation constraint** would have been violated).

Let **digraph** `H`

represent a **feasible maximum flow solution**; the value above is called the **s-t Flow Value** of `H`

.

Let:

```
mfps=MaxFlowProblemState(H, maxFlowProblem.sourceNodeUid, maxFlowProblem.terminalNodeUid, maxFlowProblem.maxFlowProblemStateUid)
```

This means that `mfps`

is a **successor state** of `maxFlowProblem`

, which just means that `mfps`

is exacly like `maxFlowProblem`

with the exception that the values of `a.flow`

for arcs `a`

in `maxFlowProblem.setOfArcs`

may be different than `a.flow`

for arcs `a`

in `mfps.setOfArcs`

.

```
def get_mfps_flow(mfps):
flow_from_s = find_node_by_uid(mfps.sourceNodeUid,mfps.G).datum.flowOut
flow_to_t = find_node_by_uid(mfps.terminalNodeUid,mfps.G).datum.flowIn
if( (flow_to_t - flow_from_s) > 0):
raise Exception('Infeasible s-t flow')
return flow_to_t
```

Here’s a visualization of a `mfps`

along with its associated `maxFlowProb`

. Each **arc** `a`

in the image has a label, these labels are `a.datum.flowFrom / a.datum.flowTo`

, each **node** `n`

in the image has a label, and these labels are `n.uid {n.datum.flowIn / a.datum.flowOut}`

.

Let `mfps`

represent a `MaxFlowProblemState`

and let `stCut`

represent a **cut** of `mfps.G`

. The **cut flow** of `stCut`

is defined:

```
def get_stcut_flow(stCut,mfps):
s = find_node_by_uid(mfps.sourceNodeUid, mfps.G)
t = find_node_by_uid(mfps.terminalNodeUid, mfps.G)
part_1 = get_first_part(stCut.cut,mfps.G)
part_2 = get_second_part(stCut.cut,mfps.G)
s_part = part_1 if s in part_1 else part_2
t_part = part_1 if t in part_1 else part_2
s_t_sum = sum(a.datum.flow for a in mfps.G.setOfArcs if (a in stCut.cut.setOfCutArcs) and (a.fromNode in s_part) )
t_s_sum = sum(a.datum.flow for a in mfps.G.setOfArcs if (a in stCut.cut.setOfCutArcs) and (a.fromNode in t_part) )
cut_flow = s_t_sum - t_s_sum
return cut_flow
```

**s-t cut flow** is the sum of flows from the partition containing the **source node** to the partition containing the **terminal node** minus the sum of flows from the partition containing the **terminal node** to the partition containing the **source node**.

Let `maxFlowProblem`

represent a **maximum flow problem** and let the solution to `maxFlowProblem`

be represented by a **flow network** represented as **digraph** `H`

.

Let `minStCut`

be the **minimum capacity cut** of the **flow network** represented by `maxFlowProblem.G`

.

Because in the **maximum flow problem** flow originates in only a single **source node** and terminates at a single **terminal node** and, because of the **capacity constraints** and the **conservation constraints**, we know that the all of the flow entering `maxFlowProblem.terminalNodeUid`

must cross any **s-t cut**, in particular it must cross `minStCut`

. This means:

```
get_flow_value(H, maxFlowProblem) <= cut_capacity(minStCut, maxFlowProblem.G)
```

The basic idea for solving a **maximum flow problem** `maxFlowProblem`

is to start with a **maximum flow solution**represented by **digraph** `H`

. Such a starting point can be `H = strip_flows(maxFlowProblem.G)`

. The task is then to use `H`

and by some greedy modification of the `a.datum.flow`

values of some **arcs** `a`

in `H.setOfArcs`

to produce another **maximum flow solution** represented by **digraph** `K`

such that `K`

cannot still represent a **flow network** with **feasible flows** and `get_flow_value(H, maxFlowProblem) < get_flow_value(K, maxFlowProblem)`

. As long as this process continues, the quality (`get_flow_value(K, maxFlowProblem)`

) of the most recently encountered **maximum flow solution** (`K`

) is better than any other **maximum flow solution** that has been found. If the process reaches a point that it knows that no other improvement is possible, the process can terminate and it will return the optimal **maximum flow solution**.

The description above is general and skips many proofs such as whether such a process is possible or how long it may take, I’ll give a few more details and the algorithm.

From the book Flows in Networks by Ford and Fulkerson, the statement of the **max flow, min cut theorem**(Theorem 5.1) is:

For any network, the maximal flow value from

`s`

to`t`

is equal to the minimum cut capacity of all cuts separating`s`

and`t`

.

Using the definitions in this post, that translates to:

The solution to a `maxFlowProblem`

represented by a **flow network** represented as **digraph** `H`

is optimal if:

```
get_flow_value(H, maxFlowProblem) == cut_capacity(minStCut, maxFlowProblem.G)
```

I like this proof of the theorem and Wikipedia has another one.

The **max flow, min cut theorem** is used to prove the correctness and completeness of the **Ford-Fulkerson method**.

I’ll also give a proof of the theorem in the section after **augmenting paths**.

CLRS defines the Ford-Fulkerson method like so (section 26.2):

```
FORD-FULKERSON-METHOD(G, s, t):
initialize flow f to 0
while there exists an augmenting path p in the residual graph G_f augment flow f along
```

The Residual Graph of a **flow network** represented as the **digraph** `G`

can be represented as a **digraph** `G_f`

:

```
ResidualDatum = namedtuple('ResidualDatum', ['residualCapacity','action'])
def agg_n_to_u_cap(n,u,G_as_dict):
arcs_out = G_as_dict[n]
return sum([a.datum.capacity for a in arcs_out if( (a.fromNode == n) and (a.toNode == u) ) ])
def agg_n_to_u_flow(n,u,G_as_dict):
arcs_out = G_as_dict[n]
return sum([a.datum.flow for a in arcs_out if( (a.fromNode == n) and (a.toNode == u) ) ])
def get_residual_graph_of(G):
G_as_dict = digraph_to_dict(G)
residual_nodes = G.setOfNodes
residual_arcs = frozenset([])
for n in G_as_dict:
arcs_from = G_as_dict[n]
nodes_to = frozenset([find_node_by_uid(a.toNode.uid,G) for a in arcs_from])
for u in nodes_to:
n_to_u_cap_sum = agg_n_to_u_cap(n,u,G_as_dict)
n_to_u_flow_sum = agg_n_to_u_flow(n,u,G_as_dict)
if(n_to_u_cap_sum > n_to_u_flow_sum):
flow = round(n_to_u_cap_sum - n_to_u_flow_sum, TOL)
residual_arcs = residual_arcs.union( frozenset([Arc(n,u,datum=ResidualDatum(flow, 'push'))]) )
if(n_to_u_flow_sum > 0.0):
flow = round(n_to_u_flow_sum, TOL)
residual_arcs = residual_arcs.union( frozenset([Arc(u,n,datum=ResidualDatum(flow, 'pull'))]) )
return DiGraph(residual_nodes, residual_arcs)
```

`agg_n_to_u_cap(n,u,G_as_dict)`

returns the sum of`a.datum.capacity`

for all**arcs**in the subset of`G.setOfArcs`

where**arc**`a`

is in the subset if`a.fromNode = n`

and`a.toNode = u`

.`agg_n_to_u_cap(n,u,G_as_dict)`

returns the sum of`a.datum.flow`

for all**arcs**in the subset of`G.setOfArcs`

where**arc**`a`

is in the subset if`a.fromNode = n`

and`a.toNode = u`

.

Briefly, the **residual graph** `G_f`

represents certain actions which can be performed on the **digraph** `G`

.

Each pair of **nodes** `n,u`

in `G.setOfNodes`

of the **flow network** represented by **digraph** `G`

can generate 0, 1, or 2 **arcs** in the **residual graph** `G_f`

of `G`

.

- The pair
`n,u`

does not generate any**arcs**in`G_f`

if there is no**arc**`a`

in`G.setOfArcs`

such that`a.fromNode = n`

and`a.toNode = u`

. - The pair
`n,u`

generates the**arc**`a`

in`G_f.setOfArcs`

where`a`

represents an**arc**labeled a**push flow arc**from`n`

to`u`

`a = Arc(n,u,datum=ResidualNode(n_to_u_cap_sum - n_to_u_flow_sum))`

if`n_to_u_cap_sum > n_to_u_flow_sum`

. - The pair
`n,u`

generates the**arc**`a`

in`G_f.setOfArcs`

where`a`

represents an**arc**labeled a**pull flow arc**from`n`

to`u`

`a = Arc(n,u,datum=ResidualNode(n_to_u_cap_sum - n_to_u_flow_sum))`

if`n_to_u_flow_sum > 0.0`

.

- Each
**push flow arc**in`G_f.setOfArcs`

represents the action of adding a total of`x <= n_to_u_cap_sum - n_to_u_flow_sum`

flow to**arcs**in the subset of`G.setOfArcs`

where**arc**`a`

is in the subset if`a.fromNode = n`

and`a.toNode = u`

. - Each
**pull flow arc**in`G_f.setOfArcs`

represents the action of subtracting a total of`x <= n_to_u_flow_sum`

flow to**arcs**in the subset of`G.setOfArcs`

where**arc**`a`

is in the subset if`a.fromNode = n`

and`a.toNode = u`

.

Performing an individual **push** or **pull** action from `G_f`

on the applicable **arcs** in `G`

might generate a **flow network** without **feasible flows** because the **capacity constraints** or the **conservation constraints** might be violated in the generated **flow network**.

Here’s a visualization of the **residual graph** of the previous example visualization of a **maximum flow solution**, in the visualization each **arc** `a`

represents `a.residualCapacity`

.

Let `maxFlowProblem`

be a **max flow problem**, and let `G_f = get_residual_graph_of(G)`

be the **residual graph** of `maxFlowProblem.G`

.

An augmenting path `augmentingPath`

for `maxFlowProblem`

is any **path** from `find_node_by_uid(maxFlowProblem.sourceNode,G_f)`

to `find_node_by_uid(maxFlowProblem.terminalNode,G_f)`

.

It turns out that an augmenting **path** `augmentingPath`

can be applied to a **max flow solution** represented by **digraph** `H`

generating another **max flow solution** represented by **digraph** `K`

where `get_flow_value(H, maxFlowProblem) < get_flow_value(K, maxFlowProblem)`

if `H`

is not **optimal**.

Here’s how:

```
def augment(augmentingPath, H):
augmentingPath = list(augmentingPath)
H_as_dict = digraph_to_dict(H)
new_nodes = frozenset({})
new_arcs = frozenset({})
visited_nodes = frozenset({})
visited_arcs = frozenset({})
bottleneck_residualCapacity = min( augmentingPath, key=lambda a: a.datum.residualCapacity ).datum.residualCapacity
for x in augmentingPath:
from_node_uid = x.fromNode.uid if x.datum.action == 'push' else x.toNode.uid
to_node_uid = x.toNode.uid if x.datum.action == 'push' else x.fromNode.uid
from_node = find_node_by_uid( from_node_uid, H )
to_node = find_node_by_uid( to_node_uid, H )
load = bottleneck_residualCapacity if x.datum.action == 'push' else -bottleneck_residualCapacity
for a in H_as_dict[from_node]:
if(a.toNode == to_node):
test_sum = a.datum.flow load
new_flow = a.datum.flow
new_from_node_flow_out = a.fromNode.datum.flowOut
new_to_node_flow_in = a.toNode.datum.flowIn
new_from_look = {n for n in new_nodes if (n.uid == a.fromNode.uid)}
new_to_look = {n for n in new_nodes if (n.uid == a.toNode.uid) }
prev_from_node = new_from_look.pop() if (len(new_from_look)>0) else a.fromNode
prev_to_node = new_to_look.pop() if (len(new_to_look)>0) else a.toNode
new_nodes = new_nodes.difference(frozenset({prev_from_node}))
new_nodes = new_nodes.difference(frozenset({prev_to_node}))
if(test_sum > a.datum.capacity):
new_flow = a.datum.capacity
new_from_node_flow_out = prev_from_node.datum.flowOut - a.datum.flow a.datum.capacity
new_to_node_flow_in = prev_to_node.datum.flowIn - a.datum.flow a.datum.capacity
load = test_sum - a.datum.capacity
elif(test_sum < 0.0):
new_flow = 0.0
new_from_node_flow_out = prev_from_node.datum.flowOut - a.datum.flow
new_to_node_flow_in = prev_to_node.datum.flowIn - a.datum.flow
load = test_sum
else:
new_flow = test_sum
new_from_node_flow_out = prev_from_node.datum.flowOut - a.datum.flow new_flow
new_to_node_flow_in = prev_to_node.datum.flowIn - a.datum.flow new_flow
load = 0.0
new_from_node_flow_out = round(new_from_node_flow_out, TOL)
new_to_node_flow_in = round(new_to_node_flow_in, TOL)
new_flow = round(new_flow, TOL)
new_from_node = Node(prev_from_node.uid, FlowNodeDatum(prev_from_node.datum.flowIn, new_from_node_flow_out))
new_to_node = Node(prev_to_node.uid, FlowNodeDatum(new_to_node_flow_in, prev_to_node.datum.flowOut))
new_arc = Arc(new_from_node, new_to_node, FlowArcDatum(a.datum.capacity, new_flow))
visited_nodes = visited_nodes.union(frozenset({a.fromNode,a.toNode}))
visited_arcs = visited_arcs.union(frozenset({a}))
new_nodes = new_nodes.union(frozenset({new_from_node, new_to_node}))
new_arcs = new_arcs.union(frozenset({new_arc}))
not_visited_nodes = H.setOfNodes.difference(visited_nodes)
not_visited_arcs = H.setOfArcs.difference(visited_arcs)
full_new_nodes = new_nodes.union(not_visited_nodes)
full_new_arcs = new_arcs.union(not_visited_arcs)
G = DiGraph(full_new_nodes, full_new_arcs)
full_new_arcs_update = frozenset([])
for a in full_new_arcs:
new_from_node = a.fromNode
new_to_node = a.toNode
new_from_node = find_node_by_uid( a.fromNode.uid, G )
new_to_node = find_node_by_uid( a.toNode.uid, G )
full_new_arcs_update = full_new_arcs_update.union( {Arc(new_from_node, new_to_node, FlowArcDatum(a.datum.capacity, a.datum.flow))} )
G = DiGraph(full_new_nodes, full_new_arcs_update)
return G
```

In the above, `TOL`

is some tolerance value for rounding the flow values in the network. This is to avoid cascading imprecision of floating point calculations. So, for example, I used `TOL = 10`

to mean round to 10 significant digits.

Let `K = augment(augmentingPath, H)`

, then `K`

represents a **feasible max flow solution** for `maxFlowProblem`

. For the statement to be true, the **flow network** represented by `K`

must have **feasible flows** (not violate the **capacity constraint** or the **conservation constraint**.

Here’s why: In the method above, each **node** added to the new **flow network** represented by **digraph** `K`

is either an exact copy of a **node** from **digraph** `H`

or a **node** `n`

which has had the same number added to its `n.datum.flowIn`

as its `n.datum.flowOut`

. This means that the **conservation constraint** is satisfied in `K`

as long as it was satisfied in `H`

. The **conservation constraint** is satisfied because we explicitly check that any new **arc**`a`

in the network has `a.datum.flow <= a.datum.capacity`

; thus, as long as the **arcs** from the set `H.setOfArcs`

which were copied unmodified into `K.setOfArcs`

do not violate the **capacity constraint**, then `K`

does not violate the **capacity constraint**.

It’s also true that `get_flow_value(H, maxFlowProblem) < get_flow_value(K, maxFlowProblem)`

if `H`

is not **optimal**.

Here’s why: For an **augmenting path** `augmentingPath`

to exist in the **digraph** representation of the **residual graph** `G_f`

of a **max flow problem** `maxFlowProblem`

then the last **arc** `a`

on `augmentingPath`

must be a ‘push’ **arc** and it must have `a.toNode == maxFlowProblem.terminalNode`

. An **augmenting path** is defined as one which terminates at the **terminal node** of the **max flow problem** for which it is an **augmenting path**. From the definition of the **residual graph**, it is clear that the last **arc** in an **augmenting path** on that **residual graph** must be a ‘push’ **arc** because any ‘pull’ **arc** `b`

in the **augmenting path** will have `b.toNode == maxFlowProblem.terminalNode`

and `b.fromNode != maxFlowProblem.terminalNode`

from the definition of **path**. Additionally, from the definition of **path**, it is clear that the **terminal node** is only modified once by the `augment`

method. Thus `augment`

modifies `maxFlowProblem.terminalNode.flowIn`

exactly once and it increases the value of `maxFlowProblem.terminalNode.flowIn`

because the last **arc** in the `augmentingPath`

must be the **arc**which causes the modification in `maxFlowProblem.terminalNode.flowIn`

during `augment`

. From the definition of `augment`

as it applies to ‘push’ **arcs**, the `maxFlowProblem.terminalNode.flowIn`

can only be increased, not decreased.

The book Algorithms, fourth edition by Robert Sedgewich and Kevin Wayne has some wonderful and short proofs (pages 892-894) that will be useful. I’ll recreate them here, though I’ll use language fitting in with previous definitions. My labels for the proofs are the same as in the Sedgewick book.

**Proposition E:** For any **digraph** `H`

representing a **feasible maximum flow solution** to a **maximum flow problem** `maxFlowProblem`

, for any `stCut`

`get_stcut_flow(stCut,H,maxFlowProblem) = get_flow_value(H, maxFlowProblem)`

.

**Proof:** Let `stCut=stCut(maxFlowProblem.sourceNode,maxFlowProblem.terminalNode,set([a for a in H.setOfArcs if a.toNode == maxFlowProblem.terminalNode]))`

. **Proposition E** holds for `stCut`

directly from the definition of **s-t flow value**. Suppose that there we wish to move some **node** `n`

from the s-partition (`get_first_part(stCut.cut, G)`

) and into the t-partition `(get_second_part(stCut.cut, G))`

, to do so we need to change `stCut.cut`

, which could change `stcut_flow = get_stcut_flow(stCut,H,maxFlowProblem)`

and invalidate **proposition E**. However, let’s see how the value of `stcut_flow`

will change as we make this change. **node** `n`

is at equilibrium meaning that the sum of flow into **node** `n`

is equal to the sum of flow out of it (this is necessary for `H`

to represent a **feasible solution**). Notice that all flow which is part of the `stcut_flow`

entering **node** `n`

enters it from the s-partition (flow entering **node** `n`

from the t-partition either directly or indirectly would not have been counted in the `stcut_flow`

value because it is heading the wrong direction based on the definition). Additionally, all flow exiting `n`

will eventually (directly or indirectly) flow into the **terminal node** (proved earlier). When we move **node** `n`

into the t-partition, all the flow entering `n`

from the s-partition must be added to the new `stcut_flow`

value; however, all flow exiting `n`

must the be subtracted from the new `stcut_flow`

value; the part of the flow heading directly into the t-partition is subtracted because this flow is now internal to the new t-partition and is not counted as `stcut_flow`

. The part of the flow from `n`

heading into **nodes** in the s-partition must also be subtracted from `stcut_flow`

: After `n`

is moved into the t-partition, these flows will be directed from the t-partition and into the s-partition and so must not be accounted for in the `stcut_flow`

, since these flows are removed the inflow into the s-partition and must be reduced by the sum of these flows, and the outflow from the s-partition into the t-partition (where all flows from s-t must end up) must be reduced by the same amount. As **node** `n`

was at equilibrium prior to the process, the update will have added the same value to the new `stcut_flow`

value as it subtracted thus leaving **proposition E** true after the update. The validity of **proposition E** then follows from induction on the size of the t-partition.

Here are some example **flow networks** to help visualize the less obvious cases where **proposition E** holds; in the image, the red areas indicate the s-partition, the blue areas represent the t-partition, and the green **arcs**indicate an **s-t cut**. In the second image, flow between **node** A and **node** B increases while the flow into **terminal node** t doesn’t change.:

**Corollary:** No **s-t cut flow** value can exceed the capacity of any **s-t cut**.

**Proposition F. (max flow, min cut theorem):** Let `f`

be an **s-t flow**. The following 3 conditions are equivalent:

- There exists an
**s-t cut**whose capacity equals the value of the flow`f`

. `f`

is a**max flow**.- There is no
**augmenting path**with respect to`f`

.

Condition 1 implies condition 2 by the corollary. Condition 2 implies condition 3 because the existence of an augmenting path implies the existence of a flow with larger values, contradicting the maximality of `f`

. Condition 3 implies condition 1: Let `C_s`

be the set of all **nodes** that can be reached from `s`

with an **augmenting path** in the **residual graph**. Let `C_t`

be the remaining **arcs**, then `t`

must be in `C_t`

(by our assumption). The **arcs** crossing from `C_s`

to `C_t`

then form an **s-t cut** which contains only **arcs** `a`

where either `a.datum.capacity = a.datum.flow`

or `a.datum.flow = 0.0`

. If this were otherwise then the **nodes**connected by an **arc** with remaining residual capacity to `C_s`

would be in the set `C_s`

since there would then be an **augmenting path** from `s`

to such a **node**. The flow across the **s-t cut** is equal to the **s-t cut’s** capacity (since **arcs** from `C_s`

to `C_t`

have flow equal to capacity) and also to the value of the **s-t flow** (by **proposition E**).

This statement of the **max flow, min cut theorem** implies the earlier statement from Flows in Networks.

**Corollary (integrality property):** When capacities are integers, there exists an integer-valued max flow, and the Ford-Fulkerson algorithm finds it.

Proof: Each **augmenting path** increases the flow by a positive integer, the minimum of the unused capacities in the ‘push’ **arcs** and the flows in the ‘pull’ **arcs**, all of which are always positive integers.

This justifies the **Ford-Fulkerson method** description from **CLRS**. The method is to keep finding **augmenting paths** and applying `augment`

to the latest `maxFlowSolution`

coming up with better solutions, until no more **augmenting path** meaning that the latest **maximum flow solution** is **optimal**.

The remaining questions regarding solving **maximum flow problems** are:

- How should
**augmenting paths**be constructed? - Will the method terminate if we use real numbers and not integers?
- How long will it take to terminate (if it does)?

The **Edmonds-Karp algorithm** specifies that each **augmenting path** is constructed by a **breadth first search**(BFS) of the **residual graph**; it turns out that this decision of point 1 above will also force the algorithm to terminate (point 2) and allows the asymptotic time and space complexity to be determined.

First, here’s a **BFS** implementation:

```
def bfs(sourceNode, terminalNode, G_f):
G_f_as_dict = digraph_to_dict(G_f)
parent_arcs = dict([])
visited = frozenset([])
deq = deque([sourceNode])
while len(deq) > 0:
curr = deq.popleft()
if curr == terminalNode:
break
for a in G_f_as_dict.get(curr):
if (a.toNode not in visited):
visited = visited.union(frozenset([a.toNode]))
parent_arcs[a.toNode] = a
deq.extend([a.toNode])
path = list([])
curr = terminalNode
while(curr != sourceNode):
if (curr not in parent_arcs):
err_msg = 'No augmenting path from {} to {}.'.format(sourceNode.uid, terminalNode.uid)
raise StopIteration(err_msg)
path.extend([parent_arcs[curr]])
curr = parent_arcs[curr].fromNode
path.reverse()
test = deque([path[0].fromNode])
for a in path:
if(test[-1] != a.fromNode):
err_msg = 'Bad path: {}'.format(path)
raise ValueError(err_msg)
test.extend([a.toNode])
return path
```

I used a deque from the python collections module.

To answer question 2 above, I’ll paraphrase another proof from Sedgewick and Wayne: **Proposition G.** The number of **augmenting paths** needed in the **Edmonds-Karp** algorithm with `N`

**nodes** and `A`

**arcs** is at most `NA/2`

. Proof: Every **augmenting path** has a *bottleneck* **arc**– an **arc** that is deleted from the **residual graph**because it corresponds either to a ‘push’ **arc** that becomes filled to capacity or a ‘pull’ **arc** through which the flow becomes 0. Each time an **arc** becomes a bottleneck **arc**, the length of any **augmenting path** through it must increase by a factor of 2. This is because each **node** in a **path** may appear only once or not at all (from the definition of **path**) since the **paths** are being explored from shortest **path** to longest that means that at least one more **node** must be visited by the next path that goes through the particular bottleneck **node** that means an additional 2 **arcs** on the path before we arrive at the **node**. Since the **augmenting path** is of length at most `N`

each **arc** can be on at most `N/2`

**augmenting paths**, and the total number of **augmenting paths** is at most `NA/2`

.

The **Edmonds-Karp algorithm** executes in `O(NA^2)`

. If at most `NA/2`

**paths** will be explored during the algorithm and exploring each **path** with **BFS** is `N A`

then the most significant term of the product and hence the asymptotic complexity is `O(NA^2)`

.

Let `mfp`

be a `maxFlowProblemState`

.

```
def edmonds_karp(mfp):
sid, tid = mfp.sourceNodeUid, mfp.terminalNodeUid
no_more_paths = False
loop_count = 0
while(not no_more_paths):
residual_digraph = get_residual_graph_of(mfp.G)
try:
asource = find_node_by_uid(mfp.sourceNodeUid, residual_digraph)
aterm = find_node_by_uid(mfp.terminalNodeUid, residual_digraph)
apath = bfs(asource, aterm, residual_digraph)
paint_mfp_path(mfp, loop_count, apath)
G = augment(apath, mfp.G)
s = find_node_by_uid(sid, G)
t = find_node_by_uid(tid, G)
mfp = MaxFlowProblemState(G, s.uid, t.uid, mfp.maxFlowProblemStateUid)
loop_count = 1
except StopIteration as e:
no_more_paths = True
return mfp
```

The version above is inefficient and has worse complexity than `O(NA^2)`

since it constructs a new **maximum flow solution** and new a **residual graph** each time (rather than modifying existing **digraphs** as the algorithm advances). To get to a true `O(NA^2)`

solution the algorithm must maintain both the **digraph** representing the **maximum flow problem state** and its associated **residual graph**. So the algorithm must avoid iterating over **arcs** and **nodes** unnecessarily and update their values and associated values in the **residual graph** only as necessary.

To write a faster **Edmonds Karp** algorithm, I rewrote several pieces of code from the above. I hope that going through the code which generated a new **digraph** was helpful in understanding what’s going on. In the fast algorithm, I use some new tricks and Python data structures that I don’t want to go over in detail. I will say that `a.fromNode`

and `a.toNode`

are now treated as strings and uids to **nodes**. For this code, let `mfps`

be a `maxFlowProblemState`

```
import uuid
def fast_get_mfps_flow(mfps):
flow_from_s = {n for n in mfps.G.setOfNodes if n.uid == mfps.sourceNodeUid}.pop().datum.flowOut
flow_to_t = {n for n in mfps.G.setOfNodes if n.uid == mfps.terminalNodeUid}.pop().datum.flowIn
if( (flow_to_t - flow_from_s) > 0.00):
raise Exception('Infeasible s-t flow')
return flow_to_t
def fast_e_k_preprocess(G):
G = strip_flows(G)
get = dict({})
get['nodes'] = dict({})
get['node_to_node_capacity'] = dict({})
get['node_to_node_flow'] = dict({})
get['arcs'] = dict({})
get['residual_arcs'] = dict({})
for a in G.setOfArcs:
if(a.fromNode not in G.setOfNodes):
err_msg = 'There is no Node {a.fromNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
if(a.toNode not in G.setOfNodes):
err_msg = 'There is no Node {a.toNode.uid!s} to match the Arc from {a.fromNode.uid!s} to {a.toNode.uid!s}'.format(**locals())
raise KeyError(err_msg)
get['nodes'][a.fromNode.uid] = a.fromNode
get['nodes'][a.toNode.uid] = a.toNode
lark = Arc(a.fromNode.uid, a.toNode.uid, FlowArcDatumWithUid(a.datum.capacity, a.datum.flow, uuid.uuid4()))
if(a.fromNode.uid not in get['arcs']):
get['arcs'][a.fromNode.uid] = dict({a.toNode.uid : dict({lark.datum.uid : lark})})
else:
if(a.toNode.uid not in get['arcs'][a.fromNode.uid]):
get['arcs'][a.fromNode.uid][a.toNode.uid] = dict({lark.datum.uid : lark})
else:
get['arcs'][a.fromNode.uid][a.toNode.uid][lark.datum.uid] = lark
for a in G.setOfArcs:
if a.toNode.uid not in get['arcs']:
get['arcs'][a.toNode.uid] = dict({})
for n in get['nodes']:
get['residual_arcs'][n] = dict()
get['node_to_node_capacity'][n] = dict()
get['node_to_node_flow'][n] = dict()
for u in get['nodes']:
n_to_u_cap_sum = sum(a.datum.capacity for a in G.setOfArcs if (a.fromNode.uid == n) and (a.toNode.uid == u) )
n_to_u_flow_sum = sum(a.datum.flow for a in G.setOfArcs if (a.fromNode.uid == n) and (a.toNode.uid == u) )
if(n_to_u_cap_sum > n_to_u_flow_sum):
flow = round(n_to_u_cap_sum - n_to_u_flow_sum, TOL)
get['residual_arcs'][n][u] = Arc(n,u,ResidualDatum(flow, 'push'))
if(n_to_u_flow_sum > 0.0):
flow = round(n_to_u_flow_sum, TOL)
get['residual_arcs'][u][n] = Arc(u,n,ResidualDatum(flow, 'pull'))
get['node_to_node_capacity'][n][u] = n_to_u_cap_sum
get['node_to_node_flow'][n][u] = n_to_u_flow_sum
return get
def fast_bfs(sid, tid, get):
parent_of = dict([])
visited = frozenset([])
deq = coll.deque([sid])
while len(deq) > 0:
n = deq.popleft()
if n == tid:
break
for u in get['residual_arcs'][n]:
if (u not in visited):
visited = visited.union(frozenset({u}))
parent_of[u] = get['residual_arcs'][n][u]
deq.extend([u])
path = list([])
curr = tid
while(curr != sid):
if (curr not in parent_of):
err_msg = 'No augmenting path from {} to {}.'.format(sid, curr)
raise StopIteration(err_msg)
path.extend([parent_of[curr]])
curr = parent_of[curr].fromNode
path.reverse()
return path
def fast_edmonds_karp(mfps):
sid, tid = mfps.sourceNodeUid, mfps.terminalNodeUid
get = fast_e_k_preprocess(mfps.G)
no_more_paths, loop_count = False, 0
while(not no_more_paths):
try:
apath = fast_bfs(sid, tid, get)
get = fast_augment(apath, get)
loop_count = 1
except StopIteration as e:
no_more_paths = True
nodes = frozenset(get['nodes'].values())
arcs = frozenset({})
for from_node in get['arcs']:
for to_node in get['arcs'][from_node]:
for arc in get['arcs'][from_node][to_node]:
arcs |= frozenset({get['arcs'][from_node][to_node][arc]})
G = DiGraph(nodes, arcs)
mfps = MaxFlowProblemState(G, sourceNodeUid=sid, terminalNodeUid=tid, maxFlowProblemStateUid=mfps.maxFlowProblemStateUid)
return mfps
```

Here’s a visualization of how this algorithm solves the example **flow network** from above. The visualization shows the steps as they are reflected in the **digraph** `G`

representing the most up-to-date **flow network** and as they are reflected in the **residual graph** of that flow network. **Augmenting paths** in the **residual graph** are shown as red paths, and the **digraph** representing the problem the set of **nodes** and **arcs** affected by a given **augmenting path** is highlighted in green. In each case, I’ll highlight the parts of the graph that will be changed (in red or green) and then show the graph after the changes (just in black).

Here’s another visualization of how this algorithm solving a different example **flow network**. Notice that this one uses real numbers and contains multiple **arcs** with the same `fromNode`

and `toNode`

values.

**Also notice that because Arcs with a ‘pull’ ResidualDatum may be part of the Augmenting Path, the nodes affected in the DiGraph of the Flown Network _may not be on a path in `G!`

.

Suppose we have a **digraph** `G`

, `G`

is bipartite if it’s possible to partition the **nodes** in `G.setOfNodes`

into two sets (`part_1`

and `part_2`

) such that for any **arc** `a`

in `G.setOfArcs`

it **cannot be true** that `a.fromNode`

in `part_1`

and `a.toNode`

in `part_1`

. It **also cannot be true** that `a.fromNode`

in `part_2`

and `a.toNode`

in `part_2`

.

In other words `G`

is **bipartite** if it can be partitioned into two sets of **nodes** such that every **arc** must connect a **node** in one set to a **node** in the other set.

Suppose we have a **digraph** `G`

, we want to test if it is **bipartite**. We can do this in `O(|G.setOfNodes| |G.setOfArcs|)`

by greedy coloring the graph into two colors.

First, we need to generate a new **digraph** `H`

. This graph will have will have the same set of **nodes** as `G`

, but it will have more **arcs** than `G`

. Every **arc** `a`

in `G`

will create 2 **arcs** in `H`

; the first **arc** will be identical to `a`

, and the second **arc** reverses the director of `a`

( `b = Arc(a.toNode,a.fromNode,a.datum)`

).

```
Bipartition = coll.namedtuple('Bipartition',['firstPart', 'secondPart', 'G'])
def bipartition(G):
nodes = frozenset(G.setOfNodes
arcs = frozenset(G.setOfArcs)
arcs = arcs.union( frozenset( {Arc(a.toNode,a.fromNode,a.datum) for a in G.setOfArcs} ) )
H = DiGraph(nodes, arcs)
H_as_dict = digraph_to_dict(H)
color = dict([])
some_node = next(iter(H.setOfNodes))
deq = coll.deque([some_node])
color[some_node] = -1
while len(deq) > 0:
curr = deq.popleft()
for a in H_as_dict.get(curr):
if (a.toNode not in color):
color[a.toNode] = -1*color[curr]
deq.extend([a.toNode])
elif(color[curr] == color[a.toNode]):
print(curr,a.toNode)
raise Exception('Not Bipartite.')
firstPart = frozenset( {n for n in color if color[n] == -1 } )
secondPart = frozenset( {n for n in color if color[n] == 1 } )
if( firstPart.union(secondPart) != G.setOfNodes ):
raise Exception('Not Bipartite.')
return Bipartition(firstPart, secondPart, G)
```

Suppose we have a **digraph** `G`

and `matching`

is a subset of **arcs** from `G.setOfArcs`

. `matching`

is a matching if for any two **arcs** `a`

and `b`

in `matching`

: `len(frozenset( {a.fromNode} ).union( {a.toNode} ).union( {b.fromNode} ).union( {b.toNode} )) == 4`

. In other words, no two **arcs** in a **matching** share a **node**.

**Matching** `matching`

, is a maximum matching if there is no other **matching** `alt_matching`

in `G`

such that `len(matching) < len(alt_matching)`

. In other words, `matching`

is a **maximum matching** if it is the largest set of **arcs** from `G.setOfArcs`

that still satisfies the definition of **matching** (the addition of any **arc** not already in the matching will break the **matching** definition).

A **maximum matching** `matching`

is a **perfect matching** if every for **node** `n`

in `G.setOfArcs`

there exists an **arc** `a`

in `matching`

where `a.fromNode == n or a.toNode == n`

.

A **maximum bipartite matching** is a **maximum matching** on a **digraph** `G`

which is **bipartite**.

Given that `G`

is **bipartite**, the problem of finding a **maximum bipartite matching** can be transformed into a **maximum flow problem** solvable with the **Edmonds-Karp** algorithm and then the **maximum bipartite matching** can be recovered from the solution to the **maximum flow problem**.

Let `bipartition`

be a **bipartition** of `G`

.

To do this, I need to generate a new **digraph** (`H`

) with some new **nodes** (`H.setOfNodes`

) and some new **arcs** (`H.setOfArcs`

). `H.setOfNodes`

contains all the **nodes** in `G.setOfNodes`

and two more **nodess**, `s`

(a **source node**) and `t`

(a **terminal node**).

`H.setOfArcs`

will contain one **arc** for each `G.setOfArcs`

. If an **arc** `a`

is in `G.setOfArcs`

and `a.fromNode`

is in `bipartition.firstPart`

and `a.toNode`

is in `bipartition.secondPart`

then include `a`

in `H`

(adding a `FlowArcDatum(1,0)`

).

If `a.fromNode`

is in `bipartition.secondPart`

and `a.toNode`

is in `bipartition.firstPart`

, then include `Arc(a.toNode,a.fromNode,FlowArcDatum(1,0))`

in `H.setOfArcs`

.

The definition of a **bipartite** graph ensures that no **arc** connects any **nodes** where both **nodes** are in the same partition. `H.setOfArcs`

also contains an **arc** from **node** `s`

to each **node** in `bipartition.firstPart`

. Finally, `H.setOfArcs`

contains an **arc** each **node** in `bipartition.secondPart`

to **node** `t`

. `a.datum.capacity = 1`

for all `a`

in `H.setOfArcs`

.

First partition the **nodes** in `G.setOfNodes`

the two disjoint sets (`part1`

and `part2`

) such that no **arc** in `G.setOfArcs`

is directed from one set to the same set (this partition is possible because `G`

is **bipartite**). Next, add all **arcs** in `G.setOfArcs`

which are directed from `part1`

to `part2`

into `H.setOfArcs`

. Then create a single **source node** `s`

and a single **terminal node** `t`

and create some more **arcs**

Then, construct a `maxFlowProblemState`

.

```
def solve_mbm( bipartition ):
s = Node(uuid.uuid4(), FlowNodeDatum(0,0))
t = Node(uuid.uuid4(), FlowNodeDatum(0,0))
translate = {}
arcs = frozenset([])
for a in bipartition.G.setOfArcs:
if ( (a.fromNode in bipartition.firstPart) and (a.toNode in bipartition.secondPart) ):
fark = Arc(a.fromNode,a.toNode,FlowArcDatum(1,0))
arcs = arcs.union({fark})
translate[frozenset({a.fromNode.uid,a.toNode.uid})] = a
elif ( (a.toNode in bipartition.firstPart) and (a.fromNode in bipartition.secondPart) ):
bark = Arc(a.toNode,a.fromNode,FlowArcDatum(1,0))
arcs = arcs.union({bark})
translate[frozenset({a.fromNode.uid,a.toNode.uid})] = a
arcs1 = frozenset( {Arc(s,n,FlowArcDatum(1,0)) for n in bipartition.firstPart } )
arcs2 = frozenset( {Arc(n,t,FlowArcDatum(1,0)) for n in bipartition.secondPart } )
arcs = arcs.union(arcs1.union(arcs2))
nodes = frozenset( {Node(n.uid,FlowNodeDatum(0,0)) for n in bipartition.G.setOfNodes} ).union({s}).union({t})
G = DiGraph(nodes, arcs)
mfp = MaxFlowProblemState(G, s.uid, t.uid, 'bipartite')
result = edmonds_karp(mfp)
lookup_set = {a for a in result.G.setOfArcs if (a.datum.flow > 0) and (a.fromNode.uid != s.uid) and (a.toNode.uid != t.uid)}
matching = {translate[frozenset({a.fromNode.uid,a.toNode.uid})] for a in lookup_set}
return matching
```

A node cover in a **digraph** `G`

is a set of **nodes** (`cover`

) from `G.setOfNodes`

such that for any **arc** `a`

of `G.setOfArcs`

this must be true: `(a.fromNode in cover) or (a.toNode in cover)`

.

A minimal node cover is the smallest possible set of **nodes** in the graph that is still a **node cover**. König’s theorem states that in a **bipartite** graph, the size of the **maximum matching** on that graph is equal to the size of the **minimal node cover**, and it suggests how the **node cover** can recovered from a **maximum matching**:

Suppose we have the **bipartition** `bipartition`

and the **maximum matching** `matching`

. Define a new **digraph** `H`

, `H.setOfNodes=G.setOfNodes`

, the **arcs** in `H.setOfArcs`

are the union of two sets.

The first set is **arcs** `a`

in `matching`

, with the change that if `a.fromNode in bipartition.firstPart`

and `a.toNode in bipartition.secondPart`

then `a.fromNode`

and `a.toNode`

are swapped in the created **arc** give such **arcs** a `a.datum.inMatching=True`

attribute to indicate that they were derived from **arcs** in a **matching**.

The second set is **arcs** `a`

NOT in `matching`

, with the change that if `a.fromNode in bipartition.secondPart`

and `a.toNode in bipartition.firstPart`

then `a.fromNode`

and `a.toNode`

are swapped in the created **arc** (give such **arcs** a `a.datum.inMatching=False`

attribute).

Next, run a **depth first search** (DFS) starting from each **node** `n`

in `bipartition.firstPart`

which is neither `n == a.fromNode`

nor `n == a.toNodes`

for any **arc** `a`

in `matching`

. During the DFS, some **nodes** are visited and some are not (store this information in a `n.datum.visited`

field). The **minimum node cover** is the union of the **nodes** `{a.fromNode for a in H.setOfArcs if ( (a.datum.inMatching) and (a.fromNode.datum.visited) ) }`

and the **nodes** `{a.fromNode for a in H.setOfArcs if (a.datum.inMatching) and (not a.toNode.datum.visited)}`

.

This can be shown to lead from a **maximum matching** to a **minimal node cover** by a proof by contradiction, take some **arc** `a`

that was supposedly not covered and consider all four cases regarding whether `a.fromNode`

and `a.toNode`

belong (whether as `toNode`

or `fromNode`

) to any **arc** in **matching** `matching`

. Each case leads to a contradiction due to the order that DFS visits **nodes** and the fact that `matching`

is a **maximum matching**.

Suppose we have a function to execute these steps and return the set of **nodes** comprising the **minimal node cover** when given the **digraph** `G`

, and the **maximum matching** `matching`

:

```
ArcMatchingDatum = coll.namedtuple('ArcMatchingDatum', ['inMatching' ])
NodeMatchingDatum = coll.namedtuple('NodeMatchingDatum', ['visited'])
def dfs_helper(snodes, G):
sniter, do_stop = iter(snodes), False
visited, visited_uids = set(), set()
while(not do_stop):
try:
stack = [ next(sniter) ]
while len(stack) > 0:
curr = stack.pop()
if curr.uid not in visited_uids:
visited = visited.union( frozenset( {Node(curr.uid, NodeMatchingDatum(False))} ) )
visited_uids = visited.union(frozenset({curr.uid}))
succ = frozenset({a.toNode for a in G.setOfArcs if a.fromNode == curr})
stack.extend( succ.difference( frozenset(visited) ) )
except StopIteration as e:
stack, do_stop = [], True
return visited
def get_min_node_cover(matching, bipartition):
nodes = frozenset( { Node(n.uid, NodeMatchingDatum(False)) for n in bipartition.G.setOfNodes} )
G = DiGraph(nodes, None)
charcs = frozenset( {a for a in matching if ( (a.fromNode in bipartition.firstPart) and (a.toNode in bipartition.secondPart) )} )
arcs0 = frozenset( { Arc(find_node_by_uid(a.toNode.uid,G), find_node_by_uid(a.fromNode.uid,G), ArcMatchingDatum(True) ) for a in charcs } )
arcs1 = frozenset( { Arc(find_node_by_uid(a.fromNode.uid,G), find_node_by_uid(a.toNode.uid,G), ArcMatchingDatum(True) ) for a in matching.difference(charcs) } )
not_matching = bipartition.G.setOfArcs.difference( matching )
charcs = frozenset( {a for a in not_matching if ( (a.fromNode in bipartition.secondPart) and (a.toNode in bipartition.firstPart) )} )
arcs2 = frozenset( { Arc(find_node_by_uid(a.toNode.uid,G), find_node_by_uid(a.fromNode.uid,G), ArcMatchingDatum(False) ) for a in charcs } )
arcs3 = frozenset( { Arc(find_node_by_uid(a.fromNode.uid,G), find_node_by_uid(a.toNode.uid,G), ArcMatchingDatum(False) ) for a in not_matching.difference(charcs) } )
arcs = arcs0.union(arcs1.union(arcs2.union(arcs3)))
G = DiGraph(nodes, arcs)
bip = Bipartition({find_node_by_uid(n.uid,G) for n in bipartition.firstPart},{find_node_by_uid(n.uid,G) for n in bipartition.secondPart},G)
match_from_nodes = frozenset({find_node_by_uid(a.fromNode.uid,G) for a in matching})
match_to_nodes = frozenset({find_node_by_uid(a.toNode.uid,G) for a in matching})
snodes = bip.firstPart.difference(match_from_nodes).difference(match_to_nodes)
visited_nodes = dfs_helper(snodes, bip.G)
not_visited_nodes = bip.G.setOfNodes.difference(visited_nodes)
H = DiGraph(visited_nodes.union(not_visited_nodes), arcs)
cover1 = frozenset( {a.fromNode for a in H.setOfArcs if ( (a.datum.inMatching) and (a.fromNode.datum.visited) ) } )
cover2 = frozenset( {a.fromNode for a in H.setOfArcs if ( (a.datum.inMatching) and (not a.toNode.datum.visited) ) } )
min_cover_nodes = cover1.union(cover2)
true_min_cover_nodes = frozenset({find_node_by_uid(n.uid, bipartition.G) for n in min_cover_nodes})
return min_cover_nodes
```

The linear assignment problem consists of finding a maximum weight matching in a weighted bipartite graph.

Problems like the one at the very start of this post can be expressed as a **linear assignment problem**. Given a set of workers, a set of tasks, and a function indicating the profitability of an assignment of one worker to one task, we want to maximize the sum of all assignments that we make; this is a **linear assignment problem**.

Assume that the number of tasks and workers are equal, though I will show that this assumption is easy to remove. In the implementation, I represent **arc weights** with an attribute `a.datum.weight`

for an **arc** `a`

.

```
WeightArcDatum = namedtuple('WeightArcDatum', [weight])
```

The Kuhn-Munkres Algorithm solves the **linear assignment problem**. A good implementation can take `O(N^{4})`

time, (where `N`

is the number of **nodes** in the **digraph** representing the problem). An implementation that is easier to explain takes `O(N^{5})`

(for a version which regenerates **DiGraphs**) and `O(N^{4})`

for (for a version which maintains **DiGraphs**). This is similar to the two different implementations of the **Edmonds-Karp** algorithm.

For this description, I’m only working with complete bipartite graphs (those where half the **nodes** are in one part of the **bipartition** and the other half in the second part). In the worker, task motivation this means that there are as many workers as tasks.

This seems like a significant condition (what if these sets are not equal!) but it is easy to fix this issue; I talk about how to do that in the last section.

The version of the algorithm described here uses the useful concept of **zero weight arcs**. Unfortunately, this concept only makes sense when we are solving a **minimization** (if rather than maximizing the profits of our worker-task assignments we were instead minimizing the cost of such assignments).

Fortunately, it is easy to turn a **maximum linear assignment problem** into a **minimum linear assignment problem** by setting each the **arc** `a`

weights to `M-a.datum.weight`

where `M=max({a.datum.weight for a in G.setOfArcs})`

. The solution to the original **maximizing problem** will be identical to the solution **minimizing problem** after the **arc** weights are changed. So for the remainder, assume that we make this change.

The **Kuhn-Munkres algorithm** solves **minimum weight matching in a weighted bipartite graph** by a sequence of **maximum matchings** in unweighted **bipartite** graphs. If a we find a **perfect matching** on the **digraph**representation of the **linear assignment problem**, and if the weight of every **arc** in the **matching** is zero, then we have found the **minimum weight matching** since this matching suggests that all **nodes** in the **digraph**have been **matched** by an **arc** with the lowest possible cost (no cost can be lower than 0, based on prior definitions).

No other **arcs** can be added to the **matching** (because all **nodes** are already matched) and no **arcs** should be removed from the **matching** because any possible replacement **arc** will have at least as great a weight value.

If we find a **maximum matching** of the subgraph of `G`

which contains only **zero weight arcs**, and it is not a **perfect matching**, we don’t have a full solution (since the **matching** is not **perfect**). However, we can produce a new **digraph** `H`

by changing the weights of **arcs** in `G.setOfArcs`

in a way that new 0-weight **arcs** appear and the optimal solution of `H`

is the same as the optimal solution of `G`

. Since we guarantee that at least one **zero weight arc** is produced at each iteration, we guarantee that we will arrive at a **perfect matching** in no more than **|G.setOfNodes|^{2}=N^{2}** such iterations.

Suppose that in **bipartition** `bipartition`

, `bipartition.firstPart`

contains **nodes** representing workers, and `bipartition.secondPart`

represents **nodes** representing tasks.

The algorithm starts by generating a new **digraph** `H`

. `H.setOfNodes = G.setOfNodes`

. Some **arcs** in `H`

are generated from **nodes** `n`

in `bipartition.firstPart`

. Each such **node** `n`

generates an **arc** `b`

in `H.setOfArcs`

for each **arc** `a`

in `bipartition.G.setOfArcs`

where `a.fromNode = n`

or `a.toNode = n`

, `b=Arc(a.fromNode, a.toNode, a.datum.weight - z)`

where `z=min(x.datum.weight for x in G.setOfArcs if ( (x.fromNode == n) or (x.toNode == n) ))`

.

More **arcs** in `H`

are generated from **nodes** `n`

in `bipartition.secondPart`

. Each such **node** `n`

generates an **arc** `b`

in `H.setOfArcs`

for each **arc** `a`

in `bipartition.G.setOfArcs`

where `a.fromNode = n`

or `a.toNode = n`

, `b=Arc(a.fromNode, a.toNode, ArcWeightDatum(a.datum.weight - z))`

where `z=min(x.datum.weight for x in G.setOfArcs if ( (x.fromNode == n) or (x.toNode == n) ))`

.

**KMA:** Next, form a new **digraph** `K`

composed of only the **zero weight arcs** from `H`

, and the **nodes** incidenton those **arcs**. Form a `bipartition`

on the **nodes** in `K`

, then use `solve_mbm( bipartition )`

to get a **maximum matching** (`matching`

) on `K`

. If `matching`

is a **perfect matching** in `H`

(the **arcs** in `matching`

are **incident** on all **nodes** in `H.setOfNodes`

) then the `matching`

is an optimal solution to the **linear assignment problem**.

Otherwise, if `matching`

is not **perfect**, generate the **minimal node cover** of `K`

using `node_cover = get_min_node_cover(matching, bipartition(K))`

. Next, define `z=min({a.datum.weight for a in H.setOfArcs if a not in node_cover})`

. Define `nodes = H.setOfNodes`

, `arcs1 = {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh-z)) for a in H.setOfArcs if ( (a.fromNode not in node_cover) and (a.toNode not in node_cover)}`

, `arcs2 = {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh)) for a in H.setOfArcs if ( (a.fromNode not in node_cover) != (a.toNode not in node_cover)}`

, `arcs3 = {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh z)) for a in H.setOfArcs if ( (a.fromNode in node_cover) and (a.toNode in node_cover)}`

. The `!=`

symbol in the previous expression acts as an XOR operator. Then `arcs = arcs1.union(arcs2.union(arcs3))`

. Next, `H=DiGraph(nodes,arcs)`

. Go back to the label **KMA**. The algorithm continues until a **perfect matching** is produced. This **matching** is also the solution to the **linear assignment problem**.

```
def kuhn_munkres( bipartition ):
nodes = bipartition.G.setOfNodes
arcs = frozenset({})
for n in bipartition.firstPart:
z = min( {x.datum.weight for x in bipartition.G.setOfArcs if ( (x.fromNode == n) or (x.toNode == n) )} )
arcs = arcs.union( frozenset({Arc(a.fromNode, a.toNode, ArcWeightDatum(a.datum.weight - z)) }) )
for n in bipartition.secondPart:
z = min( {x.datum.weight for x in bipartition.G.setOfArcs if ( (x.fromNode == n) or (x.toNode == n) )} )
arcs = arcs.union( frozenset({Arc(a.fromNode, a.toNode, ArcWeightDatum(a.datum.weight - z)) }) )
H = DiGraph(nodes, arcs)
assignment, value = dict({}), 0
not_done = True
while( not_done ):
zwarcs = frozenset( {a for a in H.setOfArcs if a.datum.weight == 0} )
znodes = frozenset( {n.fromNode for n in zwarcs} ).union( frozenset( {n.toNode for n in zwarcs} ) )
K = DiGraph(znodes, zwarcs)
k_bipartition = bipartition(K)
matching = solve_mbm( k_bipartition )
mnodes = frozenset({a.fromNode for a in matching}).union(frozenset({a.toNode for a in matching}))
if( len(mnodes) == len(H.setOfNodes) ):
for a in matching:
assignment[ a.fromNode.uid ] = a.toNode.uid
value = sum({a.datum.weight for a in matching})
not_done = False
else:
node_cover = get_min_node_cover(matching, bipartition(K))
z = min( frozenset( {a.datum.weight for a in H.setOfArcs if a not in node_cover} ) )
nodes = H.setOfNodes
arcs1 = frozenset( {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh-z)) for a in H.setOfArcs if ( (a.fromNode not in node_cover) and (a.toNode not in node_cover)} )
arcs2 = frozenset( {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh)) for a in H.setOfArcs if ( (a.fromNode not in node_cover) != (a.toNode not in node_cover)} )
arcs3 = frozenset( {Arc(a.fromNode,a.toNode,ArcWeightDatum(a.datum.weigh z)) for a in H.setOfArcs if ( (a.fromNode in node_cover) and (a.toNode in node_cover)} )
arcs = arcs1.union(arcs2.union(arcs3))
H = DiGraph(nodes,arcs)
return value, assignment
```

This implementation is `O(N^{5})`

because it generates a new **maximum matching** `matching`

at each iteration; similar to the previous two implementations of **Edmonds-Karp** this algorithm can be modified so that it keeps track of the matching and adapts it intelligently to each iteration. When this is done, the complexity becomes `O(N^{4})`

. A more advanced and more recent version of this algorithm (requiring some more advanced data structures) can run in `O(N^{3})`

. Details of both the simpler implementation above and the more advanced implementation can be found at this post which motivated this blog post.

None of the operations on **arc** weights modify the final assignment returned by the algorithm. Here’s why: Since our input graphs are always **complete bipartite graphs** a solution must map each **node** in one partition to another **node** in the second partition, via the **arc** between these two **nodes**. Notice that the operations performed on the **arc** weights never changes the order (ordered by weight) of the **arcs** incident on any particular **node**.

Thus when the algorithm terminates at a **perfect complete bipartite matching** each **node** is assigned a **zero weight arc**, since the relative order of the **arcs** from that **node** hasn’t changed during the algorithm, and since a **zero weight arc** is the cheapest possible **arc** and the **perfect complete bipartite matching** guarantees that one such **arc** exists for each **node**. This means that the solution generated is indeed the same as the solution from the original **linear assignment problem** without any modification of **arc** weights.

It seems like the algorithm is quite limited since as described it operates only on **complete bipartite graphs**(those where half the **nodes** are in one part of the **bipartition** and the other half in the second part). In the worker, task motivation this means that there are as many workers as tasks (seems quite limiting).

However, there is an easy transformation that removes this restriction. Suppose that there are fewer workers than tasks, we add some dummy workers (enough to make the resulting graph a **complete bipartite graph**). Each dummy worker has an **arc** directed from the worker to each of the tasks. Each such **arc** has weight 0 (placing it in a matching gives no added profit). After this change the graph is a **complete bipartite graph**which we can solve for. Any task assigned a dummy worker is not initiated.

Suppose that there are more tasks than workers. We add some dummy tasks (enough to make the resulting graph a **complete bipartite graph**). Each dummy task has an **arc** directed from each worker to the dummy task. Each such **arc** has a weight of 0 (placing it in a matching gives no added profit). After this change the graph is a **complete bipartite graph** which we can solve for. Any worker assigned to dummy task is not employed during the period.

Finally, let’s do an example with the code I’ve been using. I’m going to modify the example problem from here. We have 3 tasks: we need to **clean the bathroom**, **sweep the floor**, and **wash the windows**.

The workers available to use are **Alice**, **Bob**, **Charlie**, and **Diane**. Each of the workers gives us the wage they require per task. Here are the wages per worker:

Clean the Bathroom | Sweep the Floor | Wash the Windows | |
---|---|---|---|

Alice | $2 | $3 | $3 |

Bob | $3 | $2 | $3 |

Charlie | $3 | $3 | $2 |

Diane | $9 | $9 | $1 |

If we want to pay the least amount of money, but still get all the tasks done, who should do what task? Start by introducing a dummy task to make the digraph representing the problem bipartite.

Clean the Bathroom | Sweep the Floor | Wash the Windows | Do Nothing | |
---|---|---|---|---|

Alice | $2 | $3 | $3 | $0 |

Bob | $3 | $2 | $3 | $0 |

Charlie | $3 | $3 | $2 | $0 |

Diane | $9 | $9 | $1 | $0 |

Supposing that the problem is encoded in a **digraph**, then `kuhn_munkres( bipartition(G) )`

will solve the problem and return the assignment. It’s easy to verify that the optimal (lowest cost) assignment will cost $5.

Here’s a visualization of the solution the code above generates:

That is it. You now know everything you need to know about the linear assignment problem.

You can find all of the code from this article on GitHub.

Always be happy and make the crazy effort for what you do in life.

Jay Ambe, Namaste (greeting we Hindu people follow same like “bye” in English)

]]>Information security is a fascinating field of knowledge that can involve anything from theoretical computer science to software engineering, and even observe the psychology of human error.

Cryptography is now one of the many anonymous technological heroes of our daily life. Social networks, web banking, military intelligence, and any other information system that deals with sensitive information all rely heavily on cryptography. Cryptography allows us to have privacy, which some consider the 12th human right.

This article will give you an introduction to the principles behind public-key cryptosystems and introduce you to the Santana Rocha-Villas Boas (SRVB), a cryptosystem developed by the author of the article and prof. Daniel Santana Rocha. At the time of writing, the algorithm authors are cooking up a campaign that includes a financial reward to anyone who manages to crack the code. Since the article will cover the algorithm functionality in detail, this is the best place to start the pursuit for the prize. More information is available on the SRVB site.

Cryptography is any method to hamper the interpretability of a message, while still allowing a way to feasibly interpret it as long as a specific instruction is provided, which is usually the so called “key.” While this is a very broad definition that encompases even the earliest techniques, it is worthy to mention that this does not cover everything there is to information security.

The technological race between encryption methods and ways to crack them is expected to never have a definitive winner. Each new generation is expected to raise the standards of information security and cryptanalysis, which is the set of techniques to systematically decipher/break encrypted messages, i.e., bypass the security or encryption.

In order for a cryptosystem (given technique of cryptography) to be deemed secure by its users, it has to receive the approval of the international community of experts, and thus be publicly known, which is known as Kerckhoffs’ principle. Yet, this very condition exposes the system to scrutiny from the world’s cryptanalysis community, who will try to devise ways of systematically breaking the encryptions.

How can one make a given encryption process secret enough that only the intended agents can decrypt it, while at the same time public enough that the world’s cryptanalysis community can attest its robustness? The answer is a component which is a key element of Cryptology: the key. A key of a cryptosystem is a parameter for either the encryption or decryption algorithms, or both. By keeping the parameters secret, rather than the algorithm family, both contradictory requirements can be achieved. Provided that the family of parameters is large enough (possibly infinite) and each of its components can be proved to have adequate properties, it will not be feasible for attackers to determine the parameters merely by inspection.

Finally, in order for a key to work effectively, it must be easily produced but nearly impossible to guess. With the computational power of today’s computers, a computer would need less time to decipher a human generated key than any human would need to even imagine it, on top of the fact that it’s not cost effective to generate keys in that way anyway. Because of that, keys tend to be generated by an algorithm.

A key generating algorithm must not create predictable/reproducible output as a result of typical use. Since algorithms perform procedures without any intelligent process to it, the question becomes how this can be done. The answer is turning key generating algorithms into maps that transform a large amount of truly random bits into keys. Truly random bits can be acquired from the operating system, which generates them from uncertainty in the universe. Some sources would be your mouse movement, network package latencies, or even dedicated hardware, depending on the application.

Prepare to be surprised yet again, because we shall now introduce a concept that seemingly contradicts what we have just said: the public key.

So far, we have seen the creation of secure communication after secret parameters (keys) have been securely exchanged, but the problem of exchanging the parameters over a public channel remains. Right now, we will introduce a concept that solves a slightly more palpable problem: the creation of a secure channel.

Suppose Alice is working with Bob, and they want to keep their work interactions secure using encryption. They can meet and exchange their encryption keys by giving each other a USB flash drive with their keys on them. But what if Alice and Bob are located on different continents. How to establish a secure channel where there are none existing?

Sending keys via email wouldn’t be an option, since their competitor Eve can intercept the exchange and use their keys to read all the encrypted data afterward. If they had any other digital channel through which they could transmit this sensitive data, then they wouldn’t need encryption, and thus keys, in the first place. Sending the key via physical mail still could also be intercepted, for it requires exchanging sensitive information to begin with. Sending a steganographed key by hiding within other data would be clever, but useless unless the sender is sure that the recipient, and the recipient alone, is aware of the existence of such a message and knows how extract it. As it happens, the awareness of the existence of a message together with the description of how to extract the key from the data is a type of key by itself, which brings us back to square one.

The solution is devising a cryptosystem for which the encryption parameter is not enough to feasibly construe the original message^{[1]}, and keeping to yourself the parameter that would allow construing of the message. We call that parameter the private key. Based on the private key, one can feasibly generate a set of parameters for an encryption tool without making those new parameters themself able to reveal what the private key is. That set of parameters can be publicly shared, because it’s not that important who can encrypt something, as long as only one person can decrypt it. Since this set of parameters for the encryption tool can be made public, it is called a public key.

Cryptography where the encryption and decryption keys differ, and the former can not feasibly be used to deduce the latter, is called asymmetric cryptography, while symmetric cryptography is what we have when those keys are the same, or are easily deduced from one another.

Alice sends Bob her public key, which can only be used to encrypt things that only she can decrypt (with her private key, which she keeps privately) and, conversely, Bob sends Alice his public key, which can only be used to encrypt things that he alone can decrypt (by means of his private key, which he also keeps privately). But how can one possibly publish a parameter for an encryption algorithm from which one cannot deduce the exact inverse algorithm?

The answer lies in the field of mathematics that is closest related to programming, the computational complexity theory. Anyone who has delved deep enough into mathematical problems has heard about transformations that are easy to do in one way, but hard to do the inverse. In calculus, for example, finding a textbook derivative typically is a straightforward exercise, while doing the inverse (like solving any slightly non trivial integral or textbook physical ODE or PDE, for example) requires a more investigative process of first hypothesizing families of functions that are guaranteed (or at least plausible) to contain the solution(s) and solve inverse problems to find solutions from these families.

An example that is actually utilized in the RSA cryptosystem is multiplying big primes versus factoring the resulting product without already knowing the factors. Doing multiplication is trivial, but factoring requires you to randomly^{[2]} guess the prime factors, which have hundreds of digits. An important property of the operation is the need for it to scale well. Adding a few digits on the size of the prime numbers in RSA will result in a key that requires thousands of times more operations to crack while adding a tiny increase in complexity to the encryption process. Very roughly speaking, the product of prime numbers is used for encrypting, while the pair of prime factors are used for decrypting.

With all of this in mind, let’s take a look at how the SRVB cryptosystem works.

Like any other public-key cryptosystem, SRVB relies on the difficulty of solving a particular problem that is easy to produce. In SRVB’s case, it’s the subset sum problem, which can be described as follows:

Given the integer w and v1,⋅⋅⋅,vN∈Z find the sequence x1,⋅⋅⋅,xN∈0,1, such that ∑i=1Nvixi=w3.

Clearly, this problem can be produced by randomly picking N integers, randomly choosing a subset of them and summing up this subset – which is trivial.

A brute-force search would have a complexity of O(N∗2N), calculating for each combination of values of the x-es. A more efficient approach was given by Horowitz and Sahni in 1972, with a complexity of O(N∗2N/2). The problem is at least as hard if we replace the x-es and w with k-dimensional vectors of integers. The realm where this more difficult problem is to be held, however, must also have an isomorphismwith a ring where an easier version of the same problem takes place, as we shall see below. For this reason, SRVB exploits the subset sum problem within Gaussian integers, where k=2.

There is a special case where this problem gets easy to compute through the use of a greedy algorithm. If we sort a sequence scaling factors v1,⋅⋅⋅,vN in which each integer in the sequence is larger than the sum of all the integers that came before it (∀i,∑j=1i−1vj<vi), one could use a greedy approach to find the sequence `x`

in linear time. A sequence with the described properties is called a **superincreasing sequence**.

Here is a simple description of the greedy solution for this case:

- Start with i=N, the currently observed factor, and w′=w, the remainder of w
- If the current scaling factor is too big to fit into what remains of w, meaning vi>w′, set xi=0 and continue to the next step. Otherwise we know that the scaling factor needs to be in the sequence (since the rest of the factors is smaller than vi) and we set xi=1.
- w′⇐w′−vi∗xi, i⇐i−1. If i>0, return to step 2.
- Verify that, now, w′==0, otherwise the problem was corrupted

This works because we know that all multipliers smaller than the currently observed one can’t collectively cover as much of the (sub)sum w′ as the current multiplier can. So if the remaining sum is larger than the current factor, we know for sure that all following factors together will fail to sum up to it without the current factor’s help. On the other hand, since all multipliers are positive, if the current factor vi is larger than the remaining sum w′, adding any other factor would make the result surpass w′ even more.

Let’s set up a notation for the rest of the article. We choose v1,⋅⋅⋅,vn and w to be the factors and sum of the superincreasing sequence, while u1,⋅⋅⋅,un and y will be the publicly available parameters that are provided to recover x1,⋅⋅⋅,xn.

With a sequence u1,⋅⋅⋅,un picked so it is not superincreasing, and number y being publicly available, not enough information is publicly provided to recover the sequence x1,⋅⋅⋅,xn. However, if there is a superincreasing sequence v1,⋅⋅⋅,vn that could take the place of sequence u1,⋅⋅⋅,un, one could use this sequence to solve the problem with a greedy approach.

Below we shall show how that works.

In 1978, Ralph Merkle and Martin Helman, devised a way to exploit those two knapsack paradigms and the linearity of the modulus operation to build the connection between the two sequences described in the previous section – thus conceiving a Public-Key Cryptosystem. The idea was to transform the *easy knapsack*(the one consisting of the superincreasing vector of integers) into the hard one (the one lacking this property) by means of a linear operation (the modulus) with secret operands. The transformation consists of multiplying every vi by a θ and taking the remainder of this product by an α, where α>∑i=1Nvi and gcd(α,θ)=1 (two constraints that will soon be justified). The result, the sequence u1,…,uN, is not superincreasing anymore, and can be considered a *hard knapsack*.

A random permutation of the sequence u1,…,uN would be given to the party that wants to encrypt and send a message to us. The permutation is done so that a third party has a harder time of guessing what the original superincreasing sequence is. Bit blocks of a message are used as the coefficients x1,…,xN. Encryption is done by multiplying the key sequence with this sequence of coefficients, and summing up the multiplications into a result, that we shall label y. Only the owner of the private key can transform y into the corresponding w that would be obtained if these same x1,…,xN blocks would have been multiplied with the *easy integers* (the sequence v1,…,vN). That is done by means of multiplying y by θ−1, the multiplicative inverse of θ modulus α (whose existence depends on that condition of gcd(α,θ)=1). In other words, (θ∗θ−1)modα=1. After that, we calculate w=(y∗θ−1)moda. The reason this is guaranteed to work is the *linearity of modulus*, i.e., that *the linear combination of the remainders equals the remainder of the linear combination.*

If we consecutively apply the definition of u, the quotient ring, and the property of linearity of the modulus operator, we see the correspondence:

y=∑i=1Nxiui=∑i=1Nxi(vi∗θmodα)=∑i=1Nxi∗vi∗θmodα=[∑i=1Nxi∗vi∗θ]modα=[∑i=1Nxi∗vi]∗θmodα=w∗θmodα

And thus the *easy sum* w can be recovered by multiplying both sides with θ−1 and taking the modulus with α. To do so, one has to know both α and θ (that allow one to easily calculate θ−1), which are to be kept private as parts of the private key.

One single constraint, α>∑i=1Nvi, was left unjustified and here goes the explanation for it: The equality between the second and third lines consists of an equality between residue classes of the quotient ring of integers modulo α. In other words, it only states the equality of the remainder of the members when divided by α, **which is not a sufficient condition for the equality of the members themselves**. As a result, more than one vector of x values could be mapped into a single y, which is prevented by limiting w to be smaller than αfor any combination of x values.

Just like any other instance of daily life, complete knowledge of all hypotheses is often impossible and never easy. As a result, we have to rely on mathematical intuition when judging if a cryptosystem is safe to use, which provides us no actual guarantees. Six years after its creation, the MH cryptosystem was broken with an attack by A. Shamir. There were several more attempts to revive MH, many of which also failed.

In 2016, after a few brainstorms with this article’s author about differently inspired^{[3]} possibilities of a cryptosystem, Daniel Santana Rocha had the idea of substituting θ and α by Gaussian Integers. For more technical reasons, this approach leads to the resistance against the aforementioned Shamir attack.

He also conceived a bit block consisting of many steps of the previously described linear combination of a *hard knapsack*. In each one of them, a new (Gaussian) integer, equivalent to one, higher than the sum of all previous would be added at the end of the sequence, while the currently smallest would be dropped.

A different and yet elegantly analogous constraint applies for α, which is now a Gaussian integer. We require for w≤|α|2, where w is, again, the highest linear combination of the natural integers of the easy knapsack. The reason is very hard to formalize, but fortunately it can be easily intuited from an elegant description:

Imagine a square lattice in the plane of complex numbers, whose side is a hypotenuse of a rectangle triangle of sides a and b, parallel to the real and imaginary axes. An example of such lattice is given below. Guassian integers modulo α=a bi can be represented by points located within such a lattice. Within such a lattice there are |α|2 distinct points. If we pick a large enough α, we can fit all of the linear combinations of the easy knapsack. So we are setting a requirement for w←|α|2, where w is [as described].

This is the graphic representation of the isomorphism f:Z/n→Z[i]/(α), where n=13 and α=a bi=3 2i (note that n and α indeed satisfy n=|α|2=a2 b2 as required). The dots represent the Gaussian Integers, i.e., the complex numbers a bi, where a and b are integers. As usual, the horizontal axis represents the real part, while the vertical represents the imaginary part. Thus, moving one dot to the right or left is equivalent to adding 1 or -1 to its current value, respectively. Likewise, moving one dot upwards or downwards corresponds to adding i or -i, respectively.

The red dots are those equivalents to 0mod(α). Apart from these, we also colored 4 more pairs of dots.

Color | Equivalent to … mod α |

Orange | 1 |

Green | i |

Blue | −1−i |

Violet | 1−i |

The isomorphism f is defined by the transformation of the i−th element of the cyclic sequence (0,1,2,⋅⋅⋅,10,11,12,0,1,2,⋅⋅⋅) into the i−th element of the also cyclic sequence of dots in the figure, that adheres to the following rules:

- It starts from the red dot of the first row;
- It follows the horizontal right arrows; except that
- When following the arrows leads the sequence outside of the lattice, it would reach one of the non-black points. Instead of going to that point, it jumps to the same colored point (i.e., the equivalent point modulo α) inside of the same square; and finally
- When this non-black point happens to be red (which happens after all the other colors have been passed through), the sequence jumps to the uppermost red dot, thus reinitiating the cycle;

In order to map at least Y natural integers, one must take a square with area |α|2 (where |α|=a2 b2 is, by Pythagorean theorem, the measure of its side) at least as high.

Notice that each “jump” changes the row number r to r←(r−b)(moda b) if one counts the rows from top down, and, equivalently, to r←(r a)(moda b) if one counts from bottom up. Hence, the necessary and sufficient condition for each row (and dot) to be roamed exactly once on each cycle is that the size of the jumps is coprime with the number of rows, or, in other words, gcd(a,a b)=gcd(b,a b)=1. Due to properties of the greatest common divisor operator, both of these are equivalent to gcd(a,b)=1.

Y. S. Villas Boas noticed the need for coprimality of a and b. In order to preserve superincreasingness, each new integer w added at the end of the sequence needs to surpass the sum of all current ones (w>∑i=1kvi). He observed that in order to achieve this, their multiplying coefficients xi would have to be at least 1, and thus, each bit could not be mapped into the coefficients 0 and 1. If the coefficients were 0 and 1, only the block composed only of ones would satisfy the superincreasingness. For this reason, the bits 0 and 1 were then mapped respectively to the multiplying coefficients 1 and 2.

Finally, and less trivially: during each step of the decoding, one new integer v1 is to be found as solution of the equation x1v1=vn 1−∑i=2nxivi, where all vi and xi are known for 1≤i≤n. Since we also don’t know x1, we end up with a system with one equation and two variables, which leaves us with one degree of freedom. To correct this, we have to arbitrate one positive value (for the sake of simplicity, 1) to be always assigned to x1, thus eliminating the ambiguity. Thus, since the first coefficient is fixed to 1, in order to encode n bits on each step, our sequences of integers must be n 1 elements long.

One final technicality to resolve is the case in which the size in bytes of the message is not a multiple of the block size. In other words, what to do with the possible remaining bytes of the last data block so that, once the data blocks are recovered, all the bytes of the original content are preserved, but no more than them? We solved that by repeating the last byte of the message once. This copy is, then, followed by a random sequence on which each component is required only to be different from the previous one. Thus, when the data blocks are retrieved, the last of them *or, in the worst case, the one before the last* is truncated in the last repetition of bytes.^{[4]}

Now let’s show an example of the SRVB cryptosystem.

We start with the parameters:

k=4;

m=4;

which yields a block size of b8=4∗4=16, and a superincreasing sequence of k 1=5 natural integers, that is operated—*i.e., linearly combined, appended with the result of this linear combination, and reduced to its last k 1 elements*—m=4 times;

For the sake of simplicity, let the following be the (superincreasing) vector of vi:

(1,2,4,8,16)

Indeed, the sequence of the first five powers of 2, just because this is the superincreasing sequence with five elements and the smallest strictly positive possible values (thus avoiding a 0 in the public key, which would trivially give away the correspondent 0 of its counterpart).

As we said earlier, for α=a bi, the integers a and b must be coprime, and according to the new constraint we mentioned, we have to request that a2 b2=|α|2≥W. A quick calculation yields W=1590. Since 1590≃39.8, a very convenient α to be chosen would be α=39 40i, for it is just large enough to accommodate an isomorphism with a ring of integers with at least 1590 components, while also satisfying gcd(a,b)=1. Also, we need to pick a θ such that gcd(a,θ)=1^{[5]} and preferably that is not too low, so that (a1∗θ)%α≠v1∗θ, (also to avoid giving away information). θ=60 does the job, yielding:

−19−1i,1 38i,3−3i,6−6i,12−12i^{[6]}

Let us get our hands dirty, then. Take the message `Hello Toptal!`

. First we map it into an array of bytes according to ASCII and our convention for truncating data blocks:

```
01001000 01100101
01101100 01101100
01101111 00100000
01010100 01101111
01110000 01110100
01100001 01101100
00100001 00100001
```

Since our data block is 16 bits = 2 bytes long, and our message has 13 characters, we end up with 7 data blocks of 2 bytes each, where the last one contains two times the bit representation of the character ‘!’ . Let us encrypt the first block step by step. Pay close attention because the bits of each byte are taken in order of their significance.

m=0100100001100101

- First nibble of first byte: (0,0,0,1)→(1,1,1,1,2)⋅(−19−1i,1 38i,3−3i,6−6i,12−12i)=15 4i
- Second nibble of first byte: (0,0,1,0)→(1,1,1,2,1)⋅(1 38i,3−3i,6−6i,12−12i,15 4)=49 9i
- First nibble of second byte: (0,1,0,0)→(1,1,2,1,2)⋅(3−3i,6−6i,12−12i,15 4i,49 9i)=106−10i
- Second nibble of second byte: (0,1,1,0)→(1,1,2,2,1)⋅(6−6i,12−12i,15 4i,49 9i,106−10i)=252−2i

And thus, we have just mapped

“He” ⇒(12−12i,15 4i,49 9i,106−10i,252−2i)

The rest of the encrypted message is as follows:

“ll” ⇒(12−12i,21−2i,61−3i,185−31i,367−59i)

“o “ ⇒(12−12i,25 33i,65 32i,111 44i,244 124i)

“To” ⇒(12−12i,9 10i,46 12i,149 5i,277 31i)

“pt” ⇒(12−12i,3 16i,46 12i,73 23i,201 49i)

“al” ⇒(12−12i,4 54i,44 53i,117 193i,231 389i)

”!!” ⇒(12−12i,4 54i,32 65i,63 92i,121 247i)

Now, for the decryption, we have θ−1=60−1=27 i:

(”He” ⇒) (12−12i,15 4i,49 9i,106−10i,252−2i)∗θ−1%α=(16,47,93,223,527)

Now, comes the greedy algorithm:

First, we subtract each contributing factor multiplied by one, because they are known to have contributed at least once for the last, yielding:

- Second nibble of the second byte:

T←(527−233−93−47−16)=148

(T≥223)=(148≥223)=false⇒x1=0;T←(T−0∗223)=148

(T≥93)=(148≥93)=true⇒x2=1;T←(T−1∗93)=55

(T≥47)=55≥47)=true⇒x3=1;T←(T−1∗47)=8

(T≥16)=8≥16)=false⇒x4=0;T←(T−0∗16)=8

Result: 0110;

Remainder: 8 (added to the beginning of the sequence as new lowest element);

Drop 527 from the final of the current sequence;

- First nibble of the second byte:

T←(233−93−47−16−8)=59

(T≥93)=(59≥93)=false⇒x1=0;T←(T−0∗93)=59

(T≥47)=(59≥47)=true⇒x2=1;T←(T−1∗47)=12

(T≥16)=(12≥16)=false⇒x3=0;T←(T−0816)=12

(T≥8)=(12≥8)=true⇒x4=1;T←(T−0∗12)=4

Result: 0101;

Remainder: 4 (added to the beginning of the sequence as new lowest element);

Drop 233 from the final of the current sequence;

- Second nibble of the first byte:

T←(93−47−16−8−4)=18

(T≥47)=(18≥47)=false⇒x1=0;T←(T−0∗47)=18

(T≥16)=(18≥16)=true⇒x2=1;T←(T−1∗16)=2

(T≥8)=(2≥8)=false⇒x3=0;T←(T−0∗8)=2

(T≥4)=(2≥4)=false⇒x4=0;T←(T−0∗4)=2

Result: 0100;

Remainder: 2 (added to the beginning of the sequence as new lowest element);

Drop 93 from the final of the current sequence;

- First nibble of the first byte:

T←(47−16−8−4−2)=17

(T≥16)=(17≥16)=true⇒x1=1;T←(T−1∗16)=1

(T≥8)=(1≥8)=false⇒x2=0;T←(T−0∗8)=1

(T≥4)=(1≥4)=false⇒x3=0;T←(T−0∗4)=1

(T≥2)=(1≥4)=false⇒x4=0;T←(T−0∗2)=1

Result: 1000;

Remainder: 1 (added to the beginning of the sequence as new lowest element);

Drop 47 from the final of the current sequence;

As a result, we have recovered the data block: “01001000 01100101” containing the first two characters “He”, of our message. Not only that, we have also correctly retrieved our private-key superincreasing sequence (1,2,4,8,16).

The other data blocks maps go in the same way.

SRVB is:

- Totally free and public;
- Considerably simpler and easier to understand and implement than ECC
^{[7]}; - Abundant on keys and hence virtually costless, contrary, for example, to RSA, which relies on prime numbers, which are expensive.

We can already sum up the most likely vulnerabilities. Since SRVB descends from MH, it is easy to suspect it would be vulnerable to a generalization of the Shamir attack, or some other that breaks it. Though the author had reasons to believe that this would not be the case, no confirmation of it has yet been done (which is very typical when dealing with cryptosystems).

Rocha observed a few generalizations for the quotient rings to be used, that can possibly lead to an increase in the complexity of the cryptanalysis. We shall investigate these possibilities as well.

As it happens, during the development and documentation of SRVB, Villas Boas came up with yet another approach to improve the concept of knapsack public-key cryptosystem that will not be explained in much details herein, in order to this article not to become too long and tiresome, but here is a skimming of it. If you don’t succeed in grasping it, don’t worry, just stay tuned for the release of our next article, in which we shall go into the details more thoroughtly: See the subset sum y, of the, say, N quotient ring elements ui (that are isomorphically correspondent to the positive integers vi of the super increasing sequence, as before) as a multiplication of a row vector of these ui by a column vector B (for binary) of zeroes and ones^{[8]}.

y=∑i=1nuixi=(u1,⋅⋅⋅,un)T⋅(x1,⋅⋅⋅,xn)=UB,

where xi∈0,1

Now, imagine that, instead of this vector of ui, you have, on the left a n by N (with n<N) matrix V, having the vi (the integers from the superincreasing sequence) vector as (without loss of generality) its first row and all the other entries filled up with noise. Notice that, now, multiplying V by the same bits vector B gives you a column vector W that has w as its first entry and noise in the others. Now, take this V matrix and multiply it by a random^{[9]} n by n matrix R on the left, defining the n by N matrix P:

P = RV

The idea is that Bob uses P as his new public key. Because of the randomness of R, the vector

Y=PB=RVB=RW

has the information w obscured by the noise in other rows of V. Bob also calculates in advance and stores the row vector S that satisfies:

RTST=e1

When, Alice sends Y to Bob, he just finds SY, because:

SY=S(PB)=S((RV)B)=e1TR−1((RV)B)=

(so far only definitions)

e1T(R−1R)(VB)=e1TW=w

(Now, exploiting the associativity to cancel the Rs)

and then proceeds as before to extract the vector of xi from w by means of the greedy algorithm.

So, in one word, the Linear Algebraic Obscuring exploits the associativity of matricial multiplication (the fact that we could expand the terms and then operate their components in a new order provided we that preserved the sequence of all the operands in the sequence) to ‘linearly’ scramble and then filter (in the encryption and in the decryption respectively) noise to/from w. And in limit case n=1, the system elegantly goes back to original to Rocha’s approach.

As explained before, in accordance to Kerckhoffs’ principle, experience shows that antiquity of a publicly known unbroken cryptosystem is the main source of reliability of it, far more than any theoretical argumentation by the own authors, apart from anything else, because definitive proof of efficacy of the algorithms usually are not available.

And here it is our great chance to put these concepts to practice to earn a big money prize: Aware of this fact, we launched the aforementioned campaign, which is basically a crowdfunding for a prize automatically awarded to the first one that manages to break a message. The money is going to be converted to bitcoins in a given wallet whose private key will be SRVB encrypted and published so that anyone able to decipher it can simply take the money anonymously, no questions asked.

This article in particular and the whole SRVB Crypto project in general have been greatly helped by Dr. Charles Figueiredo de Barros, assistant professor at the Federal University of São João Del Rei. Prof. Barros provided us a technical review of the SRVB cryptosystem itself. I judged it necessary to submit to before daring to publish, and that I would certainly take much longer to do by myself.

In addition, I also would like to extend my deep gratitude to professor Adnan Ademovic for his extraordinarily insightful, attentive, and patient work as the editor of this article.

Glossary

**Cryptology/Cryptography:**The science/practice of making a message nearly impossible to interpret without a specific set of instructions (in this context, the so-called “key”), thus allowing agents who share these instructions to communicate securely even if tapped by third parties;**Steganography:**The science/practice of hiding a message within another by means of adding apparently innocuous modifications to the latter;**Key generation:**the mapping of (expectedly) random inputs into (as random) valid keys;**Encryption/Encoding:**The easily computable mapping of an easily interpretable message into another that is either hard or impossible to construe, by means of an (as randomly specified) element*the one correspondent to the key*of a (by Kerckhoffs’ principle, publicly known and validated) family of algorithms;**Decryption/Decoding:**The easily computable mapping that consists of the inverse of the previous, also being definable by an (as randomly specified, and therefore, unknown and hard to be guessed by third parties) element _again, the one correspondent to the key_ of a (by the same principle, usually known) family of algorithms, that thus outputs the original message when input with the encrypted one;**Cryptosystem:**A triad of the family of encoding algorithms, the family of corresponding decrypting algorithms, and a key generating algorithm;**Allies:**The agents with whom the communication is intended, and who are expected to act according to the protocol’s rules;**Enemies/Third Parties:**The agents with whom the communication is not intended, but try, nevertheless, to eavesdrop the communication and bypass the security enhanced by the cryptosystem;**Secure Channel:**Any protocol (procedure) for communication that is easy to use while also effectively preventing third parties to feasibly construe what is meant by its users;**Insecure Channel:**any channel (i.e., protocol or procedure) that, as the name suggests, is not a secure channel;**Breaking a Key:**The process of discovering a key by means of public pieces of information (like an encrypted message or public key) other than the key itself to be discovered and that was not expected to feasibly allow the discovery of the key. Since the information that results from this process grants the decryption of the messages, this is a particular case of…**Breaking/Deciphering a message:**Any way to deduce the original content of an encrypted message only by means of the encrypted message itself and other pieces of information that were not expected to suffice for the deduction of the original content;**Breaking a Cryptosystem:**Discovery of a systematic way to feasibly break whatever message is encrypted by this method under whatever parameter;**Kerckhoffs’ Principle/Desideratum/Axiom/Law:**A cryptologic principle named after the dutch cryptographer Auguste Kerckhoffs, according to which, in order for a cryptosystem to be deemed secure, everything about it except by its (private) keys must be of public knowledge;**Key:**Secret parametrization of a cryptosystem allowing it to be infeasible to be guessed (and consequently broken) by third parties while also being validated by the community of cryptanalysts (in accordance to Kerckhoffs’ principle);**Symmetric Cryptosystem:**Any cryptosystem on which any parameter for the encoding suffices for easily deducing the parameter for decoding, and, for this reason, must be kept private. One can rephrase it by saying that the encryption and decryption parameters are both equivalent to the key;**Asymmetric/Public Key Cryptosystem:**Any cryptosystem for which there is a way to express the parameters for the encoding that does not suffice to feasibly deduce the correspondent parameter for decoding, allowing it to be sent to allies through an insecure channel, or even made public, and thus creating a secure channel where there was none;**Public Key:**A component of an asymmetric cryptosystem that suffices for parameterizing the encryption but does not suffice for feasibly deducing the decryption parameter, i.e., the…**Private Key:**A component of an asymmetric cryptosystem that suffices for parameterizing the decryption*and thus must be kept privately*and usually also suffices for parameterizing the encryption;

^{[1]} Note that, here, the phrases *decipher* or *decrypt* do not apply, because before a given cryptosystem (with all its components, including its keys) is well defined, one cannot classify a given method of construing the original message from the encrypted one as the intended communication (decryption) or an attack (deciphering).

^{[2]} Though there are techniques to improve this guessing work, it still remains far more difficult discovering than multiplying them.

^{[3]} The first inspiration was to look at the tree of the tau conjecture, an infinite tree rooted in the number 1, whose other nodes consist of integers resulting in one binary operation of sum, subtraction, or multiplication between previous nodes, possibly one node operated with itself. The theory’s goal relates to the depth, in this tree, in which each integer first appears. It is apparently hard to find large numbers in low branches (even if we relax the need for it), but is it immediate to check if a given sequence of operations indeed produces a given result.

^{[4]} This is surely not the most natural approach, but by adopting this, one ensures that this byte filling (called padding)…

- Conceals the size of the padding (differently, for example of ciphertext stealing) and obscures the end of the message, thus rendering chosen-plaintext attacks more difficult;
- Enhances a distribution of bits as close to uniform as possible;

If the last blocks of every message were known to be systematically biased in a far from uniform distribution, an attacker could exploit this fact to do a statistical cryptanalysis, for any given sample of messages would be statistically more representative than otherwise. In other words, the last blocks being statistically less diverse, they become they become the weakest links of the message.

^{[5]} Make no mistake: this greatest common divisor is Gaussian, while the previous is real.

^{[6]} …which is not perfect, because it easily gives away the fact that the last three components are proportional to 1, 2, and 4. But, again, for the sake of simplicity, we will ignore this detail.

^{[7]} …which is so complex that there are a few notorious cases of failure to implement and maintain protocols based on it.

^{[8]} Here, we will not adopt Rocha’s approach of a multiple linear combinations block, which also allows us to randomly permute the bis to obscure them even more.

^{[9]} Though not totally random. Its transpose must span the subspace generated by the vector e1 = (1,0,…,0).

Always be happy and make the crazy effort for what you do in life.

Jay Ambe, Namaste (greeting we Hindu people follow same like “bye” in English)

]]>Business cards are a necessary part of our life. Let’s assume you meet someone, and you don’t have enough time to stand and talk to that person not even to write down the contact details. Even with the advancement of technology, there is simply too much information to input quickly.

Not to mention there is still something business-like about giving or receiving a business card. That said, you do not want a whole stack of business cards working out at home.

Where do you even buy Rolodex’s anymore? Well, if you are after a business card scanner to help keep all those important contact details safe then check out ** The Tech’s** pick of the best business card scanner apps for Android.

CamCard is one of the most popular card scanner app available being used by 100 million users worldwide. As a Business Card reader application, CamCard allows you to read and save your business card directly into the device instead of keeping it in your wallet. CamCard Scanner also provides some other features along with Card Scanning like exchange e-cards as well as call and find directions to contacts (based on inputted cards) directly from within the app. As business is international, it is also worth noting this one can read sixteen languages. If you want a tried and testing option, then this might be the one for you.

ABBYY offers business Card Reader Free. It is popular app being used by 1 Million peoples. Business Card Read Free allow scanning and reading of cards in up to 21 languages. There are other features besides the card scanning which enable you to annotate notes for each card, share via your device’s internal stock options and stay on top of those important contacts.

Around 50K users are using this application to scan a business card. This one is pro-business card reader it includes property scanning features and offers higher levels of integration with the compatibility of 250 apps. This app is compatible with services like SalesForce, SugarCRM, Dropbox and Evernote. If you are serious about card reading app then it worth a look.

Hope this list helps you to choose the **best business card scanner app for Android**.

Always be happy and make the crazy effort for what you do in life.

Jay Ambe, Namaste (greeting we Hindu people follow same like “bye” in English)

]]>Since the term the World Wide Web was coined back in 1990, web application development has evolved from serving static HTML pages to completely dynamic, complex business applications.

Today we have thousands of digital and printed resources that provide step-by-step instructions about developing all kinds of different web applications. Development environments are “smart” enough to catch and fix many mistakes that early developers battled with regularly. There are even many different development platforms that easily turn simple static HTML pages into highly interactive applications.

All of these development patterns, practices, and platforms share common ground, and they are all prone to similar web development issues caused by the very nature of web applications.

The purpose of these web development tips is to shed light on some of the common mistakes made in different stages of the web development process and to help you become a better developer. I have touched on a few general topics that are common to virtually all web developers such as validation, security, scalability, and SEO. You should of course not be bound by the specific examples I’ve described in this guide, as they are listed only to give you an idea of the potential problems you might encounter.

Validating user input on client and server side is simply **a must do**! We are all aware of the sage advice **“do not trust user input”** but, nevertheless, mistakes stemming from validation happen all too often.

One of the most common consequences of this mistake is **SQL Injection** which is in OWASP Top 10 year after year.

Remember that most front-end development frameworks provide out-of-the-box validation rules that are incredibly simple to use. Additionally, most major back-end development platforms use simple annotations to assure that submitted data are adhering to expected rules. Implementing validation might be time consuming, but it should be part of your standard coding practice and never set aside.

Before we proceed, let’s make sure we are aligned on these two terms. As stated in the 10 Most Common Web Security Vulnerabilities:

**Authentication**: Verifying that a person is (or at least appears to be) a specific user, since he/she has correctly provided their security credentials (password, answers to security questions, fingerprint scan, etc.).

**Authorization**: Confirming that a particular user has access to a specific resource or is granted permission to perform a particular action.

Stated another way, authentication is knowing who an entity is, while authorization is knowing what a given entity can do.

Let me demonstrate this issue with an example:

Consider that your browser holds currently logged user information in an object similar to the following:

```
{
username:'elvis',
role:'singer',
token:'123456789'
}
```

When doing a password change, your application makes the POST:

```
POST /changepassword/:username/:newpassword
```

In your `/changepassword`

method, you verify that user is logged and **token has not expired**. Then you find the user profile based on the `:username`

parameter, and you change your user’s password.

So, you validated that your user is properly logged-in, and then you executed his request thus changing his password. Process seems OK, right? Unfortunately, the answer is NO!

At this point it is important to verify that the user executing the action and the user whose password is changed are the same. Any information stored on the browser can be tampered with, and any advanced user could easily update `username:'elvis'`

to `username:'Administrator'`

without using anything else but built-in browser tools.

So in this case, we just took care of `Authentication`

making sure that the user provided security credentials. We can even add validation that `/changepassword`

method can only be executed by `Authenticated`

users. However, this is still not enough to protect your users from malicious attempts.

You need to make sure that you verify actual requestor and content of request within your `/changepassword`

method and implement proper `Authorization`

of the request making sure that user can change only her data.

`Authentication`

and `Authorization`

are two sides of the same coin. Never treat them separately.

In today’s world of high speed development, startup accelerators, and instant global reach of great ideas, having your MVP (Minimum Viable Product) out in the market as soon as possible is a common goal for many companies.

However, this constant time pressure is causing even good web development teams to often overlook certain issues. Scaling is often one of those things teams take for granted. The MVP concept is great, but push it too far, and you’ll have serious problems. Unfortunately, selecting a scalable database and web server and separating all application layers on independent scalable servers is not enough. There are many details you need to think about if you wish to avoid rewriting significant parts of your application later – which becomes a major web development problem.

For example, say that you choose to store uploaded profile pictures of your users directly on a web server. This is a perfectly valid solution–files are quickly accessible to the application, file handling methods are available in every development platform, and you can even serve these images as static content, which means minimum load on your application.

But what happens when your application grows, and you need to use two or more web servers behind a load balancer? Even though you nicely scaled your database storage, session state servers, and web servers, your application scalability fails because of a simple thing like profile images. Thus, you need to implement some kind of file synchronization service (that will have a delay and will cause temporary 404 errors) or another workaround to assure that files are spread across your web servers.

What you needed to do to avoid the problem in the first place was just use shared file storage location, database, or any other remote storage solution. It would have probably cost few extra hours of work to have it all implemented, but it would have been worth the trouble.

The root cause of incorrect or missing SEO best practices on web sites is **misinformed “SEO specialists”**. Many web developers believe that they know enough about SEO and that it is not especially complex, but that’s just not true. SEO mastery requires significant time spent researching best practices and the ever-changing rules about how Google, Bing, and Yahoo index the web. Unless you constantly experiment and have accurate tracking analysis, you are not a SEO specialist, and you should not claim to be one.

Furthermore, SEO is too often postponed as some activity that is done at the end. This comes at a high price of web development issues. SEO is not just related to setting good content, tags, keywords, meta-data, image alt tags, site map, etc. It also includes eliminating duplicate content, having crawlable site architecture, efficient load times, intelligent back linking, etc.

Like with scalability, you should think about SEO from the moment you start building your web application, or you might find that completing your SEO implementation project means rewriting your whole system.

One of the best examples of this mistake is sending email based on a user action. Too often developers think that making a SMTP call and sending a message directly from user request handler is the solution.

Let’s say you created an online book store, and you expect to start with a few hundred orders daily. As part of your order intake process, you send confirmation emails each time a user posts an order. This will work without problem at first, but what happens when you scale your system, and you suddenly get thousands of requests sending confirmation emails? You either get SMTP connection timeouts, quota exceeded, or your application response time degrades significantly as it is now handling emails instead of users.

Any time or processor consuming action should be handled by an external process while you release your HTTP requests as soon as possible. In this case, you should have an external mailing service that is picking up orders and sending notifications.

Most development and testing takes place in a local network environment. So when you are downloading 5 background images each being 3MB or more, you might not identify an issue with 1Gbit connection speed in your development environment. But when your users start loading a 15MB home page over 3G connections on their smartphones, you should prepare yourself for a list of complaintsand problems.

Optimizing your bandwidth usage could give you a great performance boost, and to gain this boost you probably only need a couple of tricks. There are few things that many good web deveopers do by default, including:

- Minification of all JavaScript
- Minification of all CSS
- Server side HTTP compression
- Optimization of image size and resolution

Responsive design has been a big topic in the past few years. Expansion of smartphones with different screen resolutions has brought many new ways of accessing online content, which also comes with a host of web development issues. The number of website visits that come from smartphones and tablets grows every day, and this trend is accelerating.

In order to ensure seamless navigation and access to website content, you must enable users to access it from all types of devices.

There are numerous patterns and practices for building responsive web applications. Each development platform has its own tips and tricks, but there are some frameworks that are platform independent. The most popular is probably Twitter Bootstrap. It is an open-source and free HTML, CSS, and JavaScript framework that has been adopted by every major development platform. Just adhere to Bootstrap patterns and practices when building your application, and you will get responsive web application with no trouble at all.

The development process is, in most cases, under a heavy time pressure. Every application needs to be released as soon as possible and even good web developers are often focused on delivering functionality over design. Regardless of the fact that most developers have Chrome, Firefox, IE installed, they are using only one of these 90% of the time. It is common practice to use one browser during development and just as the application nears completion will you start testing it in other browsers. This is perfectly reasonable–assuming you have a lot of time to test and fix issues that show up at this stage.

However, there are some web development tips that can save you significant time when your application reaches the cross-browser testing phase:

- You don’t need to test in all browsers during development; it is time consuming and ineffective. However, that does not mean that you cannot switch browsers frequently. Use a different browser every couple of days, and you will at least recognize major problems early in development phase.
- Be careful of using statistics to justify not supporting a browser. There are many organizations that are slow in adopting new software or upgrading. Thousands of users working there might still need access to your application, and they cannot install the latest free browser due to internal security and business policies.
- Avoid browser specific code. In most cases there is an elegant solution that is cross-browser compatible.

*Assumption is the mother of all problems*! When it comes to portability, this saying is more true than ever. How many times have you seen issues in web development like hard coded file paths, database connection strings, or assumptions that a certain library will be available on the server? Assuming that the production environment will match your local development computer is simply wrong.

Ideal application setup should be maintenance-free:

- Make sure that your application can scale and run on a load-balanced multiple server environment.
- Allow simple and clear configuration–possibly in a single configuration file.
- Handle exceptions when web server configuration is not as expected.

RESTful API’s have taken their place in web development and are here to stay. Almost every web application has implemented some kind of REST services, whether for internal use or integrating with external system. But we still see broken RESTful patterns and services that do not adhere to expected practices.

Two of the most common mistakes made when writing a RESTful API are:

- Using wrong HTTP verbs. For example using GET for writing data. HTTP GET has been designed to be idempotent and safe, meaning that no matter how many times you call GET on the same resource, the response should always be the same and no change in application state should occur.
- Not sending correct HTTP status codes. The best example of this mistake is sending error messages with response code 200.
`HTTP 200 OK { message:'there was an error' }`

You should only send HTTP 200 OK when the request has not generated an error. In the case of an error, you should send 400, 401, 500 or any other status code that is appropriate for the error that has occurred.

A detailed overview of standard HTTP status codes can be found here.

Web development is an extremely broad term that can legitimately encompass development of a website, web service, or complex web application.

The main takeaway of this web development guide is the reminder that you should always be careful about authentication and authorization, plan for scalability, and never hastily assume anything – or be ready to deal with a long list of web development problems!

hey guys, checkout TOPTAL for very good articles like this.

Always be happy and make the crazy effort for what you do in life.

Jay Ambe, Namaste (greeting we Hindu people follow same like “bye” in English)

]]>The central government recently announced that **Aadhaar card is mandatory for bank accounts.** It shall be mandatory to link Aadhaar numbers to all non-small bank accounts, failing which, access to the bank accounts will be disabled after December 31. This requirement has been brought into the law via Prevention of Money-laundering (Maintenance of Records) (Second Amendment) Rules, 2017 which have been notified by the government under powers delegated to it by the parliament through the Prevention of Money Laundering Act, 2002 (PMLA).

Government has made Aadhaar card mandatory for opening new accounts. It has noted that all existing bank accounts will have to be linked with Aadhaar number by December 31, 2017 or else they will be declared invalid.

More significantly, not only Aadhaar Card has been mandatory for opening new accounts but also for carrying out high-value transactions. The government has said that transactions worth Rs 50,000 or more will now require Aadhaar number. This is similar to how PAN number was required for high-value transactions. But now instead of PAN, consumers will have to quote Aadhaar number. While the deadline for linking bank accounts to Aadhaar number is the end of the year, it is not yet clear since when quoting Aadhaar for transactions will become mandatory.

The government move to link all bank accounts with Aadhaar number comes days after the Supreme Court partially struck down the government proposal to make Aadhaar mandatory for filing of tax returns. While the government wanted all tax payers to quote Aadhaar number, the court said that only those who have the Aadhaar could be compelled to do so. Those who do not have Aadhaar number can file the tax without it after July 1 and their PAN card will not be invalidated, noted the court. However, the latest move from the government ensures that all tax payers, irrespective of the Supreme Court directive, will have to quote Aadhaar number while filing the tax returns.

The important points:

1- Aadhaar number is now mandatory for opening any new bank account.

2- It is now mandatory to link Aadhaar number with a bank account, even if your bank account is fully KYCed. This has to be done by December 31, 2017.

3- It is now mandatory to quote Aadhaar number in case of a transaction worth Rs 50,000 or more.

4- In case you don’t have Aadhaar number, you will not be able to avail banking services after December 31.

Namaste.

]]>Hey Guys today I am informing you about “**Rumor about nine banks to be closed**“.

Recently, you must have come across a WatsApp message, which lists nine banks that Reserve Bank of India will apparently shut down. The message ends with a warning for readers to manage their cash immediately. This message creates chaos and make people freaking out. Also, a video published by “Whistleblower News India” on YouTube about nine banks will be shutting down due to their NPA (Non performing Asset) or bad loan problem. People are worrying about their accounts with these listed banks. However, turns out this is just a spam. So, take a look and know what this is about.

This WatsApp message in question lists Corporation Bank, UCO Bank, IDBI Bank, Bank of Maharashtra, Andhra Bank, Indian Overseas Bank, Central Bank of India, Dena Bank, and the United Bank of India. According to the forwarded message,” these nine banks will be permanently shut down by the central bank, and that people should take suitable action in respect of your cash in your account (all types).”

Or

Nine banks will be closed permanently by Reserve bank of India. If anybody having transactions in it please kindly withdraw it.

The names of the banks are:

Corporation Bank,

UCO Bank,

IDBI,

Bank of Maharashtra,

Andhra Bank,

Indian Overseas Bank,

Central Bank of India,

Dena Bank and United Bank of India

However, the truth being, Reserve Bank of India cannot actually shut these banks down, even if it were to; these listed banks are owned by the government of India. Reportedly, there is no discussion of any permanent shut down of these banks, but they are going under a Prompt Corrective Action (PCA) invoked by the Reserve Bank of India. The PCA is essentially meant to have a bank focus on their recovery of bad loans. And despite going under the PCA, there is no restriction on taking deposits or giving out loans for these banks.

As per the RBI notification(June 5,2017)

RBI Clarification on Banks under Prompt Corrective Action

The Reserve Bank of India has come across some misinformed communication circulating in some section of media including social media, about the Prompt Corrective Action (PCA) framework.

The Reserve Bank has clarified that the PCA framework is not intended to constrain normal operations of the banks for the general public.

It is further clarified that the Reserve Bank, under its supervisory framework, uses various measures/tools to maintain sound financial health of banks. PCA framework is one of such supervisory tools, which involves monitoring of certain performance indicators of the banks as an early warning exercise and is initiated once such thresholds as relating to capital, asset quality etc. are breached. Its objective is to facilitate the banks to take corrective measures including those prescribed by the Reserve Bank, in a timely manner, in order to restore their financial health. The framework also provides an opportunity to the Reserve Bank to pay focused attention on such banks by engaging with the management more closely in those areas. The PCA framework is, thus, intended to encourage banks to eschew certain riskier activities and focus on conserving capital so that their balance sheets can become stronger.

The Reserve Bank has emphasized that the PCA framework has been in operation since December 2002 and the guidelines issued on April 13, 2017 is only a revised version of the earlier framework.

Ajit Prasad

Assistant AdviserPress Release: 2016-2017/3288

You can check every information which RBI release on below link of RBI website:

https://www.rbi.org.in/Scripts/BS_PressReleaseDisplay.aspx

]]>

Reliance **Jio Hacked**, yes guys your heard it right. 2 days before Private data of customers of Jio was compromised through the hacking attack and users information like name, email, activation date, and AAdhar number was showing up.

Company Jio said breach data is “unverified and unsubstantiated claims”, but added that it has informed the government about the incident.

A website **magicapk.com** went live last night, providing information for every Reliance Jio owner. It has data like names, email IDs, mobile numbers, date of activation of sim card and circle of activation.

Even though the website has been taken down ever since, the data is out there and might pop up on some other website. You could easily search for someone’s data by entering the Jio mobile number. **Thankfully Aadhaar number was hidden or blurred, but this means that it can be still be made public.**

But many users confirmed their personal data showed up on the website, displaying their names, email addresses and most alarmingly, in some cases, Aadhaar numbers.

In response to the breach, Reliance Jio released a statement, saying that the claims are unverified and that the leaked data appears to be “unauthentic.”

“We have come across the unverified and unsubstantiated claims of the website and are investigating it. Prima facie, the data appears to be unauthentic,” a spokesperson said.

“We want to assure our subscribers that their data is safe and maintained with highest security. Data is only shared with authorities as per their requirement.”

The Jio spokesperson said the company has “informed law enforcement agencies about the claims of the website and will follow through to ensure strict action is taken.”

when this breach occurred many people tried it and verified the leak for a few Jio numbers, and the data came out to be accurate for some Jio numbers, but not for all.

Therefore, the data on the website seems to be authentic, but luckily some customers are spared–probably those who have been issued Jio SIM after the breach.

hackers details are still not available. The website which was showing hacked data was hosted by GoDaddy.com and was registered in May 2017, but so far it is not clear who owned the domain.

Also, it is not clear that how the hackers got access to Jio customers details and were it Jio who got hacked or some third-party marketing company with whom the company shared its customer’s data.

Though there is very little victims (especially those who have exposed their Aadhaar number) can do to protect themselves from future attacks. All Jio customers are highly recommended to be alert for the suspicious calls and message who ask for further details or account passwords. No company asks for these details over phone calls or emails.

Victims should also particularly be alert of the Phishing emails, which are usually the next step of cyber criminals after a large-scale hack at any telecoms company. Phishing tricks users into giving up further personal details like passwords.

This episode is a reminder that your data with large organizations is unsafe too unless the company has some strict encryption measures in place. However, even online organizations like Google, Facebook, and Twitter have had data breaches in the past, only to have stronger algorithms in place to tackle hackers.

find out our video on youtube below.