class_docstr: Fast Adaptive Boundary Attack (Linf, L2, L1)
  https://arxiv.org/abs/1907.02044
  
  :param predict:       forward pass function
  :param norm:          Lp-norm to minimize ('Linf', 'L2', 'L1' supported)
  :param n_restarts:    number of random restarts
  :param n_iter:        number of iterations
  :param eps:           epsilon for the random restarts
  :param alpha_max:     alpha_max
  :param eta:           overshooting
  :param beta:          backward step
  :param device:        device to use ('cuda' or 'cpu')
code: def projection_l1(
      self, points_to_project, w_hyperplane, b_hyperplane
  ):
      t = points_to_project.clone()
      w = w_hyperplane.clone()
      b = b_hyperplane.clone()
  
      c = (w * t).sum(1) - b
      ind2 = (c < 0).nonzero().squeeze()
      ind2 = self.check_shape(ind2)
      w[ind2] *= -1
      c[ind2] *= -1
  
      r = torch.max(1 / w, -1 / w)
      r = torch.min(r, 1e12 * torch.ones(r.shape).to(self.device))
      rs, indr = torch.sort(r, dim=1)
      _, indr_rev = torch.sort(indr)
  
      u = torch.arange(0, w.shape[0]).unsqueeze(1)
      u2 = torch.arange(0, w.shape[1]).repeat(w.shape[0], 1)
      c6 = (w < 0).float()
      d = (-t + c6) * (w != 0).float()
      d2 = torch.min(-w * t, w * (1 - t))
      ds = d2[u, indr]
      ds2 = torch.cat((c.unsqueeze(-1), ds), 1)
      s = torch.cumsum(ds2, dim=1)
  
      c4 = s[:, -1] < 0
      c2 = c4.nonzero().squeeze(-1)
      c2 = self.check_shape(c2)
  
      counter = 0
      lb = torch.zeros(c2.shape[0])
      ub = torch.ones(c2.shape[0]) * (s.shape[1])
      nitermax = torch.ceil(
          torch.log2(torch.tensor(s.shape[1]).float())
      )
      counter2 = torch.zeros(lb.shape).long()
  
      while counter < nitermax:
          counter4 = torch.floor((lb + ub) / 2)
          counter2 = counter4.long()
          c3 = s[c2, counter2] > 0
          ind3 = c3.nonzero().squeeze()
          ind32 = (~c3).nonzero().squeeze()
          ind3 = self.check_shape(ind3)
          ind32 = self.check_shape(ind32)
          lb[ind3] = counter4[ind3]
          ub[ind32] = counter4[ind32]
          counter += 1
  
      lb2 = lb.long()
  
      if c2.nelement() != 0:
          alpha = -s[c2, lb2] / w[c2, indr[c2, lb2]]
          c5 = u2[c2].float() < lb.unsqueeze(-1).float()
          u3 = c5[u[: c5.shape[0]], indr_rev[c2]]
          d[c2] = d[c2] * u3.float().to(self.device)
          d[c2, indr[c2, lb2]] = alpha
  
      return d * (w.abs() > 1e-8).float()
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import torch
  import time
  from advertorch.utils import replicate_input
  from advertorch.attacks.utils import zero_gradients
  from .base import Attack
  from .base import LabelMixin
label_desc: Use image node_id 6 for calling the FABAttack obj's underlying member method code with example usage: obj.projection_l1(points_to_project, w_hyperplane, b_hyperplane) and returns: unknown