Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

""" 

Dancing links C++ wrapper 

""" 

#***************************************************************************** 

# Copyright (C) 2008 Carlo Hamalainen <carlo.hamalainen@gmail.com>, 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# 

# This code is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 

# General Public License for more details. 

# 

# The full text of the GPL is available at: 

# 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

from __future__ import print_function 

from __future__ import absolute_import 

 

# OneExactCover and AllExactCovers are almost exact copies of the 

# functions with the same name in sage/combinat/dlx.py by Tom Boothby. 

 

from .dancing_links import dlx_solver 

 

def DLXCPP(rows): 

""" 

Solves the Exact Cover problem by using the Dancing Links algorithm 

described by Knuth. 

 

Consider a matrix M with entries of 0 and 1, and compute a subset 

of the rows of this matrix which sum to the vector of all 1's. 

 

The dancing links algorithm works particularly well for sparse 

matrices, so the input is a list of lists of the form:: 

 

[ 

[i_11,i_12,...,i_1r] 

... 

[i_m1,i_m2,...,i_ms] 

] 

 

where M[j][i_jk] = 1. 

 

The first example below corresponds to the matrix:: 

 

1110 

1010 

0100 

0001 

 

which is exactly covered by:: 

 

1110 

0001 

 

and 

 

:: 

 

1010 

0100 

0001 

 

If soln is a solution given by DLXCPP(rows) then 

 

[ rows[soln[0]], rows[soln[1]], ... rows[soln[len(soln)-1]] ] 

 

is an exact cover. 

 

Solutions are given as a list. 

 

EXAMPLES:: 

 

sage: rows = [[0,1,2]] 

sage: rows+= [[0,2]] 

sage: rows+= [[1]] 

sage: rows+= [[3]] 

sage: [x for x in DLXCPP(rows)] 

[[3, 0], [3, 1, 2]] 

""" 

 

if len(rows) == 0: return 

 

x = dlx_solver(rows) 

 

while x.search(): 

yield x.get_solution() 

 

def AllExactCovers(M): 

""" 

Solves the exact cover problem on the matrix M (treated as a dense 

binary matrix). 

 

EXAMPLES: No exact covers:: 

 

sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) 

sage: [cover for cover in AllExactCovers(M)] 

[] 

 

Two exact covers:: 

 

sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) 

sage: [cover for cover in AllExactCovers(M)] 

[[(1, 1, 0), (0, 0, 1)], [(1, 0, 1), (0, 1, 0)]] 

""" 

rows = [] 

for R in M.rows(): 

row = [] 

for i in range(len(R)): 

if R[i]: 

row.append(i) 

rows.append(row) 

for s in DLXCPP(rows): 

yield [M.row(i) for i in s] 

 

def OneExactCover(M): 

""" 

Solves the exact cover problem on the matrix M (treated as a dense 

binary matrix). 

 

EXAMPLES:: 

 

sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) #no exact covers 

sage: print(OneExactCover(M)) 

None 

sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) #two exact covers 

sage: OneExactCover(M) 

[(1, 1, 0), (0, 0, 1)] 

""" 

 

for s in AllExactCovers(M): 

return s