How to Add Numbers in a Matrix to Yield Minimum Result? - c++

This is more of an algorithmic/math problem but I'm hoping to implement a solution in C++.
Suppose I have a matrix like so where the dots represent integers:
W X Y Z
A . . . .
B . . . .
C . . . .
D . . . .
How would I yield the minimum result if I had to pick one number from each column such that there is at most one number from each row?
For instance, I could choose AW BX CY DZ or AZ BX CY DW but NOT AW BW CZ DZ
The brute force approach would seem to take n! calculations. Is there a quicker way? Eventually I would like to add numbers in matrices of size ~60.
Also, all numbers range from 0 to 256.

And if you'd rather not code it yourself, you could always use someone else' hard-work and kind publication. This one in Haskell, solves a 60x60 random matrix in less than two tenths of a second on my old laptop. What a great algorithm!
import Data.Algorithm.Munkres
import Data.Array.Unboxed
import Data.List (transpose)
solve n matrix =
hungarianMethodInt (listArray ((1,1),(n,n)) $ concat $ transpose matrix)

Related

SymPy cannot solve the equation cos(x) = - 1 /cosh(x)

In Wolfram|Alpha, one can solve cos λ = -1/cosh λ:
λ = ± 1.87510406871196...
λ = ± 4.69409113297417...
λ = ± 7.85475743823761...
λ = ± 10.9955407348755...
Why does cos(x) = - 1 /cosh(x) not work in SymPy?
I tried this:
from sympy import *
x = symbols('x', real=True)
eq = cos(x) + 1 /cosh(x)
ans=solve(eq)
print(ans)
# NotImplementedError: multiple generators [cos(x), exp(x)]
# No algorithms are implemented to solve equation cos(x) + 1/(exp(x)/2 + exp(-x)/2)
--------------
(2018/08/21)
Graphing Calculator
https://www.numberempire.com/graphingcalculator.php?functions=cos(x)%2C-1%2Fcosh(x)&xmin=0&xmax=10&ymin=-1.5&ymax=1.5&var=x
https://www.numberempire.com/graphingcalculator.php?functions=cos(x)*cosh(x)%2C-1&xmin=-10&xmax=10&ymin=-1.5&ymax=1.5&var=x
"Sym" in SymPy stands for symbolic. Did WolframAlpha find a symbolic solution? No, it did not; because there isn't one. So, SymPy did not find one, either.
What you got from WolframAlpha is a numeric solution. To get those, there are other Python libraries, most notably SciPy.
However, SymPy can get you numeric solutions too, by calling mpmath under the hood. This is done with nsolve. It takes a second argument, initial point of the search for solution, and returns one solution.
>>> nsolve(eq, 0)
7.85475743823761
If you want more, try multiple starting points:
>>> {nsolve(eq, n) for n in range(-10, 10)}
{4.69409113297418, -1.87510406871196, 7.85475743823761, -7.85475743823761, 1.87510406871196, -10.9955407348755, -4.69409113297418}
Here I tried 20 starting points, some roots were repeated, hence the use of a set to eliminate the repetition.
There are infinitely many solutions; whatever tool is used, you'll only get several of those. But for large x, 1/cosh(x) is effectively 0, so the roots are approximately the same as cos(x) = 0, which are pi/2 + pi*k, any integer k.

Fitting a Gaussian, getting a straight line. Python 2.7

As my title suggests, I'm trying to fit a Gaussian to some data and I'm just getting a straight line. I've been looking at these other discussion Gaussian fit for Python and Fitting a gaussian to a curve in Python which seem to suggest basically the same thing. I can make the code in those discussions work fine for the data they provide, but it won't do it for my data.
My code looks like this:
import pylab as plb
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy import asarray as ar,exp
y = y - y[0] # to make it go to zero on both sides
x = range(len(y))
max_y = max(y)
n = len(y)
mean = sum(x*y)/n
sigma = np.sqrt(sum(y*(x-mean)**2)/n)
# Someone on a previous post seemed to think this needed to have the sqrt.
# Tried it without as well, made no difference.
def gaus(x,a,x0,sigma):
return a*exp(-(x-x0)**2/(2*sigma**2))
popt,pcov = curve_fit(gaus,x,y,p0=[max_y,mean,sigma])
# It was suggested in one of the other posts I looked at to make the
# first element of p0 be the maximum value of y.
# I also tried it as 1, but that did not work either
plt.plot(x,y,'b:',label='data')
plt.plot(x,gaus(x,*popt),'r:',label='fit')
plt.legend()
plt.title('Fig. 3 - Fit for Time Constant')
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()
The data I am trying to fit is as follows:
y = array([ 6.95301373e+12, 9.62971320e+12, 1.32501876e+13,
1.81150568e+13, 2.46111132e+13, 3.32321345e+13,
4.45978682e+13, 5.94819771e+13, 7.88394616e+13,
1.03837779e+14, 1.35888594e+14, 1.76677210e+14,
2.28196006e+14, 2.92781632e+14, 3.73133045e+14,
4.72340762e+14, 5.93892782e+14, 7.41632194e+14,
9.19750269e+14, 1.13278296e+15, 1.38551838e+15,
1.68291212e+15, 2.02996957e+15, 2.43161742e+15,
2.89259207e+15, 3.41725793e+15, 4.00937676e+15,
4.67187762e+15, 5.40667931e+15, 6.21440313e+15,
7.09421973e+15, 8.04366842e+15, 9.05855930e+15,
1.01328502e+16, 1.12585509e+16, 1.24257598e+16,
1.36226443e+16, 1.48356404e+16, 1.60496345e+16,
1.72482199e+16, 1.84140400e+16, 1.95291969e+16,
2.05757166e+16, 2.15360187e+16, 2.23933053e+16,
2.31320228e+16, 2.37385276e+16, 2.42009864e+16,
2.45114362e+16, 2.46427484e+16, 2.45114362e+16,
2.42009864e+16, 2.37385276e+16, 2.31320228e+16,
2.23933053e+16, 2.15360187e+16, 2.05757166e+16,
1.95291969e+16, 1.84140400e+16, 1.72482199e+16,
1.60496345e+16, 1.48356404e+16, 1.36226443e+16,
1.24257598e+16, 1.12585509e+16, 1.01328502e+16,
9.05855930e+15, 8.04366842e+15, 7.09421973e+15,
6.21440313e+15, 5.40667931e+15, 4.67187762e+15,
4.00937676e+15, 3.41725793e+15, 2.89259207e+15,
2.43161742e+15, 2.02996957e+15, 1.68291212e+15,
1.38551838e+15, 1.13278296e+15, 9.19750269e+14,
7.41632194e+14, 5.93892782e+14, 4.72340762e+14,
3.73133045e+14, 2.92781632e+14, 2.28196006e+14,
1.76677210e+14, 1.35888594e+14, 1.03837779e+14,
7.88394616e+13, 5.94819771e+13, 4.45978682e+13,
3.32321345e+13, 2.46111132e+13, 1.81150568e+13,
1.32501876e+13, 9.62971320e+12, 6.95301373e+12,
4.98705540e+12])
I would show you what it looks like, but apparently I don't have enough reputation points...
Anyone got any idea why it's not fitting properly?
Thanks for your help :)
The importance of the initial guess, p0 in curve_fit's default argument list, cannot be stressed enough.
Notice that the docstring mentions that
[p0] If None, then the initial values will all be 1
So if you do not supply it, it will use an initial guess of 1 for all parameters you're trying to optimize for.
The choice of p0 affects the speed at which the underlying algorithm changes the guess vector p0 (ref. the documentation of least_squares).
When you look at the data that you have, you'll notice that the maximum and the mean, mu_0, of the Gaussian-like dataset y, are
2.4e16 and 49 respectively. With the peak value so large, the algorithm, would need to make drastic changes to its initial guess to reach that large value.
When you supply a good initial guess to the curve fitting algorithm, convergence is more likely to occur.
Using your data, you can supply a good initial guess for the peak_value, the mean and sigma, by writing them like this:
y = np.array([...]) # starting from the original dataset
x = np.arange(len(y))
peak_value = y.max()
mean = x[y.argmax()] # observation of the data shows that the peak is close to the center of the interval of the x-data
sigma = mean - np.where(y > peak_value * np.exp(-.5))[0][0] # when x is sigma in the gaussian model, the function evaluates to a*exp(-.5)
popt,pcov = curve_fit(gaus, x, y, p0=[peak_value, mean, sigma])
print(popt) # prints: [ 2.44402560e+16 4.90000000e+01 1.20588976e+01]
Note that in your code, for the mean you take sum(x*y)/n , which is strange, because this would modulate the gaussian by a polynome of degree 1 (it multiplies a gaussian with a monotonously increasing line of constant slope) before taking the mean. That will offset the mean value of y (in this case to the right). A similar remark can be made for your calculation of sigma.
Final remark: the histogram of y will not resemble a Gaussian, as y is already a Gaussian. The histogram will merely bin (count) values into different categories (answering the question "how many datapoints in y reach a value between [a, b]?").

Multiplot Animation

I am working on a project and I wanted to animate some of my results. For my project there is lots of computation done but there is one parameter that I would like to vary.
I have made up some mock code to illustrate my question:
import matplotlib.pyplot as plt
import numpy as np
alpha = np.linspace(1, 10, 50)
x = np.linspace(0, 10, 100)
y = x * x
for i in range(len(alpha)):
plt.plot(x, alpha[i] * y)
plt.title("Alpha = " + str(alpha[i]))
plt.xlim(0, 10)
plt.ylim(1, 100)
plt.savefig("./animation_test/" + str(i) + "_Alpha=" + str(alpha[i]) + ".png")
plt.close()
This leaves me with a my images in a folder I made called animation_test. Now I was just going to run something in my bash terminal like
$convert -delay 50 * test.gif
to make a simple little animated gif but the ordering in my terminal is a little funny
0_Alpha=1.0.png
10_Alpha=2.83673469388.png
11_Alpha=3.02040816327.png
.
.
.
19_Alpha=4.48979591837.png
1_Alpha=1.18367346939.png
20_Alpha=4.67346938776.png
21_Alpha=4.85714285714.png
.
.
.
Now in my Finder they are listed in the correct order. Is there a better way to label these files or even a better way to do the animation as a whole? The final product doesn't have to be a .gif, just something I can play.
You have two solutions:
use human sorting
prepend zeros to your numbers in order to have a fixed number of digits.
Example, if you have labels like:
1-file.ext
2-file.ext
...
99-file.ext
you want to have something like:
01-file.ext
02-file.ext
...
99-file.ext

Computation of Kullback-Leibler (KL) distance between text-documents using numpy

My goal is to compute the KL distance between the following text documents:
1)The boy is having a lad relationship
2)The boy is having a boy relationship
3)It is a lovely day in NY
I first of all vectorised the documents in order to easily apply numpy
1)[1,1,1,1,1,1,1]
2)[1,2,1,1,1,2,1]
3)[1,1,1,1,1,1,1]
I then applied the following code for computing KL distance between the texts:
import numpy as np
import math
from math import log
v=[[1,1,1,1,1,1,1],[1,2,1,1,1,2,1],[1,1,1,1,1,1,1]]
c=v[0]
def kl(p, q):
p = np.asarray(p, dtype=np.float)
q = np.asarray(q, dtype=np.float)
return np.sum(np.where(p != 0,(p-q) * np.log10(p / q), 0))
for x in v:
KL=kl(x,c)
print KL
Here is the result of the above code: [0.0, 0.602059991328, 0.0].
Texts 1 and 3 are completely different, but the distance between them is 0, while texts 1 and 2, which are highly related has a distance of 0.602059991328. This isn't accurate.
Does anyone has an idea of what I'm not doing right with regards to KL? Many thanks for your suggestions.
Though I hate to add another answer, there are two points here. First, as Jaime pointed out in the comments, KL divergence (or distance - they are, according to the following documentation, the same) is designed to measure the difference between probability distributions. This means basically that what you pass to the function should be two array-likes, the elements of each of which sum to 1.
Second, scipy apparently does implement this, with a naming scheme more related to the field of information theory. The function is "entropy":
scipy.stats.entropy(pk, qk=None, base=None)
http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.stats.entropy.html
From the docs:
If qk is not None, then compute a relative entropy (also known as
Kullback-Leibler divergence or Kullback-Leibler distance) S = sum(pk *
log(pk / qk), axis=0).
The bonus of this function as well is that it will normalize the vectors you pass it if they do not sum to 1 (though this means you have to be careful with the arrays you pass - ie, how they are constructed from data).
Hope this helps, and at least a library provides it so don't have to code your own.
After a bit of googling to undersand the KL concept, I think that your problem is due to the vectorization : you're comparing the number of appearance of different words. You should either link your column indice to one word, or use a dictionnary:
# The boy is having a lad relationship It lovely day in NY
1)[1 1 1 1 1 1 1 0 0 0 0 0]
2)[1 2 1 1 1 0 1 0 0 0 0 0]
3)[0 0 1 0 1 0 0 1 1 1 1 1]
Then you can use your kl function.
To automatically vectorize to a dictionnary, see How to count the frequency of the elements in a list? (collections.Counter is exactly what you need). Then you can loop over the union of the keys of the dictionaries to compute the KL distance.
A potential issue might be in your NP definition of KL. Read the wikipedia page for formula: http://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
Note that you multiply (p-q) by the log result. In accordance with the KL formula, this should only be p:
return np.sum(np.where(p != 0,(p) * np.log10(p / q), 0))
That may help...

What is actually applying a filter?

I'm trying solve a challenging problem in C++ with the concepts I'm not familiar with.
I'm trying to apply a filter to a matrix. However like I said I'm quite new at this and after some investigation I've found this link where it shows applying a filter is basically a multiplication
However what confuses me that what if my filter is [0,1,0] and I have to apply it to a 5x5 matrix. How would I be able to do that?
GIMP Filtering with kernel
An alternative to first link
EDIT:Second link really confused me. I am pretty much right now trying to decide the "application" process. If I follow the idea of creating a 3x3 matrix with only diagonal [0,1,0] am i going to apply it like in the second link or do I have to apply it to every single cell in matrix. Or if its really going to be a 1-D filter should I,again, apply it to every single cell or leave out the edges and corners?
That's a convolution kernel.
The idea is that you replace each pixel with a weighted average of it and its neighbors, where the weight are given by your convolution kernel. The process is explained nicely e.g. here.
I find strange that you have a 1-D convolution kernel (i.e. that would be suitable for a one-dimensional image), when usually for image processing 2-D convolution kernels (which take pixels also from the rows above/below) are used, but it could be that your algorithm needs to work only with pixel from the current row.
I think the thing that's being overlooked is that the multiplication is repeated for every element of the input array using subsets of the input data.
The GIMP example showed how to filter a 5x5 image using a 3x3 filter for a single pixel:
. . . . . . . . . .
. - - - . . . . . . . . .
. - # - . x . . . -> . . # . .
. - - - . . . . . . . . .
. . . . . . . . . .
I've labelled one input pixel with a # and its neighbors with -. You use the smaller matrix:
- - - . . .
- # - x . . . = 3x3 array
- - - . . .
Sum up the numbers in the resultant 3x3 array, and store that value into the new image, in place of the # pixel.
To take this to your example, when filtering a 5x5 image using a 3x1 filter:
. . . . . . . . . .
. . . . . . . . . .
. - # - . x . . . -> . . # . .
. . . . . . . . . .
. . . . . . . . . .
You'll use a smaller subset of the input array, to match your kernel;
- # - x . . . = 1x3 array
Then, again, sum the numbers in the resultant array, and store that value into the new image in place of the # pixel.
It's confusing what you are looking for in an answer. If we make the assumption that your filter is stored in a std::vector<double> called filter and that your image is really 2D and has type std::vector< std::vector<double> > called image, then we can do the following to apply the 1-D filter [-1,0,1]:
std::vector< std::vector<double> > new_image;
std::vector<double> filter;
filter.push_back(-1.0); filter.push_back(0.0); filter.push_back(1.0);
for(int i = 0; i < image.size(); i++){
for(int j = 0; j < image.at(i).size(); j++){
new_image.at(i).push_back( filter.at(0)*image.at(i).at(j-1)
+ filter.at(1)*image.at(i).at(j)
+ filter.at(2)*image.at(i).at(j+1) );
}
}
If you want to have a 2-dimensional filter like this one for example
[0 1 0]
[1 0 1]
[0 1 0]
then we assume it is stored as a vector of vectors as well, and basically do the same.
std::vector< std::vector<double> > new_image;
for(int i = 0; i < image.size(); i++){
for(int j = 0; j < image.at(i).size(); j++){
top_filter_term = filter.at(0).at(0)*image.at(i-1).at(j-1)
+ filter.at(0).at(1)*image.at(i-1).at(j)
+ filter.at(0).at(2)*image.at(i-1).at(j+1);
mid_filter_term = filter.at(1).at(0)*image.at(i).at(j-1)
+ filter.at(1).at(1)*image.at(i).at(j)
+ filter.at(1).at(2)*image.at(i).at(j+1);
bot_filter_term = filter.at(2).at(0)*image.at(i+1).at(j-1)
+ filter.at(2).at(1)*image.at(i+1).at(j)
+ filter.at(2).at(2)*image.at(i+1).at(j+1);
new_image.at(i).push_back(top_filter_term + mid_filter_term + bot_filter_term);
}
}
Please note -- I'm not making any effort to do bounds checking for the filter arrays, you really you should only apply this away from the edges of the image, or add code to apply whatever kinds of boundary conditions you want for your filter. I'm also not making any claims about this being optimized. For most purposes, using vectors is a good way to go because they are dynamically resizable and provide enough built-in support to do a lot of useful image manipulations. But for really large-scale processing, you'll want to optimize things like filter operations.
As for your question about filtering a 3D array, there are a couple of things to consider. One, make sure that you really do want to filter the whole array. For many image processing tasks, it is better and more efficient to split all of the color channels into their own 2D arrays, do your processing, and then put them back together. If you do want a true 3D filter, then be sure that your filter actually is 3D, that is, it will be a vector of vectors of vectors. Then you'll use the exact same logic as above, but you'll have an additional layer of terms for the parts of the filter applied to each color channel, or "slice", of the image.
I think you are talking about color filter. Technically a 5X5 image is actually a 5X5X3 (A), where the '3' corresponds to 3 basic colors (RGB). Now, create a matrix of 3X3 with diagonal [0,1,0] (T).
Now multiply the two matrices (AXT) to get the new 5X5X3 image matrix.