class_docstr: Constraints put extra requirements to make one sample valid.
  
  For example, a constraint can be used to express that a variable should be larger than another variable,
  or certain combinations of variables should be strictly avoided.
  
  :class:`Constraint` is a subclass of :class:`MutableAnnotation`, and thus can be used as a normal mutable.
  It has a special :meth:`contains` method, which is used to check whether a sample satisfies the constraint.
  A constraint is satisfied if and only if :meth:`contains` returns ``None``.
  
  In general, users should inherit from :class:`Constraint` to implement customized constraints.
  :class:`ExpressionConstraint` is a special constraint
  that can be used to express constraints in a more concise way.
  
  See Also
  --------
  ExpressionConstraint
docstr: Yield all samples that satisfy the constraint.
  
  If some samples the constraint relies on have not been frozen yet,
  it will be sampled here and put into the memo.
  After that, it checks whether the sample satisfies the constraint after sampling (via ``contains()``).
  If the sample doesn't satisfy the constraint, it will be discarded.
  
  Each yielded sample of the :meth:`Constraint.grid` itself is None,
  because :meth:`Constraint.freeze` also returns None.
docstr_tok: ["Yield","all","samples","that","satisfy","the","constraint",".","If","some","samples","the","constraint","relies","on","have","not","been","frozen","yet",",","it","will","be","sampled","here","and","put","into","the","memo",".","After","that",",","it","checks","whether","the","sample","satisfies","the","constraint","after","sampling","(","via","``","contains","(",")","``",")",".","If","the","sample","does","n't","satisfy","the","constraint",",","it","will","be","discarded",".","Each","yielded","sample","of","the",":","meth",":","`","Constraint.grid","`","itself","is","None",",","because",":","meth",":","`","Constraint.freeze","`","also","returns","None","."]
code: def grid(
      self, memo: Sample | None = None, granularity: int | None = None
  ) -> Iterable[None]:
      """Yield all samples that satisfy the constraint.
  
      If some samples the constraint relies on have not been frozen yet,
      it will be sampled here and put into the memo.
      After that, it checks whether the sample satisfies the constraint after sampling (via ``contains()``).
      If the sample doesn't satisfy the constraint, it will be discarded.
  
      Each yielded sample of the :meth:`Constraint.grid` itself is None,
      because :meth:`Constraint.freeze` also returns None.
      """
      memo = {} if memo is None else memo
      mutables_wo_self = [
          mutable
          for mutable in self.simplify().values()
          if mutable is not self
      ]
      from .container import MutableList
  
      for _ in MutableList(mutables_wo_self).grid(memo, granularity):
          if self.contains(memo):
              yield self.freeze(memo)
          else:
              _logger.debug(
                  "Constraint violation detected. Skip this grid point: %s",
                  memo,
              )
  
imports: from __future__ import annotations
  import logging
  from typing import Iterable, Callable
  from numpy.random import RandomState
  from .exception import ConstraintViolation, SampleValidationError
  from .mutable import LabeledMutable, Mutable, Sample, MutableExpression
  from .utils import auto_label
label_desc: Use image node_id 6 for calling the Constraint obj's underlying member method code with example usage: obj.grid(memo, granularity) without return types