code: def advance(self, word_id: int) -> 'ConstrainedHypothesis':
          
  
          obj = copy.deepcopy(self)
  
          # First, check if we're updating a sequential constraint.
          if obj.last_met != -1 and obj.is_sequence[obj.last_met] == 1:
              if word_id == obj.constraints[obj.last_met + 1]:
                  # Here, the word matches what we expect next in the constraint, so we update everything
                  obj.met[obj.last_met + 1] = True
                  obj.last_met += 1
              else:
                  # Here, the word is not the expected next word of the constraint, so we back out of the constraint.
                  index = obj.last_met
                  while obj.is_sequence[index]:
                      obj.met[index] = False
                      index -= 1
                  obj.last_met = -1
  
          # If not, check whether we're meeting a single-word constraint
          else:
              # Build a list from all constraints of tuples of the
              # form (constraint, whether it's a non-initial sequential, whether it's been met)
              constraint_tuples = list(zip(obj.constraints, [False] + obj.is_sequence[:-1], obj.met))
              # We are searching for an unmet constraint (word_id) that is not the middle of a phrase and is not met
              query = (word_id, False, False)
              try:
                  pos = constraint_tuples.index(query)
                  obj.met[pos] = True
                  obj.last_met = pos
              except ValueError:
                  # query not found; identical but duplicated object will be returned
                  pass
  
          return obj
docs: Updates the constraints object based on advancing on word_id.
          There is a complication, in that we may have started but not
          yet completed a multi-word constraint.  We need to allow constraints
          to be added as unconstrained words, so if the next word is
          invalid, we must "back out" of the current (incomplete) phrase,
          re-setting all of its words as unmet.
  
          :param word_id: The word ID to advance on.
          :return: A deep copy of the object, advanced on word_id.