如何在 monte carlo 集成中查找点 x,y 是否在给定矩形内

how to find if a point x,y is inside a given rectangle in monte carlo integration

我正在对包含 rectangle/s 的矩形进行蒙特卡洛积分,该矩形位于封闭矩形内。我想找出未被任何嵌入矩形覆盖的矩形区域。

下面是矩形的class和蒙特卡洛积分。我需要帮助检查一个点是否在给定的矩形内(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) + " width=" + str(rects[i].width) + ")"
            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) + " width=" + str(rect.width) + ")"

        return sb

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

主要问题:

  • 当方法区使用时,方法内部需要一个矩形列表
  • 内部方法在单元测试中使用时,例如 testInsideRectBorderline1Y,需要一个矩形。
  • 修改了里面的方法,所以它需要一个或多个矩形

代码

文件rectangle.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
                                                # 
                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) + " width=" + str(rects[i].width) + ")"
            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) + " width=" + str(rect.width) + ")"

        return sb

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