Graphviz 14.1.2~dev.20260123.1158
Loading...
Searching...
No Matches
lu.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 v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * This code was (mostly) written by Ken Turkowski, who said:
13 *
14 * Oh, that. I wrote it in college the first time. It's open source - I think I
15 * posted it after seeing so many people solve equations by inverting matrices
16 * by computing minors naïvely.
17 * -Ken
18 *
19 * The views represented here are mine and are not necessarily shared by
20 * my employer.
21 Ken Turkowski turk@apple.com
22 Immersive Media Technologist http://www.worldserver.com/turk/
23 Apple Computer, Inc.
24 1 Infinite Loop, MS 302-3VR
25 Cupertino, CA 95014
26 */
27
28
29
30/* This module solves linear equations in several variables (Ax = b) using
31 * LU decomposition with partial pivoting and row equilibration. Although
32 * slightly more work than Gaussian elimination, it is faster for solving
33 * several equations using the same coefficient matrix. It is
34 * particularly useful for matrix inversion, by sequentially solving the
35 * equations with the columns of the unit matrix.
36 *
37 * lu_decompose() decomposes the coefficient matrix into the LU matrix,
38 * and lu_solve() solves the series of matrix equations using the
39 * previous LU decomposition.
40 *
41 * Ken Turkowski (apple!turk)
42 * written 3/2/79, revised and enhanced 8/9/83.
43 */
44
45#include "config.h"
46
47#include <math.h>
48#include <neatogen/neato.h>
49#include <util/alloc.h>
50
51static double *scales;
52static double **lu;
53static int *ps;
54
55/* lu_decompose() decomposes the coefficient matrix A into upper and lower
56 * triangular matrices, the composite being the LU matrix.
57 *
58 * The arguments are:
59 *
60 * a - the (n x n) coefficient matrix
61 * n - the order of the matrix
62 *
63 * 1 is returned if the decomposition was successful,
64 * and 0 is returned if the coefficient matrix is singular.
65 */
66
67int lu_decompose(double **a, int n)
68{
69 int i, j, k;
70 int pivotindex = 0;
71 double pivot, biggest, mult, tempf;
72
73 if (lu)
75 lu = new_array(n, n, 0.0);
76 free(ps);
77 ps = gv_calloc(n, sizeof(int));
78 free(scales);
79 scales = gv_calloc(n, sizeof(double));
80
81 for (i = 0; i < n; i++) { /* For each row */
82 /* Find the largest element in each row for row equilibration */
83 biggest = 0.0;
84 for (j = 0; j < n; j++)
85 biggest = fmax(biggest, fabs(lu[i][j] = a[i][j]));
86 if (biggest > 0.0)
87 scales[i] = 1.0 / biggest;
88 else {
89 scales[i] = 0.0;
90 return 0; /* Zero row: singular matrix */
91 }
92 ps[i] = i; /* Initialize pivot sequence */
93 }
94
95 for (k = 0; k < n - 1; k++) { /* For each column */
96 /* Find the largest element in each column to pivot around */
97 biggest = 0.0;
98 for (i = k; i < n; i++) {
99 if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
100 biggest = tempf;
101 pivotindex = i;
102 }
103 }
104 if (biggest <= 0.0)
105 return 0; /* Zero column: singular matrix */
106 if (pivotindex != k) { /* Update pivot sequence */
107 j = ps[k];
108 ps[k] = ps[pivotindex];
109 ps[pivotindex] = j;
110 }
111
112 /* Pivot, eliminating an extra variable each time */
113 pivot = lu[ps[k]][k];
114 for (i = k + 1; i < n; i++) {
115 lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
116 for (j = k + 1; j < n; j++)
117 lu[ps[i]][j] -= mult * lu[ps[k]][j];
118 }
119 }
120
121 if (lu[ps[n - 1]][n - 1] == 0.0)
122 return 0; /* Singular matrix */
123 return 1;
124}
125
126/* lu_solve() solves the linear equation (Ax = b) after the matrix A has
127 * been decomposed with lu_decompose() into the lower and upper triangular
128 * matrices L and U.
129 *
130 * The arguments are:
131 *
132 * x - the solution vector
133 * b - the constant vector
134 * n - the order of the equation
135*/
136
137void lu_solve(double *x, double *b, int n)
138{
139 int i, j;
140 double dot;
141
142 /* Vector reduction using U triangular matrix */
143 for (i = 0; i < n; i++) {
144 dot = 0.0;
145 for (j = 0; j < i; j++)
146 dot += lu[ps[i]][j] * x[j];
147 x[i] = b[ps[i]] - dot;
148 }
149
150 /* Back substitution, in L triangular matrix */
151 for (i = n - 1; i >= 0; i--) {
152 dot = 0.0;
153 for (j = i + 1; j < n; j++)
154 dot += lu[ps[i]][j] * x[j];
155 x[i] = (x[i] - dot) / lu[ps[i]][i];
156 }
157}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define dot(v, w)
Definition geom.c:191
void free(void *)
void lu_solve(double *x, double *b, int n)
Definition lu.c:137
static double ** lu
Definition lu.c:52
int lu_decompose(double **a, int n)
Definition lu.c:67
static double * scales
Definition lu.c:51
static int * ps
Definition lu.c:53
NEATOPROCS_API void free_array(double **rv)
Definition stuff.c:54
NEATOPROCS_API double ** new_array(int i, int j, double val)
Definition stuff.c:39