{"id":21990,"url":"https://patchwork.libcamera.org/api/patches/21990/?format=json","web_url":"https://patchwork.libcamera.org/patch/21990/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20241119103740.1919807-3-stefan.klug@ideasonboard.com>","date":"2024-11-19T10:37:29","name":"[v2,2/9] libcamera: Copy Matrix class from libipa to libcamera","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"5e62b225fe24397b1019e88de29de0c0b8fe8063","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/?format=json","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/21990/mbox/","series":[{"id":4803,"url":"https://patchwork.libcamera.org/api/series/4803/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4803","date":"2024-11-19T10:37:27","name":"ove Matrix class from libipa to libcamera","version":2,"mbox":"https://patchwork.libcamera.org/series/4803/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/21990/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/21990/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 060FEC326B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 19 Nov 2024 10:37:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5F94265EF1;\n\tTue, 19 Nov 2024 11:37:54 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6D1D265EEB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 19 Nov 2024 11:37:51 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:bf40:cdab:103d:2270])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 22DFB641;\n\tTue, 19 Nov 2024 11:37:34 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"cAoejkZC\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1732012654;\n\tbh=RRvc2L3SSk6XZuUrnPxtGOUDlSvpL//UR+2sHogKWXQ=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=cAoejkZCdP9xC0yl5q1vnLwMbNUYL0YOLI320r/dTLAEMJ36TeFgcaVTLmq7RgxVk\n\tHk/M+9NBlgimJ80dX+unYiFNFzOfWlo1iIZZeZy6ajhFJNE1e0Q1/FxMF113/mVNty\n\toLph/44p7WqfJoancIc8qQYekAcP7H3MFfkPM15o=","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","Subject":"[PATCH v2 2/9] libcamera: Copy Matrix class from libipa to libcamera","Date":"Tue, 19 Nov 2024 11:37:29 +0100","Message-ID":"<20241119103740.1919807-3-stefan.klug@ideasonboard.com>","X-Mailer":"git-send-email 2.43.0","In-Reply-To":"<20241119103740.1919807-1-stefan.klug@ideasonboard.com>","References":"<20241119103740.1919807-1-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"In preparation to moving the matrix implementation from libipa to\nlibcamera copy the corresponding files to the new location. The files\nare copied without modification to make upcoming integration changes\neasier to see. The new files are not included in the build and therefore\nhave no negative side effects on the build.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n---\n include/libcamera/internal/matrix.h | 203 ++++++++++++++++++++++++++++\n src/libcamera/matrix.cpp            | 149 ++++++++++++++++++++\n 2 files changed, 352 insertions(+)\n create mode 100644 include/libcamera/internal/matrix.h\n create mode 100644 src/libcamera/matrix.cpp","diff":"diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\nnew file mode 100644\nindex 000000000000..5471e6975b74\n--- /dev/null\n+++ b/include/libcamera/internal/matrix.h\n@@ -0,0 +1,203 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>\n+ *\n+ * Matrix and related operations\n+ */\n+#pragma once\n+\n+#include <algorithm>\n+#include <sstream>\n+#include <vector>\n+\n+#include <libcamera/base/log.h>\n+#include <libcamera/base/span.h>\n+\n+#include \"libcamera/internal/yaml_parser.h\"\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(Matrix)\n+\n+namespace ipa {\n+\n+#ifndef __DOXYGEN__\n+template<typename T, unsigned int Rows, unsigned int Cols,\n+\t std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>\n+#else\n+template<typename T, unsigned int Rows, unsigned int Cols>\n+#endif /* __DOXYGEN__ */\n+class Matrix\n+{\n+public:\n+\tMatrix()\n+\t{\n+\t\tdata_.fill(static_cast<T>(0));\n+\t}\n+\n+\tMatrix(const std::vector<T> &data)\n+\t{\n+\t\tstd::copy(data.begin(), data.end(), data_.begin());\n+\t}\n+\n+\tstatic Matrix identity()\n+\t{\n+\t\tMatrix ret;\n+\t\tfor (size_t i = 0; i < std::min(Rows, Cols); i++)\n+\t\t\tret[i][i] = static_cast<T>(1);\n+\t\treturn ret;\n+\t}\n+\n+\t~Matrix() = default;\n+\n+\tconst std::string toString() const\n+\t{\n+\t\tstd::stringstream out;\n+\n+\t\tout << \"Matrix { \";\n+\t\tfor (unsigned int i = 0; i < Rows; i++) {\n+\t\t\tout << \"[ \";\n+\t\t\tfor (unsigned int j = 0; j < Cols; j++) {\n+\t\t\t\tout << (*this)[i][j];\n+\t\t\t\tout << ((j + 1 < Cols) ? \", \" : \" \");\n+\t\t\t}\n+\t\t\tout << ((i + 1 < Rows) ? \"], \" : \"]\");\n+\t\t}\n+\t\tout << \" }\";\n+\n+\t\treturn out.str();\n+\t}\n+\n+\tSpan<const T, Cols> operator[](size_t i) const\n+\t{\n+\t\treturn Span<const T, Cols>{ &data_.data()[i * Cols], Cols };\n+\t}\n+\n+\tSpan<T, Cols> operator[](size_t i)\n+\t{\n+\t\treturn Span<T, Cols>{ &data_.data()[i * Cols], Cols };\n+\t}\n+\n+#ifndef __DOXYGEN__\n+\ttemplate<typename U, std::enable_if_t<std::is_arithmetic_v<U>>>\n+#else\n+\ttemplate<typename U>\n+#endif /* __DOXYGEN__ */\n+\tMatrix<T, Rows, Cols> &operator*=(U d)\n+\t{\n+\t\tfor (unsigned int i = 0; i < Rows * Cols; i++)\n+\t\t\tdata_[i] *= d;\n+\t\treturn *this;\n+\t}\n+\n+private:\n+\tstd::array<T, Rows * Cols> data_;\n+};\n+\n+#ifndef __DOXYGEN__\n+template<typename T, typename U, unsigned int Rows, unsigned int Cols,\n+\t std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>\n+#else\n+template<typename T, typename U, unsigned int Rows, unsigned int Cols>\n+#endif /* __DOXYGEN__ */\n+Matrix<U, Rows, Cols> operator*(T d, const Matrix<U, Rows, Cols> &m)\n+{\n+\tMatrix<U, Rows, Cols> result;\n+\n+\tfor (unsigned int i = 0; i < Rows; i++) {\n+\t\tfor (unsigned int j = 0; j < Cols; j++)\n+\t\t\tresult[i][j] = d * m[i][j];\n+\t}\n+\n+\treturn result;\n+}\n+\n+#ifndef __DOXYGEN__\n+template<typename T, typename U, unsigned int Rows, unsigned int Cols,\n+\t std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>\n+#else\n+template<typename T, typename U, unsigned int Rows, unsigned int Cols>\n+#endif /* __DOXYGEN__ */\n+Matrix<U, Rows, Cols> operator*(const Matrix<U, Rows, Cols> &m, T d)\n+{\n+\treturn d * m;\n+}\n+\n+#ifndef __DOXYGEN__\n+template<typename T,\n+\t unsigned int R1, unsigned int C1,\n+\t unsigned int R2, unsigned int C2,\n+\t std::enable_if_t<C1 == R2> * = nullptr>\n+#else\n+template<typename T, unsigned int R1, unsigned int C1, unsigned int R2, unsigned in C2>\n+#endif /* __DOXYGEN__ */\n+Matrix<T, R1, C2> operator*(const Matrix<T, R1, C1> &m1, const Matrix<T, R2, C2> &m2)\n+{\n+\tMatrix<T, R1, C2> result;\n+\n+\tfor (unsigned int i = 0; i < R1; i++) {\n+\t\tfor (unsigned int j = 0; j < C2; j++) {\n+\t\t\tT sum = 0;\n+\n+\t\t\tfor (unsigned int k = 0; k < C1; k++)\n+\t\t\t\tsum += m1[i][k] * m2[k][j];\n+\n+\t\t\tresult[i][j] = sum;\n+\t\t}\n+\t}\n+\n+\treturn result;\n+}\n+\n+template<typename T, unsigned int Rows, unsigned int Cols>\n+Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &m1, const Matrix<T, Rows, Cols> &m2)\n+{\n+\tMatrix<T, Rows, Cols> result;\n+\n+\tfor (unsigned int i = 0; i < Rows; i++) {\n+\t\tfor (unsigned int j = 0; j < Cols; j++)\n+\t\t\tresult[i][j] = m1[i][j] + m2[i][j];\n+\t}\n+\n+\treturn result;\n+}\n+\n+#ifndef __DOXYGEN__\n+bool matrixValidateYaml(const YamlObject &obj, unsigned int size);\n+#endif /* __DOXYGEN__ */\n+\n+} /* namespace ipa */\n+\n+#ifndef __DOXYGEN__\n+template<typename T, unsigned int Rows, unsigned int Cols>\n+std::ostream &operator<<(std::ostream &out, const ipa::Matrix<T, Rows, Cols> &m)\n+{\n+\tout << m.toString();\n+\treturn out;\n+}\n+\n+template<typename T, unsigned int Rows, unsigned int Cols>\n+struct YamlObject::Getter<ipa::Matrix<T, Rows, Cols>> {\n+\tstd::optional<ipa::Matrix<T, Rows, Cols>> get(const YamlObject &obj) const\n+\t{\n+\t\tif (!ipa::matrixValidateYaml(obj, Rows * Cols))\n+\t\t\treturn std::nullopt;\n+\n+\t\tipa::Matrix<T, Rows, Cols> matrix;\n+\t\tT *data = &matrix[0][0];\n+\n+\t\tunsigned int i = 0;\n+\t\tfor (const YamlObject &entry : obj.asList()) {\n+\t\t\tconst auto value = entry.get<T>();\n+\t\t\tif (!value)\n+\t\t\t\treturn std::nullopt;\n+\n+\t\t\tdata[i++] = *value;\n+\t\t}\n+\n+\t\treturn matrix;\n+\t}\n+};\n+#endif /* __DOXYGEN__ */\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\nnew file mode 100644\nindex 000000000000..8346f0d34160\n--- /dev/null\n+++ b/src/libcamera/matrix.cpp\n@@ -0,0 +1,149 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>\n+ *\n+ * Matrix and related operations\n+ */\n+\n+#include \"matrix.h\"\n+\n+#include <libcamera/base/log.h>\n+\n+/**\n+ * \\file matrix.h\n+ * \\brief Matrix class\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(Matrix)\n+\n+namespace ipa {\n+\n+/**\n+ * \\class Matrix\n+ * \\brief Matrix class\n+ * \\tparam T Type of numerical values to be stored in the matrix\n+ * \\tparam Rows Number of rows in the matrix\n+ * \\tparam Cols Number of columns in the matrix\n+ */\n+\n+/**\n+ * \\fn Matrix::Matrix()\n+ * \\brief Construct a zero matrix\n+ */\n+\n+/**\n+ * \\fn Matrix::Matrix(const std::vector<T> &data)\n+ * \\brief Construct a matrix from supplied data\n+ * \\param[in] data Data from which to construct a matrix\n+ *\n+ * \\a data is a one-dimensional vector and will be turned into a matrix in\n+ * row-major order. The size of \\a data must be equal to the product of the\n+ * number of rows and columns of the matrix (Rows x Cols).\n+ */\n+\n+/**\n+ * \\fn Matrix::identity()\n+ * \\brief Construct an identity matrix\n+ */\n+\n+/**\n+ * \\fn Matrix::toString()\n+ * \\brief Assemble and return a string describing the matrix\n+ * \\return A string describing the matrix\n+ */\n+\n+/**\n+ * \\fn Span<const T, Cols> Matrix::operator[](size_t i) const\n+ * \\brief Index to a row in the matrix\n+ * \\param[in] i Index of row to retrieve\n+ *\n+ * This operator[] returns a Span, which can then be indexed into again with\n+ * another operator[], allowing a convenient m[i][j] to access elements of the\n+ * matrix. Note that the lifetime of the Span returned by this first-level\n+ * operator[] is bound to that of the Matrix itself, so it is not recommended\n+ * to save the Span that is the result of this operator[].\n+ *\n+ * \\return Row \\a i from the matrix, as a Span\n+ */\n+\n+/**\n+ * \\fn Matrix::operator[](size_t i)\n+ * \\copydoc Matrix::operator[](size_t i) const\n+ */\n+\n+/**\n+ * \\fn Matrix<T, Rows, Cols> &Matrix::operator*=(U d)\n+ * \\brief Multiply the matrix by a scalar in-place\n+ * \\tparam U Type of the numerical scalar value\n+ * \\param d The scalar multiplier\n+ * \\return Product of this matrix and scalar \\a d\n+ */\n+\n+/**\n+ * \\fn Matrix::Matrix<U, Rows, Cols> operator*(T d, const Matrix<U, Rows, Cols> &m)\n+ * \\brief Multiply the matrix by a scalar\n+ * \\tparam T Type of the numerical scalar value\n+ * \\tparam U Type of numerical values in the matrix\n+ * \\tparam Rows Number of rows in the matrix\n+ * \\tparam Cols Number of columns in the matrix\n+ * \\param d The scalar multiplier\n+ * \\param m The matrix\n+ * \\return Product of scalar \\a d and matrix \\a m\n+ */\n+\n+/**\n+ * \\fn Matrix::Matrix<U, Rows, Cols> operator*(const Matrix<U, Rows, Cols> &m, T d)\n+ * \\copydoc operator*(T d, const Matrix<U, Rows, Cols> &m)\n+ */\n+\n+/**\n+ * \\fn Matrix<T, R1, C2> operator*(const Matrix<T, R1, C1> &m1, const Matrix<T, R2, C2> &m2)\n+ * \\brief Matrix multiplication\n+ * \\tparam T Type of numerical values in the matrices\n+ * \\tparam R1 Number of rows in the first matrix\n+ * \\tparam C1 Number of columns in the first matrix\n+ * \\tparam R2 Number of rows in the second matrix\n+ * \\tparam C2 Number of columns in the second matrix\n+ * \\param m1 Multiplicand matrix\n+ * \\param m2 Multiplier matrix\n+ * \\return Matrix product of matrices \\a m1 and \\a m2\n+ */\n+\n+/**\n+ * \\fn Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &m1, const Matrix<T, Rows, Cols> &m2)\n+ * \\brief Matrix addition\n+ * \\tparam T Type of numerical values in the matrices\n+ * \\tparam Rows Number of rows in the matrices\n+ * \\tparam Cols Number of columns in the matrices\n+ * \\param m1 Summand matrix\n+ * \\param m2 Summand matrix\n+ * \\return Matrix sum of matrices \\a m1 and \\a m2\n+ */\n+\n+#ifndef __DOXYGEN__\n+/*\n+ * The YAML data shall be a list of numerical values. Its size shall be equal\n+ * to the product of the number of rows and columns of the matrix (Rows x\n+ * Cols). The values shall be stored in row-major order.\n+ */\n+bool matrixValidateYaml(const YamlObject &obj, unsigned int size)\n+{\n+\tif (!obj.isList())\n+\t\treturn false;\n+\n+\tif (obj.size() != size) {\n+\t\tLOG(Matrix, Error)\n+\t\t\t<< \"Wrong number of values in matrix: expected \"\n+\t\t\t<< size << \", got \" << obj.size();\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+#endif /* __DOXYGEN__ */\n+\n+} /* namespace ipa */\n+\n+} /* namespace libcamera */\n","prefixes":["v2","2/9"]}