(*                                                                        *)
(*  Copyright (C) Jean-Christophe Filliatre                               *)
(*                                                                        *)
(*  This software is free software; you can redistribute it and/or        *)
(*  modify it under the terms of the GNU Library General Public           *)
(*  License version 2.1, with the special exception on linking            *)
(*  described in file LICENSE.                                            *)
(*                                                                        *)
(*  This software is distributed in the hope that it will be useful,      *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*                                                                        *)

(* This module implements Knuth's dancing links algorithm, also known as DLX
   (see [http://en.wikipedia.org/wiki/Dancing_Links]).

   This is a backtracking algorithm to find all solutions of the exact cover
   problem, which is stated as follows: given a matrix of 0s and 1s, does it
   have a set of rows containing exactly one 1 in each column?


(* The first step is to build the matrix's columns, using the following
   abstract data type [column]. Each column is given a name, to be identified
   within solutions. *)

type column

val create_column : string -> column

(* The next step is to fill the matrix, row by row. This is done using the
   following function [add_row] which inserts a new row in the matrix. A row
   is defined as the list of its columns containing a 1.

   Note that row insertion is performed as a side effect on columns. A column
   is indeed a mutable data structure, and thus must not be shared across
   several exact cover problems. *)

val add_row : column list -> unit

(* Finally, an exact cover problem is defined as the list of the matrix's
   columns. Note that this implementation deals with the generalized exact
   cover problem where the columns can be divided into primary and secondary
   columns. A solution must cover the primary columns exactly once and the
   secondary columns at most once. When creating a problem with
   [create_problem] one only gives the set of primary columns (and secondary
   columns are implicitely given when mentioned in [add_row]). *)

type problem

val create_problem : column list -> problem

(* Finally, [find_all_solutions p f] finds out all solutions for problem [p]
   and applies [f] on each solution. *)

type solution

val find_all_solutions : problem -> (solution -> unit) -> unit

(* The type of solution is abstract but a solution can be unpacked with
   [unpack_solution] as the list of rows, each row being the set of its columns
   containing a 1. A function [print_solution] is also provided, which is
   more efficient than calling [unpack_solution] and then printing the result.
   [print_solution] prints each row of the solution on a separate line, and
   each row as the names of its columns containing a 1. *)

val unpack_solution : solution -> string list list

val print_solution : Format.formatter -> solution -> unit

(* The following function counts the number of solutions.  It is
   slightly more efficient than using [find_all_solutions] and
   incrementing a reference for each solution. *)

val count_all_solutions : problem -> int
val count_all_solutions_int64 : problem -> int64

This document was generated using caml2html