Как я могу повлиять на Graphviz/dot, чтобы сделать графы потока управления более красивыми, убрав извилистость и улучшив пересечение ребер?

Я рисую графы потока управления для программ Python и хотел бы повлиять на то, какие края не должны пересекаться. Есть ли способ сделать это?

Рассмотрим эту простую программу на Python:

try:
    a += 1
except:
    a += 2
else:
    a = 3

И точечная программа для представления потока управления для сгенерированного через https://github.com/rocky/python-control-flow/

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1 -> node_4 [weight=1];
  node_0 -> node_3 [weight=1];
}

Изображение, которое точка создает для приведенного выше, это введите здесь описание изображения

Обратите внимание, как одна линия извивается и пересекает прямую стрелку вниз. Вместо этого я бы предпочел, чтобы ни одна из прямых стрелок вниз не пересекалась. Шлицевые кромки улучшат места пересечения.

Если вы посмотрите на точку, у меня есть два невидимых нисходящих края, которые я использую для выравнивания. (В байт-коде они следуют линейной последовательности инструкций).

Таким образом, если необходимо пересечь прямую линию, направленную вниз (а здесь этого не происходит), невидимые ребра предпочтительнее видимых.

Мысли?

Изменить

Единственный отличный ответ на данный момент предлагает изменить порядок определения ребер и указать в определенных ситуациях, где следует выполнять присоединения ребер.

В этом приложении у меня есть иерархическая информация о вложенности из дерева доминаторов, и я могу классифицировать ребра: те, которые зацикливаются, те, которые переходят в конец составной структуры, те, которые разрывают петлю и так далее.

Итак, теперь проблема заключается именно в том, как использовать эту информацию, чтобы избежать этих извилистых стрелок, и гарантировать, что выходы из циклов предпочтительнее пересечения ребер, чем, скажем, ребер перехода «если»/«иначе».

Это похоже на дизайн СБИС: придумайте набор шаблонов, которые работают для каждого типа структуры (потока управления), и затем они будут правильно вложены друг в друга и упорядочены.

Я экспериментировал с порядком и размещением ребер, и у меня просто нет интуитивного понимания, когда что-то ставить раньше или позже.

Мы будем очень признательны за руководство или, что еще лучше, за правило проектирования для структурированных краев потока управления.


person rocky    schedule 25.11.2018    source источник


Ответы (1)


Чтобы улучшить ситуацию, вам нужно сделать две вещи:

  • нарисуйте (одно из) ребер, которыми вы хотите управлять, раньше других,
  • сообщите graphviz, где вы хотите, чтобы они были прикреплены (север, восток...)

Я отредактировал ваш код соответствующим образом

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_3:nw [weight=1];           /* moved up and added directions*/
  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1:se -> node_4:ne [weight=1];            /* added directions */
}

что дает тебе

введите здесь описание изображения

Здесь есть немного проб и ошибок, но я уверен, что это должно помочь.

person vaettchen    schedule 25.11.2018
comment
Это интересно. Я могу использовать структуру программы (в частности, дерево доминаторов), чтобы помочь мне в определении внутренней и внешней структуры. Но мне нужно понять, как порядок меняет вещи. Делать ли внутренние блоки первыми, а внешние — последними, или наоборот? Те вещи, которые более подходят для пересечения границ (например, разрыв внутри цикла, который может пересекать внутренние операторы if/try), я отрисовываю их последними? Я полагаю, я мог бы поместить все задние края петли на одну сторону. - person rocky; 26.11.2018
comment
В моих предыдущих экспериментах я использовал [headport=nw, tailport=sw] вместо двоеточия, которое у вас есть на узле, что работает лучше. Какая разница? - person rocky; 26.11.2018
comment
На ваш первый вопрос: у меня нет хорошего ответа, и тема кажется сложной для также инсайдеры. В общем, по моему опыту, ребра, определенные ранее, имеют более высокий приоритет, но это не настоящее знание. Что касается второго пункта, я считаю, что двоеточие - это просто стенография, но опять же не могу точно подтвердить. - person vaettchen; 26.11.2018
comment
В порядке. Это полезно, даже если это то, что есть. Я играл с макетом вручную, и у меня действительно нет хорошего понимания алгоритмического способа получить хороший результат. Поэтому я оставлю это непринятым на пару дней на случай, если у кого-то еще появятся подробности. Спасибо. - person rocky; 26.11.2018