This is the seventh part of the ILP series. For your convenience you can find other parts in the table of contents in Part 1 – Boolean algebra
We have already seen how to multiply variables in ILP. In part 5 we saw how to define minimum and absolute value. Last time we improved our multiplication algorithm. Today we are going to handle negative numbers.
Table of Contents
General idea
First let’s summarize what we can do already:
- We are able to decompose variable and extract its digits
- We can multiply two binary digits by calculating their conjunction
- We know how to multiply non-negative number by single binary digit using minimum function
- We can multiply two non-negative numbers by decomposing latter argument, multiplying its digits by former argument and power of two, and summing the results
- We know how to compare numbers and so we are able to deduce whether a number is negative (by comparing it with zero)
We would like to multiply possibly negative numbers. We will do that by multiplying their absolute values (so ignoring the sign) and then changing the sign if necessary.
First step – multiplying absolute values
We start with the following variables:
We have arguments (), result (), upper bound (), and digits of . We first define:
Here we multiply variables by using already described algorithms.
Second step – calculating the sign
Next, we calculate the sign:
will be one only when and have the same sign (so they are both negative or both positive). When the arguments have different signs, will be equal to zero.
Final step – changing the sign of the result
Now we are going to set the sign of the result. We multiply the result of multiplication of absolute values by the sign:
When the sign is equal to one the will be equal to . Otherwise, it will be equal to zero.
Now we are going to set the final result using this formula:
When the result should be non-negative, the sign will be equal to one, so the will be equal to , and we will get . However, when the result should be negative, the sign will be zero, the will be equal to zero, and we will get .
Division poses multiple difficulties. First, it may introduce representation errors since we need to use fractions. Second, some solvers do not support non-integer values at all so they cannot multiply negative variables. There are ways to avoid division completely and we should use them if possible.
Changing the result sign with maximum and minimum
Instead of dividing we can use maximum and minimum. This formula is a basic extension of multiplication by a binary digit:
When the result should be positive then is equal to one and first component of the sum is equal to . Second part of the sum is equal to zero as we take maximum of some negative number and zero. Hence the whole sum is equal to which is as expected.
However, when is equal to zero and the result should be negative, first part of the sum is equal to zero because we take minimum of and zero. Second part of the sum is equal to because we take maximum of and very small number.
Changing the result sign with subtraction
We can calculate the final result even easier using subtraction:
If the result should be non-negative then is equal to one so the formula simplifies to . However, when result should be non-postive and is equal to zero then we obtain .
This is simple and elegant, and it doesn’t introduce unnecessary floating point issues.
Summary
We are now able to multiply any integer variables for which we know upper and lower bound. In the next part we will use this operation to calculate greatest common divisor (GCD).