def coordinate_descent(U, f, max_iter=None):
    """
    Givens coordinate descent algorithm on the orthogonal group.

    f is a function from O(d) -> R
    """
    d = U.shape[0]
    if max_iter is None:
        max_iter = d * (d - 1) // 2

    trajectory = []

    idx_to_check = list(range(d))
    subspace_results = {}
    rotation = Rotation()

    for it in range(max_iter):
        for i in range(d):
            for j in range(i+1, d):
                if i not in idx_to_check and j not in idx_to_check:
                    continue
                else:
                    f_diff, theta = minimize_subspace(U, i, j, f)
                    subspace_results[(i,j)] = (f_diff, theta)
        idx, max_result = max(subspace_results.items(), key=lambda x : operator.itemgetter(1)(x)[0])
        theta = max_result[1]
        idx_to_check = list(idx)

        U[idx, :] = rotation.rotate(theta, U[idx, :].copy())
        trajectory.append((theta, idx[0], idx[1]))

    return trajectory
def minimize_subspace(X, i, j, distance_fn):
    """
    For an input X, get a vector v = X[[i,j],:] of size (2 x N) with N points in 2D, find the rotation that minimizes
    the entry-wise l1 norm / smoothed l1 norm of v.
    The specific distance function is specified by distance_fn and can be a l1 norm or smoothed l1 norm.
    """
    v = X[[i, j], :]
    v_distance = distance_fn(v)

    angles = map_angles_to_first_quadrant(compute_angles(v))
    assert np.all(angles > -1e-6) and np.all(angles < np.pi / 2 + 1e-6), angles

    # use apriori knowledge about smallest rotation angle to a coordinate axis
    below_diag_ind = (angles < np.pi / 4)
    above_diag_ind = (angles >= np.pi / 4)
    angles[below_diag_ind] = -angles[below_diag_ind]
    angles[above_diag_ind] = np.pi / 2 - angles[above_diag_ind]

    # simulate a rotation with all possible angles
    rotated_norms = np.zeros_like(angles)
    rotation = Rotation()
    for k, alpha in enumerate(angles):
        rotated_v = rotation.rotate(alpha, v)
        rotated_norms[k] = distance_fn(rotated_v)

    # choose the rotation that yields the overall minimal rotated norm
    k_argmin = np.argmin(rotated_norms)
    min_distance = rotated_norms[k_argmin]
    min_rotation_angle = angles[k_argmin]

    # compute absolute progress on the distance function for the two subselected rows
    distance_diff = v_distance - min_distance

    return distance_diff, min_rotation_angle
def greedy_baseline(U, max_iter=None):
    """
    Greedily chooses Givens factor that minimizes Frobenius norm to the target U
    """
    U = U.copy()
    d = U.shape[0]

    if max_iter is None:
        max_iter = d * (d - 1) // 2

    trajectory = []
    idx_to_check = list(range(d))
    rotation = Rotation()
    for it in range(max_iter):
        subspace_results = []
        for i in range(d):
            for j in range(i + 1, d):
                if i not in idx_to_check and j not in idx_to_check:
                    continue
                else:
                    f_diff, theta = minimize_frobenius_subspace(U, i, j)
                    subspace_results.append((f_diff, theta, (i, j)))
        _, theta, idx = max(subspace_results, key=lambda t: t[0])
        idx_to_check = list(idx)

        U[idx, :] = rotation.rotate(theta, U[idx, :])
        trajectory.append((theta, idx[0], idx[1]))
    return trajectory
Exemple #4
0
 def from_dict(cls, card_description):
     """
     Return RotationCard from data received from server.
     """
     priority = card_description["RotationCard"]["priority"]
     rotation = card_description["RotationCard"]["rotation"]
     return RotationCard(priority, Rotation(rotation))
Exemple #5
0
 def __init__(self, direction, name, tile_type, properties):
     if properties["direction_out"] == 0:
         self.direction_out = Direction.N
     else:
         self.direction_out = Rotation(properties["direction_out"])
     self.express = properties["express"]
     super().__init__(direction, name, tile_type, properties)
Exemple #6
0
 def __init__(self, priority, value):
     if isinstance(value, int):
         value = Rotation(value)
     self.rotation = value
     super().__init__(priority)
Exemple #7
0
 def __init__(self, direction, name, tile_type, properties):
     self.move_direction = Rotation(properties["move_direction"])
     super().__init__(direction, name, tile_type, properties)