1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/* 2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath Copyright (c) 2011, Intel Corporation. All rights reserved. 3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr> 4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath Redistribution and use in source and binary forms, with or without modification, 6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath are permitted provided that the following conditions are met: 7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath * Redistributions of source code must retain the above copyright notice, this 9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath list of conditions and the following disclaimer. 10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath * Redistributions in binary form must reproduce the above copyright notice, 11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath this list of conditions and the following disclaimer in the documentation 12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath and/or other materials provided with the distribution. 13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath * Neither the name of Intel Corporation nor the names of its contributors may 14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath be used to endorse or promote products derived from this software without 15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath specific prior written permission. 16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ******************************************************************************** 29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath * Content : Documentation on the use of Intel MKL through Eigen 30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ******************************************************************************** 31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath*/ 32c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 33c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace Eigen { 34c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 35c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/** \page TopicUsingIntelMKL Using Intel® Math Kernel Library from Eigen 36c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 37c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\section TopicUsingIntelMKL_Intro Eigen and Intel® Math Kernel Library (Intel® MKL) 38c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 39c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathSince Eigen version 3.1 and later, users can benefit from built-in Intel MKL optimizations with an installed copy of Intel MKL 10.3 (or later). 40c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<a href="http://eigen.tuxfamily.org/Counter/redirect_to_mkl.php"> Intel MKL </a> provides highly optimized multi-threaded mathematical routines for x86-compatible architectures. 41c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIntel MKL is available on Linux, Mac and Windows for both Intel64 and IA32 architectures. 42c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez\warning Be aware that Intel® MKL is a proprietary software. It is the responsibility of the users to buy MKL licenses for their products. Moreover, the license of the user product has to allow linking to proprietary software that excludes any unmodified versions of the GPL. 44c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathUsing Intel MKL through Eigen is easy: 46c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath-# define the \c EIGEN_USE_MKL_ALL macro before including any Eigen's header 47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath-# link your program to MKL libraries (see the <a href="http://software.intel.com/en-us/articles/intel-mkl-link-line-advisor/">MKL linking advisor</a>) 48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath-# on a 64bits system, you must use the LP64 interface (not the ILP64 one) 49c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 50c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathWhen doing so, a number of Eigen's algorithms are silently substituted with calls to Intel MKL routines. 51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathThese substitutions apply only for \b Dynamic \b or \b large enough objects with one of the following four standard scalar types: \c float, \c double, \c complex<float>, and \c complex<double>. 52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathOperations on other scalar types or mixing reals and complexes will continue to use the built-in algorithms. 53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIn addition you can coarsely select choose which parts will be substituted by defining one or multiple of the following macros: 55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<table class="manual"> 57c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>\c EIGEN_USE_BLAS </td><td>Enables the use of external BLAS level 2 and 3 routines (currently works with Intel MKL only)</td></tr> 58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>\c EIGEN_USE_LAPACKE </td><td>Enables the use of external Lapack routines via the <a href="http://www.netlib.org/lapack/lapacke.html">Intel Lapacke</a> C interface to Lapack (currently works with Intel MKL only)</td></tr> 59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>\c EIGEN_USE_LAPACKE_STRICT </td><td>Same as \c EIGEN_USE_LAPACKE but algorithm of lower robustness are disabled. This currently concerns only JacobiSVD which otherwise would be replaced by \c gesvd that is less robust than Jacobi rotations.</td></tr> 60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>\c EIGEN_USE_MKL_VML </td><td>Enables the use of Intel VML (vector operations)</td></tr> 61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>\c EIGEN_USE_MKL_ALL </td><td>Defines \c EIGEN_USE_BLAS, \c EIGEN_USE_LAPACKE, and \c EIGEN_USE_MKL_VML </td></tr> 62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath</table> 63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezFinally, the PARDISO sparse solver shipped with Intel MKL can be used through the \ref PardisoLU, \ref PardisoLLT and \ref PardisoLDLT classes of the \ref PardisoSupport_Module. 65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\section TopicUsingIntelMKL_SupportedFeatures List of supported features 68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathThe breadth of Eigen functionality covered by Intel MKL is listed in the table below. 70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<table class="manual"> 71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><th>Functional domain</th><th>Code example</th><th>MKL routines</th></tr> 72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>Matrix-matrix operations \n \c EIGEN_USE_BLAS </td><td>\code 73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1*m2.transpose(); 74c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.selfadjointView<Lower>()*m2; 75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1*m2.triangularView<Upper>(); 76c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.selfadjointView<Lower>().rankUpdate(m2,1.0); 77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gemm 79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?symm/?hemm 80c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?trmm 81c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathdsyrk/ssyrk 82c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 83c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>Matrix-vector operations \n \c EIGEN_USE_BLAS </td><td>\code 84c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.adjoint()*b; 85c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.selfadjointView<Lower>()*b; 86c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.triangularView<Upper>()*b; 87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 88c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gemv 89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?symv/?hemv 90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?trmv 91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 92c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>LU decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code 93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv1 = m1.lu().solve(v2); 94c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 95c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?getrf 96c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 97c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>Cholesky decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code 98c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv1 = m2.selfadjointView<Upper>().llt().solve(v2); 99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 100c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?potrf 101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 102c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>QR decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code 103c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.householderQr(); 104c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathm1.colPivHouseholderQr(); 105c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 106c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?geqrf 107c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?geqp3 108c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 109c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>Singular value decomposition \n \c EIGEN_USE_LAPACKE </td><td>\code 110c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathJacobiSVD<MatrixXd> svd; 111c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathsvd.compute(m1, ComputeThinV); 112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 113c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gesvd 114c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 115c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>Eigen-value decompositions \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code 116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathEigenSolver<MatrixXd> es(m1); 117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathComplexEigenSolver<MatrixXcd> ces(m1); 118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathSelfAdjointEigenSolver<MatrixXd> saes(m1+m1.transpose()); 119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathGeneralizedSelfAdjointEigenSolver<MatrixXd> 120c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath gsaes(m1+m1.transpose(),m2+m2.transpose()); 121c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gees 123c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gees 124c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?syev/?heev 125c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?syev/?heev, 126c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?potrf 127c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 128c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr class="alt"><td>Schur decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code 129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathRealSchur<MatrixXd> schurR(m1); 130c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathComplexSchur<MatrixXcd> schurC(m1); 131c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath?gees 133c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 134c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath<tr><td>Vector Math \n \c EIGEN_USE_MKL_VML </td><td>\code 135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().sin(); 136c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().asin(); 137c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().cos(); 138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().acos(); 139c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().tan(); 140c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().exp(); 141c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().log(); 142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().sqrt(); 143c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().square(); 144c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv2=v1.array().pow(1.5); 145c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td><td>\code 146c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Sin 147c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Asin 148c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Cos 149c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Acos 150c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Tan 151c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Exp 152c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Ln 153c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Sqrt 154c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Sqr 155c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathv?Powx 156c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\endcode</td></tr> 157c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath</table> 158c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIn the examples, m1 and m2 are dense matrices and v1 and v2 are dense vectors. 159c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 160c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 161c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath\section TopicUsingIntelMKL_Links Links 162c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath- Intel MKL can be purchased and downloaded <a href="http://eigen.tuxfamily.org/Counter/redirect_to_mkl.php">here</a>. 163c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath- Intel MKL is also bundled with <a href="http://software.intel.com/en-us/articles/intel-composer-xe/">Intel Composer XE</a>. 164c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 165c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 166c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath*/ 167c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 169