class_docstr: An optimization configuration, which comprises an objective,
  outcome constraints and an optional risk measure.
  
  There is no minimum or maximum number of outcome constraints, but an
  individual metric can have at most two constraints--which is how we
  represent metrics with both upper and lower bounds.
class_docstr_tok: ["An","optimization","configuration",",","which","comprises","an","objective",",","outcome","constraints","and","an","optional","risk","measure",".","There","is","no","minimum","or","maximum","number","of","outcome","constraints",",","but","an","individual","metric","can","have","at","most","two","constraints","--","which","is","how","we","represent","metrics","with","both","upper","and","lower","bounds","."]
docstr: Ensure outcome constraints are valid and the risk measure is
  compatible with the objective.
  
  Either one or two outcome constraints can reference one metric.
  If there are two constraints, they must have different 'ops': one
      LEQ and one GEQ.
  If there are two constraints, the bound of the GEQ op must be less
      than the bound of the LEQ op.
  
  Args:
      objective: Metric+direction to use for the optimization.
      outcome_constraints: Constraints to validate.
      risk_measure: An optional risk measure to validate.
docstr_tok: ["Ensure","outcome","constraints","are","valid","and","the","risk","measure","is","compatible","with","the","objective",".","Either","one","or","two","outcome","constraints","can","reference","one","metric",".","If","there","are","two","constraints",",","they","must","have","different","'ops","'",":","one","LEQ","and","one","GEQ",".","If","there","are","two","constraints",",","the","bound","of","the","GEQ","op","must","be","less","than","the","bound","of","the","LEQ","op",".","Args",":","objective",":","Metric+direction","to","use","for","the","optimization",".","outcome_constraints",":","Constraints","to","validate",".","risk_measure",":","An","optional","risk","measure","to","validate","."]
code: def _validate_optimization_config(
      objective: Objective,
      outcome_constraints: Optional[List[OutcomeConstraint]] = None,
      risk_measure: Optional[RiskMeasure] = None,
  ) -> None:
      """Ensure outcome constraints are valid and the risk measure is
      compatible with the objective.
  
      Either one or two outcome constraints can reference one metric.
      If there are two constraints, they must have different 'ops': one
          LEQ and one GEQ.
      If there are two constraints, the bound of the GEQ op must be less
          than the bound of the LEQ op.
  
      Args:
          objective: Metric+direction to use for the optimization.
          outcome_constraints: Constraints to validate.
          risk_measure: An optional risk measure to validate.
      """
      if type(objective) is MultiObjective:
          # Raise error on exact equality; `ScalarizedObjective` is OK
          raise ValueError(
              (
                  "OptimizationConfig does not support MultiObjective. "
                  "Use MultiObjectiveOptimizationConfig instead."
              )
          )
      outcome_constraints = outcome_constraints or []
      # Only vaidate `outcome_constraints`
      outcome_constraints = [
          constraint
          for constraint in outcome_constraints
          if isinstance(constraint, ScalarizedOutcomeConstraint)
          is False
      ]
      unconstrainable_metrics = objective.get_unconstrainable_metrics()
      OptimizationConfig._validate_outcome_constraints(
          unconstrainable_metrics=unconstrainable_metrics,
          outcome_constraints=outcome_constraints,
      )
  
imports: from itertools import groupby
  from logging import Logger
  from typing import Dict, List, Optional
  from ax.core.metric import Metric
  from ax.core.objective import MultiObjective, Objective, ScalarizedObjective
  from ax.core.outcome_constraint import ComparisonOp, ObjectiveThreshold, OutcomeConstraint, ScalarizedOutcomeConstraint
  from ax.core.risk_measures import RiskMeasure
  from ax.exceptions.core import UserInputError
  from ax.utils.common.base import Base
  from ax.utils.common.logger import get_logger
label_desc: Use image node_id 11 for calling the OptimizationConfig obj's underlying member method code with example usage: obj._validate_optimization_config(objective, outcome_constraints, risk_measure) without return types