code: def penalized_logp(mol):
      """
      Calculate the reward that consists of log p penalized by SA and # long cycles,
      as described in (Kusner et al. 2017). Scores are normalized based on the
      statistics of 250k_rndm_zinc_drugs_clean.smi dataset.
  
      Args:
          mol: Rdkit mol object
  
      :rtype:
          :class:`float`
      """
  
      # normalization constants, statistics from 250k_rndm_zinc_drugs_clean.smi
      logP_mean = 2.4570953396190123
      logP_std = 1.434324401111988
      SA_mean = -3.0525811293166134
      SA_std = 0.8335207024513095
      cycle_mean = -0.0485696876403053
      cycle_std = 0.2860212110245455
  
      log_p = MolLogP(mol)
      SA = -calculateScore(mol)
  
      # cycle score
      cycle_list = nx.cycle_basis(
          nx.Graph(Chem.rdmolops.GetAdjacencyMatrix(mol))
      )
      if len(cycle_list) == 0:
          cycle_length = 0
      else:
          cycle_length = max([len(j) for j in cycle_list])
      if cycle_length <= 6:
          cycle_length = 0
      else:
          cycle_length = cycle_length - 6
      cycle_score = -cycle_length
  
      normalized_log_p = (log_p - logP_mean) / logP_std
      normalized_SA = (SA - SA_mean) / SA_std
      normalized_cycle = (cycle_score - cycle_mean) / cycle_std
  
      return normalized_log_p + normalized_SA + normalized_cycle
  
file_path: DIG/dig/ggraph/utils/environment.py
imports: import copy
  import itertools
  import networkx
  from rdkit import Chem, DataStructs
  from rdkit.Chem import AllChem, rdMolDescriptors
  from rdkit.Chem.Descriptors import MolLogP, qed
  from rdkit.Chem.FilterCatalog import FilterCatalogParams, FilterCatalog
  from .sascorer import calculateScore
label_desc: Use image node_id 4 for calling a global function with example usage: penalized_logp(mol) and returns: unknown