def check_init_valid(
    state: state_def.State,
    name: str,
    obj_planes: list,
    assigned_planes: list,
    margins: list,
    rev_normals: list[bool],
):
    """
    Check that the plane assignments to the object is valid. First checks that the rotations can be satisfied, then
    checks that the translations can be satisfied. Returns a boolean indicating if the assignments are valid, the number
    of degrees of freedom remaining, and the translation vector if the assignments are valid.
    """
    if len(obj_planes) == 0:
        raise ValueError(f"{check_init_valid.__name__} for {name=} got {obj_planes=}")
    if len(obj_planes) > 3:
        raise ValueError(
            f"{check_init_valid.__name__} for {name=} got {len(obj_planes)=}"
        )

    def get_rot(ind):
        """
        Get the rotation axis and angle needed to align the object's plane with the assigned plane.
        """
        try:
            a = obj_planes[ind][0]
            b = assigned_planes[ind][0]
        except IndexError:
            raise ValueError(f"Invalid {ind=} {obj_planes=} {assigned_planes=}")

        a_plane = obj_planes[ind]
        b_plane = assigned_planes[ind]
        rev_normal = rev_normals[ind]
        a_obj = bpy.data.objects[a]
        b_obj = bpy.data.objects[b]

        a_poly_index = a_plane[1]
        a_poly = a_obj.data.polygons[a_poly_index]
        b_poly_index = b_plane[1]
        b_poly = b_obj.data.polygons[b_poly_index]
        plane_normal_a = butil.global_polygon_normal(a_obj, a_poly)
        plane_normal_b = butil.global_polygon_normal(b_obj, b_poly, rev_normal)
        plane_normal_b = -plane_normal_b
        rotation_axis = np.cross(plane_normal_a, plane_normal_b)

        if not np.isclose(np.linalg.norm(rotation_axis), 0, atol=1e-03):
            rotation_axis = rotation_axis / np.linalg.norm(rotation_axis)
        else:
            rotation_axis = np.array([0, 0, 1])
        dot = plane_normal_a.dot(plane_normal_b)
        rotation_angle = np.arccos(np.clip(dot, -1, 1))
        if np.isnan(rotation_angle):
            raise ValueError(f"Invalid {rotation_angle=}")
        return a, b, rotation_axis, rotation_angle, plane_normal_b

    def is_rotation_allowed(rotation_axis, reference_normal):
        # Check if rotation axis is the same as the reference normal (with some tolerance)
        res = np.allclose(rotation_axis, reference_normal, atol=1e-02) or np.allclose(
            rotation_axis, -reference_normal, atol=1e-02
        )
        if not res:
            dot = rotation_axis.dot(reference_normal)
            logger.debug(
                f"{is_rotation_allowed.__name__} got {res=} with {rotation_axis=} {reference_normal=} {dot=}"
            )
        return res

    a, b, rotation_axis, rotation_angle, plane_normal_b = get_rot(0)
    iu.rotate(state.trimesh_scene, a, rotation_axis, rotation_angle)
    first_plane_normal = plane_normal_b  # Save the normal of the first plane

    dof_remaining = True  # Degree of freedom remaining after the first alignment

    # Check and apply rotations for subsequent planes
    for i in range(1, len(obj_planes)):
        a, b, rotation_axis, rotation_angle, plane_normal_b = get_rot(i)

        if np.isclose(np.linalg.norm(rotation_angle), 0, atol=1e-01):
            logger.debug(f"no rotation needed for {i=} of {len(obj_planes)}")
            continue

        rot_allowed = is_rotation_allowed(rotation_axis, first_plane_normal)
        if dof_remaining and rot_allowed:
            # Rotate around the normal of the first plane
            iu.rotate(state.trimesh_scene, a, rotation_axis, rotation_angle)
            dof_remaining = False  # No more degrees of freedom remaining
            logger.debug(f"rotated {a=} to satisfy assignment {i=}")
        else:
            logger.debug(
                f"dofs failed for {i=} of {len(obj_planes)=}, {rot_allowed=} {dof_remaining=}"
            )
            return False, None, None

    # Construct the system of linear equations for translation
    A = []
    c = []
    for i in range(len(obj_planes)):
        a_obj_name, a_poly_index = obj_planes[i]
        b_obj_name, b_poly_index = assigned_planes[i]
        margin = margins[i]
        rev_normal = rev_normals[i]

        a_obj = bpy.data.objects[a_obj_name]
        b_obj = bpy.data.objects[b_obj_name]

        a_poly = a_obj.data.polygons[a_poly_index]
        b_poly = b_obj.data.polygons[b_poly_index]

        # Get global coordinates and normals
        plane_point_a = butil.global_vertex_coordinates(
            a_obj, a_obj.data.vertices[a_poly.vertices[0]]
        )
        plane_point_b = butil.global_vertex_coordinates(
            b_obj, b_obj.data.vertices[b_poly.vertices[0]]
        )
        plane_normal_b = butil.global_polygon_normal(b_obj, b_poly, rev_normal)
        plane_point_b += plane_normal_b * margin

        # Append to the matrix A and vector b for Ax = c
        A.append(plane_normal_b)
        c.append(plane_normal_b.dot(plane_point_b - plane_point_a))

    # Solve the linear system
    A = np.array(A)
    c = np.array(c)

    t, residuals, rank, s = np.linalg.lstsq(A, c, rcond=None)
    a_obj_name, a_poly_index = obj_planes[0]

    a_obj = bpy.data.objects[a_obj_name]

    # Check if the solution is valid
    # You can define a threshold to determine if the residuals are acceptable
    # Manually compute residuals if m <= n
    if residuals.size == 0:
        computed_residuals = np.dot(A, t) - c
        residuals_sum = np.sum(computed_residuals**2)
        if residuals_sum < 1e-03:
            return True, A.shape[1] - rank, t  # Solution is valid
        else:
            logger.debug(f"{check_init_valid.__name__} failed with {residuals_sum=}")
            return False, None, None  # Solution is not valid
    else:
        if np.all(residuals < 1e-03):
            return True, A.shape[1] - rank, t  # Solution is valid
        else:
            logger.debug(f"{check_init_valid.__name__} failed with {residuals=}")
            return False, None, None  # No valid solution

    Check that the plane assignments to the object is valid. First checks that the rotations can be satisfied, then
    checks that the translations can be satisfied. Returns a boolean indicating if the assignments are valid, the number
    of degrees of freedom remaining, and the translation vector if the assignments are valid.
    
infinigen/core/constraints/example_solver/geometry/dof.py