"""Module for performing tutte embeddings""" from typing import Iterable, cast, Any from sage.all import vector, Graph, cos, pi, sin # type: ignore def create_tutte_embedding( graph: Graph, outer_face: list[Any], max_iter: int=50, set_pos: bool = True) -> dict[Any, Any]: """ Performs a tutte force embedding with a prescribed outer face on a given sage graph. For a description on tutte embeddings, see the video [here](\ https://www.youtube.com/watch?v=mEzPPMhR8XE). """ radius = 1000 pos: dict[Any, Any] = {} num_outer_points = len(outer_face) for i, v in enumerate(outer_face): pos[v] = ( radius * cos((i / num_outer_points) * 2 * pi), radius * sin((i / num_outer_points) * 2 * pi) ) # start off setting all other points to (0, 0) num_inner_points = cast(int, graph.order()) - num_outer_points for i, v in enumerate(cast(Iterable[Any], graph.vertices())): # type: ignore if v in pos: continue pos[v] = ( radius/3 * cos((i / num_inner_points) * 2 * pi), radius/3 * sin((i / num_inner_points) * 2 * pi) ) i = 0 while i < max_iter: for v in cast(Iterable[Any], graph.vertices()): # type: ignore if v in outer_face: continue neighbors = cast(list[Any], graph.neighbors(v)) # type: ignore deg = len(neighbors) x_desired = sum(map(lambda n: pos[n][0], neighbors)) / deg y_desired = sum(map(lambda n: pos[n][1], neighbors)) / deg pos[v] = tuple( vector(pos[v]) - vector([ # type: ignore pos[v][0] - x_desired, pos[v][1] - y_desired ]) ) i += 1 if set_pos: graph.set_pos(pos) # type: ignore return pos