[{"id":25858,"web_url":"https://patchwork.libcamera.org/comment/25858/","msgid":"<Y3148hwgEFwQ8fmF@pendragon.ideasonboard.com>","date":"2022-11-23T01:35:46","subject":"Re: [libcamera-devel] [PATCH v3 02/12] utils: tuning: libtuning:\n\tImplement math helpers","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch.\n\nOn Fri, Nov 11, 2022 at 02:31:44AM +0900, Paul Elder via libcamera-devel wrote:\n> Implement math helpers for libtuning. This includes:\n> - Average, a wrapper class for numpy averaging functions\n> - Gradient, a class that represents gradients, for distributing and\n>   mapping\n> - Smoothing, a wrapper class for cv2 smoothing functions\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n> ---\n> Changes in v3:\n> - Newly split from the first patch \"utils: tuning: libtuning: Implement\n>   the core of libtuning\"\n>   - See changelog from that patch\n> ---\n>  utils/tuning/libtuning/average.py   | 21 ++++++++\n>  utils/tuning/libtuning/gradient.py  | 75 +++++++++++++++++++++++++++++\n>  utils/tuning/libtuning/smoothing.py | 24 +++++++++\n>  3 files changed, 120 insertions(+)\n>  create mode 100644 utils/tuning/libtuning/average.py\n>  create mode 100644 utils/tuning/libtuning/gradient.py\n>  create mode 100644 utils/tuning/libtuning/smoothing.py\n> \n> diff --git a/utils/tuning/libtuning/average.py b/utils/tuning/libtuning/average.py\n> new file mode 100644\n> index 00000000..e28770d7\n> --- /dev/null\n> +++ b/utils/tuning/libtuning/average.py\n> @@ -0,0 +1,21 @@\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +#\n> +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> +#\n> +# average.py - Wrapper for numpy averaging functions to enable duck-typing\n> +\n> +import numpy as np\n> +\n> +\n> +# @brief Wrapper for np averaging functions so that they can be duck-typed\n> +class Average(object):\n> +    def __init__(self):\n> +        pass\n> +\n> +    def average(self, np_array):\n> +        raise NotImplementedError\n> +\n> +\n> +class Mean(Average):\n> +    def average(self, np_array):\n> +        return np.mean(np_array)\n> diff --git a/utils/tuning/libtuning/gradient.py b/utils/tuning/libtuning/gradient.py\n> new file mode 100644\n> index 00000000..64a96369\n> --- /dev/null\n> +++ b/utils/tuning/libtuning/gradient.py\n> @@ -0,0 +1,75 @@\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +#\n> +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> +#\n> +# gradient.py - Gradients that can be used to distribute or map numbers\n> +\n> +import libtuning as lt\n> +\n> +import math\n> +from numbers import Number\n> +\n> +\n> +# @brief Gradient for how to allocate pixels to sectors\n> +# @description There are no parameters for the gradients as the domain is the\n> +#              number of pixels and the range is the number of sectors, and\n> +#              there is only one curve that has a startpoint and endpoint at\n> +#              (0, 0) and at (#pixels, #sectors). The exception is for curves\n> +#              that *do* have multiple solutions for only two points, such as\n> +#              gaussian, and curves of higher polynomial orders if we had them.\n> +#\n> +# \\todo There will probably be a helper in the Gradient class, as I have a\n> +# feeling that all the other curves (besides Linear and Gaussian) can be\n> +# implemented in the same way.\n> +class Gradient(object):\n> +    def __init__(self):\n> +        pass\n> +\n> +    # @brief Distribute pixels into sectors (only in one dimension)\n> +    # @param domain Number of pixels\n> +    # @param sectors Number of sectors\n> +    # @return A list of number of pixels in each sector\n> +    def distribute(self, domain: list, sectors: list, ) -> list:\n\nIs the training ', ' a Python syntax I don't know about ?\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +        raise NotImplementedError\n> +\n> +    # @brief Map a number on a curve\n> +    # @param domain Domain of the curve\n> +    # @param rang Range of the curve\n> +    # @param x Input on the domain of the curve\n> +    # @return y from the range of the curve\n> +    def map(self, domain: tuple, rang: tuple, x: Number) -> Number:\n> +        raise NotImplementedError\n> +\n> +\n> +class Linear(Gradient):\n> +    # @param remainder Mode of handling remainder\n> +    def __init__(self, remainder: lt.Remainder = lt.Remainder.Float):\n> +        self.remainder = remainder\n> +\n> +    def distribute(self, domain: list, sectors: list) -> list:\n> +        size = domain / sectors\n> +        rem = domain % sectors\n> +\n> +        if rem == 0:\n> +            return [int(size)] * sectors\n> +\n> +        size = math.ceil(size)\n> +        rem = domain % size\n> +        output_sectors = [int(size)] * (sectors - 1)\n> +\n> +        if self.remainder == lt.Remainder.Float:\n> +            size = domain / sectors\n> +            output_sectors = [size] * sectors\n> +        elif self.remainder == lt.Remainder.DistributeFront:\n> +            output_sectors.append(int(rem))\n> +        elif self.remainder == lt.Remainder.DistributeBack:\n> +            output_sectors.insert(0, int(rem))\n> +        else:\n> +            raise ValueError\n> +\n> +        return output_sectors\n> +\n> +    def map(self, domain: tuple, rang: tuple, x: Number) -> Number:\n> +        m = (rang[1] - rang[0]) / (domain[1] - domain[0])\n> +        b = rang[0] - m * domain[0]\n> +        return m * x + b\n> diff --git a/utils/tuning/libtuning/smoothing.py b/utils/tuning/libtuning/smoothing.py\n> new file mode 100644\n> index 00000000..b8a5a242\n> --- /dev/null\n> +++ b/utils/tuning/libtuning/smoothing.py\n> @@ -0,0 +1,24 @@\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +#\n> +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> +#\n> +# smoothing.py - Wrapper for cv2 smoothing functions to enable duck-typing\n> +\n> +import cv2\n> +\n> +\n> +# @brief Wrapper for cv2 smoothing functions so that they can be duck-typed\n> +class Smoothing(object):\n> +    def __init__(self):\n> +        pass\n> +\n> +    def smoothing(self, src):\n> +        raise NotImplementedError\n> +\n> +\n> +class MedianBlur(Smoothing):\n> +    def __init__(self, ksize):\n> +        self.ksize = ksize\n> +\n> +    def smoothing(self, src):\n> +        return cv2.medianBlur(src.astype('float32'), self.ksize).astype('float64')","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 1D73CBDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 23 Nov 2022 01:36:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6FE6863314;\n\tWed, 23 Nov 2022 02:36:04 +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 1ADED61F2B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Nov 2022 02:36:03 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7B54388F;\n\tWed, 23 Nov 2022 02:36:02 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1669167364;\n\tbh=oR2CTJJMrQ2EoVc3R7UkTM5K/cs+FDR8XeQz3P46HFw=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=baHFrn6E94QD6ry6b1PxxNPmqyRB0Iq52xBDbOhwqiFqVjgC0lhhA4MFdsgiRQkte\n\tlSncEMrbbf/5tkiFpPTKqthQ4M++PHMQbOOMQn/XHcwoMYWb4X16Gs7L6Q79iTCJvY\n\tNq24r+FX11+tn42/PTUW9StaQdL9VNTHhKcOSiVtvwrGXrLxrF7P0tmefx7WsjAxoK\n\tlmgnnAhaBoeHoKFcC2DZZVXqM+gNOrA2he8tt0O4FgUYhTx5PRmcJ8ipV2AKFhr3vD\n\tTXD0kQhAQjvCe4AjqNsGUxqKp0gg8Hri5ufyvaH9XvvRQoTDGdPG2wsE+FJKuV/kWd\n\t3z3mYudSftVeQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1669167362;\n\tbh=oR2CTJJMrQ2EoVc3R7UkTM5K/cs+FDR8XeQz3P46HFw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=bQwsyoEhryobXnnAeo+ro1t8VDJLX5qehy2nNPu1KegrG9M8O0pBOzO+ALAJ4EAkY\n\tluWnBvwU5E43e43gnTSex1Y27reOrsY2J0ZgHOXe7IPwd5CdBHKmr661uANgv/Wf+J\n\tn9qggRe6qoIKCo5b5sMmujPF9dX/h++l3Tz6T5eM="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"bQwsyoEh\"; dkim-atps=neutral","Date":"Wed, 23 Nov 2022 03:35:46 +0200","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<Y3148hwgEFwQ8fmF@pendragon.ideasonboard.com>","References":"<20221110173154.488445-1-paul.elder@ideasonboard.com>\n\t<20221110173154.488445-3-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221110173154.488445-3-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 02/12] utils: tuning: libtuning:\n\tImplement math helpers","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25864,"web_url":"https://patchwork.libcamera.org/comment/25864/","msgid":"<Y330yUJJneIsSQfB@pyrite.rasen.tech>","date":"2022-11-23T10:24:09","subject":"Re: [libcamera-devel] [PATCH v3 02/12] utils: tuning: libtuning:\n\tImplement math helpers","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"On Wed, Nov 23, 2022 at 03:35:46AM +0200, Laurent Pinchart wrote:\n> Hi Paul,\n> \n> Thank you for the patch.\n> \n> On Fri, Nov 11, 2022 at 02:31:44AM +0900, Paul Elder via libcamera-devel wrote:\n> > Implement math helpers for libtuning. This includes:\n> > - Average, a wrapper class for numpy averaging functions\n> > - Gradient, a class that represents gradients, for distributing and\n> >   mapping\n> > - Smoothing, a wrapper class for cv2 smoothing functions\n> > \n> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > \n> > ---\n> > Changes in v3:\n> > - Newly split from the first patch \"utils: tuning: libtuning: Implement\n> >   the core of libtuning\"\n> >   - See changelog from that patch\n> > ---\n> >  utils/tuning/libtuning/average.py   | 21 ++++++++\n> >  utils/tuning/libtuning/gradient.py  | 75 +++++++++++++++++++++++++++++\n> >  utils/tuning/libtuning/smoothing.py | 24 +++++++++\n> >  3 files changed, 120 insertions(+)\n> >  create mode 100644 utils/tuning/libtuning/average.py\n> >  create mode 100644 utils/tuning/libtuning/gradient.py\n> >  create mode 100644 utils/tuning/libtuning/smoothing.py\n> > \n> > diff --git a/utils/tuning/libtuning/average.py b/utils/tuning/libtuning/average.py\n> > new file mode 100644\n> > index 00000000..e28770d7\n> > --- /dev/null\n> > +++ b/utils/tuning/libtuning/average.py\n> > @@ -0,0 +1,21 @@\n> > +# SPDX-License-Identifier: GPL-2.0-or-later\n> > +#\n> > +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> > +#\n> > +# average.py - Wrapper for numpy averaging functions to enable duck-typing\n> > +\n> > +import numpy as np\n> > +\n> > +\n> > +# @brief Wrapper for np averaging functions so that they can be duck-typed\n> > +class Average(object):\n> > +    def __init__(self):\n> > +        pass\n> > +\n> > +    def average(self, np_array):\n> > +        raise NotImplementedError\n> > +\n> > +\n> > +class Mean(Average):\n> > +    def average(self, np_array):\n> > +        return np.mean(np_array)\n> > diff --git a/utils/tuning/libtuning/gradient.py b/utils/tuning/libtuning/gradient.py\n> > new file mode 100644\n> > index 00000000..64a96369\n> > --- /dev/null\n> > +++ b/utils/tuning/libtuning/gradient.py\n> > @@ -0,0 +1,75 @@\n> > +# SPDX-License-Identifier: GPL-2.0-or-later\n> > +#\n> > +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> > +#\n> > +# gradient.py - Gradients that can be used to distribute or map numbers\n> > +\n> > +import libtuning as lt\n> > +\n> > +import math\n> > +from numbers import Number\n> > +\n> > +\n> > +# @brief Gradient for how to allocate pixels to sectors\n> > +# @description There are no parameters for the gradients as the domain is the\n> > +#              number of pixels and the range is the number of sectors, and\n> > +#              there is only one curve that has a startpoint and endpoint at\n> > +#              (0, 0) and at (#pixels, #sectors). The exception is for curves\n> > +#              that *do* have multiple solutions for only two points, such as\n> > +#              gaussian, and curves of higher polynomial orders if we had them.\n> > +#\n> > +# \\todo There will probably be a helper in the Gradient class, as I have a\n> > +# feeling that all the other curves (besides Linear and Gaussian) can be\n> > +# implemented in the same way.\n> > +class Gradient(object):\n> > +    def __init__(self):\n> > +        pass\n> > +\n> > +    # @brief Distribute pixels into sectors (only in one dimension)\n> > +    # @param domain Number of pixels\n> > +    # @param sectors Number of sectors\n> > +    # @return A list of number of pixels in each sector\n> > +    def distribute(self, domain: list, sectors: list, ) -> list:\n> \n> Is the training ', ' a Python syntax I don't know about ?\n\nYeah I think it's a new feature called a typo :p\n\n> \n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n\nThanks,\n\nPaul\n\n> \n> > +        raise NotImplementedError\n> > +\n> > +    # @brief Map a number on a curve\n> > +    # @param domain Domain of the curve\n> > +    # @param rang Range of the curve\n> > +    # @param x Input on the domain of the curve\n> > +    # @return y from the range of the curve\n> > +    def map(self, domain: tuple, rang: tuple, x: Number) -> Number:\n> > +        raise NotImplementedError\n> > +\n> > +\n> > +class Linear(Gradient):\n> > +    # @param remainder Mode of handling remainder\n> > +    def __init__(self, remainder: lt.Remainder = lt.Remainder.Float):\n> > +        self.remainder = remainder\n> > +\n> > +    def distribute(self, domain: list, sectors: list) -> list:\n> > +        size = domain / sectors\n> > +        rem = domain % sectors\n> > +\n> > +        if rem == 0:\n> > +            return [int(size)] * sectors\n> > +\n> > +        size = math.ceil(size)\n> > +        rem = domain % size\n> > +        output_sectors = [int(size)] * (sectors - 1)\n> > +\n> > +        if self.remainder == lt.Remainder.Float:\n> > +            size = domain / sectors\n> > +            output_sectors = [size] * sectors\n> > +        elif self.remainder == lt.Remainder.DistributeFront:\n> > +            output_sectors.append(int(rem))\n> > +        elif self.remainder == lt.Remainder.DistributeBack:\n> > +            output_sectors.insert(0, int(rem))\n> > +        else:\n> > +            raise ValueError\n> > +\n> > +        return output_sectors\n> > +\n> > +    def map(self, domain: tuple, rang: tuple, x: Number) -> Number:\n> > +        m = (rang[1] - rang[0]) / (domain[1] - domain[0])\n> > +        b = rang[0] - m * domain[0]\n> > +        return m * x + b\n> > diff --git a/utils/tuning/libtuning/smoothing.py b/utils/tuning/libtuning/smoothing.py\n> > new file mode 100644\n> > index 00000000..b8a5a242\n> > --- /dev/null\n> > +++ b/utils/tuning/libtuning/smoothing.py\n> > @@ -0,0 +1,24 @@\n> > +# SPDX-License-Identifier: GPL-2.0-or-later\n> > +#\n> > +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>\n> > +#\n> > +# smoothing.py - Wrapper for cv2 smoothing functions to enable duck-typing\n> > +\n> > +import cv2\n> > +\n> > +\n> > +# @brief Wrapper for cv2 smoothing functions so that they can be duck-typed\n> > +class Smoothing(object):\n> > +    def __init__(self):\n> > +        pass\n> > +\n> > +    def smoothing(self, src):\n> > +        raise NotImplementedError\n> > +\n> > +\n> > +class MedianBlur(Smoothing):\n> > +    def __init__(self, ksize):\n> > +        self.ksize = ksize\n> > +\n> > +    def smoothing(self, src):\n> > +        return cv2.medianBlur(src.astype('float32'), self.ksize).astype('float64')","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 3FCAEBE08B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 23 Nov 2022 10:24:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D51A563319;\n\tWed, 23 Nov 2022 11:24:18 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DAFF66330D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Nov 2022 11:24:16 +0100 (CET)","from pyrite.rasen.tech (h175-177-042-159.catv02.itscom.jp\n\t[175.177.42.159])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id ABF09890;\n\tWed, 23 Nov 2022 11:24:15 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1669199058;\n\tbh=vdq8rzGriApO5q/8RmoBq+26WmTNZ512Awu7Uhs+wvA=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=KNxDYpSj/8pkCVSvxNDTgPCOs0jhLbOWTGW78c5Lr2Hc1GCmQZZLyh1r5fS0KmfDv\n\tBgaUde8GhGk0roqmDpwtiblBydhJpd6mFUZd8SMtl4aHY3MxPrOaMPrWo45hRhznuh\n\tB5RVgx5J6JhJ2xg0i1RR0Kl3H1TuLFQ7na1+pdy9F5GTKsw/WRgnFTgzrhDQMaml9y\n\tnwY0M4hu7L+ij3Druiieb/xdeeiSg8deVdhP7lz6sAyJ+QlTNu5UUgrGqaPH87OTZ+\n\t+UDOC+sidacwMziHKoH7gOBOWgN6uiUZkOB9nC2S8oxwqIawZcfAL23LdHNSpNDitf\n\teTi5ooHho+XCQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1669199056;\n\tbh=vdq8rzGriApO5q/8RmoBq+26WmTNZ512Awu7Uhs+wvA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=LZtYz+JcQoI8ZXCcsRxacZyZLEKSupZqNYhsSgKqJF6jNzUCEHLomtrOhf+Yy83hR\n\tWBl8a7/95g9fBKhf4aZMMTmaKdw3HKtuYGI55D5omy18aTVLcLLae09SDd6ydOUSi8\n\tbnbM0J2VOka9K+E02TcZ5YtkXNpDy6KqtmG46guc="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"LZtYz+Jc\"; dkim-atps=neutral","Date":"Wed, 23 Nov 2022 19:24:09 +0900","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<Y330yUJJneIsSQfB@pyrite.rasen.tech>","References":"<20221110173154.488445-1-paul.elder@ideasonboard.com>\n\t<20221110173154.488445-3-paul.elder@ideasonboard.com>\n\t<Y3148hwgEFwQ8fmF@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<Y3148hwgEFwQ8fmF@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 02/12] utils: tuning: libtuning:\n\tImplement math helpers","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>","From":"Paul Elder via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]