Graphviz 16.1.1~dev.20261004.1917
Loading...
Searching...
No Matches
matrix_ops.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <math.h>
14#include <neatogen/matrix_ops.h>
15#include <stdbool.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <util/alloc.h>
19
20static const double p_iteration_threshold = 1e-3;
21
22bool power_iteration(double *const *square_mat, int n, int neigs,
23 double **eigs) {
24 /* compute the 'neigs' top eigenvectors of 'square_mat' using power iteration
25 */
26
27 int i;
28 double *tmp_vec = gv_calloc(n, sizeof(double));
29 double *last_vec = gv_calloc(n, sizeof(double));
30 double angle;
31 int iteration = 0;
32 const int Max_iterations = 30 * n;
33
34 double tol = 1 - p_iteration_threshold;
35
36 if (neigs >= n) {
37 neigs = n;
38 }
39
40 double *const evals = gv_calloc(neigs, sizeof(evals[0]));
41 for (i = 0; i < neigs; i++) {
42 double *const curr_vector = eigs[i];
43 /* guess the i-th eigen vector */
44 choose:
45 for (int j = 0; j < n; j++)
46 curr_vector[j] = rand() % 100;
47 /* orthogonalize against higher eigenvectors */
48 for (int j = 0; j < i; j++) {
49 const double alpha = -vectors_inner_product(n, eigs[j], curr_vector);
50 scadd(curr_vector, n - 1, alpha, eigs[j]);
51 }
52 double len = norm(curr_vector, n - 1);
53 if (len < 1e-10) {
54 // we have chosen a vector colinear with previous ones
55 goto choose;
56 }
57 vectors_scalar_mult(n, curr_vector, 1.0 / len, curr_vector);
58 iteration = 0;
59 do {
60 iteration++;
61 copy_vector(n, curr_vector, last_vec);
62
63 right_mult_with_vector_d(square_mat, n, n, curr_vector, tmp_vec);
64 copy_vector(n, tmp_vec, curr_vector);
65
66 /* orthogonalize against higher eigenvectors */
67 for (int j = 0; j < i; j++) {
68 const double alpha = -vectors_inner_product(n, eigs[j], curr_vector);
69 scadd(curr_vector, n - 1, alpha, eigs[j]);
70 }
71 len = norm(curr_vector, n - 1);
72 if (len < 1e-10 || iteration > Max_iterations) {
73 /* We have reached the null space (e.vec. associated with e.val. 0) */
74 goto exit;
75 }
76
77 vectors_scalar_mult(n, curr_vector, 1.0 / len, curr_vector);
78 angle = vectors_inner_product(n, curr_vector, last_vec);
79 } while (fabs(angle) < tol);
80 evals[i] = angle * len; /* this is the Rayleigh quotient (up to errors due
81 to orthogonalization): u*(A*u)/||A*u||)*||A*u||,
82 where u=last_vec, and ||u||=1
83 */
84 }
85exit:
86 for (; i < neigs; i++) {
87 /* compute the smallest eigenvector, which are */
88 /* probably associated with eigenvalue 0 and for */
89 /* which power-iteration is dangerous */
90 double *const curr_vector = eigs[i];
91 /* guess the i-th eigen vector */
92 for (int j = 0; j < n; j++)
93 curr_vector[j] = rand() % 100;
94 /* orthogonalize against higher eigenvectors */
95 for (int j = 0; j < i; j++) {
96 const double alpha = -vectors_inner_product(n, eigs[j], curr_vector);
97 scadd(curr_vector, n - 1, alpha, eigs[j]);
98 }
99 const double len = norm(curr_vector, n - 1);
100 vectors_scalar_mult(n, curr_vector, 1.0 / len, curr_vector);
101 evals[i] = 0;
102 }
103
104 /* sort vectors by their evals, for overcoming possible mis-convergence: */
105 for (i = 0; i < neigs - 1; i++) {
106 int largest_index = i;
107 double largest_eval = evals[largest_index];
108 for (int j = i + 1; j < neigs; j++) {
109 if (largest_eval < evals[j]) {
110 largest_index = j;
111 largest_eval = evals[largest_index];
112 }
113 }
114 if (largest_index != i) { /* exchange eigenvectors: */
115 copy_vector(n, eigs[i], tmp_vec);
116 copy_vector(n, eigs[largest_index], eigs[i]);
117 copy_vector(n, tmp_vec, eigs[largest_index]);
118
119 evals[largest_index] = evals[i];
120 evals[i] = largest_eval;
121 }
122 }
123
124 free(evals);
125 free(tmp_vec);
126 free(last_vec);
127
128 return iteration <= Max_iterations;
129}
130
131void mult_dense_mat_d(double **A, float **B, int dim1, int dim2, int dim3,
132 double ***CC) {
133 // A is dim1 × dim2, B is dim2 × dim3, C = A × B
134
135 int i, j, k;
136 double sum;
137
138 double *storage = gv_calloc(dim1 * dim3, sizeof(double));
139 double **C = *CC = gv_calloc(dim1, sizeof(double *));
140
141 for (i = 0; i < dim1; i++) {
142 C[i] = storage;
143 storage += dim3;
144 }
145
146 for (i = 0; i < dim1; i++) {
147 for (j = 0; j < dim3; j++) {
148 sum = 0;
149 for (k = 0; k < dim2; k++) {
150 sum += A[i][k] * B[k][j];
151 }
152 C[i][j] = sum;
153 }
154 }
155}
156
157void mult_sparse_dense_mat_transpose(vtx_data *A, double **B, int dim1,
158 int dim2, float ***CC) {
159 // A is dim1 × dim1 and sparse, B is dim2 × dim1, C = A × B
160
161 int i, j;
162 double sum;
163 float *ewgts;
164 int *edges;
165 float *storage = gv_calloc(dim1 * dim2, sizeof(A[0]));
166 float **C = *CC = gv_calloc(dim1, sizeof(A));
167
168 for (i = 0; i < dim1; i++) {
169 C[i] = storage;
170 storage += dim2;
171 }
172
173 for (i = 0; i < dim1; i++) {
174 edges = A[i].edges;
175 ewgts = A[i].ewgts;
176 const size_t nedges = A[i].nedges;
177 for (j = 0; j < dim2; j++) {
178 sum = 0;
179 for (size_t k = 0; k < nedges; k++) {
180 sum += ewgts[k] * B[j][edges[k]];
181 }
182 C[i][j] = (float)(sum);
183 }
184 }
185}
186
187/* Scaled add - fills double vec1 with vec1 + alpha*vec2 over range*/
188void scadd(double *vec1, int end, double fac, double *vec2) {
189 int i;
190
191 for (i = end + 1; i; i--) {
192 (*vec1++) += fac * (*vec2++);
193 }
194}
195
196/* Returns 2-norm of a double n-vector over range. */
197double norm(double *vec, int end) {
198 return sqrt(vectors_inner_product(end + 1, vec, vec));
199}
200
201void orthog1(int n, double *vec /* vector to be orthogonalized against 1 */
202) {
203 int i;
204 double *pntr;
205 double sum;
206
207 sum = 0.0;
208 pntr = vec;
209 for (i = n; i; i--) {
210 sum += *pntr++;
211 }
212 sum /= n;
213 pntr = vec;
214 for (i = n; i; i--) {
215 *pntr++ -= sum;
216 }
217}
218
219#define RANGE 500
220
221void init_vec_orth1(int n, double *vec) {
222 /* randomly generate a vector orthogonal to 1 (i.e., with mean 0) */
223 int i;
224
225 for (i = 0; i < n; i++)
226 vec[i] = rand() % RANGE;
227
228 orthog1(n, vec);
229}
230
231void right_mult_with_vector(const vtx_data *matrix, int n, const double *vector,
232 double *restrict result) {
233 for (int i = 0; i < n; i++) {
234 double res = 0;
235 for (size_t j = 0; j < matrix[i].nedges; j++)
236 res += matrix[i].ewgts[j] * vector[matrix[i].edges[j]];
237 result[i] = res;
238 }
239}
240
241void vectors_subtraction(int n, double *vector1, double *vector2,
242 double *result) {
243 int i;
244 for (i = 0; i < n; i++) {
245 result[i] = vector1[i] - vector2[i];
246 }
247}
248
249void vectors_addition(int n, double *vector1, double *vector2, double *result) {
250 int i;
251 for (i = 0; i < n; i++) {
252 result[i] = vector1[i] + vector2[i];
253 }
254}
255
256void vectors_scalar_mult(int n, const double *vector, double alpha,
257 double *result) {
258 int i;
259 for (i = 0; i < n; i++) {
260 result[i] = vector[i] * alpha;
261 }
262}
263
264void copy_vector(int n, const double *restrict source, double *restrict dest) {
265 int i;
266 for (i = 0; i < n; i++)
267 dest[i] = source[i];
268}
269
270double vectors_inner_product(int n, const double *vector1,
271 const double *vector2) {
272 int i;
273 double result = 0;
274 for (i = 0; i < n; i++) {
275 result += vector1[i] * vector2[i];
276 }
277
278 return result;
279}
280
281double max_abs(int n, double *vector) {
282 double max_val = -1e50;
283 int i;
284 for (i = 0; i < n; i++)
285 max_val = fmax(max_val, fabs(vector[i]));
286
287 return max_val;
288}
289
290void right_mult_with_vector_transpose(double **matrix, int dim1, int dim2,
291 double *vector, double *result) {
292 // matrix is dim2 × dim1, vector has dim2 components,
293 // result = matrixᵀ × vector
294 int i, j;
295
296 double res;
297 for (i = 0; i < dim1; i++) {
298 res = 0;
299 for (j = 0; j < dim2; j++)
300 res += matrix[j][i] * vector[j];
301 result[i] = res;
302 }
303}
304
305void right_mult_with_vector_d(double *const *matrix, int dim1, int dim2,
306 const double *vector, double *restrict result) {
307 // matrix is dim1 × dim2, vector has dim2 components,
308 // result = matrix × vector
309 for (int i = 0; i < dim1; i++) {
310 double res = 0;
311 for (int j = 0; j < dim2; j++)
312 res += matrix[i][j] * vector[j];
313 result[i] = res;
314 }
315}
316
317/*****************************
318** Single precision (float) **
319** version **
320*****************************/
321
322void orthog1f(int n, float *vec) {
323 int i;
324 float *pntr;
325 float sum;
326
327 sum = 0.0;
328 pntr = vec;
329 for (i = n; i; i--) {
330 sum += *pntr++;
331 }
332 sum /= n;
333 pntr = vec;
334 for (i = n; i; i--) {
335 *pntr++ -= sum;
336 }
337}
338
339void right_mult_with_vector_ff(const float *packed_matrix, int n,
340 const float *vector, float *restrict result) {
341 /* packed matrix is the upper-triangular part of a symmetric matrix arranged
342 * in a vector row-wise */
343 for (int i = 0; i < n; i++) {
344 result[i] = 0;
345 }
346 for (int index = 0, i = 0; i < n; i++) {
347 const float vector_i = vector[i];
348 /* deal with main diag */
349 float res = packed_matrix[index++] * vector_i;
350 /* deal with off diag */
351 for (int j = i + 1; j < n; j++, index++) {
352 res += packed_matrix[index] * vector[j];
353 result[j] += packed_matrix[index] * vector_i;
354 }
355 result[i] += res;
356 }
357}
358
359void vectors_subtractionf(int n, float *vector1, float *vector2,
360 float *result) {
361 int i;
362 for (i = 0; i < n; i++) {
363 result[i] = vector1[i] - vector2[i];
364 }
365}
366
367void vectors_additionf(int n, float *vector1, float *vector2, float *result) {
368 int i;
369 for (i = 0; i < n; i++) {
370 result[i] = vector1[i] + vector2[i];
371 }
372}
373
374void vectors_mult_additionf(int n, float *vector1, float alpha,
375 float *vector2) {
376 int i;
377 for (i = 0; i < n; i++) {
378 vector1[i] = vector1[i] + alpha * vector2[i];
379 }
380}
381
382void copy_vectorf(int n, float *source, float *dest) {
383 int i;
384 for (i = 0; i < n; i++)
385 dest[i] = source[i];
386}
387
388double vectors_inner_productf(int n, float *vector1, float *vector2) {
389 int i;
390 double result = 0;
391 for (i = 0; i < n; i++) {
392 result += vector1[i] * vector2[i];
393 }
394
395 return result;
396}
397
398void set_vector_valf(int n, float val, float *result) {
399 int i;
400 for (i = 0; i < n; i++)
401 result[i] = val;
402}
403
404double max_absf(int n, float *vector) {
405 int i;
406 float max_val = -1e30f;
407 for (i = 0; i < n; i++)
408 max_val = fmaxf(max_val, fabsf(vector[i]));
409
410 return max_val;
411}
412
413void square_vec(int n, float *vec) {
414 int i;
415 for (i = 0; i < n; i++) {
416 vec[i] *= vec[i];
417 }
418}
419
420void invert_vec(int n, float *vec) {
421 int i;
422 for (i = 0; i < n; i++) {
423 if (vec[i] != 0.0) {
424 vec[i] = 1.0f / vec[i];
425 }
426 }
427}
428
429void sqrt_vecf(int n, float *source, float *target) {
430 int i;
431 for (i = 0; i < n; i++) {
432 if (source[i] >= 0.0) {
433 target[i] = sqrtf(source[i]);
434 }
435 }
436}
437
438void invert_sqrt_vec(int n, float *vec) {
439 int i;
440 for (i = 0; i < n; i++) {
441 if (vec[i] > 0.0) {
442 vec[i] = 1.0f / sqrtf(vec[i]);
443 }
444 }
445}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define A(n, t)
Definition expr.h:76
#define CC
Definition gc.c:47
static double len(glCompPoint p)
Definition glutils.c:138
void free(void *)
#define B
Definition hierarchy.c:120
double vectors_inner_product(int n, const double *vector1, const double *vector2)
Definition matrix_ops.c:270
void orthog1f(int n, float *vec)
Definition matrix_ops.c:322
void right_mult_with_vector_d(double *const *matrix, int dim1, int dim2, const double *vector, double *restrict result)
Definition matrix_ops.c:305
void right_mult_with_vector_transpose(double **matrix, int dim1, int dim2, double *vector, double *result)
Definition matrix_ops.c:290
void init_vec_orth1(int n, double *vec)
Definition matrix_ops.c:221
void invert_vec(int n, float *vec)
Definition matrix_ops.c:420
void copy_vector(int n, const double *restrict source, double *restrict dest)
Definition matrix_ops.c:264
void mult_sparse_dense_mat_transpose(vtx_data *A, double **B, int dim1, int dim2, float ***CC)
Definition matrix_ops.c:157
void invert_sqrt_vec(int n, float *vec)
Definition matrix_ops.c:438
double max_absf(int n, float *vector)
Definition matrix_ops.c:404
void vectors_additionf(int n, float *vector1, float *vector2, float *result)
Definition matrix_ops.c:367
void set_vector_valf(int n, float val, float *result)
Definition matrix_ops.c:398
void orthog1(int n, double *vec)
Definition matrix_ops.c:201
void copy_vectorf(int n, float *source, float *dest)
Definition matrix_ops.c:382
void sqrt_vecf(int n, float *source, float *target)
Definition matrix_ops.c:429
bool power_iteration(double *const *square_mat, int n, int neigs, double **eigs)
Definition matrix_ops.c:22
void right_mult_with_vector(const vtx_data *matrix, int n, const double *vector, double *restrict result)
Definition matrix_ops.c:231
void scadd(double *vec1, int end, double fac, double *vec2)
Definition matrix_ops.c:188
#define RANGE
Definition matrix_ops.c:219
void mult_dense_mat_d(double **A, float **B, int dim1, int dim2, int dim3, double ***CC)
Definition matrix_ops.c:131
void vectors_mult_additionf(int n, float *vector1, float alpha, float *vector2)
Definition matrix_ops.c:374
void square_vec(int n, float *vec)
Definition matrix_ops.c:413
static const double p_iteration_threshold
Definition matrix_ops.c:20
double max_abs(int n, double *vector)
Definition matrix_ops.c:281
void right_mult_with_vector_ff(const float *packed_matrix, int n, const float *vector, float *restrict result)
Definition matrix_ops.c:339
double norm(double *vec, int end)
Definition matrix_ops.c:197
void vectors_subtraction(int n, double *vector1, double *vector2, double *result)
Definition matrix_ops.c:241
void vectors_addition(int n, double *vector1, double *vector2, double *result)
Definition matrix_ops.c:249
void vectors_scalar_mult(int n, const double *vector, double alpha, double *result)
Definition matrix_ops.c:256
void vectors_subtractionf(int n, float *vector1, float *vector2, float *result)
Definition matrix_ops.c:359
double vectors_inner_productf(int n, float *vector1, float *vector2)
Definition matrix_ops.c:388
#define C
Definition pack.c:33
static int nedges
total no. of edges used in routing
Definition routespl.c:32
#define alpha
Definition shapes.c:4034
static const double tol
size_t nedges
no. of neighbors, including self
Definition sparsegraph.h:30