oILAB
Loading...
Searching...
No Matches
DiophantineSolver.h
Go to the documentation of this file.
1/* This file is part of MODEL, the Mechanics Of Defect Evolution Library.
2 *
3 * Copyright (C) 2015 by Giacomo Po <gpo@ucla.edu>
4 *
5 * MODEL is distributed without any warranty under the
6 * GNU General Public License (GPL) v2 <http://www.gnu.org/licenses/>.
7 */
8
9#ifndef gbLAB_DiophantineSolver_h_
10#define gbLAB_DiophantineSolver_h_
11
12#include <Eigen/Dense>
13#include "IntegerMath.h"
14#include <climits>
15#include <cmath>
16#include "../Utilities/sortIndices.h"
17namespace oILAB {
18template <typename IntScalarType> class DiophantineSolver {
19public:
20 // Finds such x and y, that a x + b y = gcd(a, b)
21 // https://github.com/ADJA/algos/blob/master/NumberTheory/DiophantineEquation.cpp
22 static IntScalarType extended_gcd(IntScalarType a, IntScalarType b,
23 IntScalarType &x, IntScalarType &y) {
24 if (b == 0) {
25 x = 1;
26 y = 0;
27 return a;
28 }
29 IntScalarType x1, y1;
30 IntScalarType g = extended_gcd(b, a % b, x1, y1);
31 x = y1;
32 y = x1 - (a / b) * y1;
33 return g;
34 }
35 /*
36 // Find u such that a_1 u_1 + a_2 u_2 + .... + a_n u_n = 1
37 // method 1 - does not work, the algorithm is incorrect
38
39 // "A fast algorithm to find reduced hyperplane unit cells and solve
40 N-dimensional Bézout's identities."
41 // Acta Crystallographica Section A: Foundations and Advances 77.5
42 (2021).
43
44 static Eigen::Vector<IntScalarType,Eigen::Dynamic> solveBezout(const
45 Eigen::Vector<IntScalarType,Eigen::Dynamic>& p)
46 {
47 int n= p.size();
48 Eigen::Vector<IntScalarType,Eigen::Dynamic> out(n);
49 out= Eigen::Vector<IntScalarType,Eigen::Dynamic>::Zero(n);
50
51 if (n==2)
52 {
53 IntScalarType g= extended_gcd(p(0),p(1),out(0),out(1));
54 std::cout << p(0) << " " << p(1) << std::endl;
55 if (g<0) out= -out;
56 return out;
57 }
58
59 int ind=0;
60 for (auto pi: p)
61 {
62 if (abs(pi)==1)
63 {
64 out(ind) = pi;
65 return out;
66 }
67 ind++;
68 }
69
70 Eigen::Vector<IntScalarType,Eigen::Dynamic> pS(n);
71 ind= -1;
72 for (auto i: sortIndices(p))
73 {
74 ind++;
75 if (p(i) == 0) break;
76 pS(ind)= p(i);
77 }
78
79 IntScalarType pSi0= pS(ind);
80 int numNonZeros= ind+1;
81 Eigen::Vector<IntScalarType,Eigen::Dynamic>
82 quotients(numNonZeros-1); Eigen::Vector<IntScalarType,Eigen::Dynamic>
83 remainders(numNonZeros-1); for(int i=0; i<quotients.size(); i++)
84 {
85 quotients(i)= pS(i)/pSi0;
86 remainders(i)= pS(i)%pSi0;
87
88 //if (pS(i)/pSi0 < 0)
89 // quotients(i)= floor((double)pS(i)/pSi0);
90 //else
91 // quotients(i)= pS(i)/pSi0;
92 //remainders(i)= pS(i)-pSi0*quotients(i);
93 }
94
95 Eigen::Vector<IntScalarType,Eigen::Dynamic> u(numNonZeros-1);
96 u= solveBezout(remainders);
97
98 out(Eigen::seq(0,numNonZeros-2))= u;
99 out(numNonZeros-1)= -quotients.dot(u);
100
101 Eigen::Vector<IntScalarType,Eigen::Dynamic> outRestored(n);
102 ind= 0;
103 for (auto i : sortIndices(p))
104 {
105 outRestored(i) = out(ind);
106 ind++;
107 }
108 return outRestored;
109 }
110 */
111 // Find u such that a_1 u_1 + a_2 u_2 + .... + a_n u_n = 1
112 // Method 0:
113 // "A fast algorithm to find reduced hyperplane unit cells and solve
114 // N-dimensional Bézout's identities."
115 // Acta Crystallographica Section A: Foundations and Advances 77.5 (2021).
116 template <typename ArrayType>
117 static ArrayType solveBezout(const ArrayType &a) {
118 int n = a.size();
119 if (n < 2)
120 throw std::runtime_error("the size of arrays should be at least two");
121 if (abs(IntegerMath<IntScalarType>::gcd(a)) != 1)
122 throw std::runtime_error("No solution since the gcd is not 1 or -1.");
123
124 ArrayType u(n);
125
126 IntScalarType p, q;
127 IntScalarType g12 =
128 extended_gcd(a(0), a(1), p, q); // g12 - gcd of a(0) and a(1)
129
130 // form the n-1 sized vector na= {g,a2,...,a_{n-1}}
131 Eigen::Vector<IntScalarType, Eigen::Dynamic> na(n - 1);
132 na(0) = g12;
133 na(Eigen::seq(1, n - 2)) = a(Eigen::seq(2, n - 1));
134
135 Eigen::Vector<IntScalarType, Eigen::Dynamic> k(n - 1);
136 if (n == 2) {
137 IntScalarType g = extended_gcd(a(0), a(1), u(0), u(1));
138 if (g < 0)
139 u = -u;
140 return u;
141 } else {
142 k = solveBezout(na);
143 // {p*k0,q*k0,k1,..,k_{n-2}}
144 u(0) = p * k(0);
145 u(1) = q * k(0);
146 u(Eigen::seq(2, n - 1)) = k(Eigen::seq(1, n - 2));
147 return u;
148 }
149 }
150
151 // Solves equation a x + b y = c, writes answer to x and y
152 static void solveDiophantine2vars(IntScalarType a, IntScalarType b,
153 IntScalarType c, IntScalarType &x,
154 IntScalarType &y) {
155
156 IntScalarType g = extended_gcd(a, b, x, y);
157
158 if (c % g != 0) {
159 std::cout << a << " " << b << " " << c << " " << g << std::endl;
160 puts("Impossible");
161 exit(0);
162 }
163
164 c /= g;
165
166 x = x * c;
167 y = y * c;
168 }
169 };
170 } // namespace oILAB
171
172#endif
static void solveDiophantine2vars(IntScalarType a, IntScalarType b, IntScalarType c, IntScalarType &x, IntScalarType &y)
static IntScalarType extended_gcd(IntScalarType a, IntScalarType b, IntScalarType &x, IntScalarType &y)
static ArrayType solveBezout(const ArrayType &a)