В ваших вопросах много неправильного или неясного, но я постараюсь ответить как можно лучше.
Вопрос 1
Вы, очевидно, пытаетесь преобразовать представление графа зависимостей из списка в матрицу.Не имеет никакого смысла иметь граф зависимостей, представленный в виде 'a list
(на самом деле интересного способа построить булеву матрицу из произвольного списка в любом случае нет), так что вы, вероятно, намеревались использовать(int * int) list
пар, каждая пара (i,j)
является зависимостью i -> j
.
Если вместо этого у вас есть ('a * 'a) list
произвольных пар, вы можете легко пронумеровать элементы, используя функцию num_of_name
, чтобы превратить его в вышеупомянутый (int * int) list
.
Получив это, вы можете легко построить матрицу:
let matrix_of_dependencies dependencies =
let n = List.fold_left (fun (i,j) acc -> max i (max j acc)) 0 dependencies in
let matrix = Array.make_matrix (n+1) (n+1) false in
List.iter (fun (i,j) -> matrix.(i).(j) <- true) dependencies ;
matrix
val matrix_of_dependencies : (int * int) list -> bool array array
Вы также можете вычислить параметр n
вне функции и передать его.
Вопрос 2
Класс эквивалентности - это набор элементов, которые все эквивалентны.Хорошим представлением для набора в OCaml будет список (модуль List
) или набор (модуль Set
).Список-списки не является допустимым представлением для набора, поэтому у вас нет причин использовать его.
Ваш алгоритм неясен, поскольку вы, очевидно, выполняете свертывание в пустом списке, который просто вернет начальное значение (пустой список).Я предполагаю, что вы намеревались вместо этого перебирать все записи в столбце матрицы.
let equivalence_class matrix element =
let column = matrix.(element) and set = ref [] in
Array.iteri begin fun element' dependency ->
if dependency then set := element' :: !set
end column ;
!set
val equivalence_class : bool array array -> int list
Я проверяю только на i -> j
, потому что, если ваши зависимости действительно являются отношениями эквивалентности (рефлексивные, транзитивные, симметричные),тогда i -> j
подразумевает j -> i
.Если ваши зависимости не отношения эквивалентности, то вы на самом деле ищете циклы в графическом представлении отношения, который полностью отличается от того, что вы предложили, если только вы не вычислите переходныйсначала закройте вашего графика зависимостей.
Наборы и списки являются хорошо документированными стандартными модулями, а их документация свободно доступна в Интернете.Задавайте вопросы по StackOverflow, если у вас есть определенные проблемы с ними.
Вы попросили нас объяснить кусок кода, который вы предоставляете для eq_classes
.Объяснение состоит в том, что он складывается на пустом множестве, поэтому он возвращает свое начальное значение - пустую карту.Это совершенно бессмысленно.Более подходящей реализацией будет:
let equivalence_classes matrix =
let classes = ref [] in
Array.iteri begin fun element _ ->
if not (List.exists (List.mem element) !classes) then
classes := equivalence_class matrix element :: !classes
end matrix ;
!classes
val equivalence_classes : bool array array -> int list list
. Возвращает все классы эквивалентности в виде списка списков (каждый класс эквивалентности является отдельным списком).
Вопрос 3
Система типов указывает, что вы определили функцию сравнения, которая работает на int
, поэтому вы можете использовать ее только для сортировки int list
.Если вы намереваетесь отсортировать int list list
(список классов эквивалентности), то вам нужно определить функцию сравнения для int list
элементов.
Предполагая, что (как упоминалось выше) ваш граф зависимостей транзитивно закрыт , все, что вам нужно сделать, это использовать существующий алгоритм сравнения и применить его к произвольным представителям каждого класса:
let compare_classes matrix c c` =
match c, c` with
| h :: _, h' :: _ -> if matrix.(h).(h') then 1 else -1
| _ -> 0
let sort_equivalence_classes matrix = List.sort (compare_classes matrix)
Этот код предполагает, что 1. каждый класс эквивалентности появляется только один раз и 1. каждый класс эквивалентности содержит хотя бы один элемент.Оба предположения разумны при работе с классами эквивалентности, и это простой процесс, позволяющий заранее исключить дубликаты и пустые классы.