prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  [Bug] save pointcloud not updates num_points when inf
  ## 🐛 Bug
  
  The function `K.utils.save_pointcloud_ply` doesn't update the final number of points to be serialized when one of the values contain an infinite value.
  
  How to  fix:
  
  update this line https://github.com/kornia/kornia/blob/master/kornia/utils/pointcloud_io.py#L34
  
  ```python
              if not bool(torch.isfinite(xyz).any()):
                  continue
  ```
  by
  
  ```python
              if not bool(torch.isfinite(xyz).any()):
                  num_points -= 1
                  continue
  ```
  
  </issue>
  <code>
  [start of kornia/utils/pointcloud_io.py]
  1 import os
  2 from typing import Optional
  3 
  4 import torch
  5 
  6 
  7 def save_pointcloud_ply(filename: str, pointcloud: torch.Tensor) -> None:
  8     r"""Utility function to save to disk a pointcloud in PLY format.
  9 
  10     Args:
  11         filename: the path to save the pointcloud.
  12         pointcloud: tensor containing the pointcloud to save.
  13           The tensor must be in the shape of :math:`(*, 3)` where the last
  14           component is assumed to be a 3d point coordinate :math:`(X, Y, Z)`.
  15     """
  16     if not isinstance(filename, str) and filename[-3:] == '.ply':
  17         raise TypeError("Input filename must be a string in with the .ply  " "extension. Got {}".format(filename))
  18 
  19     if not torch.is_tensor(pointcloud):
  20         raise TypeError(f"Input pointcloud type is not a torch.Tensor. Got {type(pointcloud)}")
  21 
  22     if not len(pointcloud.shape) == 3 and pointcloud.shape[-1] == 3:
  23         raise TypeError("Input pointcloud must be in the following shape " "HxWx3. Got {}.".format(pointcloud.shape))
  24 
  25     # flatten the input pointcloud in a vector to iterate points
  26     xyz_vec: torch.Tensor = pointcloud.reshape(-1, 3)
  27 
  28     with open(filename, 'w') as f:
  29         data_str: str = ''
  30         num_points: int = xyz_vec.shape[0]
  31         for idx in range(num_points):
  32             xyz = xyz_vec[idx]
  33             if not bool(torch.isfinite(xyz).any()):
  34                 continue
  35             x: float = xyz[0].item()
  36             y: float = xyz[1].item()
  37             z: float = xyz[2].item()
  38             data_str += f'{x} {y} {z}\n'
  39 
  40         f.write("ply\n")
  41         f.write("format ascii 1.0\n")
  42         f.write("comment arraiy generated\n")
  43         f.write("element vertex %d\n" % num_points)
  44         f.write("property double x\n")
  45         f.write("property double y\n")
  46         f.write("property double z\n")
  47         f.write("end_header\n")
  48         f.write(data_str)
  49 
  50 
  51 def load_pointcloud_ply(filename: str, header_size: int = 8) -> torch.Tensor:
  52     r"""Utility function to load from disk a pointcloud in PLY format.
  53 
  54     Args:
  55         filename: the path to the pointcloud.
  56         header_size: the size of the ply file header that will
  57           be skipped during loading.
  58 
  59     Return:
  60         tensor containing the loaded point with shape :math:`(*, 3)` where
  61         :math:`*` represents the number of points.
  62     """
  63     if not isinstance(filename, str) and filename[-3:] == '.ply':
  64         raise TypeError("Input filename must be a string in with the .ply  " "extension. Got {}".format(filename))
  65     if not os.path.isfile(filename):
  66         raise ValueError("Input filename is not an existing file.")
  67     if not (isinstance(header_size, int) and header_size > 0):
  68         raise TypeError(f"Input header_size must be a positive integer. Got {header_size}.")
  69     # open the file and populate tensor
  70     with open(filename) as f:
  71         points = []
  72 
  73         # skip header
  74         lines = f.readlines()[header_size:]
  75 
  76         # iterate over the points
  77         for line in lines:
  78             x_str, y_str, z_str = line.split()
  79             points.append((torch.tensor(float(x_str)), torch.tensor(float(y_str)), torch.tensor(float(z_str))))
  80 
  81         # create tensor from list
  82         pointcloud: torch.Tensor = torch.tensor(points)
  83         return pointcloud
  84
  [end of kornia/utils/pointcloud_io.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/kornia/utils/pointcloud_io.py b/kornia/utils/pointcloud_io.py
  --- a/kornia/utils/pointcloud_io.py
  +++ b/kornia/utils/pointcloud_io.py
  @@ -31,6 +31,7 @@
           for idx in range(num_points):
               xyz = xyz_vec[idx]
               if not bool(torch.isfinite(xyz).any()):
  +                num_points -= 1
                   continue
               x: float = xyz[0].item()
               y: float = xyz[1].item()
  
verification_info: {"golden_diff": "diff --git a/kornia/utils/pointcloud_io.py b/kornia/utils/pointcloud_io.py\n--- a/kornia/utils/pointcloud_io.py\n+++ b/kornia/utils/pointcloud_io.py\n@@ -31,6 +31,7 @@\n         for idx in range(num_points):\n             xyz = xyz_vec[idx]\n             if not bool(torch.isfinite(xyz).any()):\n+                num_points -= 1\n                 continue\n             x: float = xyz[0].item()\n             y: float = xyz[1].item()\n", "issue": "[Bug] save pointcloud not updates num_points when inf\n## \ud83d\udc1b Bug\r\n\r\nThe function `K.utils.save_pointcloud_ply` doesn't update the final number of points to be serialized when one of the values contain an infinite value.\r\n\r\nHow to  fix:\r\n\r\nupdate this line https://github.com/kornia/kornia/blob/master/kornia/utils/pointcloud_io.py#L34\r\n\r\n```python\r\n            if not bool(torch.isfinite(xyz).any()):\r\n                continue\r\n```\r\nby\r\n\r\n```python\r\n            if not bool(torch.isfinite(xyz).any()):\r\n                num_points -= 1\r\n                continue\r\n```\n", "before_files": [{"content": "import os\nfrom typing import Optional\n\nimport torch\n\n\ndef save_pointcloud_ply(filename: str, pointcloud: torch.Tensor) -> None:\n    r\"\"\"Utility function to save to disk a pointcloud in PLY format.\n\n    Args:\n        filename: the path to save the pointcloud.\n        pointcloud: tensor containing the pointcloud to save.\n          The tensor must be in the shape of :math:`(*, 3)` where the last\n          component is assumed to be a 3d point coordinate :math:`(X, Y, Z)`.\n    \"\"\"\n    if not isinstance(filename, str) and filename[-3:] == '.ply':\n        raise TypeError(\"Input filename must be a string in with the .ply  \" \"extension. Got {}\".format(filename))\n\n    if not torch.is_tensor(pointcloud):\n        raise TypeError(f\"Input pointcloud type is not a torch.Tensor. Got {type(pointcloud)}\")\n\n    if not len(pointcloud.shape) == 3 and pointcloud.shape[-1] == 3:\n        raise TypeError(\"Input pointcloud must be in the following shape \" \"HxWx3. Got {}.\".format(pointcloud.shape))\n\n    # flatten the input pointcloud in a vector to iterate points\n    xyz_vec: torch.Tensor = pointcloud.reshape(-1, 3)\n\n    with open(filename, 'w') as f:\n        data_str: str = ''\n        num_points: int = xyz_vec.shape[0]\n        for idx in range(num_points):\n            xyz = xyz_vec[idx]\n            if not bool(torch.isfinite(xyz).any()):\n                continue\n            x: float = xyz[0].item()\n            y: float = xyz[1].item()\n            z: float = xyz[2].item()\n            data_str += f'{x} {y} {z}\\n'\n\n        f.write(\"ply\\n\")\n        f.write(\"format ascii 1.0\\n\")\n        f.write(\"comment arraiy generated\\n\")\n        f.write(\"element vertex %d\\n\" % num_points)\n        f.write(\"property double x\\n\")\n        f.write(\"property double y\\n\")\n        f.write(\"property double z\\n\")\n        f.write(\"end_header\\n\")\n        f.write(data_str)\n\n\ndef load_pointcloud_ply(filename: str, header_size: int = 8) -> torch.Tensor:\n    r\"\"\"Utility function to load from disk a pointcloud in PLY format.\n\n    Args:\n        filename: the path to the pointcloud.\n        header_size: the size of the ply file header that will\n          be skipped during loading.\n\n    Return:\n        tensor containing the loaded point with shape :math:`(*, 3)` where\n        :math:`*` represents the number of points.\n    \"\"\"\n    if not isinstance(filename, str) and filename[-3:] == '.ply':\n        raise TypeError(\"Input filename must be a string in with the .ply  \" \"extension. Got {}\".format(filename))\n    if not os.path.isfile(filename):\n        raise ValueError(\"Input filename is not an existing file.\")\n    if not (isinstance(header_size, int) and header_size > 0):\n        raise TypeError(f\"Input header_size must be a positive integer. Got {header_size}.\")\n    # open the file and populate tensor\n    with open(filename) as f:\n        points = []\n\n        # skip header\n        lines = f.readlines()[header_size:]\n\n        # iterate over the points\n        for line in lines:\n            x_str, y_str, z_str = line.split()\n            points.append((torch.tensor(float(x_str)), torch.tensor(float(y_str)), torch.tensor(float(z_str))))\n\n        # create tensor from list\n        pointcloud: torch.Tensor = torch.tensor(points)\n        return pointcloud\n", "path": "kornia/utils/pointcloud_io.py"}]}