code: def move_permutation_towards(B, A, debug=False):
      global num_diffs
      B = move_groups_to_match(B, A, debug)
      wrong_entries = group_differences(A, B)
      num_diffs = len(wrong_entries)
  
      # nothing to do, early out
      if len(wrong_entries) == 0:
          if debug:
              print("MPT: early out")
          return B
  
      if debug:
          print(
              f"MPT: checking {len(wrong_entries)} diffs: {wrong_entries}"
          )
  
      # look for a group of three wrong entries that want to do the same thing
      entry_dict = dictify(wrong_entries)
      for k in entry_dict.keys():
          entry = entry_dict[k]
          if len(entry) == 3:
              if debug:
                  print(
                      f"MPT: found a triple swap at {k}: {entry_dict[k]}"
                  )
              (src, dst) = k
              # find the index of the one needed to complete the group
              # the value is the value in A[dst] that's not in B[src]
              # it's already in the destination group and may or may not need to move
              group_id = dst
              Ag = make_grouped(np.copy(A))
              Bg = make_grouped(np.copy(B))
              value = -1
              for c in range(4):
                  if Ag[dst][c] not in Bg[src]:
                      value = Ag[dst][c]
                      if debug:
                          print(
                              f"\tMPT: found the missing value {value} in A group {dst} offset {c}"
                          )
                      break
              assert value != -1
  
              # now find that value in B
              idx0 = np.where(B == value)[0][0]
              # find the index of the one this group doesn't need
              # it's a member of the group but not in the dict entry
              group_id = src
              for c in range(4):
                  if B[group_id * 4 + c] not in entry_dict[k]:
                      if debug:
                          print(
                              f"\tMPT: swapping {idx0} and {group_id*4+c}"
                          )
                      return swap_and_correct(B, idx0, group_id * 4 + c)
  
      # look for a group of two entries that are heading to the same place as another wrong entry
      victim_loner_pair = None
      for k in entry_dict.keys():
          entry = entry_dict[k]
          if len(entry) == 2:
              if debug:
                  print(
                      f"MPT: found a double swap at {k}: {entry_dict[k]}"
                  )
              (src, dst) = k
              # find a wrong entry whose dst is the same
              for k2 in entry_dict.keys():
                  if k2 == k:
                      continue
  
                  # k2 is a key whose value also belongs in stripe k2[1] (dst2)
                  if dst == k2[1]:
                      if debug:
                          print(
                              f"\tMPT: found a loner going in the same direction at {k2}: {entry_dict[k2][0]}"
                          )
                      # instead of moving these three to where they're headed, start merging them by moving the loner into the double
  
                      # look for a complement: something moving from src to src2
                      (src2, dst2) = k2
                      complement_key = (src, src2)
                      if complement_key in entry_dict:
                          complement = entry_dict[complement_key][0]
                          if debug:
                              print(
                                  f"\t\tMPT: found a complement to the loner:{complement}"
                              )
                          return swap_and_correct(
                              B,
                              np.where(B == entry_dict[k2][0])[0][0],
                              np.where(B == complement)[0][0],
                          )
                      # didn't find a complement, choose one of the two in the src group that don't belong
                      elif victim_loner_pair is None:
                          for k3 in entry_dict.keys():
                              if k3 == k:
                                  continue
  
                              if k3[0] == src:  # found the victim
                                  victim = entry_dict[k3][0]
                                  if debug:
                                      print(
                                          f"\t\tMPT: found a victim for the double swap:{k3} -> {victim}"
                                      )
                                  victim_loner_pair = (
                                      victim,
                                      entry_dict[k2][0],
                                  )
                                  # return swap_and_correct(B, np.where(B == entry_dict[k2][0])[0][0], np.where(B == victim)[0][0])
  
      if victim_loner_pair is not None:
          if debug:
              print(
                  f"\t\tMPT: couldn't find any complements for double swaps, so going with a loner to make a triple: {victim_loner_pair}"
              )
          return swap_and_correct(
              B,
              np.where(B == victim_loner_pair[0])[0][0],
              np.where(B == victim_loner_pair[1])[0][0],
          )
  
      # look for one swap that will correct two entries
      candidate_second = None
      for we in range(len(wrong_entries)):
          cur_entry = wrong_entries[we]
          # if debug:
          #    print(f"\tMPT: checking {cur_entry} for complement")
          for we2 in range(0, len(wrong_entries)):
              pos_swap = wrong_entries[we2]
              # if debug:
              #    print(f"\t\tMPT: is {pos_swap}?")
              if (
                  cur_entry[1] == pos_swap[2]
                  and cur_entry[2] == pos_swap[1]
              ):
                  if debug:
                      print(
                          f"\t\tfound complements: swapping {cur_entry} and {pos_swap}"
                      )
                  return swap_and_correct(
                      B,
                      np.where(B == cur_entry[0])[0][0],
                      np.where(B == pos_swap[0])[0][0],
                  )
              elif (
                  wrong_entries[0][2] == pos_swap[1]
              ):  # if pos_swap is currently where we[0] wants to go, keep it in mind
                  candidate_second = pos_swap
  
      # fall back on picking the first one we come across
      assert candidate_second is not None
      if debug:
          print(
              f"No complement, swapping two entries: {wrong_entries[0]} {candidate_second}"
          )
      return swap_and_correct(
          B,
          np.where(B == wrong_entries[0][0])[0][0],
          np.where(B == candidate_second[0])[0][0],
      )
  
imports: import numpy
  import time
  import subprocess
  import math
label_desc: Use image node_id 17 for calling a global function with example usage: move_permutation_towards(B, A, debug) and returns: swap_and_correct, B, swap_and_correct, swap_and_correct, swap_and_correct, swap_and_correct