如何在蒙特卡洛积分中查找点x,y是不是在给定矩形内

Posted

技术标签:

【中文标题】如何在蒙特卡洛积分中查找点x,y是不是在给定矩形内【英文标题】:how to find if a point x,y is inside a given rectangle in monte carlo integration如何在蒙特卡洛积分中查找点x,y是否在给定矩形内 【发布时间】:2021-12-11 18:36:11 【问题描述】:

我正在对一个矩形进行蒙特卡罗积分,该矩形在封闭矩形内包含矩形。我想找出没有被任何嵌入矩形覆盖的矩形区域。

下面是矩形类和蒙特卡罗积分。我需要帮助来检查一个点是否在给定的矩形内(def inside(...))。我得到了错误

File "/skeleton_assignment01_example1/example1/montecarlo.py", line 67, in inside
    number_recs = len(rect)
TypeError: 'method' object cannot be interpreted as an integer

我不知道如何解释这一点,也不是很熟悉使用对象。也许有不同的方法可以做到这一点,或者我的方法是错误的。谢谢


class Rectangle():

    def __init__(self, origin_x, origin_y, length, width):
        self.origin_x = origin_x
        self.origin_y = origin_y
        self.length = length
        self.width = width
    
    def rect_values(self):
        return self.origin_x, self.origin_y, self.length, self.width

from random import random


class MonteCarlo:

    def __init__(self, length, width, rectangles):
       
        rect_specs = length or width or rectangles
        
        if isinstance(rect_specs, type(None)):
            raise ValueError
        
        self.rec_length = length
        self.rec_width = width
        self.rects = rectangles
        
        
    
    def area(self, num_of_shots):
        """Method to estimate the area of the enclosing rectangle that is not covered by the embedded rectangles
        """
    
        if isinstance(num_of_shots, type(None)):
            raise ValueError
            
        inside = 0
        total = num_of_shots
        
        for i in range(num_of_shots):
            
            x = random() * self.rec_length
            y = random() * self.rec_width
            
            if self.inside(x,y, self.rects) == True:
                inside += 1
        area = (total - inside) / (total * self.rec_length * self.rec_width)
        return area
    
        
    
    
    def inside(self, x, y, rect):
        """Method to determine if a given point (x,y) is inside a given rectangle
        """
        if (x or y or rect) == None:
            raise ValueError

        number_recs = len(rect)
        for i in range(number_recs):
            origin_x, origin_y, length, width = rect[i].rect_values()
            
            x_line = length+origin_x
            y_line = width+origin_y

            if (x <= x_line and y <= y_line) and (x >= origin_x and y >= origin_y):
                return True

这是运行时抛出错误的长单元测试!希望这会有所帮助。

import unittest

from montecarlo import MonteCarlo
from rectangle import Rectangle

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def get_x(self):
        return self.x

    def get_y(self):
        return self.y


class TestAssignment01ex01Student(unittest.TestCase):
    def testMCwith3rects(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rect2 = Rectangle(6.0, 3.0, 6.0, 4.0)
        rect3 = Rectangle(10.0, 5.0, 4.0, 4.0)
        rects = [rect1, rect2, rect3]

        mc = MonteCarlo(15.0, 10.0, rects)

        area = mc.area(1000000)
        self.assertTrue((area >= 97.5 and area <= 98.5),
                        "MonteCarlo.area(1000000) with the enclosing rectangle 15.0x10.0 " +
                        "and the following embedded rectangles failed (area should be +/- 0.5 to the result 98 but your result is: " + str(
                            area) + " " + self.printRectanglesData(rects))

    def testMCwith2Rects(self):
        # area of enclosing rectangle is 50
        # area of embedded rectangles is 2+12=14
        # result is: 50-14=36
        #
        # embedded rectangle 1 is at position (0,0) with a size of 1x2
        rect1 = Rectangle(0.0, 0.0, 1.0, 2.0)
        # embedded rectangle 2 is at position (7,1) with a size of 3x4
        rect2 = Rectangle(7.0, 1.0, 3.0, 4.0)
        rects = [rect1, rect2]

        mc = MonteCarlo(10.0, 5.0, rects)

        area = mc.area(10000)
        # for 10k random points the estimated area should already be close to correct result of 36
        self.assertTrue((area > 30 and area < 40),
                        "MonteCarlo.area() according to the provided unit test failed! Area should be between 30 and 40 but was " + str(
                            area))

    def testInsideRectBorderline1Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 4.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline2Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 0.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline3Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 4.01)

        self.assertFalse(mc.inside(pt.get_x(), pt.get_y(), rect1),
                         "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                             pt.get_y()) + ") and the rectangle "
                         + self.printRectangleData(rect1) + " returned True but should be False!")

    def testInsideRectBorderline4Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, -0.01)

        self.assertFalse(mc.inside(pt.get_x(), pt.get_y(), rect1),
                         "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                             pt.get_y()) + ") and the rectangle "
                         + self.printRectangleData(rect1) + " returned True but should be False!")

    def testInsideRectBorderline1X(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(0.0, 3.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline2X(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(4.0, 3.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")


   
    # /*************************************
    #  *
    #  * private methods
    #  *
    #  */

    def printRectanglesData(self, rects):
        i = 0
        sb = ""
        while i < len(rects):
            sb += "\n Rectangle ".format(i + 1) + "(x="
            sb += str(rects[i].origin_x) + " y=" + str(rects[i].origin_y)
            sb += " length="
            sb += str(rects[i].length) + " )"
            i += 1
        return sb

    def printRectangleData(self, rect):
        sb = " (x="
        sb += str(rect.origin_x) + " y=" + str(rect.origin_y)
        sb += " length="
        sb += str(rect.length) + " )"

        return sb

if __name__ == '__main__':
    unittest.main()

【问题讨论】:

您希望Rectangle.__len__ 做什么?目前该方法只是返回自身,正如错误所说,len() 需要返回一个整数,但您正在返回一个方法 *** 鼓励为您的代码提供 Minimal, Reproducible Example 和错误信息。提供的代码不会导致错误(即您应该添加正在使用的类的示例)。 感谢 DarrylG 指出! Phydeaux, Rectangle.__len__ 只是我忘记删除的废话,抱歉 @Gunners -- *** 鼓励最小的可重现示例。这是因为你拥有的代码越多,你从读者那里得到答案的可能性就越小。两个建议 1) 最小化代码(即不要包含说明问题所不需要的代码),以及 2) 代码应该适当地从 atted。 【参考方案1】:

主要问题:

方法区域使用时内部的方法需要一个矩形列表 在 testInsideRectBorderline1Y 等单元测试中使用内部方法时,需要一个矩形。 修改了内部方法,使其包含一个或多个矩形

代码

文件矩形.py

class Rectangle():

    def __init__(self, origin_x, origin_y, length, width):
        self.origin_x = origin_x
        self.origin_y = origin_y
        self.length = length
        self.width = width
    
    def rect_values(self):
        return self.origin_x, self.origin_y, self.length, self.width
    

文件 montecarlo.py

from random import random

class MonteCarlo:

    def __init__(self, length, width, rectangles):
       
        if None in (length, width, rectangles):
            raise ValueError
        
        self.rec_length = length
        self.rec_width = width
        self.rects = rectangles
        
        
    
    def area(self, num_of_shots):
        """Method to estimate the area of the enclosing rectangle that is not covered by the embedded rectangles
        """
    
        if isinstance(num_of_shots, type(None)):
            raise ValueError
            
        inside = 0
        total = num_of_shots
        
        for i in range(num_of_shots):
            x = random() * self.rec_length
            y = random() * self.rec_width
            
            if self.inside(x, y, *self.rects):  # Use list unpacking into arguments
                                                # https://***.com/questions/7527849/how-to-extract-parameters-from-a-list-and-pass-them-to-a-function-call
                inside += 1
                
        area = (total - inside) / (total * self.rec_length * self.rec_width)
        return area
    
    
    def inside(self, x, y, *rects):
        """Method to determine if a given point (x,y) is inside one or more rectangles
        """
        if None in (x, y, rects):
            raise ValueError

        for rect in rects:
            origin_x, origin_y, length, width = rect.rect_values()

            x_line = length+origin_x
            y_line = width+origin_y

            # Simplify conditionals and return boolean
            if origin_x <= x <= x_line and origin_y <= y < y_line:
                return True
            
        return False
    

文件 main.py

import unittest

from montecarlo import MonteCarlo
from rectangle import Rectangle

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def get_x(self):
        return self.x

    def get_y(self):
        return self.y


class TestAssignment01ex01Student(unittest.TestCase):
    def testMCwith3rects(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rect2 = Rectangle(6.0, 3.0, 6.0, 4.0)
        rect3 = Rectangle(10.0, 5.0, 4.0, 4.0)
        rects = [rect1, rect2, rect3]

        mc = MonteCarlo(15.0, 10.0, rects)

        area = mc.area(1000000)
        self.assertTrue((area >= 97.5 and area <= 98.5),
                        "MonteCarlo.area(1000000) with the enclosing rectangle 15.0x10.0 " +
                        "and the following embedded rectangles failed (area should be +/- 0.5 to the result 98 but your result is: " + str(
                            area) + " " + self.printRectanglesData(rects))

    def testMCwith2Rects(self):
        # area of enclosing rectangle is 50
        # area of embedded rectangles is 2+12=14
        # result is: 50-14=36
        #
        # embedded rectangle 1 is at position (0,0) with a size of 1x2
        rect1 = Rectangle(0.0, 0.0, 1.0, 2.0)
        # embedded rectangle 2 is at position (7,1) with a size of 3x4
        rect2 = Rectangle(7.0, 1.0, 3.0, 4.0)
        rects = [rect1, rect2]

        mc = MonteCarlo(10.0, 5.0, rects)

        area = mc.area(10000)
        # for 10k random points the estimated area should already be close to correct result of 36
        self.assertTrue((area > 30 and area < 40),
                        "MonteCarlo.area() according to the provided unit test failed! Area should be between 30 and 40 but was " + str(
                            area))

    def testInsideRectBorderline1Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 4.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline2Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 0.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline3Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, 4.01)

        self.assertFalse(mc.inside(pt.get_x(), pt.get_y(), rect1),
                         "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                             pt.get_y()) + ") and the rectangle "
                         + self.printRectangleData(rect1) + " returned True but should be False!")

    def testInsideRectBorderline4Y(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(1.0, -0.01)

        self.assertFalse(mc.inside(pt.get_x(), pt.get_y(), rect1),
                         "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                             pt.get_y()) + ") and the rectangle "
                         + self.printRectangleData(rect1) + " returned True but should be False!")

    def testInsideRectBorderline1X(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(0.0, 3.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")

    def testInsideRectBorderline2X(self):
        rect1 = Rectangle(0.0, 0.0, 4.0, 4.0)
        rects = []

        mc = MonteCarlo(15.0, 10.0, rects)

        pt = Point(4.0, 3.0)

        self.assertTrue(mc.inside(pt.get_x(), pt.get_y(), rect1),
                        "MonteCarlo.inside() with point (x=" + str(pt.get_x()) + "/y=" + str(
                            pt.get_y()) + ") and the rectangle "
                        + self.printRectangleData(rect1) + " returned False but should be True!")


   
    # /*************************************
    #  *
    #  * private methods
    #  *
    #  */

    def printRectanglesData(self, rects):
        i = 0
        sb = ""
        while i < len(rects):
            sb += "\n Rectangle ".format(i + 1) + "(x="
            sb += str(rects[i].origin_x) + " y=" + str(rects[i].origin_y)
            sb += " length="
            sb += str(rects[i].length) + " )"
            i += 1
        return sb

    def printRectangleData(self, rect):
        sb = " (x="
        sb += str(rect.origin_x) + " y=" + str(rect.origin_y)
        sb += " length="
        sb += str(rect.length) + " )"

        return sb

if __name__ == '__main__':
    unittest.main()
    # Note: use line below instead with Jupyter Notebook
    # unittest.main(argv=['first-arg-is-ignored'], exit=False)

【讨论】:

以上是关于如何在蒙特卡洛积分中查找点x,y是不是在给定矩形内的主要内容,如果未能解决你的问题,请参考以下文章

给定两个矩形的坐标,找出矩形是不是重叠

matlab下二重积分的蒙特卡洛算法

怎么判断当前坐标是不是在矩形内(外)部

C语言,给定一个矩形和一个点,判断这个点与矩形的位置关系(顶点 边 矩形内外),用函数形式并返回

在java中判断一个点是不是在一个有斜度的矩形内的 Rectangle的用法

C语言如何求定积分?