示例#1
0
    def test_project_clone(self):

        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        graph = create_graph_from_text(g_str)

        # Test clone
        cloned = gtn.clone(graph)
        self.assertTrue(gtn.equal(graph, cloned))

        # Test projecting input
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        inputExpected = create_graph_from_text(g_str)
        self.assertTrue(gtn.equal(gtn.project_input(graph), inputExpected))

        # Test projecting output
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        outputExpected = create_graph_from_text(g_str)
        self.assertTrue(gtn.equal(gtn.project_output(graph), outputExpected))
示例#2
0
    def test_viterbi_path_grad(self):
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 3",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)
        gtn.backward(gtn.viterbi_path(g))
        expected = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0]
        self.assertEqual(g.grad().weights_to_list(), expected)
        g.zero_grad()

        def forward_fn(g):
            paths = [
                gtn.viterbi_path(g),
                gtn.viterbi_path(g),
                gtn.viterbi_path(g)
            ]
            return gtn.forward_score(gtn.union(paths))

        gtn.backward(forward_fn(g))
        self.assertTrue(numerical_grad_check(forward_fn, g, 1e-3, 1e-5))
示例#3
0
    def test_viterbi_score_grad(self):
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 1)
        g.add_arc(0, 1, 1, 1, 2)
        g.add_arc(0, 1, 2, 2, 3)
        g.add_arc(1, 2, 0, 0, 1)
        g.add_arc(1, 2, 1, 1, 2)
        g.add_arc(1, 2, 2, 2, 3)
        gtn.backward(gtn.viterbi_score(g))
        expected = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0]
        self.assertEqual(g.grad().weights_to_list(), expected)

        # Handle two start nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -5)
        g.add_arc(0, 2, 0, 0, 1)
        g.add_arc(1, 2, 0, 0, 2)
        gtn.backward(gtn.viterbi_score(g))
        expected = [0.0, 0.0, 1.0]
        self.assertEqual(g.grad().weights_to_list(), expected)

        # Handle two accept nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        g.add_arc(1, 2, 0, 0, 2)
        gtn.backward(gtn.viterbi_score(g))
        expected = [1.0, 0.0, 1.0]
        self.assertEqual(g.grad().weights_to_list(), expected)

        # A more complex test case
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)
        gtn.backward(gtn.viterbi_score(g))
        # two possible paths with same viterbi score
        expected1 = [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
        expected2 = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0]
        self.assertTrue(g.grad().weights_to_list() == expected1
                        or g.grad().weights_to_list() == expected2)
示例#4
0
    def test_viterbi_score(self):

        # Check score of empty graph
        g = gtn.Graph()
        self.assertEqual(gtn.viterbi_score(g).item(), -math.inf)

        # A simple test case
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 1)
        g.add_arc(0, 1, 1, 1, 2)
        g.add_arc(0, 1, 2, 2, 3)
        g.add_arc(1, 2, 0, 0, 1)
        g.add_arc(1, 2, 1, 1, 2)
        g.add_arc(1, 2, 2, 2, 3)
        self.assertEqual(gtn.viterbi_score(g).item(), 6.0)

        # Handle two start nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -5)
        g.add_arc(0, 2, 0, 0, 1)
        g.add_arc(1, 2, 0, 0, 2)
        self.assertEqual(gtn.viterbi_score(g).item(), 2.0)

        # Handle two accept nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        g.add_arc(1, 2, 0, 0, 2)
        self.assertEqual(gtn.viterbi_score(g).item(), 4.0)

        # A more complex test case
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)
        self.assertEqual(gtn.viterbi_score(g).item(), 7.0)
示例#5
0
    def test_savetxt(self):

        # Acceptor test
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node()
        g.add_node()
        g.add_node(False, True)
        g.add_node(False, True)

        g.add_arc(0, 1, 0, 0, 1.1)
        g.add_arc(1, 2, 1, 1, 2.1)
        g.add_arc(2, 3, 2, 2, 3.1)
        g.add_arc(3, 4, 3, 3, 4.1)
        g.add_arc(4, 5, 4, 4, 5.1)

        g_str = [
            "0 1",
            "4 5",
            "0 1 0 0 1.1",
            "1 2 1 1 2.1",
            "2 3 2 2 3.1",
            "3 4 3 3 4.1",
            "4 5 4 4 5.1",
        ]
        g = create_graph_from_text(g_str)
        _, tmpfile = tempfile.mkstemp()
        gtn.savetxt(tmpfile, g)
        with open(tmpfile) as f:
            lines = f.readlines()
            self.assertEqual(len(g_str), len(lines))
            for i, line in enumerate(lines):
                self.assertEqual(line.strip(), g_str[i])

        # Transducer test
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node()
        g.add_node()
        g.add_node(False, True)
        g.add_node(False, True)

        g.add_arc(0, 1, 0, 1, 1.1)
        g.add_arc(1, 2, 1, 2, 2.1)
        g.add_arc(2, 3, 2, 3, 3.1)
        g.add_arc(3, 4, 3, 4, 4.1)
        g.add_arc(4, 5, 4, gtn.epsilon, 5.1)

        g_str = [
            "0 1",
            "4 5",
            "0 1 0 1 1.1",
            "1 2 1 2 2.1",
            "2 3 2 3 3.1",
            "3 4 3 4 4.1",
            "4 5 4 -1 5.1",
        ]
        g = create_graph_from_text(g_str)
        _, tmpfile = tempfile.mkstemp()
        gtn.savetxt(tmpfile, g)
        with open(tmpfile) as f:
            lines = f.readlines()
            self.assertEqual(len(g_str), len(lines))
            for i, line in enumerate(lines):
                self.assertEqual(line.strip(), g_str[i])
示例#6
0
    def test_loadtxt(self):

        g1 = gtn.Graph()
        g1.add_node(True, True)
        g1.add_node(False, True)
        g1.add_node()
        g1.add_arc(0, 0, 1)
        g1.add_arc(0, 2, 1, 1, 1.1)
        g1.add_arc(2, 1, 2, 2, 2.1)

        g_str = ["0", "0 1", "0 0 1 1 0", "0 2 1 1 1.1", "2 1 2 2 2.1"]
        g2 = create_graph_from_text(g_str)
        self.assertTrue(gtn.equal(g1, g2))
        self.assertTrue(gtn.isomorphic(g1, g2))

        _, tmpfile = tempfile.mkstemp()

        # Write the test file
        gtn.savetxt(tmpfile, g2)
        g3 = gtn.loadtxt(tmpfile)
        self.assertTrue(gtn.equal(g1, g3))

        # Empty graph doesn't load

        g_str = [""]
        self.assertRaises(ValueError, create_graph_from_text, g_str)

        # Graph without accept nodes doesn't load

        g_str = ["1"]
        self.assertRaises(ValueError, create_graph_from_text, g_str)

        # Graph with repeat start nodes doesn't load

        g_str = ["1 0 0", "0 1"]
        self.assertRaises(ValueError, create_graph_from_text, g_str)

        # Graph loads if the start and accept nodes are specified

        g_str = ["0", "1"]
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        self.assertTrue(gtn.equal(g, create_graph_from_text(g_str)))

        # Graph doesn't load if arc incorrect

        g_str = ["0", "1", "0 2"]
        self.assertRaises(ValueError, create_graph_from_text, g_str)
        g_str = ["0", "1", "0 1 2 3 4 5"]
        self.assertRaises(ValueError, create_graph_from_text, g_str)

        # Transducer loads

        g1 = gtn.Graph()
        g1.add_node(True, True)
        g1.add_node(False, True)
        g1.add_node()
        g1.add_arc(0, 0, 1, 1)
        g1.add_arc(0, 2, 1, 2, 1.1)
        g1.add_arc(2, 1, 2, 3, 2.1)

        g_str = ["0", "0 1", "0 0 1", "0 2 1 2 1.1", "2 1 2 3 2.1"]
        g2 = create_graph_from_text(g_str)
        self.assertTrue(gtn.equal(g1, g2))
        self.assertTrue(gtn.isomorphic(g1, g2))
示例#7
0
    def test_forward_score_grad(self):
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 1)
        g.add_arc(0, 1, 1, 1, 2)
        g.add_arc(0, 1, 2, 2, 3)
        g.add_arc(1, 2, 0, 0, 1)
        g.add_arc(1, 2, 1, 1, 2)
        g.add_arc(1, 2, 2, 2, 3)
        gtn.backward(gtn.forward_score(g))
        self.assertTrue(numerical_grad_check(gtn.forward_score, g, 1e-3, 1e-3))

        # Handle two start nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -5)
        g.add_arc(0, 2, 0, 0, 1)
        g.add_arc(1, 2, 0, 0, 2)
        gtn.backward(gtn.forward_score(g))
        self.assertTrue(numerical_grad_check(gtn.forward_score, g, 1e-3, 1e-3))

        denom = 1 / (math.exp(-3) + math.exp(1) + math.exp(2))
        grad = g.grad()
        grad_weights = grad.weights_to_list()
        self.assertAlmostEqual(grad_weights[0], (denom * math.exp(-3)))
        self.assertAlmostEqual(grad_weights[1], (denom * math.exp(1)))
        self.assertAlmostEqual(grad_weights[2],
                               (denom * (math.exp(-3) + math.exp(2))))

        # Handle two accept nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        g.add_arc(1, 2, 0, 0, 2)
        gtn.backward(gtn.forward_score(g))
        self.assertTrue(numerical_grad_check(gtn.forward_score, g, 1e-3, 1e-3))

        denom = 1 / (2 * math.exp(2) + math.exp(4))
        grad = g.grad()
        grad_weights = grad.weights_to_list()
        self.assertAlmostEqual(grad_weights[0],
                               (denom * (math.exp(2) + math.exp(4))),
                               places=5)
        self.assertAlmostEqual(grad_weights[1], (denom * math.exp(2)),
                               places=5)
        self.assertAlmostEqual(grad_weights[2], (denom * math.exp(4)),
                               places=5)

        # Handle case where some arcs don't lead to accepting states
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, False)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        gtn.backward(gtn.forward_score(g))
        self.assertTrue(numerical_grad_check(gtn.forward_score, g, 1e-3, 1e-3))
        grad = g.grad()
        grad_weights = grad.weights_to_list()
        self.assertAlmostEqual(grad_weights[0], (0.0))
        self.assertAlmostEqual(grad_weights[1], (1.0))

        # Handles negative infinity
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -math.inf)
        g.add_arc(0, 1, 1, 1, -math.inf)
        gtn.backward(gtn.forward_score(g))

        grad = g.grad()
        grad_weights = grad.weights_to_list()
        self.assertTrue(math.isnan(grad_weights[0]))
        self.assertTrue(math.isnan(grad_weights[1]))

        g2 = gtn.Graph()
        g2.add_node(True)
        g2.add_node(False, True)
        g2.add_arc(0, 1, 0, 0, -math.inf)
        g2.add_arc(0, 1, 1, 1, 1.0)
        gtn.backward(gtn.forward_score(g2))

        grad2 = g2.grad()
        grad_weights = grad2.weights_to_list()
        self.assertAlmostEqual(grad_weights[0], (0.0))
        self.assertAlmostEqual(grad_weights[1], (1.0))

        # Handles infinity
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, math.inf)
        g.add_arc(0, 1, 1, 1, math.inf)
        gtn.backward(gtn.forward_score(g))
        grad = g.grad()
        grad_weights = grad.weights_to_list()
        self.assertTrue(math.isnan(grad_weights[0]))
        self.assertTrue(math.isnan(grad_weights[1]))

        g2 = gtn.Graph()
        g2.add_node(True)
        g2.add_node(False, True)
        g2.add_arc(0, 1, 0, 0, math.inf)
        g2.add_arc(0, 1, 1, 1, 1.0)
        gtn.backward(gtn.forward_score(g2))
        grad2 = g2.grad()
        grad_weights = grad.weights_to_list()
        self.assertTrue(math.isnan(grad_weights[0]))
        self.assertTrue(math.isnan(grad_weights[1]))

        # A more complex test case
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)
        gtn.backward(gtn.forward_score(g))
        self.assertTrue(numerical_grad_check(gtn.forward_score, g, 1e-3, 1e-3))
示例#8
0
    def test_composition(self):
        # Compos,ing with an empty graph gives an empty graph
        g1 = gtn.Graph()
        g2 = gtn.Graph()
        self.assertTrue(gtn.equal(gtn.compose(g1, g2), gtn.Graph()))

        g1.add_node(True)
        g1.add_node()
        g1.add_arc(0, 1, 0)

        g2.add_node(True)
        g2.add_node(False, True)
        g2.add_arc(0, 1, 0)
        g2.add_arc(0, 1, 0)

        self.assertTrue(gtn.equal(gtn.compose(g1, g2), gtn.Graph()))
        self.assertTrue(gtn.equal(gtn.compose(g2, g1), gtn.Graph()))
        self.assertTrue(gtn.equal(gtn.intersect(g2, g1), gtn.Graph()))

        # Check singly sorted version
        g1.arc_sort(True)
        self.assertTrue(gtn.equal(gtn.compose(g1, g2), gtn.Graph()))

        # Check doubly sorted version
        g2.arc_sort()
        self.assertTrue(gtn.equal(gtn.compose(g1, g2), gtn.Graph()))

        # Self-loop in the composed graph
        g1 = gtn.Graph()
        g1.add_node(True)
        g1.add_node(False, True)
        g1.add_arc(0, 0, 0)
        g1.add_arc(0, 1, 1)
        g1.add_arc(1, 1, 2)

        g2 = gtn.Graph()
        g2.add_node(True)
        g2.add_node()
        g2.add_node(False, True)
        g2.add_arc(0, 1, 0)
        g2.add_arc(1, 1, 0)
        g2.add_arc(1, 2, 1)

        g_str = ["0", "2", "0 1 0", "1 1 0", "1 2 1"]
        expected = create_graph_from_text(g_str)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))
        self.assertTrue(gtn.isomorphic(gtn.intersect(g1, g2), expected))

        # Check singly sorted version
        g1.arc_sort(True)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))

        # Check doubly sorted version
        g2.arc_sort()
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))

        # Loop in the composed graph
        g1 = gtn.Graph()
        g1.add_node(True)
        g1.add_node(False, True)
        g1.add_arc(0, 1, 0)
        g1.add_arc(1, 1, 1)
        g1.add_arc(1, 0, 0)

        g2 = gtn.Graph()
        g2.add_node(True)
        g2.add_node(False, True)
        g2.add_arc(0, 0, 0)
        g2.add_arc(0, 1, 1)
        g2.add_arc(1, 0, 1)

        g_str = ["0", "2", "0 1 0", "1 0 0", "1 2 1", "2 1 1"]
        expected = create_graph_from_text(g_str)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))
        self.assertTrue(gtn.isomorphic(gtn.intersect(g1, g2), expected))

        # Check singly sorted version
        g1.arc_sort(True)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))

        # Check doubly sorted version
        g2.arc_sort()
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))

        g1 = gtn.Graph()
        g1.add_node(True)
        g1.add_node()
        g1.add_node()
        g1.add_node()
        g1.add_node(False, True)
        for i in range(g1.num_nodes() - 1):
            for j in range(3):
                g1.add_arc(i, i + 1, j, j, j)

        g2 = gtn.Graph()
        g2.add_node(True)
        g2.add_node()
        g2.add_node(False, True)
        g2.add_arc(0, 1, 0, 0, 3.5)
        g2.add_arc(1, 1, 0, 0, 2.5)
        g2.add_arc(1, 2, 1, 1, 1.5)
        g2.add_arc(2, 2, 1, 1, 4.5)
        g_str = [
            "0",
            "6",
            "0 1 0 0 3.5",
            "1 2 0 0 2.5",
            "1 4 1 1 2.5",
            "2 3 0 0 2.5",
            "2 5 1 1 2.5",
            "4 5 1 1 5.5",
            "3 6 1 1 2.5",
            "5 6 1 1 5.5",
        ]
        expected = create_graph_from_text(g_str)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))
        self.assertTrue(gtn.isomorphic(gtn.intersect(g1, g2), expected))

        # Check singly sorted version
        g1.arc_sort(True)
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))

        # Check doubly sorted version
        g2.arc_sort()
        self.assertTrue(gtn.isomorphic(gtn.compose(g1, g2), expected))
示例#9
0
    def test_viterbi_path(self):

        g = gtn.Graph()

        # Empty graph gives empty path
        self.assertTrue(gtn.equal(gtn.viterbi_path(g), g))

        # Accepting empty string
        g.add_node(True, True)
        self.assertTrue(gtn.equal(gtn.viterbi_path(g), g))

        # A simple test case
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 1)
        g.add_arc(0, 1, 1, 1, 2)
        g.add_arc(0, 1, 2, 2, 3)
        g.add_arc(1, 2, 0, 0, 1)
        g.add_arc(1, 2, 1, 1, 2)
        g.add_arc(1, 2, 2, 2, 3)

        best = gtn.Graph()
        best.add_node(True)
        best.add_node()
        best.add_node(False, True)
        best.add_arc(0, 1, 2, 2, 3)
        best.add_arc(1, 2, 2, 2, 3)

        path = gtn.viterbi_path(g)
        self.assertTrue(gtn.rand_equivalent(path, best))
        self.assertEqual(gtn.viterbi_score(path).item(), gtn.viterbi_score(g).item())

        # Handle a single node.
        g = gtn.Graph()
        g.add_node(True, True)

        best = gtn.Graph()
        best.add_node(True, True)
        path = gtn.viterbi_path(g)
        self.assertTrue(gtn.rand_equivalent(path, best))
        self.assertEqual(gtn.viterbi_score(path).item(), gtn.viterbi_score(g).item())

        # Handle two start nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -5)
        g.add_arc(0, 2, 0, 0, 1)
        g.add_arc(1, 2, 0, 0, 2)

        best = gtn.Graph()
        best.add_node(True)
        best.add_node(False, True)
        best.add_arc(0, 1, 0, 0, 2)

        path = gtn.viterbi_path(g)
        self.assertTrue(gtn.rand_equivalent(path, best))
        self.assertEqual(gtn.viterbi_score(path).item(), gtn.viterbi_score(g).item())

        # Handle two accept nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 3)
        g.add_arc(0, 2, 0, 0, 2)
        g.add_arc(1, 2, 0, 0, 2)

        best = gtn.Graph()
        best.add_node(True)
        best.add_node()
        best.add_node(False, True)
        best.add_arc(0, 1, 0, 0, 3)
        best.add_arc(1, 2, 0, 0, 2)

        path = gtn.viterbi_path(g)
        self.assertTrue(gtn.rand_equivalent(path, best))
        self.assertEqual(gtn.viterbi_score(path).item(), gtn.viterbi_score(g).item())

        # A more complex test case
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)

        # There are three options for the best path, the
        # viterbiPath may return any of them.
        best1 = gtn.Graph()
        best1.add_node(True)
        best1.add_node()
        best1.add_node()
        best1.add_node()
        best1.add_node(False, True)
        best1.add_arc(0, 1, 0, 0, 2)
        best1.add_arc(1, 2, 0, 0, 2)
        best1.add_arc(2, 3, 0, 0, 1)
        best1.add_arc(3, 4, 0, 0, 2)

        best2 = gtn.Graph()
        best2.add_node(True)
        best2.add_node()
        best2.add_node()
        best2.add_node()
        best2.add_node(False, True)
        best2.add_arc(0, 1, 0, 0, 2)
        best2.add_arc(1, 2, 0, 0, 2)
        best2.add_arc(2, 3, 1, 1, 1)
        best2.add_arc(3, 4, 0, 0, 2)

        best3 = gtn.Graph()
        best3.add_node(True)
        best3.add_node()
        best3.add_node()
        best3.add_node(False, True)
        best3.add_arc(0, 1, 0, 0, 2)
        best3.add_arc(1, 2, 0, 0, 2)
        best3.add_arc(2, 3, 1, 1, 3)

        path = gtn.viterbi_path(g)
        self.assertTrue(
            (
                gtn.rand_equivalent(path, best1)
                or gtn.rand_equivalent(path, best2)
                or gtn.rand_equivalent(path, best3)
            )
        )

        self.assertEqual(gtn.viterbi_score(path).item(), gtn.viterbi_score(g).item())
示例#10
0
    def test_forward(self):

        # Check score of empty graph
        g = gtn.Graph()
        self.assertEqual(gtn.forward_score(g).item(), -math.inf)

        # Throws on self-loops
        g = gtn.Graph()
        g.add_node(True, True)
        g.add_arc(0, 0, 1)
        self.assertRaises(ValueError, gtn.forward_score, g)

        # Throws on internal self-loop
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0)
        g.add_arc(1, 2, 0)
        g.add_arc(1, 1, 0)
        self.assertRaises(ValueError, gtn.forward_score, g)

        # Throws on self-loop in accept node
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0)
        g.add_arc(1, 2, 0)
        g.add_arc(2, 2, 0)
        self.assertRaises(ValueError, gtn.forward_score, g)

        # Throws on cycle
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0)
        g.add_arc(1, 2, 0)
        g.add_arc(2, 0, 0)
        self.assertRaises(ValueError, gtn.forward_score, g)

        # Throws if a non-start node has no incoming arcs
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 2, 0)
        g.add_arc(1, 2, 0)
        self.assertRaises(ValueError, gtn.forward_score, g)

        # Handles negative infinity
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -math.inf)
        g.add_arc(0, 1, 1, 1, -math.inf)
        self.assertEqual(gtn.forward_score(g).item(), -math.inf)

        # Handles infinity
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, math.inf)
        g.add_arc(0, 1, 1, 1, 0)
        self.assertEqual(gtn.forward_score(g).item(), math.inf)

        # Single Node
        g = gtn.Graph()
        g.add_node(True, True)
        self.assertEqual(gtn.forward_score(g).item(), 0.0)

        # A simple test case
        g = gtn.Graph()
        g.add_node(True)
        g.add_node()
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 1)
        g.add_arc(0, 1, 1, 1, 2)
        g.add_arc(0, 1, 2, 2, 3)
        g.add_arc(1, 2, 0, 0, 1)
        g.add_arc(1, 2, 1, 1, 2)
        g.add_arc(1, 2, 2, 2, 3)
        self.assertAlmostEqual(gtn.forward_score(g).item(), (6.8152), places=4)

        # Handle two start nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, -5)
        g.add_arc(0, 2, 0, 0, 1)
        g.add_arc(1, 2, 0, 0, 2)
        expected = math.log(math.exp(1) + math.exp(-5 + 2) + math.exp(2))
        self.assertAlmostEqual(gtn.forward_score(g).item(), (expected), places=4)

        # Handle two accept nodes
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, True)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        g.add_arc(1, 2, 0, 0, 2)
        expected = math.log(2 * math.exp(2) + math.exp(4))
        self.assertAlmostEqual(gtn.forward_score(g).item(), (expected), places=4)

        # Handle case where some arcs don't lead to accepting states
        g = gtn.Graph()
        g.add_node(True)
        g.add_node(False, False)
        g.add_node(False, True)
        g.add_arc(0, 1, 0, 0, 2)
        g.add_arc(0, 2, 0, 0, 2)
        self.assertEqual(gtn.forward_score(g).item(), 2.0)

        # A more complex test case
        g_str = [
            "0 1",
            "3 4",
            "0 1 0 0 2",
            "0 2 1 1 1",
            "1 2 0 0 2",
            "2 3 0 0 1",
            "2 3 1 1 1",
            "1 4 0 0 2",
            "2 4 1 1 3",
            "3 4 0 0 2",
        ]
        g = create_graph_from_text(g_str)
        self.assertAlmostEqual(gtn.forward_score(g).item(), (8.36931), places=4)