User Documentation
 All Files Functions Groups
conjugate_gradient.sql_in
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------- *//**
2  *
3  * @file conjugate_gradient.sql_in
4  *
5  * @brief SQL function computing Conjugate Gradient
6  * @date March 2011
7  *
8  *
9  *//* ----------------------------------------------------------------------- */
10 
11 /**
12 @addtogroup grp_cg
13 
14 \warning <em> This MADlib method is still in early stage development. There may be some
15 issues that will be addressed in a future version. Interface and implementation
16 is subject to change. </em>
17 
18 @about
19 This function uses the iterative conjugate gradient method [1] to find a solution to the function: \f[ \boldsymbol Ax = \boldsymbol b \f]
20 where \f$ \boldsymbol A \f$ is a symmetric, positive definite matrix and \f$x\f$ and \f$ \boldsymbol b \f$ are vectors.
21 
22 @input
23 Matrix \f$ \boldsymbol A \f$ is assumed to be stored in a table where each row consists of at least two columns: array containing values of a given row, row number:
24 <pre>{TABLE|VIEW} <em>matrix_A</em> (
25  <em>row_number</em> FLOAT,
26  <em>row_values</em> FLOAT[],
27 )</pre>
28 The number of elements in each row should be the same.
29 
30 \f$ \boldsymbol b \f$ is passed as a FLOAT[] to the function.
31 
32 @usage
33 Conjugate gradient can be called as follows:
34 <pre>SELECT \ref conjugate_gradient('<em>table_name</em>',
35  '<em>name_of_row_values_col</em>', '<em>name_of_row_number_col</em>', '<em>aray_of_b_values</em>',
36  '<em>desired_precision</em>');</pre>
37 Function returns x as an array.
38 
39 @examp
40 -# Construct matrix A according to structure:
41 \code
42 sql> SELECT * FROM data;
43  row_num | row_val
44 ---------+---------
45  1 | {2,1}
46  2 | {1,4}
47 (2 rows)
48 \endcode
49 -# Call conjugate gradient function:
50 \code
51 sql> SELECT conjugate_gradient('data','row_val','row_num','{2,1}',1E-6,1);
52 INFO: COMPUTE RESIDUAL ERROR 14.5655661859659
53 INFO: ERROR 0.144934004246004
54 INFO: ERROR 3.12963615962926e-31
55 INFO: TEST FINAL ERROR 2.90029642185163e-29
56  conjugate_gradient
57 ---------------------------
58  {1,-1.31838984174237e-15}
59 (1 row)
60 \endcode
61 
62 @literature
63 [1] "Conjugate gradient method" Wikipedia - http://en.wikipedia.org/wiki/Conjugate_gradient_method
64 
65 @sa File conjugate_gradient.sql_in documenting the SQL function.
66 */
67 
68 /**
69  * @brief Compute conjugate gradient
70  *
71  * @param matrix Name of the table containing argument matrix A
72  * @param val_id Name of the column contains row values
73  * @param row_id Name of the column contains row number
74  * @param b Array containing values of b
75  * @param precision_limit Precision threshold after which process will terminate
76  * @param verbosity Verbose flag (0 = false, 1 = true)
77  * @returns Array containing values of x
78  *
79  */
80 CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.conjugate_gradient(Matrix TEXT, val_id TEXT, row_id TEXT, b FLOAT[], precision_limit FLOAT, verbosity INT) RETURNS FLOAT[] AS $$
81 declare
82  r FLOAT[];
83  p FLOAT[];
84  x FLOAT[];
85  k INT;
86  iter INT = 0;
87  recidual_refresh INT := 30;
88  alpha FLOAT;
89  r_size FLOAT;
90  r_new_size FLOAT;
91  Ap FLOAT[];
92  Ax FLOAT[];
93  pAp_size FLOAT;
94  beta FLOAT;
95  exit_if_no_progess_in INT := 15;
96 begin
97  DROP TABLE IF EXISTS X_val;
98  CREATE TEMP TABLE X_val(
99  value FLOAT[]
100  );
101 
102  DROP TABLE IF EXISTS P_val;
103  CREATE TEMP TABLE P_val(
104  value FLOAT[]
105  );
106 
107  SELECT INTO k array_upper(b,1);
108  --INSERT INTO X_val SELECT ARRAY(SELECT random() FROM generate_series(1, k));
109  EXECUTE 'INSERT INTO X_val SELECT ARRAY(SELECT random() FROM generate_series(1,' ||k|| '))';
110  LOOP
111  IF(iter%recidual_refresh = 0)THEN
112  EXECUTE 'SELECT ARRAY(SELECT MADLIB_SCHEMA.array_dot('||val_id||', j.x) FROM (SELECT value AS x FROM X_val) AS j, '|| Matrix ||' ORDER BY '||row_id||' LIMIT '|| k ||')' INTO Ax;
113  SELECT INTO r MADLIB_SCHEMA.array_sub(b, Ax);
114  SELECT INTO r_size MADLIB_SCHEMA.array_dot(r, r);
115  IF(verbosity > 0) THEN
116  RAISE INFO 'COMPUTE RESIDUAL ERROR %', r_size;
117  END IF;
118  SELECT INTO p r;
119  END IF;
120  iter = iter + 1;
121  TRUNCATE TABLE P_val;
122  --INSERT INTO P_val VALUES(p);
123  EXECUTE 'INSERT INTO P_val(value) VALUES(array['|| array_to_string(p,',') ||'])';
124  EXECUTE 'SELECT ARRAY(SELECT MADLIB_SCHEMA.array_dot('||val_id||', j.p) FROM (SELECT value AS p FROM P_val) AS j,'|| Matrix ||' ORDER BY '||row_id||' LIMIT '|| k ||')' INTO Ap;
125  SELECT INTO pAp_size MADLIB_SCHEMA.array_dot(p, Ap);
126  alpha = r_size/pAp_size;
127 
128  --SELECT INTO x MADLIB_SCHEMA.array_add(value, MADLIB_SCHEMA.array_scalar_mult(p,alpha)) FROM X_val;
129  EXECUTE 'SELECT MADLIB_SCHEMA.array_add(value, MADLIB_SCHEMA.array_scalar_mult(array['|| array_to_string(p,',') ||']::float[],'||alpha||'::float)) FROM X_val' INTO x;
130  TRUNCATE TABLE X_val;
131  --INSERT INTO X_val VALUES(x);
132  EXECUTE 'INSERT INTO X_val VALUES(array['|| array_to_string(x,',') ||'])';
133 
134  SELECT INTO r MADLIB_SCHEMA.array_add(r,MADLIB_SCHEMA.array_scalar_mult(Ap, -alpha));
135  SELECT INTO r_new_size MADLIB_SCHEMA.array_dot(r,r);
136 
137  IF(verbosity > 0) THEN
138  RAISE INFO 'ERROR %',r_new_size;
139  END IF;
140  IF (r_new_size < precision_limit) THEN
141  EXECUTE 'SELECT ARRAY(SELECT MADLIB_SCHEMA.array_dot('||val_id||', j.x) FROM (SELECT value AS x FROM X_val) AS j, '|| Matrix ||' ORDER BY '||row_id||' LIMIT '|| k ||')' INTO Ax;
142  SELECT INTO r MADLIB_SCHEMA.array_sub(b, Ax);
143  SELECT INTO r_new_size MADLIB_SCHEMA.array_dot(r, r);
144  IF(verbosity > 0) THEN
145  RAISE INFO 'TEST FINAL ERROR %', r_new_size;
146  END IF;
147  IF (r_new_size < precision_limit) THEN
148  EXIT;
149  END IF;
150  END IF;
151  SELECT INTO p MADLIB_SCHEMA.array_add(r, MADLIB_SCHEMA.array_scalar_mult(p, r_new_size/r_size));
152  IF(r_size < r_new_size) THEN
153  exit_if_no_progess_in = exit_if_no_progess_in-1;
154  RAISE INFO 'No progress! count = %',exit_if_no_progess_in;
155 
156  IF(exit_if_no_progess_in <= 0) THEN
157  RAISE EXCEPTION 'Algorithm failed to converge. Check is input is positive definate.';
158  END IF;
159  ELSE
160  exit_if_no_progess_in = 15;
161  END IF;
162  r_size = r_new_size;
163  END LOOP;
164  IF(verbosity > 1) THEN
165  RETURN ARRAY[r_new_size];
166  END IF;
167  --SELECT INTO x value FROM X_val;
168  EXECUTE 'SELECT value FROM X_val' INTO x;
169  RETURN x;
170 end
171 $$ LANGUAGE plpgsql;
172 
173 CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.conjugate_gradient(Matrix TEXT, val_id TEXT, row_id TEXT, b FLOAT[], precision_limit FLOAT) RETURNS FLOAT[] AS $$
174 declare
175 begin
176  RETURN MADLIB_SCHEMA.conjugate_gradient(Matrix, val_id, row_id, b, precision_limit,0);
177 end
178 $$ LANGUAGE plpgsql;