def LadderGraph(n): """ Returns a ladder graph with 2\*n nodes. A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top horizontal line. EXAMPLES: Construct and show a ladder graph with 14 nodes :: sage: g = graphs.LadderGraph(7) sage: g.show() # long time Create several ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): pos_dict[i] = (i,1) for i in range(n,2*n): x = i - n pos_dict[i] = (x,0) G = Graph(pos=pos_dict, name="Ladder graph") G.add_vertices( range(2*n) ) G.add_path( range(n) ) G.add_path( range(n,2*n) ) G.add_edges( (i,i+n) for i in range(n) ) return G
def LadderGraph(n): """ Returns a ladder graph with 2\*n nodes. A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top horizontal line. EXAMPLES: Construct and show a ladder graph with 14 nodes :: sage: g = graphs.LadderGraph(7) sage: g.show() # long time Create several ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): pos_dict[i] = (i, 1) for i in range(n, 2 * n): x = i - n pos_dict[i] = (x, 0) G = Graph(pos=pos_dict, name="Ladder graph") G.add_vertices(range(2 * n)) G.add_path(range(n)) G.add_path(range(n, 2 * n)) G.add_edges((i, i + n) for i in range(n)) return G
def random_cycle_paths(max_cycle_len, max_path_len, max_vertices, p=0, min_cycle_len=1): '''Funkcja losująca grafy nieskierowane o dokładnie jedym cyklu, z którego wychodzą ścieżki dwóch typów. Pierwszym z nich jest typ "zewnętrzny", czyli ścieżki, które zaczynają się w jednym z wierzchołków cyklu i których pozostałe wierzchołki są z cyklem rozłączne. Drugi typ jest "wewnętrzny", do którego należą ścieżki o dwóch wierzchołkach końcowych należących do cyklu lub innej ścieżki wewnętrznej. Wszystkie ścieżki wewnętrzne są losowane tak, żeby graf był planarny pod warukiem, że rysowanie ścieżek wewnętrznych ograniczamy do wnętrza cyklu. :param min_cycle_len: Int Minimalna dozwolona długość cyklu. :param max_cycle_len: Int Największa dozwolona długość cyklu. Jeżeli długość wylosowanego cyklu będzie równa `1`, to wygenerowany zostanie wierzchołek, a jeżeli będzie równa `2`, to wygenerowana zostanie krawędź. :param max_path_len: Int Największa dozwolona długość ścieżki wychodzącej z cyklu. :param p: Float Określa, z jakim prawdopodobieństwem do grafu zostanie dodana kolejna ścieżka zewnętrzna. Z prawdopodobieństwem `1-p` zostanie dodana krawędź wewnętrzna. :param max_vertices: Int Największa dozwolona liczba krawędzi. :return: tuple Para składająca się z opisanego grafu skierowanego, oraz listy wierzchołków składającej się z wierzchołków cyklu oraz ścieżek "zewnętrznych". ''' if p < 0 or p > 1: raise ValueError("Niepoprawna wartość prawdopodobieństwa. `p` musi " "należeć do przedziału [0, 1]") if min_cycle_len < 1: raise ValueError("Minimalna długość cyklu nie może być mniejsza od 1.") if min_cycle_len > max_cycle_len: raise ValueError("Minimalna długość cyklu musi być mniejsza lub równa " "maksymalnej.") if min_cycle_len < 3 and p < 1: warnings.warn("Minimalna długość cyklu pozwala na stworzenie cykli " "bez wnętrza, a wartość `p` dopuszcza istnienie ścieżek " "wewnętrznych. W przypadku wylosowania krótkiego cyklu, " "wszystkie ścieżki będą zewnętrzne.") G = Graph() cycle_len = np.random.randint(min_cycle_len, max_cycle_len + 1) if cycle_len == 1: p = 1 G.add_vertex(0) outside_vertices = [0] elif cycle_len == 2: p = 1 G.add_edge((0, 1)) outside_vertices = [0, 1] else: G.add_cycle(list(range(0, cycle_len))) outside_vertices = list(range(0, cycle_len)) n = cycle_len got_max_vertices = n >= max_vertices cycle_partitions = [list(range(0, n))] for i in range(cycle_len): if got_max_vertices: break n_paths = np.random.poisson(1) path_lengths = np.random.poisson(lam=int(max_path_len / 2), size=n_paths) for path_length in path_lengths: if n + path_length > max_vertices: path_length = max_vertices - n got_max_vertices = True if path_length == 0: if got_max_vertices: break else: continue if np.random.rand(1) > p: available_parts = [tab for tab in cycle_partitions if i in tab] cycle_part = \ available_parts[np.random.randint(0, len(available_parts))] j = i while j == i: j = np.random.choice(cycle_part) # split k = 0 parts = [[], []] part_id = 0 new_path = list(range(n, n + path_length - 1)) for k in cycle_part: parts[part_id].append(k) if k in [i, j]: if k == i: parts[part_id] += new_path else: parts[part_id] += new_path[::-1] part_id = 1 - part_id parts[part_id].append(k) cycle_partitions.remove(cycle_part) cycle_partitions.append(parts[0]) cycle_partitions.append(parts[1]) G.add_path([i] + new_path + [j]) else: G.add_path([i] + list(range(n, n + path_length))) outside_vertices += list(range(n, n + path_length)) n += path_length if got_max_vertices: break return G, outside_vertices