1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <string.h>
5
6 // This would normally be in a header file, but as we do not need one,
7 // we will explicitly include it here.
8 #if defined(_WIN32) || defined(_WIN64)
9 # if defined(BUILDING_PYNUMERO_MA27)
10 # define PYNUMERO_HSL_EXPORT __declspec(dllexport)
11 # else
12 # define PYNUMERO_HSL_EXPORT __declspec(dllimport)
13 # endif
14 #else
15 # define PYNUMERO_HSL_EXPORT
16 #endif
17
18 // Forward declaration of MA27 fortran routines
19 extern "C" {
20 void ma27id_(int* ICNTL, double* CNTL);
21 void ma27ad_(int *N, int *NZ, int *IRN, int* ICN,
22 int *IW, int* LIW, int* IKEEP, int *IW1,
23 int* NSTEPS, int* IFLAG, int* ICNTL,
24 double* CNTL, int *INFO, double* OPS);
25 void ma27bd_(int *N, int *NZ, int *IRN, int* ICN,
26 double* A, int* LA, int* IW, int* LIW,
27 int* IKEEP, int* NSTEPS, int* MAXFRT,
28 int* IW1, int* ICNTL, double* CNTL,
29 int* INFO);
30 void ma27cd_(int *N, double* A, int* LA, int* IW,
31 int* LIW, double* W, int* MAXFRT,
32 double* RHS, int* IW1, int* NSTEPS,
33 int* ICNTL, int* INFO);
34 } // extern "C"
35
abort_bad_memory(int status)36 void abort_bad_memory(int status) {
37 printf("Bad memory allocation in MA27 C interface. Aborting.");
38 exit(status);
39 }
40
41
42 struct MA27_struct {
43 // Constructor: set defaults, initialize cached arrays to NULL
MA27_structMA27_struct44 MA27_struct():
45 LA(0),
46 LIW_a(0),
47 LIW_b(0),
48 NSTEPS(0),
49 IFLAG(0),
50 MAXFRT(0),
51 IW_factor(1.2),
52 A_factor(2.0),
53 OPS(0),
54 IW_a(NULL),
55 IW_b(NULL),
56 IKEEP(NULL),
57 A(NULL)
58 {
59 ma27id_(this->ICNTL, this->CNTL);
60 }
61 // Destructor: delete all cached arrays
~MA27_structMA27_struct62 virtual ~MA27_struct() {
63 if ( this->A ) {
64 delete[] this->A;
65 }
66 if ( this->IW_a ) {
67 delete[] this->IW_a;
68 }
69 if ( this->IW_b ) {
70 delete[] this->IW_b;
71 }
72 if ( this->IKEEP ) {
73 delete[] this->IKEEP;
74 }
75 }
76
77 int LA, LIW_a, LIW_b, NSTEPS, IFLAG, MAXFRT;
78 double IW_factor, A_factor, OPS;
79 int* IW_a;
80 int* IW_b;
81 // Use different arrays for IW that is sent to MA27A and that sent to
82 // MA27B because IW must be discarded after MA27A but kept after MA27B.
83 // If these arrays are the same, and a symbolic factorization is performed
84 // after a numeric factorization (e.g. on a new matrix), user-defined
85 // and MA27B-defined allocations of IW can be conflated.
86 int* IKEEP;
87 double* A;
88 int ICNTL[30], INFO[20];
89 double CNTL[5];
90 };
91
92 extern "C" {
93
94 PYNUMERO_HSL_EXPORT
new_MA27_struct(void)95 MA27_struct* new_MA27_struct(void) {
96 MA27_struct* ma27 = new MA27_struct;
97 if (ma27 == NULL) { abort_bad_memory(1); }
98 // Return pointer to ma27 that Python program can pass to other
99 // functions in this code
100 return ma27;
101 }
102
103
104 PYNUMERO_HSL_EXPORT
free_MA27_struct(MA27_struct * ma27)105 void free_MA27_struct(MA27_struct* ma27) {
106 delete ma27;
107 }
108
109 // Functions for setting/accessing INFO/CNTL arrays:
110 PYNUMERO_HSL_EXPORT
set_icntl(MA27_struct * ma27,int i,int val)111 void set_icntl(MA27_struct* ma27, int i, int val) {
112 ma27->ICNTL[i] = val;
113 }
114
115 PYNUMERO_HSL_EXPORT
get_icntl(MA27_struct * ma27,int i)116 int get_icntl(MA27_struct* ma27, int i) {
117 return ma27->ICNTL[i];
118 }
119
120 PYNUMERO_HSL_EXPORT
set_cntl(MA27_struct * ma27,int i,double val)121 void set_cntl(MA27_struct* ma27, int i, double val) {
122 ma27->CNTL[i] = val;
123 }
124
125 PYNUMERO_HSL_EXPORT
get_cntl(MA27_struct * ma27,int i)126 double get_cntl(MA27_struct* ma27, int i) {
127 return ma27->CNTL[i];
128 }
129
130 PYNUMERO_HSL_EXPORT
get_info(MA27_struct * ma27,int i)131 int get_info(MA27_struct* ma27, int i) {
132 return ma27->INFO[i];
133 }
134
135 // Functions for allocating WORK/FACT arrays:
136 PYNUMERO_HSL_EXPORT
alloc_iw_a(MA27_struct * ma27,int l)137 void alloc_iw_a(MA27_struct* ma27, int l) {
138 if ( ma27->IW_a ) {
139 delete[] ma27->IW_a;
140 }
141 ma27->LIW_a = l;
142 ma27->IW_a = new int[l];
143 if (ma27->IW_a == NULL) { abort_bad_memory(1); }
144 }
145
146 PYNUMERO_HSL_EXPORT
alloc_iw_b(MA27_struct * ma27,int l)147 void alloc_iw_b(MA27_struct* ma27, int l) {
148 if ( ma27->IW_b ) {
149 delete[] ma27->IW_b;
150 }
151 ma27->LIW_b = l;
152 ma27->IW_b = new int[l];
153 if (ma27->IW_b == NULL) { abort_bad_memory(1); }
154 }
155
156 PYNUMERO_HSL_EXPORT
alloc_a(MA27_struct * ma27,int l)157 void alloc_a(MA27_struct* ma27, int l) {
158 if ( ma27->A ) {
159 delete[] ma27->A;
160 }
161 ma27->LA = l;
162 ma27->A = new double[l];
163 if (ma27->A == NULL) { abort_bad_memory(1); }
164 }
165
166 PYNUMERO_HSL_EXPORT
do_symbolic_factorization(MA27_struct * ma27,int N,int NZ,int * IRN,int * ICN)167 void do_symbolic_factorization(MA27_struct* ma27, int N, int NZ,
168 int* IRN, int* ICN) {
169 // Arrays, presumably supplied from Python, are assumed to have base-
170 // zero indices. Convert to base-one before sending to Fortran.
171 for (int i=0; i<NZ; i++) {
172 IRN[i] = IRN[i] + 1;
173 ICN[i] = ICN[i] + 1;
174 }
175
176 if ( ! ma27->IW_a ) {
177 int min_size = 2*NZ + 3*N + 1;
178 int size = (int)(ma27->IW_factor*min_size);
179 alloc_iw_a(ma27, size);
180 }
181
182 if ( ma27->IKEEP ) {
183 delete[] ma27->IKEEP;
184 }
185 ma27->IKEEP = new int[3*N];
186 if (ma27->IKEEP == NULL) { abort_bad_memory(1); }
187 int* IW1 = new int[2*N];
188 if (IW1 == NULL) { abort_bad_memory(1); }
189
190 ma27ad_(&N,
191 &NZ,
192 IRN,
193 ICN,
194 ma27->IW_a,
195 &(ma27->LIW_a),
196 ma27->IKEEP,
197 IW1,
198 &(ma27->NSTEPS),
199 &(ma27->IFLAG),
200 ma27->ICNTL,
201 ma27->CNTL,
202 ma27->INFO,
203 &(ma27->OPS));
204
205 delete[] IW1;
206 delete[] ma27->IW_a;
207 ma27->IW_a = NULL;
208 }
209
210 PYNUMERO_HSL_EXPORT
do_numeric_factorization(MA27_struct * ma27,int N,int NZ,int * IRN,int * ICN,double * A)211 void do_numeric_factorization(MA27_struct* ma27, int N, int NZ,
212 int* IRN, int* ICN, double* A) {
213
214 // Convert indices to base-one for Fortran
215 for (int i=0; i<NZ; i++) {
216 IRN[i] = IRN[i] + 1;
217 ICN[i] = ICN[i] + 1;
218 }
219
220 // Get memory estimates from INFO, allocate A and IW
221 if ( ! ma27->A ) {
222 int info5 = ma27->INFO[5-1];
223 int size = (int)(ma27->A_factor*info5);
224 alloc_a(ma27, size);
225 // A is now allocated
226 }
227 // Regardless of ma27->A's previous allocation status, copy values from A.
228 memcpy(ma27->A, A, NZ*sizeof(double));
229
230 if ( ! ma27->IW_b ) {
231 int info6 = ma27->INFO[6-1];
232 int size = (int)(ma27->IW_factor*info6);
233 alloc_iw_b(ma27, size);
234 }
235
236 int* IW1 = new int[N];
237 if (IW1 == NULL) { abort_bad_memory(1); }
238
239 ma27bd_(&N,
240 &NZ,
241 IRN,
242 ICN,
243 ma27->A,
244 &(ma27->LA),
245 ma27->IW_b,
246 &(ma27->LIW_b),
247 ma27->IKEEP,
248 &(ma27->NSTEPS),
249 &(ma27->MAXFRT),
250 IW1,
251 ma27->ICNTL,
252 ma27->CNTL,
253 ma27->INFO);
254
255 delete[] IW1;
256 }
257
258 PYNUMERO_HSL_EXPORT
do_backsolve(MA27_struct * ma27,int N,double * RHS)259 void do_backsolve(MA27_struct* ma27, int N, double* RHS) {
260
261 double* W = new double[ma27->MAXFRT];
262 if (W == NULL) { abort_bad_memory(1); }
263 int* IW1 = new int[ma27->NSTEPS];
264 if (IW1 == NULL) { abort_bad_memory(1); }
265
266 ma27cd_(
267 &N,
268 ma27->A,
269 &(ma27->LA),
270 ma27->IW_b,
271 &(ma27->LIW_b),
272 W,
273 &(ma27->MAXFRT),
274 RHS,
275 IW1,
276 &(ma27->NSTEPS),
277 ma27->ICNTL,
278 ma27->INFO
279 );
280
281 delete[] IW1;
282 delete[] W;
283 }
284
285 } // extern "C"
286