github.com/gopherd/gonum@v0.0.4/graph/formats/rdf/iso_canonical_example_test.go (about) 1 // Copyright ©2020 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rdf_test 6 7 import ( 8 "crypto/md5" 9 "fmt" 10 "log" 11 "os" 12 "sort" 13 "strings" 14 "text/tabwriter" 15 16 "github.com/gopherd/gonum/graph/formats/rdf" 17 ) 18 19 func ExampleIsoCanonicalHashes_isomorphisms() { 20 for _, statements := range []string{ 21 ` 22 <https://example.com/1> <https://example.com/2> <https://example.com/3> . 23 <https://example.com/3> <https://example.com/4> <https://example.com/5> . 24 `, 25 ` 26 _:a <ex:q> <ex:p> . 27 _:b <ex:q> <ex:p> . 28 _:c <ex:p> _:a . 29 _:d <ex:p> _:b . 30 _:c <ex:r> _:d . 31 `, 32 ` 33 _:a1 <ex:q> <ex:p> . 34 _:b1 <ex:q> <ex:p> . 35 _:c1 <ex:p> _:a1 . 36 _:d1 <ex:p> _:b1 . 37 _:c1 <ex:r> _:d1 . 38 `, 39 ` 40 # G 41 <ex:p> <ex:q> _:a . 42 <ex:p> <ex:q> _:b . 43 <ex:s> <ex:p> _:a . 44 <ex:s> <ex:r> _:c . 45 _:c <ex:p> _:b . 46 47 # H 48 <ex:p> <ex:q> _:d . 49 <ex:p> <ex:q> _:e . 50 _:f <ex:p> _:d . 51 _:f <ex:r> _:g . 52 _:g <ex:p> _:e . 53 `, 54 ` 55 _:greet <l:is> "hola"@es . 56 `, 57 } { 58 // Decode the statement stream. 59 dec := rdf.NewDecoder(strings.NewReader(statements)) 60 var s []*rdf.Statement 61 for { 62 l, err := dec.Unmarshal() 63 if err != nil { 64 break 65 } 66 s = append(s, l) 67 } 68 69 // Get the node label to hash look-up table. 70 hashes, _ := rdf.IsoCanonicalHashes(s, false, true, md5.New(), make([]byte, 16)) 71 72 // Get all the blank nodes. 73 var blanks []string 74 for k := range hashes { 75 if strings.HasPrefix(k, "_:") { 76 blanks = append(blanks, k) 77 } 78 } 79 sort.Strings(blanks) 80 81 if len(blanks) == 0 { 82 fmt.Println("No blank nodes.") 83 } else { 84 w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) 85 fmt.Fprintln(w, "Node\tHash") 86 for _, k := range blanks { 87 fmt.Fprintf(w, "%s\t%032x\n", k, hashes[k]) 88 } 89 w.Flush() 90 } 91 fmt.Println() 92 } 93 94 // Output: 95 // 96 // No blank nodes. 97 // 98 // Node Hash 99 // _:a d4db6df055d5611e9d8aa6ea621561d1 100 // _:b ad70e47f2b026064c7f0922060512b9a 101 // _:c dafd81e6fa603d3e11c898d631e8673f 102 // _:d 7e318557b09444e88791721becc2a8e7 103 // 104 // Node Hash 105 // _:a1 d4db6df055d5611e9d8aa6ea621561d1 106 // _:b1 ad70e47f2b026064c7f0922060512b9a 107 // _:c1 dafd81e6fa603d3e11c898d631e8673f 108 // _:d1 7e318557b09444e88791721becc2a8e7 109 // 110 // Node Hash 111 // _:a 44ad49b6df3aea91ddbcef932c93e3b4 112 // _:b ba3ffd8b271a8545b1a3a9042e75ce4b 113 // _:c 34e1bd90b6758b4a766e000128caa6a6 114 // _:d eb2a47c1032f623647d0497a2ff74052 115 // _:e 1d9ed02f28d87e555feb904688bc2449 116 // _:f d3b00d36ea503dcc8d234e4405feab81 117 // _:g 55127e4624c0a4fe5990933a48840af8 118 // 119 // Node Hash 120 // _:greet 0d9ba18a037a3fa67e46fce821fe51b4 121 } 122 123 func ExampleIsoCanonicalHashes_isomorphicParts() { 124 for _, statements := range []string{ 125 ` 126 # Part 1 127 _:a <ex:q> <ex:p> . 128 _:b <ex:q> <ex:p> . 129 _:c <ex:p> _:a . 130 _:d <ex:p> _:b . 131 _:c <ex:r> _:d . 132 133 # Part 2 134 _:a1 <ex:q> <ex:p> . 135 _:b1 <ex:q> <ex:p> . 136 _:c1 <ex:p> _:a1 . 137 _:d1 <ex:p> _:b1 . 138 _:c1 <ex:r> _:d1 . 139 `, 140 } { 141 // Decode the statement stream. 142 dec := rdf.NewDecoder(strings.NewReader(statements)) 143 var s []*rdf.Statement 144 for { 145 l, err := dec.Unmarshal() 146 if err != nil { 147 break 148 } 149 s = append(s, l) 150 } 151 152 // Get the node label to hash look-up table. This time 153 // we will decompose the dataset into splits and not 154 // distinguish nodes. This will then group nodes from 155 // the two isomorphic parts. Otherwise each node in 156 // the complete dataset would get a unique hash. 157 hashes, _ := rdf.IsoCanonicalHashes(s, true, false, md5.New(), make([]byte, 16)) 158 159 // Get all the blank nodes. 160 var blanks []string 161 for k := range hashes { 162 if strings.HasPrefix(k, "_:") { 163 blanks = append(blanks, k) 164 } 165 } 166 sort.Strings(blanks) 167 168 if len(blanks) == 0 { 169 fmt.Println("No blank nodes.") 170 } else { 171 w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) 172 fmt.Fprintln(w, "Node\tHash") 173 for _, k := range blanks { 174 fmt.Fprintf(w, "%s\t%032x\n", k, hashes[k]) 175 } 176 w.Flush() 177 } 178 fmt.Println() 179 } 180 181 // Output: 182 // 183 // Node Hash 184 // _:a d4db6df055d5611e9d8aa6ea621561d1 185 // _:a1 d4db6df055d5611e9d8aa6ea621561d1 186 // _:b ad70e47f2b026064c7f0922060512b9a 187 // _:b1 ad70e47f2b026064c7f0922060512b9a 188 // _:c dafd81e6fa603d3e11c898d631e8673f 189 // _:c1 dafd81e6fa603d3e11c898d631e8673f 190 // _:d 7e318557b09444e88791721becc2a8e7 191 // _:d1 7e318557b09444e88791721becc2a8e7 192 } 193 194 func ExampleC14n() { 195 for _, statements := range []string{ 196 ` 197 _:a <ex:q> <ex:p> . 198 _:b <ex:q> <ex:p> . 199 _:c <ex:p> _:a . 200 _:d <ex:p> _:b . 201 _:c <ex:r> _:d . 202 `, 203 ` 204 _:c1 <ex:p> _:a1 . 205 _:b1 <ex:q> <ex:p> . 206 _:d1 <ex:p> _:b1 . 207 _:a1 <ex:q> <ex:p> . 208 _:c1 <ex:r> _:d1 . 209 `, 210 } { 211 // Decode the statement stream. 212 dec := rdf.NewDecoder(strings.NewReader(statements)) 213 var s []*rdf.Statement 214 for { 215 l, err := dec.Unmarshal() 216 if err != nil { 217 break 218 } 219 s = append(s, l) 220 } 221 222 // Get the hash to term label look-up table. 223 _, terms := rdf.IsoCanonicalHashes(s, false, true, md5.New(), make([]byte, 16)) 224 225 relabeled, err := rdf.C14n(nil, s, terms) 226 if err != nil { 227 log.Fatal(err) 228 } 229 230 for _, s := range relabeled { 231 fmt.Println(s) 232 } 233 fmt.Println() 234 } 235 236 // Output: 237 // 238 // _:c14n0 <ex:p> _:c14n1 . 239 // _:c14n1 <ex:q> <ex:p> . 240 // _:c14n2 <ex:q> <ex:p> . 241 // _:c14n3 <ex:p> _:c14n2 . 242 // _:c14n3 <ex:r> _:c14n0 . 243 // 244 // _:c14n0 <ex:p> _:c14n1 . 245 // _:c14n1 <ex:q> <ex:p> . 246 // _:c14n2 <ex:q> <ex:p> . 247 // _:c14n3 <ex:p> _:c14n2 . 248 // _:c14n3 <ex:r> _:c14n0 . 249 }