You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@madlib.apache.org by ri...@apache.org on 2016/10/25 22:45:26 UTC
incubator-madlib git commit: PCA: Update train and project docs
Repository: incubator-madlib
Updated Branches:
refs/heads/master d62bfbe52 -> e4e93e090
PCA: Update train and project docs
Closes #72
Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/e4e93e09
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/e4e93e09
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/e4e93e09
Branch: refs/heads/master
Commit: e4e93e0904f17b612799be226952d0c3bda0200d
Parents: d62bfbe
Author: Frank McQuillan <fm...@pivotal.io>
Authored: Tue Oct 25 15:43:57 2016 -0700
Committer: Rahul Iyer <ri...@apache.org>
Committed: Tue Oct 25 15:43:57 2016 -0700
----------------------------------------------------------------------
src/ports/postgres/modules/pca/pca.sql_in | 200 +++++++++++++------
.../postgres/modules/pca/pca_project.sql_in | 143 ++++++++-----
2 files changed, 234 insertions(+), 109 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/e4e93e09/src/ports/postgres/modules/pca/pca.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/pca/pca.sql_in b/src/ports/postgres/modules/pca/pca.sql_in
index 7873bdf..9f573f3 100644
--- a/src/ports/postgres/modules/pca/pca.sql_in
+++ b/src/ports/postgres/modules/pca/pca.sql_in
@@ -41,11 +41,11 @@ constraint that it be orthogonal to (i.e., uncorrelated with) the preceding
components.
See the \ref background_pca "Technical Background" for an introduction to
- principal component analysis and the implementation notes.
+ principal component analysis.
@anchor train
@par Training Function
-The training functions have the following formats:
+The training functions are slightly different for dense and sparse matrices. For dense matrices:
<pre class="syntax">
pca_train( source_table,
out_table,
@@ -57,15 +57,15 @@ pca_train( source_table,
result_summary_table
)
</pre>
-and
+For sparse matrices:
<pre class="syntax">
pca_sparse_train( source_table,
out_table,
row_id,
- col_id,
- val_id,
- row_dim,
- col_dim,
+ col_id, -- Sparse matrices only
+ val_id, -- Sparse matrices only
+ row_dim, -- Sparse matrices only
+ col_dim, -- Sparse matrices only
components_param,
grouping_cols,
lanczos_iter,
@@ -86,7 +86,7 @@ A dense input table is expected to be in the one of the
two standard MADlib dense matrix formats, and a sparse input table
should be in the standard MADlib sparse matrix format.
-The two standard MADlib dense matrix formats are
+The two standard MADlib dense matrix formats are:
<pre>{TABLE|VIEW} <em>source_table</em> (
<em>row_id</em> INTEGER,
<em>row_vec</em> FLOAT8[],
@@ -115,11 +115,13 @@ The input table for sparse PCA is expected to be in the form:
The <em>row_id</em> and <em>col_id</em> columns specify which entries
in the matrix are nonzero, and the <em>val_id</em> column defines the values
of the nonzero entries.
+
+Please refer to the \ref grp_matrix documentation for more details on defining matrices.
</DD>
<DT>out_table</DT>
<DD>TEXT. The name of the table that will contain the output.
-The output is divided into three tables.
+There are three possible output tables as described below.
The primary output table (<em>out_table</em>) encodes the principal components
with the <em>k</em> highest eigenvalues where <em>k</em> is either directly
@@ -136,7 +138,7 @@ The table has the following columns:
</tr>
<tr>
<th>std_dev</th>
-<td>The standart deviation of each principal component.</td>
+<td>The standard deviation of each principal component.</td>
</tr>
<tr>
<th>proportion</th>
@@ -144,7 +146,7 @@ The table has the following columns:
</tr>
</table>
-The table <em>out_table</em>_mean contains the column means.
+The table <em>out_table_mean</em> contains the column means.
This table has just one column:
<table class="output">
<tr>
@@ -158,22 +160,37 @@ The optional table <em>result_summary_table</em> contains information about the
<DT>row_id</DT>
<DD>TEXT. Column name containing the row IDs in the input source table. The column
-needs to be of type that can be cast to INT and should only contain values between 1 and
-<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>.</DD>
+should be of type INT (or a type that can be cast to INT) and should only contain values between 1 and
+<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>
+describing the full matrix.</DD>
<DT>col_id</DT>
-<DD>TEXT. Column name of containing the col IDS in sparse matrix representation
-(sparse matrices only). The column should be of type that can be cast to INT and
-contain values between 1 and <em>M</em>.</DD>
+<DD>TEXT. Column name containing the column IDs in sparse matrix representation.
+The column should be of type INT (or a type that can be cast to INT)
+and should only contain values between 1 and <em>M</em>. <em>This parameter applies to
+sparse matrices only.</em></DD>
<DT>val_id</DT>
-<DD>TEXT. Name of 'val_id' column in sparse matrix representation (sparse matrices only). </DD>
+<DD>TEXT. Name of 'val_id' column in sparse matrix representation defining the values of the nonzero entries.
+<em>This parameter applies to sparse matrices only.</em></DD>
<DT>row_dim</DT>
-<DD>INTEGER. The number of rows in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER. The actual number of rows in the matrix. That is,
+if the matrix was transformed into dense format, this is the number of rows
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
<DT>col_dim</DT>
-<DD>INTEGER. The number of columns in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER. The actual number of columns in the matrix. That is,
+if the matrix was transformed into dense format, this is the number of columns
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
+
+@note The parameters 'row_dim' and 'col_dim' could actually be inferred from the
+sparse matrix representation, so they will be removed in the future.
+For now they are maintained for backward compatability so you must enter them.
+Making 'row_dim' or 'col_dim' larger than the actual matrix has the effect of padding it with
+zeros, which is probably not useful.
<DT>components_param</DT>
<DD>INTEGER or FLOAT. The parameter to control the number of principal
@@ -203,14 +220,16 @@ principal components, i.e., proportion of variance of 100%.
computed for each combination of the grouping columns.</DD>
<DT>lanczos_iter (optional)</DT>
-<DD>INTEGER, default: minimum of {k+40, smallest matrix dimension}.
-The number of Lanczos iterations for the SVD calculation.
+<DD>INTEGER, default: minimum of {<em>k+40</em>, smallest matrix dimension}
+where <em>k</em> is the number of principle components specified in the
+parameter 'components_param'. This parameter defines the
+number of Lanczos iterations for the SVD calculation.
The Lanczos iteration number roughly corresponds to the accuracy of the SVD
-calculation, and a higher iteration number corresponds to greater accuracy
+calculation, and a higher number of iterations corresponds to greater accuracy
but longer computation time. The number of iterations must be at least as
large as the value of <em>k</em>, but no larger than the smallest dimension
-of the matrix. If the iteration number is given as zero, then the default
-number of iterations is used.</DD>
+of the matrix. If the number of iterations is set to zero, then the default
+number of iterations will be used.</DD>
@note If both 'lanczos_iter' and proportion of variance (via
the 'components_param' parameter) are defined, 'lanczos_iter'
@@ -221,7 +240,7 @@ proportion had not been reached).
<DT>use_correlation (optional)</DT>
<DD>BOOLEAN, default FALSE. Whether to use the correlation matrix for calculating the principal components instead of the covariance matrix. Currently
-<em>use_correlation</em> is a placeholder for forward compatibility, and
+<em>use_correlation</em> is a placeholder for forward compatibility, so
this value must be set to false.</DD>
<DT>result_summary_table (optional)</DT>
@@ -261,41 +280,35 @@ This sumary table has the following columns:
@anchor examples
@examp
--# View online help for the PCA training function.
+-# View online help for the PCA training function:
<pre class="example">
SELECT madlib.pca_train();
+or
+SELECT madlib.pca_sparse_train();
</pre>
--# Create the sample data.
+-# Create sample data in dense matrix form:
<pre class="example">
DROP TABLE IF EXISTS mat;
CREATE TABLE mat (
- row_id integer,
- row_vec double precision[]
+ row_id integer,
+ row_vec double precision[]
);
-COPY mat (row_id, row_vec) FROM stdin DELIMITER '|';
-1|{1,2,3}
-2|{2,1,2}
-3|{3,2,1}
-\\.
-</pre>
-
--# Run the PCA function for a fixed number of components:
-<pre class="example">
-DROP TABLE IF EXISTS result_table;
-DROP TABLE IF EXISTS result_table_mean;
-SELECT pca_train( 'mat',
- 'result_table',
- 'row_id',
- 3
- );
+INSERT INTO mat VALUES
+(1, '{1,2,3}'),
+(2, '{2,1,2}'),
+(3, '{3,2,1}');
</pre>
--# View the PCA results:
+-# Run the PCA function for a specified number of principle components and view the results:
<pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train( 'mat',
+ 'result_table',
+ 'row_id',
+ 3);
SELECT * FROM result_table;
</pre>
-Result
<pre class="result">
row_id | principal_components | std_dev | proportion
--------+--------------------------------------------------------------+----------------------+----------------------
@@ -304,22 +317,15 @@ Result
3 | {-0.707106781186548,1.11022302462516e-16,-0.707106781186547} | 1.59506745224211e-16 | 1.09038864737157e-32
</pre>
--# Run the PCA function for a proportion of variance:
-<pre class="example">
-DROP TABLE IF EXISTS result_table;
-DROP TABLE IF EXISTS result_table_mean;
-SELECT pca_train( 'mat',
- 'result_table',
- 'row_id',
- 0.9
- );
-</pre>
-
--# View the PCA results:
+-# Run the PCA function for a specified proportion of variance and view the results:
<pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train( 'mat',
+ 'result_table',
+ 'row_id',
+ 0.9);
SELECT * FROM result_table;
</pre>
-Result
<pre class="result">
row_id | principal_components | std_dev | proportion
--------+--------------------------------------------------------------+-------------------+-------------------
@@ -327,6 +333,74 @@ Result
2 | {2.22044604925031e-16,-1,1.11022302462516e-16} | 0.577350269189626 | 0.142857142857041
</pre>
+-# Create sample data in sparse matrix form:
+<pre class="example">
+DROP TABLE IF EXISTS sparse_mat;
+CREATE TABLE sparse_mat (
+ row_id integer,
+ col_id integer,
+ val_id integer
+ );
+INSERT INTO sparse_mat VALUES
+(1, 2, 4.0),
+(1, 5, 6.0),
+(3, 8, 4.0),
+(5, 4, 2.0),
+(6, 6, 12.0),
+(8, 1, 2.0),
+(8, 7, 2.0),
+(9, 3, 4.0),
+(9, 8, 2.0);
+</pre>
+
+-# This matrix is what this matrix looks like in dense form:
+<pre class="example">
+DROP TABLE IF EXISTS dense_mat;
+SELECT madlib.matrix_densify(
+ 'sparse_mat',
+ 'row=row_id, col=col_id, val=val_id',
+ 'dense_mat');
+SELECT * FROM dense_mat order by row_id;
+</pre>
+<pre class="result">
+ row_id | val_id
+--------+--------------------
+ 1 | {0,4,0,0,6,0,0,0}
+ 2 | {0,0,0,0,0,0,0,0}
+ 3 | {0,0,0,0,0,0,0,4}
+ 4 | {0,0,0,0,0,0,0,0}
+ 5 | {0,0,0,2,0,0,0,0}
+ 6 | {0,0,0,0,0,12,0,0}
+ 7 | {0,0,0,0,0,0,0,0}
+ 8 | {2,0,0,0,0,0,2,0}
+ 9 | {0,0,4,0,0,0,0,2}
+</pre>
+
+-# Run the PCA sparse function for a specified number of principle components and view the results:
+<pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_sparse_train(
+ 'sparse_mat',
+ 'result_table',
+ 'row_id',
+ 'col_id',
+ 'val_id',
+ 9,
+ 8,
+ 5);
+SELECT * FROM result_table;
+</pre>
+Result (with principle components truncated for readability):
+<pre class="result">
+ row_id | principal_components | std_dev | proportion
+--------+----------------------------------------------------------------------------------------
+ 1 | {0.0189854059340971,0.0593979357345431,\u2026 | 4.03069474374092 | 0.604208682045711
+ 2 | {0.0346801706473592,-0.536234300404824,\u2026 | 2.42282285507368 | 0.218308410262949
+ 3 | {0.166190350977087,-0.112693750915351,\u2026 | 1.54680674776235 | 0.0889814051004931
+ 4 | {-0.0699448377725649,0.00569475043252321,\u2026 | 1.10233418049845 | 0.0451911810308358
+ 5 | {0.645363366217337,0.0403370697192613,\u2026 | 0.906957663197704 | 0.0305915282045503
+</pre>
+
@anchor notes
@par Notes
@@ -340,8 +414,8 @@ string should be double-quoted; in this case the input would be '"MyTable"').
- Because of the centering step in PCA (see
\ref background_pca "Technical Background"), sparse matrices almost always
-become dense during the training process. Thus, this implementation
-automatically densifies sparse matrix input, and there should be no expected
+become dense during the training process. Since this implementation
+automatically densifies sparse matrix input, there should be no expected
performance improvement in using sparse matrix input over dense matrix input.
- For the parameter 'components_param', INTEGER and FLOAT are
@@ -360,7 +434,7 @@ proportion had not been reached).
@anchor background_pca
@par Technical Background
-The PCA implemented here uses an SVD decomposition implementation to recover
+The PCA implemented here uses a distributed SVD decomposition implementation to recover
the principal components (as opposed to the directly computing the eigenvectors
of the covariance matrix). Let \f$ \boldsymbol X \f$ be the data matrix, and
let \f$ \hat{x} \f$ be a vector of the column averages of \f$ \boldsymbol{X}\f$.
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/e4e93e09/src/ports/postgres/modules/pca/pca_project.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/pca/pca_project.sql_in b/src/ports/postgres/modules/pca/pca_project.sql_in
index 0a1bfdc..fde15d0 100644
--- a/src/ports/postgres/modules/pca/pca_project.sql_in
+++ b/src/ports/postgres/modules/pca/pca_project.sql_in
@@ -20,7 +20,7 @@ m4_include(`SQLCommon.m4')
<li class="level1"><a href="#project">Projection Function</a></li>
<li class="level1"><a href="#examples">Examples</a></li>
<li class="level1"><a href="#notes">Notes</a></li>
-<li class="level1"><a href="#background">Technical Background</a></li>
+<li class="level1"><a href="#background_project">Technical Background</a></li>
<li class="level1"><a href="#related">Related Topics</a></li>
</ul>
</div>
@@ -33,14 +33,16 @@ procedure.
Principal component projection is a mathematical procedure that projects high
dimensional data onto a lower dimensional space. This lower dimensional space
is defined by the \f$ k \f$ principal components with the highest variance in
-the training data. More details on the mathematics of PCA can be found in \ref
-pca_train and some details about the principal component projection calculations
-can be found in the \ref background "Technical Background".
+the training data.
+
+More details on the mathematics of PCA can be found in \ref
+grp_pca_train and some details about principal component projection calculations
+can be found in the \ref background_project "Technical Background".
@anchor project
@par Projection Function
-The projection functions have the following formats:
+The projection functions are slightly different for dense and sparse matrices. For dense matrices:
<pre class="syntax">
madlib.pca_project( source_table,
pc_table,
@@ -50,23 +52,23 @@ madlib.pca_project( source_table,
result_summary_table
)
</pre>
-and
+For sparse matrices:
<pre class="syntax">
madlib.pca_sparse_project( source_table,
pc_table,
out_table,
row_id,
- col_id,
- val_id,
- row_dim,
- col_dim,
+ col_id, -- Sparse matrices only
+ val_id, -- Sparse matrices only
+ row_dim, -- Sparse matrices only
+ col_dim, -- Sparse matrices only
residual_table,
result_summary_table
)
</pre>
-@par Arguments
+\b Arguments
<DL class="arglist">
<DT>source_table</DT>
<DD>TEXT. Source table name.
@@ -75,9 +77,9 @@ and \f$ M \f$ columns, where \f$ N \f$ is the number of data points, and \f$ M
\f$ is the number of features for each data point.
The input table for <em> pca_project </em> is expected to be in the one of the
-two standard MADlib dense matrix formats, and the sparse input table for <em>
-pca_sparse_project </em> should be in the standard MADlib sparse matrix format.
-These formats are described in the documentation for \ref pca_train.</DD>
+two standard MADlib dense matrix formats, and the sparse input table for <em>
+pca_sparse_project </em> should be in the standard MADlib sparse matrix format.
+These formats are described in the documentation for \ref grp_pca_train.</DD>
<DT>pc_table</DT>
<DD>TEXT. Table name for the table containing principal components. </DD>
@@ -98,26 +100,41 @@ principal components. The table has the following columns:
<td>A vector containing elements in the row of the matrix.</td>
</tr>
</table>
-
</DD>
+
<DT>row_id</DT>
<DD>TEXT. Column name containing the row IDs in the input source table. The column
-needs to be of type that can be cast to INT and should only contain values between 1 and
-<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>.</DD>
+should be of type INT (or a type that can be cast to INT) and should only contain values between 1 and
+<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>
+describing the full matrix.</DD>
<DT>col_id</DT>
-<DD>TEXT. Column name of containing the col IDS in sparse matrix representation
-(sparse matrices only). The column should be of type that can be cast to INT and
-contain values between 1 and <em>M</em>.</DD>
+<DD>TEXT. Column name containing the column IDs in sparse matrix representation.
+The column should be of type INT (or a type that can be cast to INT)
+and should only contain values between 1 and <em>M</em>. <em>This parameter applies to
+sparse matrices only.</em></DD>
<DT>val_id</DT>
-<DD>TEXT. Name of 'val_id' column in sparse matrix representation (sparse matrices only). </DD>
+<DD>TEXT. Name of 'val_id' column in sparse matrix representation defining the values of the nonzero entries.
+<em>This parameter applies to sparse matrices only.</em></DD>
<DT>row_dim</DT>
-<DD>INTEGER. The number of rows in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER. The actual number of rows in the matrix. That is,
+if the matrix was transformed into dense format, this is the number of rows
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
<DT>col_dim</DT>
-<DD>INTEGER. The number of columns in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER. The actual number of columns in the matrix. That is,
+if the matrix was transformed into dense format, this is the number of columns
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
+
+@note The parameters 'row_dim' and 'col_dim' could actually be inferred from the
+sparse matrix representation, so they will be removed in the future.
+For now they are maintained for backward compatability so you must enter them.
+Making 'row_dim' or 'col_dim' larger than the actual matrix has the effect of padding it with
+zeros, which is probably not useful.
<DT>residual_table (optional)</DT>
<DD>TEXT, default: NULL. Name of the optional residual table.
@@ -143,7 +160,7 @@ The <em>result_summary_table</em> contains information about the performance tim
<table class="output">
<tr>
<th>exec_time</th>
- <td>Wall clock time (ms) of the function.</td>
+ <td>Elapsed time (ms) for execution of the function.</td>
</tr>
<tr>
<th>residual_norm</th>
@@ -158,12 +175,12 @@ The <em>result_summary_table</em> contains information about the performance tim
@anchor examples
@examp
--# View online help for the PCA projection function.
+-# View online help for the PCA projection function:
<pre class="example">
SELECT madlib.pca_project();
</pre>
--# Create the sample data.
+-# Create the sample data:
<pre class="example">
DROP TABLE IF EXISTS mat;
CREATE TABLE mat (
@@ -178,35 +195,69 @@ INSERT INTO mat VALUES
(5, ARRAY[8,5,7]),
(6, ARRAY[0,5,5]);
</pre>
--# Run the PCA function and keep only the top two PCs:
+-# Run the PCA function and keep only the top two principle components:
<pre class="example">
-DROP TABLE IF EXISTS result_table;
-SELECT pca_train ( 'mat',
- 'result_table',
- 'row_id',
- 2
- );
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train ( 'mat',
+ 'result_table',
+ 'row_id',
+ 2
+ );
+SELECT * FROM result_table;
</pre>
--# Project the original data into a low-dimensional representation.
+<pre class="result">
+ row_id | principal_components | std_dev | proportion
+--------+-------------------------------------------------------------+------------------+-------------------
+ 1 | {-0.995725178022077,0.0921925100100751,0.00564897786728818} | 3.7757341932744 | 0.745095924995985
+ 2 | {0.0900421470942019,0.955231794466691,0.281823758023718} | 1.97776947254051 | 0.204437565497132
+</pre>
+-# Project the original data into a low-dimensional representation:
<pre class="example">
DROP TABLE IF EXISTS residual_table, result_summary_table, out_table;
-SELECT pca_project( 'mat',
- 'result_table',
- 'out_table'
- 'row_id',
- 'residual_table',
- 'result_summary_table'
- );
+SELECT madlib.pca_project( 'mat',
+ 'result_table',
+ 'out_table',
+ 'row_id',
+ 'residual_table',
+ 'result_summary_table'
+ );
+</pre>
+-# View dense matrix with the projection onto the principal components:
+<pre class="example">
+SELECT * FROM out_table ORDER BY row_id;
+</pre>
+<pre class="result">
+ row_id | row_vec
+--------+---------------------------------------
+ 1 | {1.09098309337665,-2.63145496174091}
+ 2 | {3.61719607739251,2.41483045187516}
+ 3 | {-2.17841894858709,0.24593773840028}
+ 4 | {-4.3542543246514,1.97631703314526}
+ 5 | {-3.06500468299723,-1.64480747723177}
+ 6 | {4.88949878544481,-0.360822784430716}
</pre>
--# Check the error in the projection.
+-# Check the error in the projection:
<pre class="example">
SELECT * FROM result_summary_table;
</pre>
-Result:
<pre class="result">
- exec_time | residual_norm | relative_residual_norm
+ exec_time | residual_norm | relative_residual_norm
---------------+---------------+------------------------
- 5685.40501595 | 2.19726255664 | 0.099262204234
+ 56.8881034851 | 2.19726255664 | 0.099262204234
+</pre>
+-# Check the residuals:
+<pre class="example">
+SELECT * FROM residual_table ORDER BY row_id;
+</pre>
+<pre class="result">
+ row_id | row_vec
+--------+------------------------------------------------------------
+ 1 | {0.0160441468047001,0.219103418411008,-0.747769465736052}
+ 2 | {-0.0141636064722857,-0.193422226365899,0.660123132354738}
+ 3 | {0.0197048332985021,0.269094791232932,-0.918383061897929}
+ 4 | {0.00897783310632772,0.122603834748268,-0.418429820364218}
+ 5 | {-0.0333376637524658,-0.455268589780183,1.55376831915842}
+ 6 | {0.00277445701511336,0.037888771752409,-0.129309103509956}
</pre>
@anchor notes
@@ -232,7 +283,7 @@ If mixed-case or multi-byte characters are desired for entity names then the
string should be double-quoted; in this case the input would be '"MyTable"').
-@anchor background
+@anchor background_project
@par Technical Background
Given a table containing some principal components \f$ \boldsymbol P \f$ and