code: def _assignment_rule(
      gt_boxes,
      anchor_boxes,
      unit_lengths,
      min_anchor_size,
      scale_thresh=2.0,
      spatial_thresh=1.0,
      uniqueness_on=True,
  ):
      """
      Given two lists of boxes of N ground truth boxes and M anchor boxes,
      compute the assignment between the two, following the assignment rules in
      https://arxiv.org/abs/1903.12174.
      The box order must be (xmin, ymin, xmax, ymax), so please make sure to convert
      to BoxMode.XYXY_ABS before calling this function.
  
      Args:
          gt_boxes, anchor_boxes (Boxes): two Boxes. Contains N & M boxes/anchors, respectively.
          unit_lengths (Tensor): Contains the unit lengths of M anchor boxes.
          min_anchor_size (float): Minimum size of the anchor, in pixels
          scale_thresh (float): The `scale` threshold: the maximum size of the anchor
                                should not be greater than scale_thresh x max(h, w) of
                                the ground truth box.
          spatial_thresh (float): The `spatial` threshold: the l2 distance between the
                                center of the anchor and the ground truth box should not
                                be greater than spatial_thresh x u where u is the unit length.
  
      Returns:
          matches (Tensor[int64]): a vector of length M, where matches[i] is a matched
                  ground-truth index in [0, N)
          match_labels (Tensor[int8]): a vector of length M, where pred_labels[i] indicates
              whether a prediction is a true or false positive or ignored
      """
      gt_boxes, anchor_boxes = gt_boxes.tensor, anchor_boxes.tensor
      N = gt_boxes.shape[0]
      M = anchor_boxes.shape[0]
      if N == 0 or M == 0:
          return (
              gt_boxes.new_full((N,), 0, dtype=torch.int64),
              gt_boxes.new_full((N,), -1, dtype=torch.int8),
          )
  
      # Containment rule
      lt = torch.min(
          gt_boxes[:, None, :2], anchor_boxes[:, :2]
      )  # [N,M,2]
      rb = torch.max(
          gt_boxes[:, None, 2:], anchor_boxes[:, 2:]
      )  # [N,M,2]
      union = cat([lt, rb], dim=2)  # [N,M,4]
  
      dummy_gt_boxes = torch.zeros_like(gt_boxes)
      anchor = (
          dummy_gt_boxes[:, None, :] + anchor_boxes[:, :]
      )  # [N,M,4]
  
      contain_matrix = torch.all(union == anchor, dim=2)  # [N,M]
  
      # Centrality rule, scale
      gt_size_lower = torch.max(
          gt_boxes[:, 2:] - gt_boxes[:, :2], dim=1
      )[
          0
      ]  # [N]
      gt_size_upper = gt_size_lower * scale_thresh  # [N]
      # Fall back for small objects
      gt_size_upper[gt_size_upper < min_anchor_size] = min_anchor_size
      # Due to sampling of locations, the anchor sizes are deducted with sampling strides
      anchor_size = (
          torch.max(anchor_boxes[:, 2:] - anchor_boxes[:, :2], dim=1)[0]
          - unit_lengths
      )  # [M]
  
      size_diff_upper = gt_size_upper[:, None] - anchor_size  # [N,M]
      scale_matrix = size_diff_upper >= 0  # [N,M]
  
      # Centrality rule, spatial
      gt_center = (gt_boxes[:, 2:] + gt_boxes[:, :2]) / 2  # [N,2]
      anchor_center = (
          anchor_boxes[:, 2:] + anchor_boxes[:, :2]
      ) / 2  # [M,2]
      offset_center = (
          gt_center[:, None, :] - anchor_center[:, :]
      )  # [N,M,2]
      offset_center /= unit_lengths[:, None]  # [N,M,2]
      spatial_square = spatial_thresh * spatial_thresh
      spatial_matrix = (
          torch.sum(offset_center * offset_center, dim=2)
          <= spatial_square
      )
  
      assign_matrix = (
          contain_matrix & scale_matrix & spatial_matrix
      ).int()
  
      # assign_matrix is N (gt) x M (predicted)
      # Max over gt elements (dim 0) to find best gt candidate for each prediction
      matched_vals, matches = assign_matrix.max(dim=0)
      match_labels = matches.new_full(
          matches.size(), 1, dtype=torch.int8
      )
  
      match_labels[matched_vals == 0] = 0
      match_labels[matched_vals == 1] = 1
  
      # find all the elements that match to ground truths multiple times
      not_unique_idxs = assign_matrix.sum(dim=0) > 1
      if uniqueness_on:
          match_labels[not_unique_idxs] = 0
      else:
          match_labels[not_unique_idxs] = -1
  
      return matches, match_labels
  
imports: import copy
  import math
  from typing import List
  import torch
  import torch.nn.functional
  from fvcore.nn import sigmoid_focal_loss_star_jit, smooth_l1_loss
  from torch import nn
  from detectron2.layers import ShapeSpec, batched_nms, cat, paste_masks_in_image
  from detectron2.modeling.anchor_generator import DefaultAnchorGenerator
  from detectron2.modeling.backbone import build_backbone
  from detectron2.modeling.box_regression import Box2BoxTransform
  from detectron2.modeling.meta_arch.build import META_ARCH_REGISTRY
  from detectron2.modeling.meta_arch.retinanet import permute_to_N_HWA_K
  from detectron2.structures import Boxes, ImageList, Instances
  from tensormask.layers import SwapAlign2Nat
label_desc: Use image node_id 2 for calling a global function with example usage: _assignment_rule(gt_boxes, anchor_boxes, unit_lengths, min_anchor_size, scale_thresh, spatial_thresh, uniqueness_on) and returns: matches,  match_labels, gt_boxes,  gt_boxes