class_docstr: Class that performs the main optimization.
  Keeps track of the current x and iterates through data to learn x given the penalty and order.
class_docstr_tok: ["Class","that","performs","the","main","optimization",".","Keeps","track","of","the","current","x","and","iterates","through","data","to","learn","x","given","the","penalty","and","order","."]
docstr: Calculate L1 Penalty.
docstr_tok: ["Calculate","L1","Penalty","."]
code: def penalty(self, s):
      """
      Calculate L1 Penalty.
      """
      to_return = torch.sum(s) / self.D
      if self.soft_groups is not None:
          # if soft_groups, there is an additional penalty for using more
          # groups
          s_grouped = torch.zeros(
              self.soft_D,
              1,
              dtype=torch.get_default_dtype(),
              device=self.device,
          )
          for group in torch.unique(self.soft_groups):
              # groups should be indexed 0 to n_group - 1
              # TODO: consider other functions here
              s_grouped[group] = s[self.soft_groups == group].max()
          # each component of the penalty contributes .5
          # TODO: could make this a user given parameter
          to_return = (
              to_return + torch.sum(s_grouped) / self.soft_D
          ) * 0.5
      return to_return
  
imports: import time
  import numpy
  import scipy.special
  import torch
  import torch.nn
  from .None import constants
  from .None import syssettings
  from .fginitialize import ChunkDataLoader
label_desc: Use image node_id 2 for calling the Solver obj's underlying member method code with example usage: obj.penalty(s) and returns: to_return