I'm very new to Golang, I'm trying to do a sudoku with backtracking algorithm.
But when I run my program, there are no errors but it only displays the grid not complete, with empty cases here is my code :
package main
import "fmt"
var sudoku = [9][9]int{
{9, 0, 0, 1, 0, 0, 0, 0, 5},
{0, 0, 5, 0, 9, 0, 2, 0, 1},
{8, 0, 0, 0, 4, 0, 0, 0, 0},
{0, 0, 0, 0, 8, 0, 0, 0, 0},
{0, 0, 0, 7, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 2, 6, 0, 0, 9},
{2, 0, 0, 3, 0, 0, 0, 0, 6},
{0, 0, 0, 2, 0, 0, 9, 0, 0},
{0, 0, 1, 9, 0, 4, 5, 7, 0},
}
func main(){
IsValid(sudoku, 0)
Display(sudoku)
}
func Display(sudoku[9][9] int){
var x, y int
for x = 0; x < 9; x++ {
fmt.Println("")
if(x == 3 || x == 6){
fmt.Println(" ")
}
for y = 0; y < 9; y++ {
if(y == 3 || y == 6){
fmt.Print("|")
}
fmt.Print(sudoku[x][y])
}
}
}
func AbsentOnLine(k int, sudoku [9][9]int, x int) bool {
var y int
for y=0; y < 9; y++ {
if (sudoku[x][y] == k){
return false
}
}
return true
}
func AbsentOnRow(k int, sudoku [9][9]int, y int) bool {
var x int
for x=0; x < 9; x++{
if (sudoku[x][y] == k){
return false;
}
}
return true;
}
func AbsentOnBloc(k int, sudoku [9][9]int, x int, y int) bool {
var firstX, firstY int;
firstX = x-(x%3)
firstY = y-(y%3)
for x = firstX; x < firstX+3; x++ {
for y = firstY; y < firstY+3; y++ {
if (sudoku[x][y] == k){
return false;
}
}
}
return true;
}
func IsValid(sudoku [9][9]int, position int) bool {
if (position == 9*9){
return true;
}
var x, y, k int
x = position/9
y = position%9
if (sudoku[x][y] != 0){
return IsValid(sudoku, position+1);
}
for k=1; k <= 9; k++ {
if (AbsentOnLine(k,sudoku,x) && AbsentOnRow(k,sudoku,y) && AbsentOnBloc(k,sudoku,x,y)){
sudoku[x][y] = k;
if (IsValid(sudoku, position+1)){
return true;
}
}
}
sudoku[x][y] = 0;
return false;
}
I'm getting this in the console :
900|100|005
005|090|201
800|040|000
000|080|000
000|700|000
000|026|009
200|300|006
000|200|900
001|904|570
I don't understand why it's not completing the grid, has anyone any ideas ?
I don't know Golang, but I have written a sudoku solving algorithm using backtracking.
Your code only iterates the board once. You start with position=0, your code than iterates over the board ,if a position has the value zero you try values 1-9 and if that doesn't work you go to the next position. When position=81, your code stops.
You added new values to the board with your Isvalid function, but you are not iterating over the new board again to see if those new values help your AbsentOn... function to return a new value that is different than the previous iteration. You have to iterate your board again and again until you are sure that there are no 0 valued cells.
That is the reason you have to many 0 on the board at the end of your program. Your program iterated only once, at It is can not solve your example sudoku on it's first try. It has to add new values to the board and make the sudoku board easier with every iteration.
Another problem is your code does not give a feedback. For example it gives 1 to an empty cell. That seems okey at first, but It doesn't mean that the final value of that cell has to be 1. It may change because in your next iterations you realize that there is another cell that can only take the value 1, so now you have to change back to your initial cell and find a new value other than 1. Your code also fails to do that. That's why humans put some possible values near a cell when they are not sure.
It looks like your problem is with the algorithm. You have to understand the backtracking algorithm. You can try it in another language that you know well first and then migrate it to golang(I wrote mine in C++). Other than that your golang code is easy to read and I don't see any golang related problems.
Your IsValid function changes the contents of the sudoku. The problem is, it actually, in your code as is, changes only a copy of the sudoku. You need to pass it as a pointer if it should change the actual variable.
Here are the changes that you need in your code, it is only five characters:
func main() {
IsValid(&sudoku, 0)
Display(sudoku)
}
// ...
func IsValid(sudoku *[9][9]int, position int) bool {
// ...
if AbsentOnLine(k, *sudoku, x) && AbsentOnRow(k, *sudoku, y) && AbsentOnBloc(k, *sudoku, x, y) {
Related
Problem is:
given mXn matrix with random (0, 1) value. from very start position start moving towards the m-1, n-1 position (last position) the only direction we can move is either down or right.
Rules:
if 1 found can't be moved
only possible move is to 0
So find the possible ways to reach the (m-1, n-1) position .
Example:
matrix((0, 0, 0), (0, 0, 0), (0, 0, 0))
answer: 6
here is my logic:
public class Main {
static int possibility = 0;
static int r = 3;
static int c = 3;
public static void main(String[] args) {
int array[][] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
// int array[][] = {{0, 1, 1}, {0, 0, 1}, {1, 0, 0}};
matrixProblem(array, 0, 0);
System.out.println("total possible solutions: ");
System.out.println(possibility);
}
static void matrixProblem(int[][] array, int i, int j) {
if (i == r - 1 && j == c - 1) {
possibility++;
return;
}
if(i+1 < r) {
if(array[++i][j] == 0) {
matrixProblem(array, i, j);
}
}
if(j+1 < c) {
if(array[i][++j] == 0) {
matrixProblem(array, i, j);
}
}
}
}
based on my logic it gives wrong answer.
Your logic is almost right but problem is in while recursive call you are passing the incremented i value instead just pass the i+1.
same for j value.
Edit 1:
if(i+1 < r) {
if(array[i+1][j] == 0) {
matrixProblem(array, i+1, j);
}
}
if(j+1 < c) {
if(array[i][j+1] == 0) {
matrixProblem(array, i, j+1);
}
}
}
Is it possible to initialize a Func from an array in a generator class? The code should look like this.
class SobelConv: public Halide::Generator<SobelConv> {
const signed char kernelx[3][3] = {
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}
};
void generate() {
for (int y = 0; y < 3; y++)
for (int x = 0; x < 3; x++)
kernel_x(x, y) = kernelx[y][x];
conv_x(x, y) += gray(x+win.x, y+win.y) * kernel_x(win.x + 1, win.y + 1);
}
Func kernel_x{"kernel_x"};
Currently, the way I did is to define Input<Buffer<int8_t>> kernel_x. I do not want it to be an argument of the pipeline function, and would like kernel_x to be replaced with the respective numbers directly.
The following compiles and illustrates one way to do this:
#include "Halide.h"
class SobelConv: public Halide::Generator<SobelConv> {
signed char weights[3][3] = {
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}
};
Input<Buffer<int8_t>> gray{"gray", 2};
Halide::Buffer<int8_t> kernel_x{&weights[0][0], 3, 3};
Output<Buffer<int8_t>> conv_x{"conv_x", 2};
Var x, y;
RDom win{0, 3};
void generate() {
conv_x(x, y) += gray(x+win.x, y+win.y) * kernel_x(win.x + 1, win.y + 1);
}
};
The weights will be embedded in the generated code at compile time. We should have a way to provide the constant values for the weights in an initializer list as well, but I'm not finding it at the moment.
I have a algorithm design puzzle that I could not solve.
The puzzle is formulated like this: There are N persons standing on a number line, each of them maybe standing on any integer number on that line. Multiple persons may stand on the same number. For any two persons to be able to communicate with each other, the distance between them should be less than K. The goal is to move them so that each pair of two persons can communicate each other (possibly via other people). In other words, we need to move them so that the distance between any neighboring two persons is smaller than K.
Question: What is the minimum number of total moves? It feels like this falls into greedy algorithm family or dynamic programming. Any hints are appreciated!
We can do the following in O(n):
Calculate the cost of moving all people to the right of person i towards person i at an acceptable distance:
costRight(A[i]) = costRight(A[i+1]) + (A[i+1] - A[i] - k + 1) * count of people to the right
K = 3; A = { 0, 3, 11, 17, 21}
costRight = {32, 28, 10, 2, 0}
Calculate the cost of moving all people to the left of person i towards person i at an acceptable distance:
costLeft(A[i]) = costLeft(A[i-1]) + (A[i] - A[i-1] - k + 1) * count of people to the left
K = 3; A = { 0, 3, 11, 17, 21}
costLeft = { 0, 1, 13, 25, 33}
costRight = {32, 28, 10, 2, 0}
Now that we have cost from both directions we can do this in O(n):
minCost = min(costRight + costLeft) for all A[i]
minCost = min(32 + 0, 28 + 1, 13 + 10, 25 + 2, 33 + 0) = 23
But sometimes that's no enough:
K = 3; A = { 0, 0, 1, 8, 8}
carry: -2 -4 3
costLeft = { 0, 0, 0, 11, 11}
carry: -3 5 -2
costRight = { 8, 8, 8, 0, 0}
The optimum is neither 11 nor 8. Test the current best by moving towards the greatest saving:
move 1 to 2, cost = 1
K = 3; A = { 0, 0, 2, 8, 8}
carry: -2 -2 -10
costLeft = { 0, 0, 0, 10, 10}
carry: -2 -2
costRight = { 6, 6, 6, 0, 0}
minCost = 1 + min(0 + 6, 0 + 6, 0 + 6, 10 + 0, 10 + 0) = 1 + 6 = 7
Not quite sure how to formularize this efficiently.
Here is a greedy algorithm written in Java, but I don't know if it gives the optimal solution in every case. Also it is more a proof of concept, there is some room for optimizations.
It is based on the fact that two neighbouring persons must not be more than K apart, the next neighbour must not be more than 2K away and so on. In each step we move the person that "violates these constraints most". The details of this calculation are in method calcForce.
package so;
import java.util.Arrays;
public class Main {
public static void main(String args[]) {
int[] position = new int[] {0, 0, 5, 11, 17, 23};
int k = 5;
solve(position, k);
}
private static void solve(int[] position, int k) {
if (!sorted(position)) {
throw new IllegalArgumentException("positions must be sorted");
}
int[] force = new int[position.length];
int steps = 0;
while (calcForce(position, k, force)) {
int mp = -1;
int mv = -1;
for (int i = 0; i < force.length; i++) {
if (mv < Math.abs(force[i])) {
mv = Math.abs(force[i]);
mp = i;
}
}
System.out.printf("move %d to the %s%n", mp, force[mp] > 0 ? "right" : "left");
if (force[mp] > 0) {
position[mp]++;
} else {
position[mp]--;
}
steps++;
}
System.out.printf("total: %d steps%n", steps);
}
private static boolean calcForce(int[] position, int k, int[] force) {
boolean commProblem = false;
Arrays.fill(force, 0);
for (int i = 0; i < position.length - 1; i++) {
for (int j = i + 1; j < position.length; j++) {
int f = position[j] - position[i] - (j - i) * k;
if (f > 0) {
force[i] += f;
force[j] -= f;
commProblem = true;
}
}
}
return commProblem;
}
private static boolean sorted(int[] position) {
for (int i = 0; i < position.length - 1; i++) {
if (position[i] > position[i+1]) {
return false;
}
}
return true;
}
}
More specifically, I'm looking for an algorithm A that takes as its inputs
a sorted multiset M = {a1, a2, …, an } of non-negative integers;
an integer 0 ≤ k ≤ n = |M |;
a "visitor" callback V (taking a k-combination of M as input);
(optional) a sorted k-combination K of M (DEFAULT: the k-combination {a1, a2, …, ak }).
The algorithm will then visit, in lexicographic order, all the k-combinations of M, starting with K, and apply the callback V to each.
For example, if M = {0, 0, 1, 2}, k = 2, and K = {0, 1}, then executing A(M, k, V, K ) will result in the application of the visitor callback V to each of the k-combinations {0, 1}, {0, 2}, {1, 2}, in this order.
A critical requirement is that the algorithm be non-recursive.
Less critical is the precise ordering in which the k-combinations are visited, so long as the ordering is consistent. For example, colexicographic order would be fine as well. The reason for this requirement is to be able to visit all k-combinations by running the algorithm in batches.
In case there are any ambiguities in my terminology, in the remainder of this post I give some definitions that I hope will clarify matters.
A multiset is like a set, except that repetitions are allowed. For example, M = {0, 0, 1, 2} is a multiset of size 4. For this question I'm interested only in finite multisets. Also, for this question I assume that the elements of the multiset are all non-negative integers.
Define a k-combination of a multiset M as any sub-multiset of M of size k. E.g. the 2-combinations of M = {0, 0, 1, 2} are {0, 0}, {0, 1}, {0, 2}, and {1, 2}.
As with sets, the ordering of a multiset's elements does not matter. (e.g. M can also be represented as {2, 0, 1, 0}, or {1, 2, 0, 0}, etc.) but we can define a canonical representation of the multiset as the one in which the elements (here assumed to be non-negative integers) are in ascending order. In this case, any collection of k-combinations of a multiset can itself be ordered lexicographically by the canonical representations of its members. (The sequence of all 2-combinations of M given earlier exhibits such an ordering.)
UPDATE: below I've translated rici's elegant algorithm from C++ to JavaScript as faithfully as I could, and put a simple wrapper around it to conform to the question's specs and notation.
function A(M, k, V, K) {
if (K === undefined) K = M.slice(0, k);
var less_than = function (a, b) { return a < b; };
function next_comb(first, last,
/* first_value */ _, last_value,
comp) {
if (comp === undefined) comp = less_than;
// 1. Find the rightmost value which could be advanced, if any
var p = last;
while (p != first && ! comp(K[p - 1], M[--last_value])) --p;
if (p == first) return false;
// 2. Find the smallest value which is greater than the selected value
for (--p; comp(K[p], M[last_value - 1]); --last_value) ;
// 3. Overwrite the suffix of the subset with the lexicographically
// smallest sequence starting with the new value
while (p !== last) K[p++] = M[last_value++];
return true;
}
while (true) {
V(K);
if (!next_comb(0, k, 0, M.length)) break;
}
}
Demo:
function print_it (K) { console.log(K); }
A([0, 0, 0, 0, 1, 1, 1, 2, 2, 3], 8, print_it);
// [0, 0, 0, 0, 1, 1, 1, 2]
// [0, 0, 0, 0, 1, 1, 1, 3]
// [0, 0, 0, 0, 1, 1, 2, 2]
// [0, 0, 0, 0, 1, 1, 2, 3]
// [0, 0, 0, 0, 1, 2, 2, 3]
// [0, 0, 0, 1, 1, 1, 2, 2]
// [0, 0, 0, 1, 1, 1, 2, 3]
// [0, 0, 0, 1, 1, 2, 2, 3]
// [0, 0, 1, 1, 1, 2, 2, 3]
A([0, 0, 0, 0, 1, 1, 1, 2, 2, 3], 8, print_it, [0, 0, 0, 0, 1, 2, 2, 3]);
// [0, 0, 0, 0, 1, 2, 2, 3]
// [0, 0, 0, 1, 1, 1, 2, 2]
// [0, 0, 0, 1, 1, 1, 2, 3]
// [0, 0, 0, 1, 1, 2, 2, 3]
// [0, 0, 1, 1, 1, 2, 2, 3]
This, of course, is not production-ready code. In particular, I've omitted all error-checking for the sake of readability. Furthermore, an implementation for production will probably structure things differently. (E.g. the option to specify the comparator used by next_combination's becomes superfluous here.) My main aim was to keep the ideas behind the original algorithm as clear as possible in a piece of functioning code.
I checked the relevant sections of TAoCP, but this problem is at most an exercise there. The basic idea is the same as Algorithm L: try to "increment" the least significant positions first, filling the positions after the successful increment to have their least allowed values.
Here's some Python that might work but is crying out for better data structures.
def increment(M, K):
M = list(M) # copy them
K = list(K)
for x in K: # compute the difference
M.remove(x)
for i in range(len(K) - 1, -1, -1):
candidates = [x for x in M if x > K[i]]
if len(candidates) < len(K) - i:
M.append(K[i])
continue
candidates.sort()
K[i:] = candidates[:len(K) - i]
return K
return None
def demo():
M = [0, 0, 1, 1, 2, 2, 3, 3]
K = [0, 0, 1]
while K is not None:
print(K)
K = increment(M, K)
In iterative programming, to make combinations of K size you would need K for loops. First we remove the repetitions from the sorted input, then we create an array that represents the for..loop indices. While the indices array doesn't overflow we keep generating combinations.
The adder function simulates the pregression of counters in a stacked for loop. There is a little bit of room for improvement in the below implementation.
N = size of the distinct input
K = pick size
i = 0 To K - 1
for(var v_{i0} = i_{0}; v_{i} < N - (K - (i + 1)); v_{i}++) {
...
for(var v_{iK-1} = i_{K-1}; v_{iK-1} < N - (K - (i + 1)); v_{iK-1}++) {
combo = [ array[v_{i0}] ... array[v_{iK-1}] ];
}
...
}
Here's the working source code in JavaScript
function adder(arr, max) {
var k = arr.length;
var n = max;
var carry = false;
var i;
do {
for(i = k - 1; i >= 0; i--) {
arr[i]++;
if(arr[i] < n - (k - (i + 1))) {
break;
}
carry = true;
}
if(carry === true && i < 0) {
return false; // overflow;
}
if(carry === false) {
return true;
}
carry = false;
for(i = i + 1; i < k; i++) {
arr[i] = arr[i - 1] + 1;
if(arr[i] >= n - (k - (i + 1))) {
carry = true;
}
}
} while(carry === true);
return true;
}
function nchoosekUniq(arr, k, cb) {
// make the array a distinct set
var set = new Set();
for(var i=0; i < arr.length; i++) { set.add(arr[i]); }
arr = [];
set.forEach(function(v) { arr.push(v); });
//
var n = arr.length;
// create index array
var iArr = Array(k);
for(var i=0; i < k; i++) { iArr[i] = i; }
// find unique combinations;
do {
var combo = [];
for(var i=0; i < iArr.length; i++) {
combo.push(arr[iArr[i]]);
}
cb(combo);
} while(adder(iArr, n) === true);
}
var arr = [0, 0, 1, 2];
var k = 2;
nchoosekUniq(arr, k, function(set) {
var s="";
set.forEach(function(v) { s+=v; });
console.log(s);
}); // 01, 02, 12
I have been looking for an algorithm to perform a transitive reduction on a graph, but without success. There's nothing in my algorithms bible (Introduction To Algorithms by Cormen et al) and whilst I've seen plenty of transitive closure pseudocode, I haven't been able to track down anything for a reduction. The closest I've got is that there is one in "Algorithmische Graphentheorie" by Volker Turau (ISBN:978-3-486-59057-9), but unfortunately I don't have access to this book! Wikipedia is unhelpful and Google is yet to turn up anything. :^(
Does anyone know of an algorithm for performing a transitive reduction?
See Harry Hsu. "An algorithm for finding a minimal equivalent graph of a digraph.", Journal of the ACM, 22(1):11-16, January 1975. The simple cubic algorithm below (using an N x N path matrix) suffices for DAGs, but Hsu generalizes it to cyclic graphs.
// reflexive reduction
for (int i = 0; i < N; ++i)
m[i][i] = false;
// transitive reduction
for (int j = 0; j < N; ++j)
for (int i = 0; i < N; ++i)
if (m[i][j])
for (int k = 0; k < N; ++k)
if (m[j][k])
m[i][k] = false;
The basic gist of the transitive reduction algorithm I used is
foreach x in graph.vertices
foreach y in graph.vertices
foreach z in graph.vertices
delete edge xz if edges xy and yz exist
The transitive closure algorithm I used in the same script is very similar but the last line is
add edge xz if edges xy and yz OR edge xz exist
Based on the reference provided by Alan Donovan, which says you should use the path matrix (which has a 1 if there is a path from node i to node j) instead of the adjacency matrix (which has a 1 only if there is an edge from node i to node j).
Some sample python code follows below to show the differences between the solutions
def prima(m, title=None):
""" Prints a matrix to the terminal """
if title:
print title
for row in m:
print ', '.join([str(x) for x in row])
print ''
def path(m):
""" Returns a path matrix """
p = [list(row) for row in m]
n = len(p)
for i in xrange(0, n):
for j in xrange(0, n):
if i == j:
continue
if p[j][i]:
for k in xrange(0, n):
if p[j][k] == 0:
p[j][k] = p[i][k]
return p
def hsu(m):
""" Transforms a given directed acyclic graph into its minimal equivalent """
n = len(m)
for j in xrange(n):
for i in xrange(n):
if m[i][j]:
for k in xrange(n):
if m[j][k]:
m[i][k] = 0
m = [ [0, 1, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0]]
prima(m, 'Original matrix')
hsu(m)
prima(m, 'After Hsu')
p = path(m)
prima(p, 'Path matrix')
hsu(p)
prima(p, 'After Hsu')
Output:
Adjacency matrix
0, 1, 1, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 1, 1
0, 0, 0, 0, 1
0, 1, 0, 0, 0
After Hsu
0, 1, 1, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 1, 0
0, 0, 0, 0, 1
0, 1, 0, 0, 0
Path matrix
0, 1, 1, 1, 1
0, 0, 0, 0, 0
0, 1, 0, 1, 1
0, 1, 0, 0, 1
0, 1, 0, 0, 0
After Hsu
0, 0, 1, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 1, 0
0, 0, 0, 0, 1
0, 1, 0, 0, 0
The Wikipedia article on transitive reduction points to an implementation within GraphViz (which is open source). Not exactly pseudocode, but maybe someplace to start?
LEDA includes a transitive reduction algorithm. I don't have a copy of the LEDA book anymore, and this function might have been added after the book was published. But if it's in there, then there will be a good description of the algorithm.
Google points to an algorithm that somebody suggested for inclusion in Boost. I didn't try to read it, so maybe not correct?
Also, this might be worth a look.
The algorithm of "girlwithglasses" forgets that a redundant edge could span a chain of three edges. To correct, compute Q = R x R+ where R+ is the transitive closure and then delete all edges from R that show up in Q. See also the Wikipedia article.
Depth-first algorithm in pseudo-python:
for vertex0 in vertices:
done = set()
for child in vertex0.children:
df(edges, vertex0, child, done)
df = function(edges, vertex0, child0, done)
if child0 in done:
return
for child in child0.children:
edge.discard((vertex0, child))
df(edges, vertex0, child, done)
done.add(child0)
The algorithm is sub-optimal, but deals with the multi-edge-span problem of the previous solutions. The results are very similar to what tred from graphviz produces.
ported to java / jgrapht, the python sample on this page from #Michael Clerx:
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.jgrapht.DirectedGraph;
public class TransitiveReduction<V, E> {
final private List<V> vertices;
final private int [][] pathMatrix;
private final DirectedGraph<V, E> graph;
public TransitiveReduction(DirectedGraph<V, E> graph) {
super();
this.graph = graph;
this.vertices = new ArrayList<V>(graph.vertexSet());
int n = vertices.size();
int[][] original = new int[n][n];
// initialize matrix with zeros
// --> 0 is the default value for int arrays
// initialize matrix with edges
Set<E> edges = graph.edgeSet();
for (E edge : edges) {
V v1 = graph.getEdgeSource(edge);
V v2 = graph.getEdgeTarget(edge);
int v_1 = vertices.indexOf(v1);
int v_2 = vertices.indexOf(v2);
original[v_1][v_2] = 1;
}
this.pathMatrix = original;
transformToPathMatrix(this.pathMatrix);
}
// (package visible for unit testing)
static void transformToPathMatrix(int[][] matrix) {
// compute path matrix
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
if (i == j) {
continue;
}
if (matrix[j][i] > 0 ){
for (int k = 0; k < matrix.length; k++) {
if (matrix[j][k] == 0) {
matrix[j][k] = matrix[i][k];
}
}
}
}
}
}
// (package visible for unit testing)
static void transitiveReduction(int[][] pathMatrix) {
// transitively reduce
for (int j = 0; j < pathMatrix.length; j++) {
for (int i = 0; i < pathMatrix.length; i++) {
if (pathMatrix[i][j] > 0){
for (int k = 0; k < pathMatrix.length; k++) {
if (pathMatrix[j][k] > 0) {
pathMatrix[i][k] = 0;
}
}
}
}
}
}
public void reduce() {
int n = pathMatrix.length;
int[][] transitivelyReducedMatrix = new int[n][n];
System.arraycopy(pathMatrix, 0, transitivelyReducedMatrix, 0, pathMatrix.length);
transitiveReduction(transitivelyReducedMatrix);
for (int i = 0; i <n; i++) {
for (int j = 0; j < n; j++) {
if (transitivelyReducedMatrix[i][j] == 0) {
// System.out.println("removing "+vertices.get(i)+" -> "+vertices.get(j));
graph.removeEdge(graph.getEdge(vertices.get(i), vertices.get(j)));
}
}
}
}
}
unit test :
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
public class TransitiveReductionTest {
#Test
public void test() {
int[][] matrix = new int[][] {
{0, 1, 1, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 1, 1},
{0, 0, 0, 0, 1},
{0, 1, 0, 0, 0}
};
int[][] expected_path_matrix = new int[][] {
{0, 1, 1, 1, 1},
{0, 0, 0, 0, 0},
{0, 1, 0, 1, 1},
{0, 1, 0, 0, 1},
{0, 1, 0, 0, 0}
};
int[][] expected_transitively_reduced_matrix = new int[][] {
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 1, 0},
{0, 0, 0, 0, 1},
{0, 1, 0, 0, 0}
};
System.out.println(Arrays.deepToString(matrix) + " original matrix");
int n = matrix.length;
// calc path matrix
int[][] path_matrix = new int[n][n];
{
System.arraycopy(matrix, 0, path_matrix, 0, matrix.length);
TransitiveReduction.transformToPathMatrix(path_matrix);
System.out.println(Arrays.deepToString(path_matrix) + " path matrix");
Assert.assertArrayEquals(expected_path_matrix, path_matrix);
}
// calc transitive reduction
{
int[][] transitively_reduced_matrix = new int[n][n];
System.arraycopy(path_matrix, 0, transitively_reduced_matrix, 0, matrix.length);
TransitiveReduction.transitiveReduction(transitively_reduced_matrix);
System.out.println(Arrays.deepToString(transitively_reduced_matrix) + " transitive reduction");
Assert.assertArrayEquals(expected_transitively_reduced_matrix, transitively_reduced_matrix);
}
}
}
test ouput
[[0, 1, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0]] original matrix
[[0, 1, 1, 1, 1], [0, 0, 0, 0, 0], [0, 1, 0, 1, 1], [0, 1, 0, 0, 1], [0, 1, 0, 0, 0]] path matrix
[[0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0]] transitive reduction