[{"id":33375,"web_url":"https://patchwork.libcamera.org/comment/33375/","msgid":"<20250217105024.GA16021@pendragon.ideasonboard.com>","date":"2025-02-17T10:50:24","subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Stefan,\n\nThank you for the patch.\n\nOn Mon, Feb 17, 2025 at 11:01:44AM +0100, Stefan Klug wrote:\n> For calculations in upcoming algorithm patches, the inverse of a matrix\n> is required. Add an implementation of the inverse() function for 3x3\n> matrices.\n> \n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> ---\n>  include/libcamera/internal/matrix.h | 24 ++++++++++++++++++++++++\n>  src/libcamera/matrix.cpp            | 10 ++++++++++\n>  2 files changed, 34 insertions(+)\n> \n> diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\n> index ca81dcda93c4..053336e9cfa4 100644\n> --- a/include/libcamera/internal/matrix.h\n> +++ b/include/libcamera/internal/matrix.h\n> @@ -90,6 +90,30 @@ public:\n>  \t\treturn *this;\n>  \t}\n>  \n> +\tMatrix<T, Rows, Cols> inverse() const\n> +\t{\n> +\t\tstatic_assert(Rows == 3 && Cols == 3, \"Matrix must be 3x3\");\n\nYou know what I'll ask, right ? :-)\n\nInverting the matrix only makes sense when T is a floating point type.\nI'd add a static assertion or enable_if for this.\n\n> +\n> +\t\tconst auto &m = *this;\n> +\t\tdouble det = m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) -\n> +\t\t\t     m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) +\n> +\t\t\t     m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);\n\nCalculating the determinant should be moved to its own function, it's\nuseful by itself.\n\n> +\n> +\t\tdouble invdet = 1 / det;\n\nWhat if det is zero (or very close) ?\n\n> +\n> +\t\tMatrix<T, Rows, Cols> ret;\n> +\t\tret[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invdet;\n> +\t\tret[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invdet;\n> +\t\tret[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invdet;\n> +\t\tret[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invdet;\n> +\t\tret[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invdet;\n> +\t\tret[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invdet;\n> +\t\tret[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invdet;\n> +\t\tret[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invdet;\n> +\t\tret[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invdet;\n\nThat's a lot of calculation for an inline function, please move it to\nthe .cpp file.\n\n> +\t\treturn ret;\n> +\t}\n> +\n>  \ttemplate<typename T2>\n>  \tMatrix<T2, Rows, Cols> cast() const\n>  \t{\n> diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\n> index 91a3f16405a3..b17a1938f1ba 100644\n> --- a/src/libcamera/matrix.cpp\n> +++ b/src/libcamera/matrix.cpp\n> @@ -77,6 +77,16 @@ LOG_DEFINE_CATEGORY(Matrix)\n>   * \\return Row \\a i from the matrix, as a Span\n>   */\n>  \n> +/**\n> + * \\fn Matrix::inverse() const\n> + * \\brief Compute the inverse of the matrix\n> + *\n> + * This function computes the inverse of the matrix. It is only implemented for\n> + * 3x3 matrices.\n> + *\n> + * \\return The inverse of the matrix\n> + */\n> +\n>  /**\n>   * \\fn template<typename T2> Matrix<T2, Rows, Cols> Matrix::cast() const\n>   * \\brief Cast the matrix to a different type","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 28B75BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Feb 2025 10:50:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B62FF68666;\n\tMon, 17 Feb 2025 11:50:40 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C59C861861\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Feb 2025 11:50:38 +0100 (CET)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 382F7B3;\n\tMon, 17 Feb 2025 11:49:17 +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=\"omzj/baW\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1739789357;\n\tbh=0rFBR92godjBZkQz4Vg9+55u0yPSkVVfR/OASnI9hwg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=omzj/baWKobx6SzRw3qEaq5N+B/DNS27liIvnnZQZ0Beq/i3MjVx3RX8Zv4KdG+hW\n\tSh4vVLwHgOVIdXVr5rX2KSGF8I6M4AGEcx0zwFDkj9g1LWfSXL9qKhORVnzzpNqtab\n\t0HUOy5GYvjrSxJvPlP+lH4fc7via2sp9PRWUTH/4=","Date":"Mon, 17 Feb 2025 12:50:24 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","Message-ID":"<20250217105024.GA16021@pendragon.ideasonboard.com>","References":"<20250217100203.297894-1-stefan.klug@ideasonboard.com>\n\t<20250217100203.297894-4-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250217100203.297894-4-stefan.klug@ideasonboard.com>","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>"}},{"id":33377,"web_url":"https://patchwork.libcamera.org/comment/33377/","msgid":"<i5tum22auf5dqnk4axo5yfyajju5qceue6howq44svcpqq7xit@36kkg5acqwrz>","date":"2025-02-17T12:04:42","subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"content":"Hi Laurent,\n\nThank you for the review. \n\nOn Mon, Feb 17, 2025 at 12:50:24PM +0200, Laurent Pinchart wrote:\n> Hi Stefan,\n> \n> Thank you for the patch.\n> \n> On Mon, Feb 17, 2025 at 11:01:44AM +0100, Stefan Klug wrote:\n> > For calculations in upcoming algorithm patches, the inverse of a matrix\n> > is required. Add an implementation of the inverse() function for 3x3\n> > matrices.\n> > \n> > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> > ---\n> >  include/libcamera/internal/matrix.h | 24 ++++++++++++++++++++++++\n> >  src/libcamera/matrix.cpp            | 10 ++++++++++\n> >  2 files changed, 34 insertions(+)\n> > \n> > diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\n> > index ca81dcda93c4..053336e9cfa4 100644\n> > --- a/include/libcamera/internal/matrix.h\n> > +++ b/include/libcamera/internal/matrix.h\n> > @@ -90,6 +90,30 @@ public:\n> >  \t\treturn *this;\n> >  \t}\n> >  \n> > +\tMatrix<T, Rows, Cols> inverse() const\n> > +\t{\n> > +\t\tstatic_assert(Rows == 3 && Cols == 3, \"Matrix must be 3x3\");\n> \n> You know what I'll ask, right ? :-)\n> \n> Inverting the matrix only makes sense when T is a floating point type.\n> I'd add a static assertion or enable_if for this.\n\nYes, I'll add a static assert for that. Even though we then remove the\ntheoretical ability to use that function with a custom defined type. But\nas that is most likely never going to happen, I can restrict it to\ndouble/float...\n\n> \n> > +\n> > +\t\tconst auto &m = *this;\n> > +\t\tdouble det = m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) -\n> > +\t\t\t     m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) +\n> > +\t\t\t     m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);\n> \n> Calculating the determinant should be moved to its own function, it's\n> useful by itself.\n\nYes, I can add that.\n\n> \n> > +\n> > +\t\tdouble invdet = 1 / det;\n> \n> What if det is zero (or very close) ?\n\nThen the values get very large :-) Jokes aside, what do you expect to\nhappen? Should we add an optional output parameter for the determinant,\nso that the caller could check it? Or limit it to something close above 0?\n\n> \n> > +\n> > +\t\tMatrix<T, Rows, Cols> ret;\n> > +\t\tret[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invdet;\n> > +\t\tret[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invdet;\n> > +\t\tret[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invdet;\n> > +\t\tret[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invdet;\n> > +\t\tret[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invdet;\n> > +\t\tret[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invdet;\n> > +\t\tret[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invdet;\n> > +\t\tret[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invdet;\n> > +\t\tret[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invdet;\n> \n> That's a lot of calculation for an inline function, please move it to\n> the .cpp file.\n\nSomehow I don't get it. How would you do that? One could possibly move\nthe function definition into the cpp and explicitly instantiate \nMatrix<float, 3, 3> and Matrix<double, 3, 3> there.\n\nSomething along the lines:\n\ntemplate<typename T, unsigned int Rows, unsigned int Cols>\nMatrix<T, Rows, Cols> Matrix<T, Rows, Cols>::inverse()\n{\n  ...\n}\n\ntemplate class Matrix<float, 3, 3>;\ntemplate class Matrix<double, 3, 3>;\n\nI gave that a quick try and failed with \"invalid use of incomplete type\nclass\". And if it worked, would that be worth it?\n\nBest regards,\nStefan\n\n> \n> > +\t\treturn ret;\n> > +\t}\n> > +\n> >  \ttemplate<typename T2>\n> >  \tMatrix<T2, Rows, Cols> cast() const\n> >  \t{\n> > diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\n> > index 91a3f16405a3..b17a1938f1ba 100644\n> > --- a/src/libcamera/matrix.cpp\n> > +++ b/src/libcamera/matrix.cpp\n> > @@ -77,6 +77,16 @@ LOG_DEFINE_CATEGORY(Matrix)\n> >   * \\return Row \\a i from the matrix, as a Span\n> >   */\n> >  \n> > +/**\n> > + * \\fn Matrix::inverse() const\n> > + * \\brief Compute the inverse of the matrix\n> > + *\n> > + * This function computes the inverse of the matrix. It is only implemented for\n> > + * 3x3 matrices.\n> > + *\n> > + * \\return The inverse of the matrix\n> > + */\n> > +\n> >  /**\n> >   * \\fn template<typename T2> Matrix<T2, Rows, Cols> Matrix::cast() const\n> >   * \\brief Cast the matrix to a different type\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","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 E3A68BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Feb 2025 12:04:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EAEB968668;\n\tMon, 17 Feb 2025 13:04:46 +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 560A261865\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Feb 2025 13:04:45 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:b47f:e20a:c4c7:ece1])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D6054842;\n\tMon, 17 Feb 2025 13:03:23 +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=\"ZFivbVIR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1739793803;\n\tbh=LAXr+F5XwCSVWnVw6pKq8gwQN4tdsoZmy1MZCEypJkI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ZFivbVIRQXHj0O3IqVN5iAZswlHzqy3t/CoP8WNez/UwHAvAS/Ty4ABH7vg0ZzIwz\n\tzBiCRZOe9do4TypxqRKUAr+nMlG+6WR7sCSaxSOvPQ0KjU3IE932aEhA9F6d29AAH2\n\tLAodDWq4L41rUjtwstDuYStg0jM923AtVhw/fH8Y=","Date":"Mon, 17 Feb 2025 13:04:42 +0100","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","Message-ID":"<i5tum22auf5dqnk4axo5yfyajju5qceue6howq44svcpqq7xit@36kkg5acqwrz>","References":"<20250217100203.297894-1-stefan.klug@ideasonboard.com>\n\t<20250217100203.297894-4-stefan.klug@ideasonboard.com>\n\t<20250217105024.GA16021@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250217105024.GA16021@pendragon.ideasonboard.com>","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>"}},{"id":33382,"web_url":"https://patchwork.libcamera.org/comment/33382/","msgid":"<20250217124223.GB28404@pendragon.ideasonboard.com>","date":"2025-02-17T12:42:23","subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Mon, Feb 17, 2025 at 01:04:42PM +0100, Stefan Klug wrote:\n> Hi Laurent,\n> \n> Thank you for the review. \n> \n> On Mon, Feb 17, 2025 at 12:50:24PM +0200, Laurent Pinchart wrote:\n> > Hi Stefan,\n> > \n> > Thank you for the patch.\n> > \n> > On Mon, Feb 17, 2025 at 11:01:44AM +0100, Stefan Klug wrote:\n> > > For calculations in upcoming algorithm patches, the inverse of a matrix\n> > > is required. Add an implementation of the inverse() function for 3x3\n> > > matrices.\n> > > \n> > > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> > > ---\n> > >  include/libcamera/internal/matrix.h | 24 ++++++++++++++++++++++++\n> > >  src/libcamera/matrix.cpp            | 10 ++++++++++\n> > >  2 files changed, 34 insertions(+)\n> > > \n> > > diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\n> > > index ca81dcda93c4..053336e9cfa4 100644\n> > > --- a/include/libcamera/internal/matrix.h\n> > > +++ b/include/libcamera/internal/matrix.h\n> > > @@ -90,6 +90,30 @@ public:\n> > >  \t\treturn *this;\n> > >  \t}\n> > >  \n> > > +\tMatrix<T, Rows, Cols> inverse() const\n> > > +\t{\n> > > +\t\tstatic_assert(Rows == 3 && Cols == 3, \"Matrix must be 3x3\");\n> > \n> > You know what I'll ask, right ? :-)\n\nBy this comment I meant can the function be generalized to other sizes ?\n\n> > Inverting the matrix only makes sense when T is a floating point type.\n> > I'd add a static assertion or enable_if for this.\n> \n> Yes, I'll add a static assert for that. Even though we then remove the\n> theoretical ability to use that function with a custom defined type. But\n> as that is most likely never going to happen, I can restrict it to\n> double/float...\n> \n> > > +\n> > > +\t\tconst auto &m = *this;\n> > > +\t\tdouble det = m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) -\n> > > +\t\t\t     m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) +\n> > > +\t\t\t     m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);\n> > \n> > Calculating the determinant should be moved to its own function, it's\n> > useful by itself.\n> \n> Yes, I can add that.\n> \n> > > +\n> > > +\t\tdouble invdet = 1 / det;\n> > \n> > What if det is zero (or very close) ?\n> \n> Then the values get very large :-) Jokes aside, what do you expect to\n> happen? Should we add an optional output parameter for the determinant,\n> so that the caller could check it? Or limit it to something close above 0?\n\nI'm concerned about divisions by zero. As long as it doesn't crash or\ncause undefined behaviour, that's fine. For use cases such as inverting\nCCM matrices I don't think it will be a practical issue, but it would\nstill be good to handle it properly in the API. An output parameter for\nthe determinant can be useful to inform the caller.\n\n> > > +\n> > > +\t\tMatrix<T, Rows, Cols> ret;\n> > > +\t\tret[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invdet;\n> > > +\t\tret[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invdet;\n> > > +\t\tret[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invdet;\n> > > +\t\tret[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invdet;\n> > > +\t\tret[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invdet;\n> > > +\t\tret[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invdet;\n> > > +\t\tret[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invdet;\n> > > +\t\tret[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invdet;\n> > > +\t\tret[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invdet;\n> > \n> > That's a lot of calculation for an inline function, please move it to\n> > the .cpp file.\n> \n> Somehow I don't get it. How would you do that? One could possibly move\n> the function definition into the cpp and explicitly instantiate \n> Matrix<float, 3, 3> and Matrix<double, 3, 3> there.\n> \n> Something along the lines:\n> \n> template<typename T, unsigned int Rows, unsigned int Cols>\n> Matrix<T, Rows, Cols> Matrix<T, Rows, Cols>::inverse()\n> {\n>   ...\n> }\n> \n> template class Matrix<float, 3, 3>;\n> template class Matrix<double, 3, 3>;\n> \n> I gave that a quick try and failed with \"invalid use of incomplete type\n> class\". And if it worked, would that be worth it?\n\nI'd make a function that operates on data_, and takes the size as an\nargument.\n\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > >  \ttemplate<typename T2>\n> > >  \tMatrix<T2, Rows, Cols> cast() const\n> > >  \t{\n> > > diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\n> > > index 91a3f16405a3..b17a1938f1ba 100644\n> > > --- a/src/libcamera/matrix.cpp\n> > > +++ b/src/libcamera/matrix.cpp\n> > > @@ -77,6 +77,16 @@ LOG_DEFINE_CATEGORY(Matrix)\n> > >   * \\return Row \\a i from the matrix, as a Span\n> > >   */\n> > >  \n> > > +/**\n> > > + * \\fn Matrix::inverse() const\n> > > + * \\brief Compute the inverse of the matrix\n> > > + *\n> > > + * This function computes the inverse of the matrix. It is only implemented for\n> > > + * 3x3 matrices.\n> > > + *\n> > > + * \\return The inverse of the matrix\n> > > + */\n> > > +\n> > >  /**\n> > >   * \\fn template<typename T2> Matrix<T2, Rows, Cols> Matrix::cast() const\n> > >   * \\brief Cast the matrix to a different type","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 E2027BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Feb 2025 12:42:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F30526866C;\n\tMon, 17 Feb 2025 13:42:39 +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 30D2961865\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Feb 2025 13:42:38 +0100 (CET)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AD741A98;\n\tMon, 17 Feb 2025 13:41:16 +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=\"WjQ8i0rT\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1739796076;\n\tbh=ld2SZ7tTj0vwqK3NxUntuMgjFx5xFYI8LVwD0Fn9VVc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=WjQ8i0rT43j+6IzX89S4Fx9rzVpto74qp1z6xMBhaqNHUpKdSqSH7RWFHk/kzymmd\n\tBK4bI347ikjrTL4aylQk9qJSvCrvytXMza3q7i2QT9H7ftx8/l2WkCPvT3K2SR9bL1\n\tz+fbDSuywy3glauADGnaA7O2KkXoLwWF3CpA3XRQ=","Date":"Mon, 17 Feb 2025 14:42:23 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 03/10] libcamera: matrix: Add inverse() function","Message-ID":"<20250217124223.GB28404@pendragon.ideasonboard.com>","References":"<20250217100203.297894-1-stefan.klug@ideasonboard.com>\n\t<20250217100203.297894-4-stefan.klug@ideasonboard.com>\n\t<20250217105024.GA16021@pendragon.ideasonboard.com>\n\t<i5tum22auf5dqnk4axo5yfyajju5qceue6howq44svcpqq7xit@36kkg5acqwrz>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<i5tum22auf5dqnk4axo5yfyajju5qceue6howq44svcpqq7xit@36kkg5acqwrz>","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>"}}]