Inverting matrices mod-26 with Eigen C++ library - c++

I'm trying to write a program to crack a Hill cipher of arbitrary dimensions (MxM) in C++. Part of the process requires me to calculate the mod-26 inverse of a matrix.
For example, the modular inverse of 2x2 array
14 3
11 0
is
0 19
9 24
I have a function that can accomplish this for 2x2 arrays only, which is not sufficient. I know that calculating inverses on larger-dimension arrays is difficult, so I'm using the Eigen C++ library. However, the Eigen inverse() function gives me this as the inverse of the above matrix:
0.000 0.091
0.333 -0.424
How can I calculate the modular 26 inverse that I need for a matrix of any dimensions with Eigen?

Try this:
#include <iostream>
#include <functional>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int inverse_mod_26(int d)
{
// We're not going to use Euclidean Alg. or
// even Fermat's Little Theorem, but brute force
int base = 26, inv = 1;
while ( (inv < base) &&
(((d * ++inv) % 26) != 1)) {}
return inv;
}
int main(int argc, char **argv)
{
Matrix2d m, minv;
int inv_factor;
m << 14, 3, 15, 0;
double mdet = m.determinant();
minv = mdet * m.inverse();
transform(&minv.data()[0], &minv.data()[4], &minv.data()[0],
[](double d){ return static_cast<int>(d) % 26;});
if ((static_cast<int>(mdet) % 26) == 1) { // no further modification}
else
{
inv_factor = inverse_mod_26(std::abs((m * minv)(0,0)));
if (inv_factor == 26)
{
cerr << "No inverse exists!" << endl;
return EXIT_FAILURE;
}
transform(&minv.data()[0], &minv.data()[4], &minv.data()[0],
[=](double d){ return static_cast<int>(d) * inv_factor;});
}
cout << "m = " << endl << m << endl;
cout << "minv = " << endl << minv << endl;
cout << "(m * minv) = " << endl << m * minv << endl;
return 0;
}
This is a 2x2 case, for base 26, but can easily be modified. The algorithm relies on modifying the normal matrix inverse, and can easily be explained, if you wish. If your original matrix has determinant (in the normal sense) that is not relatively prime to 26; i.e., if GCD(det(m), 26) != 1, then it will not have an inverse.
Tip: to avoid this problem, and the else clause above, pad your dictionary with three arbitrary characters, bringing the size to 29, which is prime, and will trivially satisfy the GCD property above.

Related

Specific right-angled Triangles are not being recognized as right-angled in Cpp

I have to take the coordinates of the vertices of a triangle from the user and tell if it is a right-angled triangle or not. I'm using Pythagoras Theorem to Find out i.e. h * h = b * b + p * p
But surprisingly this doesn't work for some specific right-angled triangles.
Here is one such Triangle:
Vertex A: (x, y) = (1, 3)
Vertex B: (x, y) = (1, 1)
Vertex C: (x, y) = (5, 1)
It calculates perfectly, which I figured out by printing the calculation, but still doesn't work.
Then I tried by using sqrt() function from the cmath library this way:
h = sqrt(b * b + p * p)
Logically it is the same, but it worked.
I want to understand, why the earlier method is not working?
Here is a simplified version of My Code:
#include <iostream>
#include <cmath>
using namespace std;
class Vertex {
double x, y;
public:
void take_input(char obj) {
cout << endl << " Taking Coordinates of Vertex " << obj << ": " << endl;
cout << " Enter the x component: ";
cin >> x;
cout << " Enter the y component: ";
cin >> y;
}
double distance(Vertex p) {
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
return dist;
}
};
class Triangle {
Vertex a, b, c;
public:
void take_inp(string obj) {
cout << endl << "Taking Vertices of the Triangle " << obj << ": " << endl;
cout << " Verteces should be in a counter clockwise order (as per convention)." << endl;
a.take_input('A');
b.take_input('B');
c.take_input('C');
}
void is_rt_ang() {
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
/*
// Strangely this attempt works which is logically the same:
double h = a.distance(c);
double bp = sqrt(a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c));
*/
if (h == bp) {
cout << "Angle is 90" << endl;
cout << h << " = " << bp << endl;
cout << "It is Right-Angled" << endl;
}
else {
cout << "Angle is not 90!" << endl;
cout << h << " != " << bp << endl;
cout << "It is Not a Right-Angled" << endl;
}
}
};
int main()
{
Triangle tri1, tri2;
tri1.take_inp("tri1");
tri1.is_rt_ang();
return 0;
}
The line
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
in the Vertex::distance method gives you an approximation of a square root which is rarely going to coincide with an exact answer. This is because most real numbers can't be represented in floating point arithmetic.
But in given code sample you can make do without sqrt. Replace Vertex::distance method with a method
double distance_square(Vertex p) {
double dist_square = (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
return dist_square;
}
and call it like this in Triangle::is_rt_ang:
double h = a.distance_square(c);
double bp = a.distance_square(b) + b.distance_square(c);
This solution is still flawed because floating-point multiplication is also a subject to rounding errors. But if it is guaranteed that you are going to work only with integer coordinates, you can replace all doubles in your code with ints and for them there is no problem with multiplication (besides possibly going out of bounds for large numbers).
EDIT: Also a comment on printing
It calculates perfectly, which I figured out by printing the
calculation, but still doesn't work.
When you print doubles you need to set precision manually in order to avoid rounding. If in your code I replace a line
cout << h << " != " << bp << endl;
with
cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed << h << " != " << bp << endl;
then for example triangle from the question I get the output
Angle is not 90!
20.000000000000004 != 20.000000000000000
It is Not a Right-Angled
For this to compile you will need to add #include <limits> and #include <iomanip>.
In your is_rt_ang function you're assuming that your hypotenuse is always going to be the edge AC, but it doesn't seem like you're doing anything to verify this.
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
You could try getting the squares of all your distances first, (AC)^2, (AB)^2, and (BC)^2, then finding the candidate for hypotenuse by taking the max value out of the three, then do something like:
bool isRightTriangle = max == (min1 + min2)
You may also be running into some kind of round-off error with floating point numbers. It is common to use a an epsilon value when comparing floating point numbers because of the inherent round-off errors with them. If you don't need floating point values maybe use an integer, or if you do need floating point values try using an epsilon value in your equalities like:
abs(h - bp) <= epsilon
You should be able to find more information about floating point values, round-off errors, and machine epsilons on the web.
Here is a link to a SO Q/A that talks about floating point math that may be a good resource for you: Is floating point math broken?

Code Review for Stroustrup - Principles of Programming - Ch - 4 - Question:3 - Error: Vector subscript out of range

Read a sequence of double values into a vector. Think of each value as
the distance between two cities along a given route. Compute and print
the total distance (the sum of all distances). Find and print the smallest
and greatest distance between two neighboring cities. Find and print the
mean distance between two neighboring cities.
The problem that I am having is that I am getting a debugging error stating that my vector subscript is out of range. I can't seem to see where that is occurring.
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
using std::cout;
using std::cin;
using std::vector;
using std::string;
int main()
{
// Read a sequence of double values into a vector
vector <double> distance; // declaring the vector named "distance"
double sum = 0;
double smallest;
double greatest;
for (double x; cin >> x;) { // read into distance, to terminate putting values in vector use anything that is not of variable type of vector
distance.push_back(x); // put distance into vector
cout << '\n';
for (int i = 0; i < distance.size(); i = i + 1) { // keeping track of elements in vector by displaying them
cout << distance[i] << '\n';
}
}
for (int i = 0; i < distance.size(); i = i + 1) { // adding up all values of vector by iterating through all elements
sum = sum + distance[i];
}
cout << "The total sum of all the elements in the vecotr is: " << sum << '\n';
for (int i = 0; i < distance.size(); i = i + 1) { // determining the smallest value in the vector
if (smallest <= distance[i]) {
smallest = distance[i];
}
}
cout << "The smallest value in the vector is: " << smallest << '\n';
for (int i = 0; i < distance.size(); i = i + 1) { // determining the greatest value in the vector
if (greatest >= distance[i]) {
greatest = distance[i];
}
}
cout << "The smallest value in the vector is: " << smallest << '\n';
cout << "The mean distance between two neigbouring cities is: " << sum / distance.size() << '\n';
}
Bjarne wants you to find the appropriate function in the standard library for the particular problem.
E.g.
auto total_distance = std::accumulate(distance.begin(), distance.end(), 0.);
"The sum of the elements are..."
Look around https://en.cppreference.com/w/cpp/algorithm most of the function calls you want/need are described there.
Run your program like
myprog < inputdoubles.txt

Long double overflows but value smaller than maximum representable value

I'm trying to compute a series using C++.
The series is:
(for those wondering)
My code is the following:
#include <iostream>
#include <fstream>
#include <cmath> // exp
#include <iomanip> //setprecision, setw
#include <limits> //numeric_limits (http://en.cppreference.com/w/cpp/types/numeric_limits)
long double SminOneCenter(long double gamma)
{
using std::endl; using std::cout;
long double result=0.0l;
for (long double k = 1; k < 1000 ; k++)
{
if(isinf(pow(1.0l+pow(gamma,k),6.0l/4.0l)))
{
cout << "infinity for reached for gamma equals: " << gamma << "value of k: " << k ;
cout << "maximum allowed: " << std::numeric_limits<long double>::max()<< endl;
break;
}
// CAS PAIR: -1^n = 1
if ((int)k%2 == 0)
{
result += pow(4.0l*pow(gamma,k),3.0l/4.0l) /(pow(1+pow(gamma,k)),6.0l/4.0l);
}
// CAS IMPAIR:-1^n = -1
else if ((int)k%2!=0)
{
result -= pow(4.0l*pow(gamma,k),3.0l/4.0l) /(pow(1+pow(gamma,k)),6.0l/4.0l);
//if (!isinf(pow(k,2.0l)*zeta/2.0l))
}
// cout << result << endl;
}
return 1.0l + 2.0l*result;
}
Output will be, for instance with gamma = 1.7 :
infinity reached for gamma equals: 1.7 value of k: 892
The maximum value a long double can represent, as provided by the STL numeric_limits, is: 1.18973e+4932.
However (1+1.7^892)= 2.19.... × 10^308 which is way lower than 10^4932, so it shouldn't be considered as infinity.
Provided my code is not wrong (but it very well might be), could anyone tell me why the discussed code evals to infinity when it should not?
You need to use powl rather than pow if you want to supply long double arguments.
Currently you are hitting the numeric_limits<double>::max() in your pow calls.
As an alternative, consider using std::pow which has appropriate overloads.
Reference http://en.cppreference.com/w/c/numeric/math/pow

separating decimal points into two integers

I have been given double x = 23.456; and two integer d and c.
I have to break it so that d gets the value 23 and c gets the value 456.
I thought of the following:-
int d;
d=(int)x;
but I cannot think of what to do with c as it is an integer and if i write
c=(x-d)*1000;
then it might be applicable for this case only and not for any other case.
Is there any way to get the number of digits after the decimal and then multiply it with equal number of zeros.
Please help!!!
You could repeatedly multiply it by 10, until there is nothing after decimal point.
double c = x - d;
while(c - floor(c) > 0.0)
{c *= 10;}
you may also need to #include <math.h> for floor function, which rounds down a number. e.g. floor(4.9) returns 4.0
Floating point calculations are little bit tricky in C++ (same is true for Java and other languages). You should avoid their direct comparison and do some other stuff to get predictable result when using them, consider:
double d1=1.1;
double d2= d1 / 10.0;
if(d2==0.11)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
d1=1.99;
float f1=0.01f;
double d3=d1+f1;
if(d3==2.0)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
d1=1.99;
d2=0.01;
d3=d1+d2-2.0;
if(d3==0.0)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
As for practical solution of the problem I can suggest 2 variants:
Var 1 is to use a function that allows to specify number of digits:
#include <iostream>
#include <cmath>
using namespace std;
void split_double(const double value, int& i_part, int& r_part,
const int max_digits_after_dp, int min_digits_after_dp){
auto powerOfTenL = [](int power){ int result = 1;
for(int i=0;i<power;++i)result *= 10;
return result;
};
//Get integral part
i_part = (int)value;
double temp = (value-i_part);
double pOfTen = powerOfTenL(max_digits_after_dp);
temp *= pOfTen;
//Get real part
r_part = round(temp);
//Remove zeroes at the right in real part
int num_of_d = max_digits_after_dp;
if(min_digits_after_dp>max_digits_after_dp)
min_digits_after_dp=max_digits_after_dp;
while (num_of_d>min_digits_after_dp) {
//If the number is divisible by 10, divide it by 10
if(0==(r_part%10)) { r_part /=10; num_of_d--;
}
else break; //Last digit is not 0
}
}
int main(int argc, char *argv[])
{
double value = 10.120019;
int ipart,rpart;
const int digitsMax = 6;
const int digitsMin = 3;
split_double(value,ipart,rpart,digitsMax,digitsMin);
cout<<"Double " <<value << " has integral part " <<ipart
<<" and real part "<<rpart<<endl;
return 0;
}
Second variant to solve the problem is to use C/C++ formatting functions like vsprintf and then split the resulting string.

Coefficient-wise custom functions in Eigen

I have a do_magic method which takes a double and adds 42 to it. I'd like to apply this method to each coefficient of a Eigen::Matrix or Eigen::Array (that means, I wouldn't mind if it's only possible with one of both types).
Is this possible?
Like this:
Eigen::MatrixXd m(2, 2);
m << 1,2,1,2;
m.applyCoefficientWise(do_magic);
// m is now 43, 44, 43, 44
You can use unaryExpr, though this returns a new view onto the matrix, rather than allowing you to modify the elements in place.
Copying the example out of the documentation:
double ramp(double x)
{
if (x > 0)
return x;
else
return 0;
}
int main(int, char**)
{
Matrix4d m1 = Matrix4d::Random();
cout << m1 << endl << "becomes: " << endl << m1.unaryExpr(ptr_fun(ramp)) << endl;
return 0;
}