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 <sortIndices.h>
17namespace gbLAB
18{
19 template<typename IntScalarType>
21 {
22 public:
23 // Finds such x and y, that a x + b y = gcd(a, b)
24 //https://github.com/ADJA/algos/blob/master/NumberTheory/DiophantineEquation.cpp
25 static IntScalarType extended_gcd(IntScalarType a, IntScalarType b, IntScalarType &x, IntScalarType &y)
26 {
27 if (b == 0)
28 {
29 x = 1;
30 y = 0;
31 return a;
32 }
33 IntScalarType x1, y1;
34 IntScalarType g = extended_gcd(b, a % b, x1, y1);
35 x = y1;
36 y = x1 - (a / b) * y1;
37 return g;
38 }
39/*
40 // Find u such that a_1 u_1 + a_2 u_2 + .... + a_n u_n = 1
41 // method 1 - does not work, the algorithm is incorrect
42
43 // "A fast algorithm to find reduced hyperplane unit cells and solve N-dimensional Bézout's identities."
44 // Acta Crystallographica Section A: Foundations and Advances 77.5 (2021).
45
46 static Eigen::Vector<IntScalarType,Eigen::Dynamic> solveBezout(const Eigen::Vector<IntScalarType,Eigen::Dynamic>& p)
47 {
48 int n= p.size();
49 Eigen::Vector<IntScalarType,Eigen::Dynamic> out(n);
50 out= Eigen::Vector<IntScalarType,Eigen::Dynamic>::Zero(n);
51
52 if (n==2)
53 {
54 IntScalarType g= extended_gcd(p(0),p(1),out(0),out(1));
55 std::cout << p(0) << " " << p(1) << std::endl;
56 if (g<0) out= -out;
57 return out;
58 }
59
60 int ind=0;
61 for (auto pi: p)
62 {
63 if (abs(pi)==1)
64 {
65 out(ind) = pi;
66 return out;
67 }
68 ind++;
69 }
70
71 Eigen::Vector<IntScalarType,Eigen::Dynamic> pS(n);
72 ind= -1;
73 for (auto i: sortIndices(p))
74 {
75 ind++;
76 if (p(i) == 0) break;
77 pS(ind)= p(i);
78 }
79
80 IntScalarType pSi0= pS(ind);
81 int numNonZeros= ind+1;
82 Eigen::Vector<IntScalarType,Eigen::Dynamic> quotients(numNonZeros-1);
83 Eigen::Vector<IntScalarType,Eigen::Dynamic> remainders(numNonZeros-1);
84 for(int i=0; i<quotients.size(); i++)
85 {
86 quotients(i)= pS(i)/pSi0;
87 remainders(i)= pS(i)%pSi0;
88
89 //if (pS(i)/pSi0 < 0)
90 // quotients(i)= floor((double)pS(i)/pSi0);
91 //else
92 // quotients(i)= pS(i)/pSi0;
93 //remainders(i)= pS(i)-pSi0*quotients(i);
94 }
95
96 Eigen::Vector<IntScalarType,Eigen::Dynamic> u(numNonZeros-1);
97 u= solveBezout(remainders);
98
99 out(Eigen::seq(0,numNonZeros-2))= u;
100 out(numNonZeros-1)= -quotients.dot(u);
101
102 Eigen::Vector<IntScalarType,Eigen::Dynamic> outRestored(n);
103 ind= 0;
104 for (auto i : sortIndices(p))
105 {
106 outRestored(i) = out(ind);
107 ind++;
108 }
109 return outRestored;
110 }
111*/
112 // Find u such that a_1 u_1 + a_2 u_2 + .... + a_n u_n = 1
113 // Method 0:
114 // "A fast algorithm to find reduced hyperplane unit cells and solve 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 {
119 int n= a.size();
120 if (n<2) 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= extended_gcd(a(0),a(1),p,q); // g12 - gcd of a(0) and a(1)
128
129 // form the n-1 sized vector na= {g,a2,...,a_{n-1}}
130 Eigen::Vector<IntScalarType,Eigen::Dynamic> na(n-1);
131 na(0)= g12; na(Eigen::seq(1,n-2))= a(Eigen::seq(2,n-1));
132
133 Eigen::Vector<IntScalarType,Eigen::Dynamic> k(n-1);
134 if (n==2)
135 {
136 IntScalarType g= extended_gcd(a(0),a(1),u(0),u(1));
137 if (g<0) u= -u;
138 return u;
139 }
140 else
141 {
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, IntScalarType c, IntScalarType &x, IntScalarType &y)
153 {
154
155 IntScalarType g = extended_gcd(a, b, x, y);
156
157 if (c % g != 0)
158 {
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}
171
172#endif
static ArrayType solveBezout(const ArrayType &a)
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)