├── .github └── workflows │ └── crystalg.yaml ├── .gitignore ├── LICENSE ├── README.md ├── shard.yml ├── spec ├── crystalg_spec.cr ├── data_structure │ ├── fenwick_tree_2d_spec.cr │ ├── fenwick_tree_spec.cr │ ├── kdtree_spec.cr │ ├── leftist_heap_spec.cr │ ├── link_cut_tree_spec.cr │ ├── priority_queue_spec.cr │ ├── queue_spec.cr │ ├── randomized_binary_search_tree_spec.cr │ ├── randomized_meldable_heap_spec.cr │ ├── segment_tree_spec.cr │ ├── skew_heap_spec.cr │ ├── skip_list_spec.cr │ ├── stack_spec.cr │ └── union_find_spec.cr ├── geometry │ ├── circle_spec.cr │ ├── geometry_spec.cr │ ├── line_spec.cr │ ├── polygon_spec.cr │ └── segment_spec.cr ├── graph │ ├── articulation_points_spec.cr │ ├── bellman_ford_spec.cr │ ├── bridge_spec.cr │ ├── cycle_detection_directed_graph_spec.cr │ ├── dijkstra_spec.cr │ ├── dinic_spec.cr │ ├── ford_fulkerson_spec.cr │ ├── hopcroft_karp_spec.cr │ ├── kruskal_spec.cr │ └── toporogical_sort_spec.cr ├── number_theory │ ├── carmichael_spec.cr │ ├── euclid_spec.cr │ ├── euler_spec.cr │ ├── mobius_spec.cr │ ├── mod_spec.cr │ ├── prime_number_spec.cr │ └── stern_brocot_tree_spec.cr ├── spec_helper.cr └── strings │ ├── aho_corasick_spec.cr │ ├── baker_bird_spec.cr │ ├── kmp_spec.cr │ ├── rolling_hash_spec.cr │ └── suffix_array_spec.cr └── src ├── crystalg.cr └── crystalg ├── concurrent ├── core │ ├── atomic_markable_reference.cr │ ├── atomic_stamped_reference.cr │ ├── exchanger.cr │ └── markable_reference.cr ├── data_structure │ ├── queue.cr │ └── unbounded_queue.cr └── lock │ ├── a_lock.cr │ ├── back_off.cr │ ├── clh_lock.cr │ ├── lock.cr │ ├── mcs_lock.cr │ ├── reentrant_lock.cr │ ├── semaphore.cr │ ├── tas_lock.cr │ ├── to_lock.cr │ ├── ttas_lock.cr │ └── wait_group.cr ├── data_structures.cr ├── data_structures ├── fenwick_tree.cr ├── fenwick_tree_2d.cr ├── kdtree.cr ├── leftist_heap.cr ├── link_cut_tree.cr ├── persistent_union_find.cr ├── priority_queue.cr ├── queue.cr ├── randomized_binary_search_tree.cr ├── randomized_meldable_heap.cr ├── segment_tree.cr ├── skew_heap.cr ├── skip_list.cr ├── stack.cr └── union_find.cr ├── geometry ├── circle.cr ├── extensions.cr ├── geometry.cr ├── line.cr ├── point.cr ├── polygon.cr └── segment.cr ├── graph ├── connected_components │ ├── articulation_points.cr │ ├── bridges.cr │ ├── context.cr │ └── cycle_detection.cr ├── directed_graph.cr ├── edge.cr ├── flow │ ├── dinic.cr │ ├── ford_fulkerson.cr │ └── hopcroft_karp.cr ├── flow_graph.cr ├── graph.cr ├── shortest_path │ └── dijkstra.cr ├── spanning_tree │ └── kruskal.cr └── undirected_graph.cr ├── helper.cr ├── number_theory ├── carmichael.cr ├── euclid.cr ├── euler_phi.cr ├── mobius.cr ├── mod.cr ├── prime_number.cr └── stern_brocot_tree.cr ├── random └── xor128.cr ├── strings ├── aho_corasick.cr ├── baker_bird.cr ├── kmp.cr ├── rolling_hash.cr └── suffix_array.cr └── version.cr /.github/workflows/crystalg.yaml: -------------------------------------------------------------------------------- 1 | name: crystalg 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | include: 11 | - {os: ubuntu-latest} 12 | - {os: macos-latest} 13 | # - {os: windows-latest} 14 | runs-on: ${{matrix.os}} 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: oprypin/install-crystal@v1 19 | with: 20 | crystal: 1.0.0 21 | - run: shards install 22 | - run: crystal spec 23 | - run: crystal tool format && git diff --exit-code 24 | if: matrix.os == 'ubuntu-latest' 25 | - run: crystal docs 26 | - name: Deploy document 27 | uses: peaceiris/actions-gh-pages@v3 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: ./docs 31 | keep_files: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | *.dwarf 6 | 7 | # Libraries don't need dependency lock 8 | # Dependencies will be locked in applications that use them 9 | /shard.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 tobias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub release](https://img.shields.io/github/release/TobiasGSmollett/crystalg.svg)](https://github.com/TobiasGSmollett/crystalg/releases) 2 | 3 | 4 | 5 | # Crystalg 6 | 7 | A generic algorithm library for crystal-lang. 8 | 9 | ## Installation 10 | 11 | Clone repository manually: 12 | 13 | ```sh 14 | $ git clone https://github.com/TobiasGSmollett/crystalg && cd crystalg/ 15 | ``` 16 | 17 | Or add this to your application's `shard.yml`: 18 | 19 | ```yaml 20 | dependencies: 21 | crystalg: 22 | github: TobiasGSmollett/crystalg 23 | ``` 24 | 25 | ## Usage 26 | 27 | The fastest way to try it is by using Crystal Playground (`crystal play`): 28 | 29 | ```crystal 30 | require "./crystalg" 31 | 32 | include Crystalg::Strings 33 | 34 | input = "mississippi" 35 | hash = RollingHash.new input 36 | hash.count("issi") # => 2 37 | ``` 38 | 39 | ## Documentation 40 | - [API Document](https://tobiasgsmollett.github.io/crystalg/) 41 | 42 | ## Development 43 | 44 | crystal spec 45 | 46 | ## To Do 47 | * Graph 48 | * Minimum-Cost Arborescence 49 | * Strongly Connected Components 50 | * Flow Alogorithm 51 | * Minimum Cost Flow 52 | * Data Structure 53 | * Red Black Tree 54 | * Link-Cut Tree 55 | * String Algorithm 56 | * Suffix Automaton 57 | * Computational Geometry 58 | * Closest Pair 59 | * Segment Intersections 60 | * Tangent to a Circle 61 | * Common Tangent 62 | * Intersection of a Circle and a Polygon 63 | 64 | ## Contributing 65 | 66 | 1. Fork it ( https://github.com/TobiasGSmollett/crystalg/fork ) 67 | 2. Create your feature branch (git checkout -b my-new-feature) 68 | 3. Commit your changes (git commit -am 'Add some feature') 69 | 4. Push to the branch (git push origin my-new-feature) 70 | 5. Create a new Pull Request 71 | 72 | ## Contributors 73 | 74 | - [TobiasGSmollett](https://github.com/TobiasGSmollett) tobias - creator, maintainer 75 | -------------------------------------------------------------------------------- /shard.yml: -------------------------------------------------------------------------------- 1 | name: crystalg 2 | version: 0.1.0 3 | 4 | authors: 5 | - tobya 6 | 7 | crystal: 1.0.0 8 | 9 | license: MIT 10 | -------------------------------------------------------------------------------- /spec/crystalg_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Crystalg do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | # false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/data_structure/fenwick_tree_2d_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "fenwick_tree_2d" do 7 | fenwick = FenwickTree2D(Int32).new(6, 6) 8 | (0..5).each { |e| fenwick[e, e] = e } 9 | 10 | (0..6).each do |e| 11 | expected = (e - 1) * e / 2 12 | fenwick.sum(e, e).should eq expected 13 | end 14 | end 15 | 16 | it "fenwick_tree_2d 2" do 17 | # fenwick tree: sum[x, y]: 18 | # 1 2 3 1 3 6 19 | # 4 5 6 5 12 21 20 | # 7 8 9 12 27 45 21 | # 10 11 12 22 48 78 22 | 23 | fenwick = FenwickTree2D(Int32).new(4, 3) 24 | (0..3).each do |row| 25 | (0..2).each do |col| 26 | fenwick[row, col] = row * 3 + col + 1 27 | end 28 | end 29 | 30 | expected = [ 31 | [0, 0, 0, 0], 32 | [0, 1, 3, 6], 33 | [0, 5, 12, 21], 34 | [0, 12, 27, 45], 35 | [0, 22, 48, 78], 36 | ] 37 | 38 | (0..4).each do |row| 39 | (0..3).each do |col| 40 | fenwick.sum(row, col).should eq expected[row][col] 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/data_structure/fenwick_tree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "fenwick_tree" do 7 | fenwick = FenwickTree(Int32).new(6) 8 | 9 | (0..5).each { |e| fenwick[e] = e } 10 | (0..6).each do |e| 11 | expected = ((e - 1) * e / 2).to_i 12 | fenwick.sum(e).should eq expected 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/data_structure/kdtree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | include Crystalg::Geometry 5 | include Crystalg::DataStructures 6 | 7 | describe Crystalg do 8 | it "kdtree" do 9 | input = [ 10 | Point.new(2.0, 1.0), 11 | Point.new(2.0, 2.0), 12 | Point.new(4.0, 2.0), 13 | Point.new(6.0, 2.0), 14 | Point.new(3.0, 3.0), 15 | Point.new(5.0, 4.0), 16 | ] 17 | 18 | kdtree = KDTree(Float64).new(input) 19 | 20 | result1 = kdtree.count(Point.new(2.0, 0.0), Point.new(4.0, 4.0)) 21 | result2 = kdtree.count(Point.new(4.0, 2.0), Point.new(10.0, 5.0)) 22 | true.should eq(result1 == 4) 23 | true.should eq(result2 == 3) 24 | end 25 | 26 | it "nearest_neighbour kdtree" do 27 | input = [ 28 | Point.new(2.0, 1.0), 29 | Point.new(2.0, 2.0), 30 | Point.new(4.0, 2.0), 31 | Point.new(6.0, 1.0), 32 | Point.new(3.0, 3.0), 33 | Point.new(5.0, 4.0), 34 | ] 35 | 36 | kdtree = KDTree(Float64).new(input) 37 | 38 | result1 = kdtree.nearest_neighbour Point.new(0.0, 0.0) 39 | 40 | true.should eq(result1 == Point.new(2.0, 1.0)) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/data_structure/leftist_heap_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "LeftistHeap" do 7 | heap = LeftistHeap(Int32).new 8 | 9 | heap.push 5 10 | heap.push 3 11 | heap.push 8 12 | heap.top.should eq 3 13 | 14 | heap.push 1 15 | heap.top.should eq 1 16 | 17 | heap.pop 18 | heap.top.should eq 3 19 | 20 | heap.pop 21 | heap.top.should eq 5 22 | 23 | heap.pop 24 | heap.top.should eq 8 25 | end 26 | 27 | it "LeftistHeap absorb" do 28 | heap1 = LeftistHeap(Int32).new 29 | heap1.push 5 30 | heap1.push 3 31 | heap1.push 8 32 | 33 | heap2 = LeftistHeap(Int32).new 34 | heap2.push 2 35 | heap2.push 3 36 | heap2.push 9 37 | 38 | heap1.absorb(heap2) 39 | 40 | heap1.top.should eq 2 41 | 42 | heap1.push 1 43 | heap1.top.should eq 1 44 | 45 | [2, 3, 3, 5, 8, 9].each do |e| 46 | heap1.pop 47 | heap1.top.should eq e 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/data_structure/link_cut_tree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "rotate" do 7 | # rotate(1) 8 | # 9 | # 0 1 10 | # / \ / \ 11 | # 1 2 <=> 3 0 12 | # / \ / \ 13 | # 3 4 4 2 14 | 15 | lctree = LinkCutTree(Int32).new(5) 16 | lctree.link(1, 0) 17 | lctree.link(2, 0) 18 | lctree.link(3, 1) 19 | lctree.link(4, 1) 20 | lctree.@rev[1] = false 21 | lctree.@rev[2] = false 22 | lctree.@rev[3] = false 23 | lctree.@rev[4] = false 24 | 25 | lctree.@left[0] = 1 26 | lctree.@left[1] = 3 27 | 28 | lctree.@right[0] = 2 29 | lctree.@right[1] = 4 30 | 31 | lctree.rotate(1) 32 | 33 | true.should eq(lctree.@parent === [1, nil, 0, 1, 0]) 34 | true.should eq(lctree.@left === [4, 3, nil, nil, nil]) 35 | true.should eq(lctree.@right === [2, 0, nil, nil, nil]) 36 | true.should eq(lctree.@rev === [false, false, false, false, false]) 37 | 38 | lctree.rotate(0) 39 | 40 | true.should eq(lctree.@parent === [nil, 0, 0, 1, 1]) 41 | true.should eq(lctree.@left === [1, 3, nil, nil, nil]) 42 | true.should eq(lctree.@right === [2, 4, nil, nil, nil]) 43 | true.should eq(lctree.@rev === [false, false, false, false, false]) 44 | end 45 | 46 | it "lca" do 47 | # 0 48 | # /|\ 49 | # 1 2 3 50 | # /\ 51 | # 4 5 52 | # /\ 53 | # 6 7 54 | 55 | lctree = LinkCutTree(Int32).new(8) 56 | lctree.link(1, 0) 57 | lctree.link(2, 0) 58 | lctree.link(3, 0) 59 | lctree.link(4, 1) 60 | lctree.link(5, 1) 61 | lctree.link(6, 5) 62 | lctree.link(7, 5) 63 | true.should eq(lctree.lca(4, 6) === 1) 64 | true.should eq(lctree.lca(4, 7) === 1) 65 | true.should eq(lctree.lca(4, 3) === 0) 66 | true.should eq(lctree.lca(5, 2) === 0) 67 | true.should eq(lctree.lca(6, 7) === 5) 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/data_structure/priority_queue_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "priority_queue" do 7 | input = [1, 2, 3, 4, 5] 8 | output = [] of Int32 9 | 10 | queue = PriorityQueue(Int32).new 11 | 12 | input.each do |e| 13 | queue.push e 14 | end 15 | 16 | while !queue.empty? 17 | tmp = queue.pop! 18 | output << tmp if !tmp.nil? 19 | end 20 | true.should eq(input === output) 21 | end 22 | 23 | it "priority_queue2" do 24 | answer = [10, 8, 2, 11] 25 | output = [] of Int32 26 | 27 | queue = PriorityQueue(Int32).new 28 | 29 | queue.push 10 30 | queue.push 11 31 | 32 | top = queue.pop! 33 | output << top if !top.nil? 34 | 35 | queue.push 8 36 | 37 | top = queue.pop! 38 | output << top if !top.nil? 39 | 40 | queue.push 2 41 | 42 | top = queue.pop! 43 | output << top if !top.nil? 44 | top = queue.pop! 45 | output << top if !top.nil? 46 | 47 | while !queue.empty? 48 | tmp = queue.pop! 49 | output << tmp if !tmp.nil? 50 | end 51 | true.should eq(answer === output) 52 | end 53 | 54 | it ":mode == max" do 55 | answer = [11, 10, 8, 2] 56 | output = [] of Int32 57 | 58 | queue = PriorityQueue(Int32).new(:max) 59 | 60 | queue.push 10 61 | queue.push 11 62 | 63 | top = queue.pop! 64 | output << top if !top.nil? 65 | 66 | queue.push 8 67 | 68 | top = queue.pop! 69 | output << top if !top.nil? 70 | 71 | queue.push 2 72 | 73 | top = queue.pop! 74 | output << top if !top.nil? 75 | top = queue.pop! 76 | output << top if !top.nil? 77 | 78 | while !queue.empty? 79 | tmp = queue.pop! 80 | output << tmp if !tmp.nil? 81 | end 82 | true.should eq(answer === output) 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /spec/data_structure/queue_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "queue" do 7 | input = [1, 2, 3, 4, 5] 8 | 9 | queue = Queue(Int32).new 10 | 11 | input.each do |e| 12 | queue.push e 13 | end 14 | 15 | output = [] of Int32 16 | while !queue.empty? 17 | tmp = queue.pop! 18 | output << tmp if !tmp.nil? 19 | end 20 | input.should eq(output) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/data_structure/randomized_binary_search_tree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "split randomized_binary_search_tree" do 7 | input = [1, 2, 3, 4, 5] 8 | tree = RandomizedBinarySearchTree(Int32).new 9 | input.each_with_index { |e, i| 10 | tree.insert i, e 11 | } 12 | 13 | left, right = tree.split 3 14 | 15 | left.find(0).should eq 1 16 | left.find(1).should eq 2 17 | left.find(2).should eq 3 18 | 19 | right.find(0).should eq 4 20 | right.find(1).should eq 5 21 | end 22 | 23 | it "merge randomized_binary_search_tree" do 24 | input = [1, 2, 3, 4, 5] 25 | tree = RandomizedBinarySearchTree(Int32).new 26 | input.each_with_index { |e, i| 27 | tree.insert i, e 28 | } 29 | 30 | left, right = tree.split 3 31 | right.merge left 32 | 33 | right.find(0).should eq 4 34 | right.find(1).should eq 5 35 | right.find(2).should eq 1 36 | right.find(3).should eq 2 37 | right.find(4).should eq 3 38 | end 39 | 40 | it "insert randomized_binary_search_tree" do 41 | input = [1, 2, 3, 4, 5] 42 | tree = RandomizedBinarySearchTree(Int32).new 43 | input.each_with_index { |e, i| 44 | tree.insert i, e 45 | } 46 | 47 | tree.find(0).should eq 1 48 | tree.find(1).should eq 2 49 | tree.find(2).should eq 3 50 | tree.find(3).should eq 4 51 | tree.find(4).should eq 5 52 | end 53 | 54 | it "erase randomized_binary_search_tree" do 55 | input = [1, 2, 3, 4, 5] 56 | tree = RandomizedBinarySearchTree(Int32).new 57 | input.each_with_index { |e, i| 58 | tree.insert i, e 59 | } 60 | 61 | tree.erase(2) 62 | 63 | tree.find(0).should eq 1 64 | tree.find(1).should eq 2 65 | tree.find(2).should eq 4 66 | tree.find(3).should eq 5 67 | end 68 | 69 | it "reverse randomized_binary_search_tree" do 70 | input = [1, 2, 3, 4, 5] 71 | tree = RandomizedBinarySearchTree(Int32).new 72 | input.each_with_index { |e, i| 73 | tree.insert i, e 74 | } 75 | 76 | tree.reverse(0, 5) 77 | 78 | tree.find(0).should eq 5 79 | tree.find(1).should eq 4 80 | tree.find(2).should eq 3 81 | tree.find(3).should eq 2 82 | tree.find(4).should eq 1 83 | end 84 | 85 | it "test" do 86 | tree = RandomizedBinarySearchTree(Int32).new 87 | tree.insert(0, 1) 88 | tree.insert(1, 2) 89 | tree.insert(2, 3) 90 | 91 | tree.erase(1) 92 | tree.erase(1) 93 | 94 | tree.insert(1, 100) 95 | tree.update(1, 1000) 96 | 97 | tree.find(0).should eq 1 98 | tree.find(1).should eq 1000 99 | tree.find(2).should eq 3 100 | tree.find(3).should eq nil 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /spec/data_structure/randomized_meldable_heap_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "randomized_meldable_heap" do 7 | heap = RandomizedMeldableHeap(Int32).new 8 | [10, 8, 2, 2, 2, 11, 2].each { |e| heap.push(e) } 9 | 10 | heap.top.should eq 2 11 | heap.pop 12 | heap.top.should eq 2 13 | heap.pop 14 | heap.top.should eq 2 15 | heap.pop 16 | heap.top.should eq 2 17 | heap.pop 18 | heap.top.should eq 8 19 | heap.pop 20 | heap.top.should eq 10 21 | heap.pop 22 | heap.top.should eq 11 23 | heap.pop 24 | heap.top.should eq nil 25 | end 26 | 27 | it "randomized_meldable_heap remove" do 28 | heap = RandomizedMeldableHeap(Int32).new 29 | [10, 1, 2, 2, 2, 11, 2].each { |e| heap.push(e) } 30 | 31 | heap.remove(2) 32 | 33 | heap.top.should eq 1 34 | heap.pop 35 | heap.top.should eq 10 36 | heap.pop 37 | heap.top.should eq 11 38 | heap.pop 39 | heap.top.should eq nil 40 | end 41 | 42 | it "randomized_meldable_heap absorb" do 43 | heap1 = RandomizedMeldableHeap(Int32).new 44 | heap2 = RandomizedMeldableHeap(Int32).new 45 | [1, 2, 3].each { |e| heap1.push(e) } 46 | [4, 5, 6].each { |e| heap2.push(e) } 47 | 48 | heap1.absorb(heap2) 49 | 50 | heap2.top.should eq nil 51 | 52 | heap1.top.should eq 1 53 | heap1.pop 54 | heap1.top.should eq 2 55 | heap1.pop 56 | heap1.top.should eq 3 57 | heap1.pop 58 | heap1.top.should eq 4 59 | heap1.pop 60 | heap1.top.should eq 5 61 | heap1.pop 62 | heap1.top.should eq 6 63 | heap1.pop 64 | heap1.top.should eq nil 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/data_structure/segment_tree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "segment_tree" do 7 | segtree = SegmetTree(Int32).new(5) 8 | (0...5).each { |i| segtree.add(i, i + 1, i) } 9 | 10 | (0...5).each do |e| 11 | true.should eq(segtree.min(e, e + 1) === e) 12 | end 13 | 14 | segtree.add(0, 5, 10) 15 | true.should eq(segtree.min(2, 5) === 12) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/data_structure/skew_heap_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | describe Crystalg do 4 | it "SkewHeap" do 5 | heap = SkewHeap(Int32).new 6 | heap.push 5 7 | heap.push 3 8 | heap.push 8 9 | 10 | heap.top.should eq 3 11 | 12 | heap.push 1 13 | heap.top.should eq 1 14 | 15 | heap.pop 16 | heap.top.should eq 3 17 | 18 | heap.pop 19 | heap.top.should eq 5 20 | 21 | heap.pop 22 | heap.top.should eq 8 23 | end 24 | 25 | it "SkewHeap absorb" do 26 | heap1 = SkewHeap(Int32).new 27 | heap1.push 5 28 | heap1.push 3 29 | heap1.push 8 30 | 31 | heap2 = SkewHeap(Int32).new 32 | heap2.push 2 33 | heap2.push 3 34 | heap2.push 9 35 | 36 | heap1.absorb(heap2) 37 | 38 | heap1.top.should eq 2 39 | 40 | heap1.push 1 41 | heap1.top.should eq 1 42 | 43 | [2, 3, 3, 5, 8, 9].each do |e| 44 | heap1.pop 45 | heap1.top.should eq e 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/data_structure/skip_list_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "SkewHeap" do 7 | sl = SkipList.new(20) 8 | false.should eq sl.includes?(7) 9 | 10 | sl.insert(88) 11 | 12 | false.should eq sl.includes?(7) 13 | true.should eq sl.includes?(88) 14 | 15 | sl.insert(7) 16 | 17 | true.should eq sl.includes?(7) 18 | true.should eq sl.includes?(88) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/data_structure/stack_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "stack" do 7 | input = [1, 2, 3, 4, 5] 8 | answer = [5, 4, 3, 2, 1] 9 | 10 | stack = Stack(Int32).new 11 | 12 | input.each do |e| 13 | stack.push e 14 | end 15 | 16 | output = [] of Int32 17 | while !stack.empty? 18 | tmp = stack.pop! 19 | output << tmp if !tmp.nil? 20 | end 21 | true.should eq(output === answer) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/data_structure/union_find_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::DataStructures 4 | 5 | describe Crystalg do 6 | it "rolling_hash" do 7 | uf = UnionFind.new(5) 8 | 9 | uf.unite(0, 1) 10 | uf.unite(3, 4) 11 | 12 | true.should eq(uf.same?(0, 1) === true) 13 | true.should eq(uf.same?(0, 2) === false) 14 | true.should eq(uf.same?(0, 4) === false) 15 | 16 | true.should eq(uf.size(0) === 2) 17 | true.should eq(uf.size(1) === 2) 18 | true.should eq(uf.size(2) === 1) 19 | true.should eq(uf.size(3) === 2) 20 | true.should eq(uf.size(4) === 2) 21 | 22 | uf.unite(0, 2) 23 | uf.unite(2, 4) 24 | 25 | true.should eq(uf.size(0) === uf.@size) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/geometry/circle_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg 4 | include Crystalg::Geometry 5 | 6 | describe Crystalg do 7 | it "intersection" do 8 | c1 = Circle(Float32).new(Point(Float32).new(1_f32, 1_f32), 1_f32) 9 | c2 = Circle(Float32).new(Point(Float32).new(6_f32, 2_f32), 2_f32) 10 | true.should eq(c1.intersection(c2) === 4) 11 | 12 | c1 = Circle(Float32).new(Point(Float32).new(1_f32, 2_f32), 1_f32) 13 | c2 = Circle(Float32).new(Point(Float32).new(4_f32, 2_f32), 2_f32) 14 | true.should eq(c1.intersection(c2) === 3) 15 | 16 | c1 = Circle(Float32).new(Point(Float32).new(1_f32, 2_f32), 1_f32) 17 | c2 = Circle(Float32).new(Point(Float32).new(3_f32, 2_f32), 2_f32) 18 | true.should eq(c1.intersection(c2) === 2) 19 | 20 | c1 = Circle(Float32).new(Point(Float32).new(0_f32, 0_f32), 1_f32) 21 | c2 = Circle(Float32).new(Point(Float32).new(1_f32, 0_f32), 2_f32) 22 | true.should eq(c1.intersection(c2) === 1) 23 | 24 | c1 = Circle(Float32).new(Point(Float32).new(0_f32, 0_f32), 1_f32) 25 | c2 = Circle(Float32).new(Point(Float32).new(0_f32, 0_f32), 2_f32) 26 | true.should eq(c1.intersection(c2) === 0) 27 | end 28 | 29 | it "intersection_points of circle and line" do 30 | circle = Circle(Float32).new(Point(Float32).new(2_f32, 1_f32), 1_f32) 31 | 32 | line = Line(Float32).new( 33 | Point(Float32).new(0_f32, 1_f32), 34 | Point(Float32).new(4_f32, 1_f32) 35 | ) 36 | answer = [Point(Float32).new(3_f32, 1_f32), Point(Float32).new(1_f32, 1_f32)] 37 | result = circle.intersection_points(line) 38 | true.should eq(result === answer) 39 | 40 | line = Line(Float32).new(Point(Float32).new(3_f32, 0_f32), Point(Float32).new(3_f32, 3_f32)) 41 | answer = [Point(Float32).new(3_f32, 1_f32), Point(Float32).new(3_f32, 1_f32)] 42 | result = circle.intersection_points(line) 43 | true.should eq(result === answer) 44 | end 45 | 46 | it "intersection_points of circles" do 47 | c1 = Circle(Float64).new(Point(Float64).new(0_f64, 0_f64), 2_f64) 48 | c2 = Circle(Float64).new(Point(Float64).new(2_f64, 0_f64), 2_f64) 49 | answer = [Point(Float64).new(1_f64, 1.73205080_f64), Point(Float64).new(1_f64, -1.73205080_f64)] 50 | result = c1.intersection_points c2 51 | true.should eq(result === answer) 52 | 53 | c1 = Circle(Float64).new(Point(Float64).new(0_f64, 0_f64), 2_f64) 54 | c2 = Circle(Float64).new(Point(Float64).new(0_f64, 3_f64), 1_f64) 55 | answer = [Point(Float64).new(0_f64, 2_f64), Point(Float64).new(0_f64, 2_f64)] 56 | result = c1.intersection_points c2 57 | true.should eq(result === answer) 58 | end 59 | 60 | it "intersection_area" do 61 | c1 = Circle(Float32).new(Point(Float32).new(20_f32, 30_f32), 15_f32) 62 | c2 = Circle(Float32).new(Point(Float32).new(40_f32, 30_f32), 30_f32) 63 | result = c1.intersection_area(c2) 64 | true.should eq(result === 608.366_f32) 65 | end 66 | 67 | it "circumscribed_circle of a triangle" do 68 | result = Circle(Float32).circumscribed_circle( 69 | Point(Float32).new(0_f32, 0_f32), 70 | Point(Float32).new(2_f32, 0_f32), 71 | Point(Float32).new(2_f32, 2_f32) 72 | ) 73 | 74 | answer = Circle(Float32).new(Point(Float32).new(1_f32, 1_f32), 1.41421356_f32) 75 | true.should eq(result === answer) 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /spec/geometry/geometry_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg 4 | include Crystalg::Geometry 5 | 6 | describe Crystalg do 7 | it "counter_clockwise" do 8 | a = Point.new(0.0, 0.0) 9 | b = Point.new(2.0, 0.0) 10 | 11 | c = Point.new(-1.0, 1.0) 12 | true.should eq(counter_clockwise(a, b, c) === CCW::COUNTER_CLOCKWISE) 13 | 14 | c = Point.new(-1.0, -1.0) 15 | true.should eq(counter_clockwise(a, b, c) === CCW::CLOCKWISE) 16 | 17 | c = Point.new(-1.0, 0.0) 18 | true.should eq(counter_clockwise(a, b, c) === CCW::ONLINE_BACK) 19 | 20 | c = Point.new(3.0, 0.0) 21 | true.should eq(counter_clockwise(a, b, c) === CCW::ONLINE_FRONT) 22 | 23 | c = Point.new(0.0, 0.0) 24 | true.should eq(counter_clockwise(a, b, c) === CCW::ON_SEGMENT) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/geometry/line_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Geometry 4 | 5 | describe Crystalg do 6 | it "projection" do 7 | line = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 4_f32)) 8 | point = Point(Float32).new(2_f32, 5_f32) 9 | true.should eq(line.project(point) === Point(Float32).new(3.12_f32, 4.16_f32)) 10 | 11 | line = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(2_f32, 0_f32)) 12 | point = Point(Float32).new(-1_f32, 1_f32) 13 | true.should eq(line.project(point) === Point(Float32).new(-1_f32, 0_f32)) 14 | point = Point(Float32).new(0_f32, 1_f32) 15 | true.should eq(line.project(point) === Point(Float32).new(0_f32, 0_f32)) 16 | point = Point(Float32).new(1_f32, 1_f32) 17 | true.should eq(line.project(point) === Point(Float32).new(1_f32, 0_f32)) 18 | end 19 | 20 | it "reflection" do 21 | line = Line(Float64).new(Point(Float64).new(0_f64, 0_f64), Point(Float64).new(3_f64, 4_f64)) 22 | point = Point(Float64).new(2_f64, 5_f64) 23 | true.should eq(line.reflect(point) === Point(Float64).new(4.24_f64, 3.32_f64)) 24 | point = Point(Float64).new(1_f64, 4_f64) 25 | true.should eq(line.reflect(point) === Point(Float64).new(3.56_f64, 2.08_f64)) 26 | point = Point(Float64).new(0_f64, 3_f64) 27 | true.should eq(line.reflect(point) === Point(Float64).new(2.88_f64, 0.84_f64)) 28 | 29 | line = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(2_f32, 0_f32)) 30 | point = Point(Float32).new(-1_f32, 1_f32) 31 | true.should eq(line.reflect(point) === Point(Float32).new(-1_f32, -1_f32)) 32 | point = Point(Float32).new(0_f32, 1_f32) 33 | true.should eq(line.reflect(point) === Point(Float32).new(0_f32, -1_f32)) 34 | point = Point(Float32).new(1_f32, 1_f32) 35 | true.should eq(line.reflect(point) === Point(Float32).new(1_f32, -1_f32)) 36 | end 37 | 38 | it "is_parallel?" do 39 | line1 = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 40 | line2 = Line(Float32).new(Point(Float32).new(0_f32, 2_f32), Point(Float32).new(3_f32, 2_f32)) 41 | true.should eq(line1.is_parallel?(line2) === true) 42 | 43 | line1 = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 44 | line2 = Line(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(2_f32, 2_f32)) 45 | true.should eq(line1.is_parallel?(line2) === false) 46 | end 47 | 48 | it "is_orthogonal?" do 49 | line1 = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 50 | line2 = Line(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(1_f32, 4_f32)) 51 | true.should eq(line1.is_orthogonal?(line2) === true) 52 | 53 | line1 = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 54 | line2 = Line(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(2_f32, 2_f32)) 55 | true.should eq(line1.is_parallel?(line2) === false) 56 | end 57 | 58 | it "is_intersection?" do 59 | line1 = Line(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 60 | line2 = Line(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(2_f32, -1_f32)) 61 | true.should eq(line1.is_intersection? line2) 62 | 63 | line2 = Line(Float32).new(Point(Float32).new(3_f32, 1_f32), Point(Float32).new(3_f32, -1_f32)) 64 | true.should eq(line1.is_intersection? line2) 65 | 66 | line2 = Line(Float32).new(Point(Float32).new(3_f32, -2_f32), Point(Float32).new(5_f32, 0_f32)) 67 | true.should eq(line1.is_intersection? line2) 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/geometry/polygon_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Geometry 4 | 5 | describe Crystalg do 6 | it "area" do 7 | pol = Polygon(Float32).new( 8 | Point(Float32).new(0_f32, 0_f32), 9 | Point(Float32).new(2_f32, 2_f32), 10 | Point(Float32).new(-1_f32, 1_f32) 11 | ) 12 | true.should eq(pol.area === 2_f32) 13 | 14 | pol = Polygon(Float32).new( 15 | Point(Float32).new(0_f32, 0_f32), 16 | Point(Float32).new(1_f32, 1_f32), 17 | Point(Float32).new(1_f32, 2_f32), 18 | Point(Float32).new(0_f32, 2_f32) 19 | ) 20 | true.should eq(pol.area === 1.5_f32) 21 | end 22 | 23 | it "is_convex?" do 24 | pol = Polygon(Float32).new( 25 | Point(Float32).new(0_f32, 0_f32), 26 | Point(Float32).new(3_f32, 1_f32), 27 | Point(Float32).new(2_f32, 3_f32), 28 | Point(Float32).new(0_f32, 3_f32) 29 | ) 30 | true.should eq(pol.is_convex?) 31 | 32 | pol = Polygon(Float32).new( 33 | Point(Float32).new(0_f32, 0_f32), 34 | Point(Float32).new(2_f32, 0_f32), 35 | Point(Float32).new(1_f32, 1_f32), 36 | Point(Float32).new(2_f32, 2_f32), 37 | Point(Float32).new(0_f32, 2_f32) 38 | ) 39 | false.should eq(pol.is_convex?) 40 | end 41 | 42 | it "polygon-point containment" do 43 | pol = Polygon(Float32).new( 44 | Point(Float32).new(0_f32, 0_f32), 45 | Point(Float32).new(3_f32, 1_f32), 46 | Point(Float32).new(2_f32, 3_f32), 47 | Point(Float32).new(0_f32, 3_f32) 48 | ) 49 | 50 | true.should eq(pol.contain(Point(Float32).new(2_f32, 1_f32)) === Polygon::Containment::IN) 51 | true.should eq(pol.contain(Point(Float32).new(0_f32, 2_f32)) === Polygon::Containment::ON) 52 | true.should eq(pol.contain(Point(Float32).new(3_f32, 2_f32)) === Polygon::Containment::OUT) 53 | end 54 | 55 | it "convex hull" do 56 | pol = Polygon(Float32).new( 57 | Point(Float32).new(2_f32, 1_f32), 58 | Point(Float32).new(0_f32, 0_f32), 59 | Point(Float32).new(1_f32, 2_f32), 60 | Point(Float32).new(2_f32, 2_f32), 61 | Point(Float32).new(4_f32, 2_f32), 62 | Point(Float32).new(1_f32, 3_f32), 63 | Point(Float32).new(3_f32, 3_f32) 64 | ) 65 | 66 | ans = Polygon(Float32).new( 67 | Point(Float32).new(0_f32, 0_f32), 68 | Point(Float32).new(2_f32, 1_f32), 69 | Point(Float32).new(4_f32, 2_f32), 70 | Point(Float32).new(3_f32, 3_f32), 71 | Point(Float32).new(1_f32, 3_f32) 72 | ) 73 | 74 | true.should eq(pol.convex_hull === ans) 75 | end 76 | 77 | it "convex cut" do 78 | pol = Polygon(Float32).new( 79 | Point(Float32).new(1_f32, 1_f32), 80 | Point(Float32).new(4_f32, 1_f32), 81 | Point(Float32).new(4_f32, 3_f32), 82 | Point(Float32).new(1_f32, 3_f32) 83 | ) 84 | 85 | res = pol.convex_cut( 86 | Line(Float32).new( 87 | Point(Float32).new(2_f32, 0_f32), 88 | Point(Float32).new(2_f32, 4_f32) 89 | ) 90 | ) 91 | true.should eq(res.area === 2_f32) 92 | 93 | res = pol.convex_cut( 94 | Line(Float32).new( 95 | Point(Float32).new(2_f32, 4_f32), 96 | Point(Float32).new(2_f32, 0_f32) 97 | ) 98 | ) 99 | true.should eq(res.area === 4_f32) 100 | end 101 | 102 | it "convex diameter 1" do 103 | pol = Polygon(Float32).new( 104 | Point(Float32).new(0_f32, 0_f32), 105 | Point(Float32).new(4_f32, 0_f32), 106 | Point(Float32).new(2_f32, 2_f32) 107 | ) 108 | 109 | true.should eq(pol.diameter === 4_f32) 110 | end 111 | 112 | it "convex diameter 2" do 113 | pol = Polygon(Float32).new( 114 | Point(Float32).new(0_f32, 0_f32), 115 | Point(Float32).new(1_f32, 0_f32), 116 | Point(Float32).new(1_f32, 1_f32), 117 | Point(Float32).new(0_f32, 1_f32) 118 | ) 119 | 120 | true.should eq(pol.diameter === 1.414213562373_f32) 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /spec/geometry/segment_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Geometry 4 | 5 | describe Crystalg do 6 | it "is_intersection?" do 7 | seg1 = Segment(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(3_f32, 0_f32)) 8 | seg2 = Segment(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(2_f32, -1_f32)) 9 | true.should eq(seg1.is_intersection? seg2) 10 | 11 | seg2 = Segment(Float32).new(Point(Float32).new(3_f32, 1_f32), Point(Float32).new(3_f32, -1_f32)) 12 | true.should eq(seg1.is_intersection? seg2) 13 | 14 | seg2 = Segment(Float32).new(Point(Float32).new(3_f32, -2_f32), Point(Float32).new(5_f32, 0_f32)) 15 | false.should eq(seg1.is_intersection? seg2) 16 | end 17 | 18 | it "intersection_point" do 19 | seg1 = Segment(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(2_f32, 0_f32)) 20 | seg2 = Segment(Float32).new(Point(Float32).new(1_f32, 1_f32), Point(Float32).new(1_f32, -1_f32)) 21 | true.should eq(seg1.intersection_point(seg2) === Point(Float32).new(1_f32, 0_f32)) 22 | 23 | seg1 = Segment(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(1_f32, 1_f32)) 24 | seg2 = Segment(Float32).new(Point(Float32).new(0_f32, 1_f32), Point(Float32).new(1_f32, 0_f32)) 25 | true.should eq(seg1.intersection_point(seg2) === Point(Float32).new(0.5_f32, 0.5_f32)) 26 | 27 | seg2 = Segment(Float32).new(Point(Float32).new(1_f32, 0_f32), Point(Float32).new(0_f32, 1_f32)) 28 | true.should eq(seg1.intersection_point(seg2) === Point(Float32).new(0.5_f32, 0.5_f32)) 29 | end 30 | 31 | it "distance" do 32 | seg1 = Segment(Float32).new(Point(Float32).new(0_f32, 0_f32), Point(Float32).new(1_f32, 0_f32)) 33 | seg2 = Segment(Float32).new(Point(Float32).new(0_f32, 1_f32), Point(Float32).new(1_f32, 1_f32)) 34 | true.should eq(seg1.distance(seg2) === 1_f32) 35 | 36 | seg2 = Segment(Float32).new(Point(Float32).new(2_f32, 1_f32), Point(Float32).new(1_f32, 2_f32)) 37 | true.should eq(seg1.distance(seg2) === 1.4142135624_f32) 38 | 39 | seg1 = Segment(Float32).new(Point(Float32).new(-1_f32, 0_f32), Point(Float32).new(1_f32, 0_f32)) 40 | seg2 = Segment(Float32).new(Point(Float32).new(0_f32, 1_f32), Point(Float32).new(0_f32, -1_f32)) 41 | true.should eq(seg1.distance(seg2) == 0_f32) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/graph/articulation_points_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "articulation_points_1" do 7 | graph = UndirectedGraph(Int32).new(4) 8 | graph.add Edge.new(0, 1, 1) 9 | graph.add Edge.new(0, 2, 1) 10 | graph.add Edge.new(1, 2, 1) 11 | graph.add Edge.new(2, 3, 1) 12 | 13 | answer = [2] 14 | result = graph.articulation_points 15 | true.should eq(result === answer) 16 | end 17 | 18 | it "articulation_points_2" do 19 | graph = UndirectedGraph(Int32).new(5) 20 | graph.add Edge.new(0, 1, 1) 21 | graph.add Edge.new(1, 2, 1) 22 | graph.add Edge.new(2, 3, 1) 23 | graph.add Edge.new(3, 4, 1) 24 | 25 | answer = [1, 2, 3] 26 | result = graph.articulation_points.sort 27 | true.should eq(result === answer) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/graph/bellman_ford_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "has_negative_loop" do 7 | graph = DirectedGraph(Int32).new(4) 8 | graph.add(Edge.new(0, 1, -1)) 9 | graph.add(Edge.new(1, 2, 2)) 10 | graph.add(Edge.new(2, 0, -4)) 11 | graph.add(Edge.new(2, 3, -1)) 12 | graph.add(Edge.new(1, 3, 5)) 13 | 14 | true.should eq graph.has_negative_cycle? 15 | 16 | graph2 = DirectedGraph(Int32).new(4) 17 | graph2.add(Edge.new(0, 1, -1)) 18 | graph2.add(Edge.new(0, 2, -4)) 19 | graph2.add(Edge.new(1, 2, 2)) 20 | graph2.add(Edge.new(2, 3, 1)) 21 | graph2.add(Edge.new(1, 3, 5)) 22 | 23 | false.should eq graph2.has_negative_cycle? 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/graph/bridge_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "bridges_1" do 7 | graph = UndirectedGraph(Int32).new(4) 8 | graph.add Edge.new(0, 1, 1) 9 | graph.add Edge.new(0, 2, 1) 10 | graph.add Edge.new(1, 2, 1) 11 | graph.add Edge.new(2, 3, 1) 12 | 13 | answer = [Edge.new(2, 3, 1)] 14 | result = graph.bridges 15 | true.should eq(result === answer) 16 | end 17 | 18 | it "bridges_2" do 19 | graph = UndirectedGraph(Int32).new(5) 20 | graph.add Edge.new(0, 1, 1) 21 | graph.add Edge.new(1, 2, 1) 22 | graph.add Edge.new(2, 3, 1) 23 | graph.add Edge.new(3, 4, 1) 24 | 25 | result = graph.bridges.sort 26 | ans = graph.edges.uniq 27 | 28 | true.should eq(result === ans) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/graph/cycle_detection_directed_graph_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "directed graph cycle detection 1" do 7 | graph = DirectedGraph(Int32).new(3) 8 | graph.add Edge.new(0, 1, 1) 9 | graph.add Edge.new(0, 2, 1) 10 | graph.add Edge.new(1, 2, 1) 11 | 12 | false.should eq graph.has_cycle? 13 | end 14 | 15 | it "directed graph cycle detection 2" do 16 | graph = DirectedGraph(Int32).new(3) 17 | graph.add Edge.new(0, 1, 1) 18 | graph.add Edge.new(1, 2, 1) 19 | graph.add Edge.new(2, 0, 1) 20 | 21 | true.should eq graph.has_cycle? 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/graph/dijkstra_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "dijkstra" do 7 | graph = DirectedGraph(Int32).new(4) 8 | graph.add(Edge.new(0, 1, 1)) 9 | graph.add(Edge.new(0, 2, 4)) 10 | graph.add(Edge.new(1, 2, 2)) 11 | graph.add(Edge.new(2, 3, 1)) 12 | graph.add(Edge.new(1, 3, 5)) 13 | 14 | result = graph.dijkstra(0) 15 | ans = [{0, nil}, {1, 0}, {3, 1}, {4, 2}] 16 | 17 | true.should eq(result === ans) 18 | 19 | result = graph.get_dijkstra_path(3, result) 20 | ans = [0, 1, 2, 3] 21 | 22 | true.should eq(result === ans) 23 | end 24 | 25 | it "dijkstra2" do 26 | graph = DirectedGraph(Int32).new(4) 27 | graph.add(Edge.new(0, 1, 1)) 28 | graph.add(Edge.new(0, 2, 4)) 29 | graph.add(Edge.new(2, 0, 1)) 30 | graph.add(Edge.new(1, 2, 2)) 31 | graph.add(Edge.new(3, 1, 1)) 32 | graph.add(Edge.new(3, 2, 5)) 33 | 34 | result = graph.dijkstra(1) 35 | ans = [{3, 2}, {0, nil}, {2, 1}, nil] 36 | 37 | true.should eq(result === ans) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/graph/dinic_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "dinic" do 7 | graph = FlowGraph(Int32).new(4) 8 | graph.add FlowEdge.new(0, 1, 2) 9 | graph.add FlowEdge.new(0, 2, 1) 10 | graph.add FlowEdge.new(1, 2, 1) 11 | graph.add FlowEdge.new(1, 3, 1) 12 | graph.add FlowEdge.new(2, 3, 2) 13 | true.should eq(Dinic(Int32).new(graph).max_flow(0, 3) === 3) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/graph/ford_fulkerson_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "ford_fulkerson" do 7 | graph = FlowGraph(Int32).new(4) 8 | graph.add FlowEdge.new(0, 1, 2) 9 | graph.add FlowEdge.new(0, 2, 1) 10 | graph.add FlowEdge.new(1, 2, 1) 11 | graph.add FlowEdge.new(1, 3, 1) 12 | graph.add FlowEdge.new(2, 3, 2) 13 | true.should eq(FordFulkerson(Int32).new(graph).max_flow(0, 3) === 3) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/graph/hopcroft_karp_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "HopcroftKarp" do 7 | hopcroft_karp = HopcroftKarp.new(3, 4) 8 | hopcroft_karp.add_edge(0, 0) 9 | hopcroft_karp.add_edge(0, 2) 10 | hopcroft_karp.add_edge(0, 3) 11 | hopcroft_karp.add_edge(1, 1) 12 | hopcroft_karp.add_edge(2, 1) 13 | hopcroft_karp.add_edge(2, 3) 14 | true.should eq(hopcroft_karp.bipartite_matching === 3) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/graph/kruskal_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "kruskal" do 7 | graph = UndirectedGraph(Int32).new(4) 8 | graph.add(Edge.new(0, 1, 1)) 9 | graph.add(Edge.new(0, 2, 4)) 10 | graph.add(Edge.new(1, 2, 2)) 11 | graph.add(Edge.new(2, 3, 1)) 12 | graph.add(Edge.new(1, 3, 5)) 13 | graph.add(Edge.new(0, 3, 6)) 14 | 15 | result = graph.kruskal 16 | 17 | ans = [ 18 | Edge.new(0, 1, 1), 19 | Edge.new(2, 3, 1), 20 | Edge.new(1, 2, 2), 21 | ] 22 | 23 | true.should eq(result === ans) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/graph/toporogical_sort_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Graph 4 | 5 | describe Crystalg do 6 | it "topological_sort" do 7 | graph = DirectedGraph(Int32).new(6) 8 | graph.add(Edge.new(0, 1, -1)) 9 | graph.add(Edge.new(1, 2, -4)) 10 | graph.add(Edge.new(3, 1, 2)) 11 | graph.add(Edge.new(3, 4, -1)) 12 | graph.add(Edge.new(4, 5, 5)) 13 | graph.add(Edge.new(5, 2, 5)) 14 | 15 | answer = [0, 3, 1, 4, 5, 2] 16 | result = graph.topological_sort 17 | 18 | (0..5).each do |i| 19 | (0..5).each do |j| 20 | true.should eq(i < j) if result[i] == 0 && result[j] == 1 21 | true.should eq(i < j) if result[i] == 0 && result[j] == 2 22 | true.should eq(i < j) if result[i] == 1 && result[j] == 2 23 | true.should eq(i < j) if result[i] == 3 && result[j] == 1 24 | true.should eq(i < j) if result[i] == 3 && result[j] == 2 25 | true.should eq(i < j) if result[i] == 3 && result[j] == 4 26 | true.should eq(i < j) if result[i] == 3 && result[j] == 5 27 | true.should eq(i < j) if result[i] == 4 && result[j] == 5 28 | true.should eq(i < j) if result[i] == 4 && result[j] == 2 29 | true.should eq(i < j) if result[i] == 5 && result[j] == 2 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/number_theory/carmichael_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "charmichael" do 7 | true.should eq(carmichael(1) === 1) 8 | true.should eq(carmichael(2) === 1) 9 | true.should eq(carmichael(3) === 2) 10 | true.should eq(carmichael(4) === 2) 11 | true.should eq(carmichael(5) === 4) 12 | true.should eq(carmichael(6) === 2) 13 | true.should eq(carmichael(7) === 6) 14 | true.should eq(carmichael(8) === 2) 15 | true.should eq(carmichael(9) === 6) 16 | true.should eq(carmichael(10) === 4) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/number_theory/euclid_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "gcd" do 7 | true.should eq(gcd(2, 3) === 1) 8 | true.should eq(gcd(8, 12) === 4) 9 | true.should eq(gcd(16, 16) === 16) 10 | true.should eq(gcd(50000000, 30000000) === 10000000) 11 | true.should eq(gcd(10000000, 1000000007) === 1) 12 | end 13 | 14 | it "lcm" do 15 | true.should eq(lcm(8, 6) === 24) 16 | true.should eq(lcm(50000000, 30000000) === 150000000) 17 | end 18 | 19 | it "extgcd" do 20 | true.should eq(extgcd(4, 12) === {4, 1, 0}) 21 | true.should eq(extgcd(3, 8) === {1, 3, -1}) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/number_theory/euler_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "phi" do 7 | true.should eq(phi(6) === 2) 8 | true.should eq(phi(1000000) === 400000) 9 | end 10 | 11 | it "phi_list" do 12 | input = Array(Int32).new 13 | (0..10000).each do |i| 14 | input << (phi i).to_i 15 | end 16 | true.should eq(phi_list(10000) === input) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/number_theory/mobius_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "mobius" do 7 | true.should eq(mobius(1) === 1) 8 | true.should eq(mobius(2) === -1) 9 | true.should eq(mobius(3) === -1) 10 | true.should eq(mobius(4) === 0) 11 | true.should eq(mobius(5) === -1) 12 | true.should eq(mobius(6) === 1) 13 | true.should eq(mobius(7) === -1) 14 | true.should eq(mobius(8) === 0) 15 | true.should eq(mobius(9) === 0) 16 | true.should eq(mobius(10) === 1) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/number_theory/mod_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "pow" do 7 | true.should eq(Mod.pow(2, 3, 100) === 8) 8 | true.should eq(Mod.pow(5, 8, 1000000007) === 390625) 9 | true.should eq(Mod.pow(2, 30, 100000007) === 73741754) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/number_theory/prime_number_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "is_prime" do 7 | false.should eq(prime?(1)) 8 | true.should eq(prime?(2)) 9 | true.should eq(prime?(3)) 10 | false.should eq(prime?(4)) 11 | true.should eq(prime?(5)) 12 | false.should eq(prime?(6)) 13 | true.should eq(prime?(7)) 14 | false.should eq(prime?(8)) 15 | false.should eq(prime?(9)) 16 | false.should eq(prime?(10)) 17 | true.should eq(prime?(11)) 18 | true.should eq(prime?(100000007)) 19 | true.should eq(prime?(1000000007)) 20 | end 21 | 22 | it "get_divisor" do 23 | result = divisor(15).sort 24 | answer = [1, 3, 5, 15] 25 | true.should eq(result === answer) 26 | end 27 | 28 | it "prime_factorize" do 29 | result = prime_factorize(33) 30 | answer = {3 => 1, 11 => 1} 31 | true.should eq(answer === result) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/number_theory/stern_brocot_tree_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::NumberTheory 4 | 5 | describe Crystalg do 6 | it "stern_brocot" do 7 | ans = [ 8 | Fraction.new(1, 4), 9 | Fraction.new(1, 3), 10 | Fraction.new(1, 2), 11 | Fraction.new(2, 3), 12 | Fraction.new(1, 1), 13 | Fraction.new(3, 2), 14 | Fraction.new(2, 1), 15 | Fraction.new(3, 1), 16 | Fraction.new(4, 1), 17 | ] 18 | 19 | result = SternBrocotTree.new.run(5) 20 | 21 | true.should eq(ans === result) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/crystalg/data_structures/*" 3 | require "../src/crystalg/graph/*" 4 | require "../src/crystalg/graph/flow/*" 5 | require "../src/crystalg/graph/connected_components/*" 6 | require "../src/crystalg/strings/*" 7 | require "../src/crystalg/number_theory/*" 8 | require "../src/crystalg/geometry/*" 9 | -------------------------------------------------------------------------------- /spec/strings/aho_corasick_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Strings 4 | 5 | describe Crystalg do 6 | it "aho_corasick match_suffix?" do 7 | aho_corasick = AhoCorasick.new(11) 8 | aho_corasick.add "abcde" 9 | aho_corasick.add "ab" 10 | aho_corasick.add "bc" 11 | aho_corasick.add "bab" 12 | aho_corasick.add "d" 13 | 14 | true.should eq aho_corasick.match_suffix? "abcde" 15 | true.should eq aho_corasick.match_suffix? "ab" 16 | true.should eq aho_corasick.match_suffix? "bc" 17 | true.should eq aho_corasick.match_suffix? "bab" 18 | true.should eq aho_corasick.match_suffix? "d" 19 | 20 | true.should eq aho_corasick.match_suffix? "abab" 21 | true.should eq aho_corasick.match_suffix? "ddddd" 22 | 23 | false.should eq aho_corasick.match_suffix? "a" 24 | false.should eq aho_corasick.match_suffix? "da" 25 | false.should eq aho_corasick.match_suffix? "zzzzz" 26 | end 27 | 28 | it "aho_corasick contain?" do 29 | aho_corasick = AhoCorasick.new(11) 30 | aho_corasick.add "abcde" 31 | aho_corasick.add "ab" 32 | aho_corasick.add "bc" 33 | aho_corasick.add "bab" 34 | aho_corasick.add "d" 35 | 36 | true.should eq aho_corasick.contain? "abcde" 37 | true.should eq aho_corasick.contain? "ab" 38 | true.should eq aho_corasick.contain? "bc" 39 | true.should eq aho_corasick.contain? "bab" 40 | true.should eq aho_corasick.contain? "d" 41 | 42 | false.should eq aho_corasick.contain? "abab" 43 | false.should eq aho_corasick.contain? "ddddd" 44 | 45 | false.should eq aho_corasick.contain? "a" 46 | false.should eq aho_corasick.contain? "da" 47 | false.should eq aho_corasick.contain? "zzzzz" 48 | end 49 | 50 | it "aho_corasick match_prefixes" do 51 | aho_corasick = AhoCorasick.new(11) 52 | aho_corasick.add "abcde" 53 | aho_corasick.add "ab" 54 | aho_corasick.add "bc" 55 | aho_corasick.add "bab" 56 | aho_corasick.add "d" 57 | 58 | true.should eq aho_corasick.match_prefixes("ab") == ["ab", "abcde"] 59 | true.should eq aho_corasick.match_prefixes("c") == [] of String 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /spec/strings/baker_bird_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Strings 4 | 5 | describe Crystalg do 6 | it "baker_bird" do 7 | field = [ 8 | "00010", 9 | "00101", 10 | "00010", 11 | "00100", 12 | ] 13 | 14 | pattern = [ 15 | "10", 16 | "01", 17 | "10", 18 | ] 19 | 20 | answer = [{0, 3}, {1, 2}] 21 | 22 | true.should eq (answer === BakerBird.new(field).search pattern) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/strings/kmp_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Strings 4 | 5 | describe Crystalg do 6 | it "kmp" do 7 | input = "mississippi" 8 | 9 | hash = RollingHash.new input 10 | 11 | result = kmp(input, "issi") 12 | 13 | true.should eq(result === [1, 4]) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/strings/rolling_hash_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Strings 4 | 5 | describe Crystalg do 6 | it "rolling_hash" do 7 | input = "mississippi" 8 | 9 | hash = RollingHash.new input 10 | 11 | true.should eq(hash.count("issi") === 2) 12 | end 13 | 14 | it "get_suffix_array" do 15 | input = "abracadabra" 16 | 17 | result = RollingHash.new(input).get_suffix_array 18 | 19 | ans = [11, 10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2] 20 | 21 | true.should eq(result === ans) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/strings/suffix_array_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | 3 | include Crystalg::Strings 4 | 5 | describe Crystalg do 6 | it "suffix_array" do 7 | input = "abracadabra" 8 | 9 | result = SuffixArray.new(input) 10 | result.construct 11 | 12 | ans = [11, 10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2] 13 | 14 | true.should eq(result.@suffix_array === ans) 15 | end 16 | 17 | it "lcp" do 18 | input = "banana" 19 | result = SuffixArray.new(input) 20 | result.construct 21 | 22 | ans = [0, 1, 3, 0, 0, 2, 0] 23 | 24 | true.should eq(result.@lcp === ans) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /src/crystalg.cr: -------------------------------------------------------------------------------- 1 | require "./crystalg/*" 2 | require "./crystalg/graph/*" 3 | require "./crystalg/data_structures/*" 4 | require "./crystalg/strings/*" 5 | 6 | module Crystalg 7 | end 8 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/core/atomic_markable_reference.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | 3 | require "./markable_reference" 4 | 5 | module Crystalg::Concurrent::Core 6 | class AtomicMarkableReference(T) 7 | MASK = 1_u64 8 | @word : Atomic(UInt64) 9 | 10 | def initialize(reference : T, mark = false) 11 | @word = pack(reference, mark) 12 | end 13 | 14 | def compare_and_set(expected_reference : T, new_reference : T, expected_mark : Bool, new_mark : Bool) : Tuple(T, Bool) 15 | expected_value = pack(expected_reference, expected_mark) 16 | new_value = pack(new_reference, new_mark) 17 | _, is_success = @word.compare_and_set(expected_value, new_value) 18 | return {nil, false} if !is_success 19 | {get(new_mark), true} 20 | end 21 | 22 | def attempt_mark(expected_reference : T, new_mark : Bool) : Bool 23 | _, is_succsess = compare_and_set(expected_reference, expected_reference, !new_mark, new_mark) 24 | is_succsess 25 | end 26 | 27 | def get(marked : Bool) : Tuple(T, Bool) 28 | {Pointer(T).new(@word & ~MASK).value, (@word & MASK) == 1_u64} 29 | end 30 | 31 | private def pack(reference : T, mark : Bool) 32 | word = (pointerof(reference).address & ~MASK) 33 | if mark 34 | word | 1_u64 35 | else 36 | word | 0_u64 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/core/atomic_stamped_reference.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | 3 | module Crystalg::Concurrent::Core 4 | class AtomicStampedReference(T) 5 | private class A(T) 6 | def initialize(@value : T?, @stamp : Int32) 7 | end 8 | 9 | def unwrap 10 | {@value, @stamp} 11 | end 12 | end 13 | 14 | @ref : Atomic(A(T)) 15 | 16 | def initialize(value : T?, stamp : Int32) 17 | @ref = Atomic(A(T)).new(A(T).new(value, stamp)) 18 | end 19 | 20 | def compare_and_set(expected_ref : T?, new_ref : T?, expected_stamp : Int, new_stamp : Int32) 21 | old_wrapped_ref = @ref.get 22 | old_ref, old_stamp = old_wrapped_ref.unwrap 23 | 24 | if old_ref == expected_ref && old_stamp == expected_stamp 25 | new_wrapped_ref = A(T).new(new_ref, new_stamp) 26 | result, is_success = @ref.compare_and_set(old_wrapped_ref, new_wrapped_ref) 27 | return result.unwrap if is_success 28 | end 29 | return nil, false 30 | end 31 | 32 | def get : Tuple(T?, Int32) 33 | @ref.get.unwrap 34 | end 35 | 36 | def set(ref : T?, stamp : Int32) 37 | @ref.set(A(T).new(ref, stamp)) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/core/exchanger.cr: -------------------------------------------------------------------------------- 1 | require "./atomic_stamped_reference" 2 | 3 | module Crystalg::Concurrent::Core 4 | class Exchanger(T) 5 | include Crystalg::Concurrent::Core 6 | 7 | EMPTY = 0 8 | WAITING = 1 9 | BUSY = 2 10 | 11 | getter slot 12 | 13 | @slot = Core::AtomicStampedReference(T).new(nil, 0) 14 | 15 | def exchange(my_item : T, timeout : Time::Span) : T? 16 | start_time = Time.now 17 | loop do 18 | raise "timeout" if timeout < Time.now - start_time 19 | yr_item, stamp = @slot.get 20 | case stamp 21 | when EMPTY 22 | _, is_success = @slot.compare_and_set(yr_item, my_item, EMPTY, WAITING) 23 | next unless is_success 24 | while Time.now - start_time < timeout 25 | yr_item, stamp = @slot.get 26 | if stamp == BUSY 27 | @slot.set(nil, EMPTY) 28 | return yr_item 29 | end 30 | end 31 | _, is_success = @slot.compare_and_set(my_item, nil, WAITING, EMPTY) 32 | raise "timeout" if is_success 33 | yr_item, stamp = @slot.get 34 | @slot.set(nil, EMPTY) 35 | return yr_item 36 | when WAITING 37 | yr_item, is_success = @slot.compare_and_set(yr_item, my_item, WAITING, BUSY) 38 | return yr_item if is_success 39 | when BUSY 40 | next 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/core/markable_reference.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Concurrent::Core 2 | class MarkableReference(T) 3 | MASK = 1 4 | @value : UInt64 5 | 6 | def initialize(reference : T, mark = false) 7 | @value = (pointerof(reference).address & ~MASK) 8 | @value |= 1 if mark 9 | end 10 | 11 | def reference : T 12 | Pointer(T).new(@value & ~MASK).value 13 | end 14 | 15 | def mark : Bool 16 | (@value & MASK) == 1 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/data_structure/queue.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Concurrent::DataStructure 2 | class Node(T) 3 | getter value : T? 4 | property next : Atomic(Node(T)?) 5 | 6 | def initialize(@value = nil) 7 | @next = Atomic(Node(T)?).new(nil) 8 | end 9 | end 10 | 11 | class Queue(T) 12 | @head : Atomic(Node(T)) 13 | @tail : Atomic(Node(T)) 14 | 15 | def initialize 16 | @head = @tail = Atomic(Node(T)).new(Node(T).new) 17 | end 18 | 19 | def enqueue(value : T) 20 | node = Node(T).new(value) 21 | loop do 22 | last = @tail.get 23 | nxt = last.next.get 24 | next if last != @tail.get 25 | if nxt.nil? 26 | _, is_success = last.next.compare_and_set(nxt, node) 27 | if is_success 28 | @tail.compare_and_set(last, node) 29 | return 30 | end 31 | else 32 | @tail.compare_and_set(last, nxt) 33 | end 34 | end 35 | end 36 | 37 | def dequeue : T? 38 | loop do 39 | first = @head.get 40 | last = @tail.get 41 | nxt = first.next.get 42 | next if first != @head.get 43 | if first == last 44 | raise EmptyException.new if nxt.nil? 45 | @tail.compare_and_set(last, nxt) 46 | else 47 | nxt = nxt.as(Node(T)) 48 | value = nxt.value 49 | return value if @head.compare_and_set(first, nxt) 50 | end 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/data_structure/unbounded_queue.cr: -------------------------------------------------------------------------------- 1 | require "../lock/ttas_lock" 2 | 3 | module Crystalg::Concurrent::DataStructure 4 | class UnboundedQueue(T) 5 | private class Node(T) 6 | getter value : T? 7 | property next : Node(T)? 8 | 9 | def initialize(@value = nil) 10 | @next = nil 11 | end 12 | end 13 | 14 | @enqueue_mutex : Crystalg::Concurrent::Lock::TTASLock 15 | @dequeue_mutex : Crystalg::Concurrent::Lock::TTASLock 16 | @head : Node(T) 17 | @tail : Node(T) 18 | 19 | def initialize 20 | @enqueue_mutex = Crystalg::Concurrent::Lock::TTASLock.new 21 | @dequeue_mutex = Crystalg::Concurrent::Lock::TTASLock.new 22 | @head = @tail = Node(T).new 23 | end 24 | 25 | def enqueue(value : T) 26 | @enqueue_mutex.lock 27 | begin 28 | e = Node(T).new(value) 29 | @tail.next = e 30 | @tail = e 31 | ensure 32 | @enqueue_mutex.unlock 33 | end 34 | end 35 | 36 | def dequeue : T? 37 | @dequeue_mutex.lock 38 | result = nil 39 | begin 40 | nxt = @head.next 41 | raise EmptyException.new if nxt.nil? 42 | result = nxt.value 43 | @head = @head.next.as(Node(T)) 44 | ensure 45 | @dequeue_mutex.unlock 46 | end 47 | result 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/a_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./lock" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class ALock 6 | include Lock 7 | 8 | @[ThreadLocal] 9 | @my_slot_index : Int32 10 | @tail : Atomic(Int32) 11 | @size : Int32 12 | @flag : Array(Bool) 13 | 14 | def initialize(@size) 15 | @my_slot_index = 0 16 | @tail = Atomic(Int32).new(0) 17 | @flag = Array(Bool).new(@size, false) 18 | @flag[0] = true 19 | end 20 | 21 | def lock 22 | slot = @tail.add(1) % @size 23 | @my_slot_index = slot 24 | loop { break if @flat[slot] } 25 | end 26 | 27 | def unlock 28 | slot = @my_slot_index 29 | @flag[slot] = false 30 | @flag[(slot + 1) % @size] = true 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/back_off.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Concurrent::Lock 2 | class BackOff 3 | @min_delay : Int32 4 | @max_delay : Int32 5 | @limit : Int32 6 | 7 | def initialize(@min_delay, @max_delay) 8 | @limit = @min_delay 9 | @random = Random.new 10 | end 11 | 12 | def back_off 13 | delay = @random.rand(@limit) 14 | @limit = Math.min(@max_delay, 2 * @limit) 15 | sleep delay.milliseconds 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/clh_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./lock" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class CLHLock 6 | include Lock 7 | 8 | class QNode 9 | property locked 10 | 11 | def initialize 12 | @locked = false 13 | end 14 | end 15 | 16 | @tail : Atomic(QNode) 17 | @[ThreadLocal] 18 | @my_pred : QNode? 19 | @[ThreadLocal] 20 | @my_node : QNode 21 | 22 | def initialize 23 | @tail = Atomic(QNode).new(QNode.new) 24 | @my_node = QNode.new 25 | @my_pred = nil 26 | end 27 | 28 | def lock 29 | qnode = @my_node 30 | qnode.locked = true 31 | pred = @tail.swap(qnode) 32 | @my_pred = pred 33 | loop { break if !pred.locked } 34 | end 35 | 36 | def unlock 37 | my_pred = @my_pred 38 | raise "Attempt to unlock a mutex which is not locked" if my_pred.nil? 39 | qnode = @my_node 40 | qnode.locked = false 41 | @my_node = my_pred 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/lock.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Concurrent::Lock 2 | module Lock 3 | abstract def lock 4 | abstract def unlock 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/mcs_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./lock" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class MCSLock 6 | include Lock 7 | 8 | @tail : Atomic(QNode?) 9 | @[ThreadLocal] 10 | @my_node : QNode 11 | 12 | class QNode 13 | property locked, nxt 14 | 15 | @locked : Atomic(Int8) 16 | @nxt : QNode? 17 | 18 | def initialize 19 | @locked = Atomic(Int8).new(0) 20 | @nxt = nil 21 | end 22 | end 23 | 24 | def initialize 25 | @tail = Atomic(QNode?).new(nil) 26 | @my_node = QNode.new 27 | end 28 | 29 | def lock 30 | qnode = @my_node 31 | pred = @tail.swap(qnode) 32 | return if pred.nil? 33 | qnode.locked.set(1) 34 | pred.nxt = qnode 35 | loop { break if !qnode.locked } 36 | end 37 | 38 | def unlock 39 | qnode = @my_node 40 | if qnode.nxt.nil? 41 | _, is_success = @tail.compare_and_set(qnode, nil) 42 | return if is_success 43 | loop { break if !qnode.nxt.nil? } 44 | end 45 | nxt = qnode.nxt 46 | nxt.locked.set(0) if !nxt.nil? 47 | qnode.nxt = nil 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/reentrant_lock.cr: -------------------------------------------------------------------------------- 1 | require "./lock" 2 | 3 | module Crystalg::Concurrent::Lock 4 | class ReentrantLock < Thread::Mutex 5 | include Lock 6 | 7 | @lock : Thread::Mutex 8 | @condition : Thread::ConditionVariable 9 | @owner : UInt64 10 | @hold_count : Int32 11 | 12 | def initialize(@lock = Thread::Mutex.new) 13 | @condition = Thread::ConditionVariable.new 14 | @owner = 0 15 | @hold_count = 0 16 | end 17 | 18 | def lock 19 | me = Fiber.current.hash 20 | @lock.lock 21 | begin 22 | if @owner == me 23 | @hold_count += 1 24 | return 25 | end 26 | while @hold_count != 0 27 | @condition.wait @lock 28 | end 29 | @owner = me 30 | @hold_count = 1 31 | ensure 32 | @lock.unlock 33 | end 34 | end 35 | 36 | def unlock 37 | @lock.lock 38 | begin 39 | raise "illegal monitor state" if @hold_count == 0 || @owner != Fiber.current.hash 40 | @hold_count -= 1 41 | @condition.signal if @hold_count == 0 42 | ensure 43 | @lock.unlock 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/semaphore.cr: -------------------------------------------------------------------------------- 1 | require "./reentrant_lock" 2 | 3 | # :nodoc: 4 | class Thread 5 | # :nodoc: 6 | class ConditionVariable 7 | def wait(mutex : Thread::Mutex | ReentrantLock) 8 | ret = LibC.pthread_cond_wait(self, mutex) 9 | raise Errno.new("pthread_cond_wait", ret) unless ret == 0 10 | end 11 | end 12 | end 13 | 14 | module Crystalg::Concurrent::Lock 15 | class Semaphore 16 | @capacity : Int32 17 | @state : Int32 18 | @mutex : ReentrantLock 19 | @condition : Thread::ConditionVariable 20 | 21 | def initialize(@capacity) 22 | @state = 0 23 | @mutex = ReentrantLock.new 24 | @condition = Thread::ConditionVariable.new 25 | end 26 | 27 | def acquire 28 | @mutex.lock 29 | begin 30 | while @state == @capacity 31 | @condition.wait @mutex 32 | end 33 | @state += 1 34 | ensure 35 | @mutex.unlock 36 | end 37 | end 38 | 39 | def release 40 | @mutex.lock 41 | begin 42 | @state -= 1 43 | @condition.broadcast 44 | ensure 45 | @mutex.unlock 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/tas_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./lock" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class TASLock 6 | include Lock 7 | 8 | @state : Atomic(Int8) 9 | 10 | def initialize 11 | @state = Atomic(Int8).new(0) 12 | end 13 | 14 | def lock 15 | loop { break if @state.swap(1) == 0 } 16 | end 17 | 18 | def unlock 19 | @state.set(0) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/to_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "time/span" 3 | 4 | module Crystalg::Concurrent::Lock 5 | # TimeOut Lock 6 | class TOLock 7 | class QNode 8 | property pred : QNode? 9 | 10 | def initialize 11 | @pred = nil 12 | end 13 | end 14 | 15 | AVAILABLE = QNode.new 16 | @tail : Atomic(QNode?) 17 | @[ThreadLocal] 18 | @my_node : QNode 19 | 20 | def initialize 21 | @tail = Atomic(QNode?).new(nil) 22 | @my_node = QNode.new 23 | end 24 | 25 | def lock 26 | qnode = QNode.new 27 | @my_node = qnode 28 | my_pred = @tail.swap(qnode) 29 | return true if my_pred.nil? || my_pred.pred == AVAILABLE 30 | loop do 31 | pred_pred = my_pred.pred 32 | return if pred_pred == AVAILABLE 33 | my_pred = pred_pred unless pred_pred.nil? 34 | end 35 | end 36 | 37 | def unlock 38 | qnode = @my_node 39 | _, is_success = @tail.compare_and_set(qnode, nil) 40 | qnode.pred = AVAILABLE if !is_success 41 | end 42 | 43 | def try_lock(patience : Time::Span) 44 | start_time = Time.now 45 | qnode = QNode.new 46 | @my_node = qnode 47 | my_pred = @tail.swap(qnode) 48 | return true if my_pred.nil? || my_pred.pred == AVAILABLE 49 | while Time.now - start_time < patience 50 | pred_pred = my_pred.pred 51 | return true if pred_pred == AVAILABLE 52 | my_pred = pred_pred if !pred_pred.nil? 53 | end 54 | _, is_success = @tail.compare_and_set(qnode, my_pred) 55 | qnode.pred = my_pred if !is_success 56 | false 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/ttas_lock.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./lock" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class TTASLock 6 | include Lock 7 | 8 | @state : Atomic(Int8) 9 | 10 | def initialize 11 | @state = Atomic(Int8).new(0) 12 | end 13 | 14 | def lock 15 | loop do 16 | loop { break if @state.get == 0 } 17 | return if @state.swap(1) == 0 18 | end 19 | end 20 | 21 | def unlock 22 | @state.set(0) 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /src/crystalg/concurrent/lock/wait_group.cr: -------------------------------------------------------------------------------- 1 | require "atomic" 2 | require "./back_off" 3 | 4 | module Crystalg::Concurrent::Lock 5 | class WaitGroup 6 | @counter : Atomic(Int32) 7 | 8 | def initialize 9 | @counter = Atomic(Int32).new(0) 10 | end 11 | 12 | def add(delta : Int32) 13 | loop do 14 | _, is_success = @counter.add(delta) 15 | break if is_success 16 | end 17 | end 18 | 19 | def done 20 | add(-1) 21 | end 22 | 23 | def wait 24 | back_off = BackOff.new(1, 5) 25 | while @counter.get != 0 26 | back_off.back_off 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /src/crystalg/data_structures.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | alias NodeID = Int32 3 | end 4 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/fenwick_tree.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # Fenwick Tree can efficiently update elements and calculate prefix sums 3 | # in a table of numbers. Type argument `T` must be the Group. 4 | # 5 | # ``` 6 | # fenwick = FenwickTree(Int32).new(5) 7 | # 8 | # fenwick[0] = 1 9 | # fenwick[1] = 3 10 | # fenwick[2] = 5 11 | # fenwick[3] = 7 12 | # fenwick[4] = 11 13 | # 14 | # # sum method returns sum of [0, index). If given index is 0, returns 0. 15 | # fenwick.sum(0) # => 0 16 | # fenwick.sum(3) # => 9 17 | # fenwick.sum(5) # => 27 18 | # ``` 19 | class FenwickTree(T) 20 | @size : Int32 21 | 22 | # Creates FenwickTree(T). 23 | def initialize(@size : Int32) 24 | @data = Array(T).new(@size * 2 - 1, T.zero) 25 | end 26 | 27 | # Sets the given value at the given index. `O(log n)`. 28 | def []=(index : Int, value : T) 29 | key = index + 1 30 | while key <= @size 31 | @data[key] += value 32 | key = key + (key & -key) 33 | end 34 | end 35 | 36 | # Adds elements that index less than or equeals `key` in the collection together. `O(log n)`. 37 | def sum(index : Int) 38 | result = T.zero 39 | while index > T.zero 40 | result += @data[index] 41 | index = index - (index & -index) 42 | end 43 | result 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/fenwick_tree_2d.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # FenwickTree2D is FenwickTree extended 2D. 3 | # 4 | # ``` 5 | # fenwick = FenwickTree2D(Int32).new(4, 3) 6 | # 7 | # # Create following grid: 8 | # # 1 2 3 9 | # # 4 5 6 10 | # # 7 8 9 11 | # # 10 11 12 12 | # 13 | # fenwick[0, 0] = 1 14 | # fenwick[1, 0] = 2 15 | # fenwick[2, 0] = 3 16 | # fenwick[0, 1] = 4 17 | # fenwick[1, 1] = 5 18 | # fenwick[2, 1] = 6 19 | # fenwick[0, 2] = 7 20 | # fenwick[1, 2] = 8 21 | # fenwick[2, 2] = 9 22 | # fenwick[0, 3] = 10 23 | # fenwick[1, 3] = 11 24 | # fenwick[2, 3] = 12 25 | # 26 | # # Sum of the above grid is: 27 | # # 0 0 0 0 28 | # # 0 1 3 6 29 | # # 0 5 12 21 30 | # # 0 12 27 45 31 | # # 0 22 48 78 32 | # 33 | # fenwick.sum(0, 0) # => 0 34 | # fenwick.sum(2, 0) # => 0 35 | # fenwick.sum(2, 3) # => 27 36 | # fenwick.sum(2, 4) # => 48 37 | # ``` 38 | class FenwickTree2D(T) 39 | @width : Int32 40 | @height : Int32 41 | 42 | # Creates FenwickTree2D(T). 43 | def initialize(@height, @width) 44 | @data = Array(FenwickTree(T)).new(@height * 2 - 1) { 45 | FenwickTree(T).new(@width * 2 - 1) 46 | } 47 | end 48 | 49 | # Sets the given value at the given row and column. `O(log^2 n)`. 50 | def []=(row, col, value) 51 | row += 1 52 | while row <= @height 53 | @data[row][col] = value 54 | row = row + (row & -row) 55 | end 56 | end 57 | 58 | # Adds elements in a square surrounded [0, row) and [0, col). `O(log^2 n)`. 59 | def sum(row, col) 60 | result = T.zero 61 | while row > T.zero 62 | result += @data[row].sum col 63 | row = row - (row & -row) 64 | end 65 | result 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/kdtree.cr: -------------------------------------------------------------------------------- 1 | require "../geometry/*" 2 | 3 | module Crystalg::DataStructures 4 | # KD Tree is a data structure for organizing points in a k-dimensional space. 5 | # KD Trees are a useful data structure for several applications, 6 | # such as range searches and nearest neighbor searches. 7 | class KDTree(T) 8 | include Crystalg::Geometry 9 | 10 | @size : Int32 11 | @points : Array(Point(T)) 12 | 13 | def initialize(@points) 14 | @size = points.size 15 | @tx = Array(T).new(@size, T.zero) 16 | @ty = Array(T).new(@size, T.zero) 17 | @minx = Array(T).new(@size, T.zero) 18 | @miny = Array(T).new(@size, T.zero) 19 | @maxx = Array(T).new(@size, T.zero) 20 | @maxy = Array(T).new(@size, T.zero) 21 | @count = Array(Int32).new(@size, 0) 22 | build 0, @size, true 23 | end 24 | 25 | def build(left, right, divx) 26 | return if left >= right 27 | middle = ((left + right) / 2).to_i 28 | 29 | sort(left, right, divx) 30 | 31 | @tx[middle], @ty[middle] = @points[middle].x, @points[middle].y 32 | @count[middle] = right - left 33 | 34 | @minx[middle], @miny[middle] = T::MAX, T::MAX 35 | @maxx[middle], @maxy[middle] = T::MIN, T::MIN 36 | (left...right).each do |i| 37 | @minx[middle] = Math.min(@minx[middle], @points[i].x) 38 | @miny[middle] = Math.min(@miny[middle], @points[i].y) 39 | @maxx[middle] = Math.max(@maxx[middle], @points[i].x) 40 | @maxy[middle] = Math.max(@maxy[middle], @points[i].y) 41 | end 42 | 43 | build(left, middle, !divx) 44 | build(middle + 1, right, !divx) 45 | end 46 | 47 | private def sort(left, right, divx = true) 48 | middle = ((left + right) / 2).to_i 49 | loop do 50 | k = partition(left, right, middle, divx) 51 | return if k == middle 52 | right = k if middle < k 53 | left = k + 1 if middle > k 54 | end 55 | end 56 | 57 | private def partition(left, right, pivotIndex, divx) 58 | i, j = left, right - 1 59 | return j if i >= j 60 | pivot = divx ? @points[pivotIndex].x : @points[pivotIndex].y 61 | swap(i, pivotIndex) 62 | i += 1 63 | while i <= j 64 | while i <= j && (divx ? @points[i].x : @points[i].y) < pivot 65 | i += 1 66 | end 67 | while i <= j && (divx ? @points[j].x : @points[j].y) > pivot 68 | j -= 1 69 | end 70 | break if i >= j 71 | swap(i, j) 72 | i += 1 73 | j -= 1 74 | end 75 | swap(j, left) 76 | j 77 | end 78 | 79 | private def swap(i, j) 80 | @points[i], @points[j] = @points[j], @points[i] 81 | end 82 | 83 | def count(bottom_left, top_right) 84 | count(0, @tx.size, bottom_left, top_right) 85 | end 86 | 87 | private def count(left, right, bottom_left, top_right) 88 | return 0 if left >= right 89 | middle = ((left + right) / 2).to_i 90 | minx, miny, maxx, maxy = @minx[middle], @miny[middle], @maxx[middle], @maxy[middle] 91 | 92 | if top_right.x < minx || maxx < bottom_left.x || top_right.y < miny || maxy < bottom_left.y 93 | return 0 94 | end 95 | 96 | if bottom_left.x <= minx && maxx <= top_right.x && bottom_left.y <= miny && maxy <= top_right.y 97 | return @count[middle] 98 | end 99 | 100 | res = 0 101 | res += count(left, middle, bottom_left, top_right) 102 | res += count(middle + 1, right, bottom_left, top_right) 103 | res += 1 if minx <= @tx[middle] && @tx[middle] <= maxx && miny <= @ty[middle] && @ty[middle] <= maxy 104 | res 105 | end 106 | 107 | def nearest_neighbour(target) 108 | result = nearest_neighbour 0, @points.size, target, true, {T::MAX, -1} 109 | @points[result[1]] 110 | end 111 | 112 | private def nearest_neighbour(left, right, target, divx, best) 113 | return best if left >= right 114 | 115 | middle = ((left + right) / 2).to_i 116 | dx, dy = target.x - @points[middle].x, target.y - @points[middle].y 117 | dist = dx ** 2 + dy ** 2 118 | delta = divx ? dx : dy 119 | 120 | best = {dist, middle} if best[0] > dist 121 | 122 | if delta <= 0.0 123 | result = nearest_neighbour left, middle, target, !divx, best 124 | result = Math.min(result, nearest_neighbour middle + 1, right, target, !divx, best) if delta ** 2 < best[0] 125 | result 126 | else 127 | result = nearest_neighbour middle + 1, right, target, !divx, best 128 | result = Math.min(result, nearest_neighbour left, middle, target, !divx, best) if delta ** 2 < best[0] 129 | result 130 | end 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/leftist_heap.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A leftist heap is a priority queue allowed merging heaps. 3 | class LeftistHeap(T) 4 | private class Node(T) 5 | property rank : Int32 6 | property left : Node(T)? 7 | property right : Node(T)? 8 | getter value : T 9 | 10 | def initialize(@value) 11 | @rank = 0 12 | @left = nil 13 | @right = nil 14 | end 15 | end 16 | 17 | # :nodoc: 18 | setter root : Node(T)? 19 | @root : Node(T)? = nil 20 | 21 | private def meld(a : Node(T)?, b : Node(T)?) 22 | return b if a.nil? 23 | return a if b.nil? 24 | a, b = b, a if a.value > b.value 25 | a.right = meld(a.right, b) 26 | if a.right.nil? || a.right.as(Node(T)).rank < a.right.as(Node(T)).rank 27 | a.left, a.right = a.right, a.left 28 | end 29 | a.rank = (a.right.nil? ? 0 : a.right.as(Node(T)).rank) + 1 30 | a 31 | end 32 | 33 | # Pushes a new value to heap. `O(log n)` 34 | # 35 | # ``` 36 | # heap = LeftistHeap(Int32).new 37 | # heap.push(2) 38 | # heap.top # => 2 39 | # ``` 40 | def push(x : T) 41 | @root = 42 | if @root.nil? 43 | Node(T).new(x) 44 | else 45 | meld(@root.as(Node(T)), Node(T).new x) 46 | end 47 | 48 | self 49 | end 50 | 51 | # Returns the higheset priority value or nil if heap is empty. `O(1)`. 52 | # 53 | # ``` 54 | # heap = LeftistHeap(Int32).new 55 | # 56 | # heap.top # => nil 57 | # heap.push(1).top # => 1 58 | # ``` 59 | def top : T? 60 | @root.try &.value 61 | end 62 | 63 | # Pops the highest priority value from heap. `O(log n)`. 64 | # 65 | # ``` 66 | # heap = LeftistHeap(Int32).new 67 | # 68 | # heap.push(3).push(2).push(1) 69 | # heap.pop 70 | # heap.top # => 2 71 | # ``` 72 | def pop 73 | return if @root.nil? 74 | root = @root.as(Node(T)) 75 | @root = meld(root.left, root.right) 76 | 77 | self 78 | end 79 | 80 | # Adds all elements of the meldable heap Q passed as parameter to this heap, and then emptying Q. `O(log n)`. 81 | # 82 | # ``` 83 | # heap1 = LeftistHeap(Int32).new 84 | # heap2 = LeftistHeap(Int32).new 85 | # [1, 2, 3].each { |e| heap1.push(e) } 86 | # [4, 5, 6].each { |e| heap2.push(e) } 87 | # 88 | # heap1.absorb(heap2) 89 | # 90 | # heap2.top # => nil 91 | # 92 | # heap1.top # => 1 93 | # heap1.pop.top # => 2 94 | # heap1.pop.top # => 3 95 | # heap1.pop.top # => 4 96 | # heap1.pop.top # => 5 97 | # heap1.pop.top # => 6 98 | # heap1.pop.top # => nil 99 | # ``` 100 | def absorb(other : LeftistHeap(T)) 101 | @root = meld(@root, other.@root) 102 | other.root = nil 103 | 104 | self 105 | end 106 | end 107 | end 108 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/link_cut_tree.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | @[Experimental] 3 | class LinkCutTree(T) 4 | def initialize(size) 5 | @left = Array(NodeID?).new(size, nil) 6 | @right = Array(NodeID?).new(size, nil) 7 | @parent = Array(NodeID?).new(size, nil) 8 | @val = Array(T).new(size, 0) 9 | @mini = Array(T).new(size, T::MAX) 10 | @minId = Array(NodeID?).new(size, nil) 11 | @lazy = Array(T).new(size, 0) 12 | @rev = Array(Bool).new(size, false) 13 | end 14 | 15 | # :nodoc: 16 | def push(id : NodeID) 17 | l = @left[id] 18 | r = @right[id] 19 | 20 | @val[id] += @lazy[id] 21 | @mini[id] += @lazy[id] 22 | 23 | @lazy[l] += @lazy[id] if !l.nil? 24 | @lazy[r] += @lazy[id] if !r.nil? 25 | @lazy[id] = 0 26 | 27 | if @rev[id] 28 | @rev[id] = false 29 | @rev[l] ^= true if !l.nil? 30 | @rev[r] ^= true if !r.nil? 31 | @left[id], @right[id] = @right[id], @left[id] 32 | end 33 | end 34 | 35 | # :nodoc: 36 | def update_min(id : NodeID, ch : NodeID) 37 | if @mini[ch] < @mini[id] 38 | @mini[id] = @mini[ch] 39 | @minId[id] = @minId[ch] 40 | end 41 | end 42 | 43 | # :nodoc: 44 | def update(id : NodeID) 45 | l = @left[id] 46 | r = @right[id] 47 | @mini[id] = @val[id] 48 | @minId[id] = id 49 | push(id) 50 | 51 | unless l.nil? 52 | push(l) 53 | update_min(id, l) 54 | end 55 | 56 | unless r.nil? 57 | push(r) 58 | update_min(id, r) 59 | end 60 | end 61 | 62 | def root?(id : NodeID) 63 | parent_index = @parent[id] 64 | return true if parent_index.nil? 65 | is_left = (@left[parent_index] != id) 66 | is_right = (@right[parent_index] != id) 67 | is_left && is_right 68 | end 69 | 70 | # :nodoc: 71 | def connect(ch : NodeID?, par : NodeID, is_left : Bool) 72 | if is_left 73 | @left[par] = ch 74 | else 75 | @right[par] = ch 76 | end 77 | @parent[ch] = par if !ch.nil? 78 | end 79 | 80 | # :nodoc: 81 | def rotate(id : NodeID) 82 | par = @parent[id].as(NodeID) 83 | q = @parent[par] 84 | push(par) 85 | push(id) 86 | is_left = (id == @left[par]) 87 | is_root = root?(par) 88 | if is_left 89 | connect(@right[id], par, is_left) 90 | else 91 | connect(@left[id], par, is_left) 92 | end 93 | connect(par, id, !is_left) 94 | if !is_root 95 | q = q.as(NodeID) 96 | connect(id, q, par == @left[q]) 97 | else 98 | @parent[id] = q 99 | end 100 | update(par) 101 | end 102 | 103 | # :nodoc: 104 | def splay(id : NodeID) 105 | until root?(id) 106 | par = @parent[id].as(NodeID) 107 | unless root?(par) 108 | is_left = (id == @left[par]) 109 | parent_is_left = (par == @left[@parent[par].as(NodeID)]) 110 | if is_left ^ parent_is_left 111 | rotate(par) 112 | else 113 | rotate(id) 114 | end 115 | end 116 | rotate(id) 117 | end 118 | update(id) 119 | end 120 | 121 | # :nodoc: 122 | def expose(id : NodeID) : NodeID? 123 | last = nil 124 | y = id 125 | until y.nil? 126 | splay(y) 127 | @right[y] = last 128 | last = y 129 | y = @parent[y] 130 | end 131 | splay(id) 132 | last 133 | end 134 | 135 | def find_root(id : NodeID) : NodeID 136 | expose(id) 137 | until @right[id].nil? 138 | id = @right[id] 139 | end 140 | id 141 | end 142 | 143 | def connected?(x : NodeID, y : NodeID) 144 | expose(x) 145 | expose(y) 146 | !@parent[x].nil? 147 | end 148 | 149 | def evert(par : NodeID) : Nil 150 | expose(par) 151 | @rev[par] ^= true 152 | end 153 | 154 | def link(ch : NodeID, par : NodeID) : Nil 155 | evert(ch) 156 | @parent[ch] = par 157 | end 158 | 159 | def cut(id : NodeID) : Nil 160 | expose(id) 161 | @parent[@right[id].as(Int32)] = nil 162 | @right[id] = nil 163 | end 164 | 165 | def lca(ch : NodeID, par : NodeID) : NodeID? 166 | expose(ch) 167 | expose(par) 168 | end 169 | 170 | def min_id(id : NodeID) : Int32 171 | expose(id) 172 | @minId[id] 173 | end 174 | 175 | def min(from : NodeID, to : NodeID) : Int32 176 | evert(from) 177 | expose(to) 178 | @mini[to] 179 | end 180 | 181 | def add(id : NodeID, val : Int32) 182 | expose(id) 183 | @lazy[id] = val 184 | end 185 | 186 | def add(from : NodeID, to : NodeID, v : Int32) 187 | evert(from) 188 | expose(to) 189 | @lazy[to] += v 190 | end 191 | end 192 | end 193 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/persistent_union_find.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | class PersistentUnionFind 3 | def initialize(size) 4 | @parent = Array(Array(Tuple(NodeID, Int32))).new(size) { [{-1, 0}] } 5 | @current = 0 6 | end 7 | 8 | def unite(u : NodeID, v : NodeID) : Bool 9 | @current += 1 10 | u, v = root(u, @current), root(v, @current) 11 | return false if u == v 12 | u, v = v, u if @parent[u].last.first > @parent[v].last.first 13 | @parent[u] << {@parent[u].last.first + @parent[v].last.first, @current} 14 | @parent[v] << {u, @current} 15 | true 16 | end 17 | 18 | def same?(u : NodeID, v : NodeID, time : Int32) : Bool 19 | root(u, time) == root(v, time) 20 | end 21 | 22 | def root(u : NodeID, time : Int32) : NodeID 23 | parent_id, parent_time = @parent[u].last 24 | return root(parent_id, time) if parent_id >= 0 && parent_time <= time 25 | u 26 | end 27 | 28 | def size(u : NodeID, time : Int32) : Int32 29 | u = root(u, time) 30 | left, right = 0, @parent[u].size 31 | while right - left > 1 32 | middle = (left + right) / 2 33 | if @parent[u][middle].last <= time 34 | left = middle 35 | else 36 | right = middle 37 | end 38 | end 39 | -@parent[u][left].first 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/priority_queue.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A PriorityQueue is a queue ordered by priority of elements. 3 | # 4 | # ``` 5 | # min_heap = PriorityQueue(Int32).new 6 | # [10, 8, 2, 11].each { |e| min_heap.push(e) } 7 | # min_heap.top # => 2 8 | # min_heap.pop.top # => 8 9 | # 10 | # min_heap.pop! # => 8 11 | # min_heap.top # => 10 12 | # 13 | # max_heap = PriorityQueue(Int32).new(:max) 14 | # [10, 8, 2, 11].each { |e| max_heap.push(e) } 15 | # max_heap.pop! # => 11 16 | # max_heap.pop! # => 10 17 | # max_heap.pop! # => 8 18 | # max_heap.pop! # => 2 19 | # ``` 20 | class PriorityQueue(A) 21 | getter size : UInt32 22 | 23 | # Creates a new `PriorityQueue`. The `order` parameter must be `:min` or `:max`. 24 | # 25 | # ``` 26 | # queue = PriorityQueue(Int32).new 27 | # queue = PriorityQueue(Int32).new(:min) 28 | # queue = PriorityQueue(Int32).new(:max) 29 | # ``` 30 | def initialize(@order = :min) 31 | Helper.assert(@order == :min || @order == :max) 32 | @heap = Array(A).new 33 | @size = 0_u32 34 | end 35 | 36 | # Append. This method returns self, so several calls can be chained. 37 | def push(val : A) 38 | @heap << val 39 | i = @size 40 | @size += 1 41 | while 0 < i 42 | parent = ((i - 1) / 2).to_i 43 | break if @order == :min && @heap[parent] <= val 44 | break if @order == :max && val <= @heap[parent] 45 | @heap[i] = @heap[parent] 46 | i = parent 47 | end 48 | @heap[i] = val 49 | self 50 | end 51 | 52 | # Removes the highest priority value based on `order` property. This method returns self, so several calls can be chained. 53 | def pop 54 | @size -= 1 55 | x = @heap[@size] 56 | pos = 0 57 | loop do 58 | child = 2 * pos + 1 59 | break if @size <= child 60 | if (@order == :min && child < @size && @heap[child + 1] < @heap[child]) || 61 | (@order == :max && child < @size && @heap[child] < @heap[child + 1]) 62 | child += 1 63 | end 64 | break if @order == :min && x <= @heap[child] 65 | break if @order == :max && @heap[child] <= x 66 | @heap[pos] = @heap[child] 67 | pos = child 68 | end 69 | @heap[pos] = x 70 | self 71 | end 72 | 73 | # Removes the highest priority value based on `order` property and returns the removed value. Returns nil if PriorityQueue is empty. 74 | def pop! : A? 75 | return if empty? 76 | result = top 77 | pop 78 | result 79 | end 80 | 81 | # Returns the highest priority value without removing the value. Returns nil if PriorityQueue is empty. 82 | def top : A? 83 | @heap.first? 84 | end 85 | 86 | # Returns true if PriorityQueue is empty. 87 | def empty? : Bool 88 | @size == 0 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/queue.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A queue is a first-in-first-out data structure. In a FIFO data structure, 3 | # the first element added to the queue will be the first one to be removed. 4 | # 5 | # ``` 6 | # queue = Queue(Int32).new 7 | # queue.push(1).push(2).push(3) 8 | # 9 | # puts queue.pop! # => 1 10 | # puts queue.pop! # => 2 11 | # puts queue.pop! # => 3 12 | # ``` 13 | class Queue(T) 14 | def initialize 15 | @array = Array(T).new 16 | end 17 | 18 | def push(val : T) 19 | @array << val 20 | self 21 | end 22 | 23 | def pop 24 | @array.shift? 25 | self 26 | end 27 | 28 | def pop! : T? 29 | result = @array.first? 30 | @array.shift? 31 | result 32 | end 33 | 34 | def top : T? 35 | @array.first? 36 | end 37 | 38 | def empty? 39 | @array.empty? 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/randomized_binary_search_tree.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A randomized binary serach tree is a binary tree selected 3 | # at random from some probability distribution on binary trees. 4 | # 5 | # ``` 6 | # tree = RandomizedBinarySearchTree(Int32).new 7 | # 8 | # tree.insert(0, 1) 9 | # tree.insert(1, 2) 10 | # tree.insert(2, 3) 11 | # tree.insert(3, 4) 12 | # tree.insert(4, 5) # => [1, 2, 3, 4, 5] 13 | # 14 | # # splits to [0, index) and [index, n) 15 | # left, right = tree.split(3) # left => [1, 2, 3], right => [4, 5] 16 | # 17 | # right.merge(left) # => [4, 5, 1, 2, 3] 18 | # 19 | # # reverses [left_index, right_index) 20 | # right.reverse(1, 4) # => [4, 2, 1, 5, 3] 21 | # 22 | # right.erase(2) # => [4, 2, 5, 3] 23 | # 24 | # right.find(0) # => 4 25 | # right.find(1) # => 2 26 | # right.find(2) # => 5 27 | # right.find(3) # => 3 28 | # ``` 29 | class RandomizedBinarySearchTree(T) 30 | private class Node(T) 31 | def initialize( 32 | @key : Int32, 33 | @value : T, 34 | @left : Node(T)? = nil, 35 | @right : Node(T)? = nil, 36 | @rev : Bool = false, 37 | @size : Int32 = 0 38 | ) 39 | end 40 | 41 | getter left : Node(T)? 42 | getter right : Node(T)? 43 | getter key, value, size, rev 44 | 45 | setter left : Node(T)? 46 | setter right : Node(T)? 47 | setter size, rev 48 | end 49 | 50 | # :nodoc: 51 | setter root : Node(T)? 52 | @root : Node(T)? = nil 53 | 54 | # Creates a empty tree. 55 | def initialize 56 | @rnd = ::Random.new 57 | end 58 | 59 | # :nodoc: 60 | def initialize(@root : Node(T)?) 61 | @rnd = ::Random.new 62 | end 63 | 64 | private def push(t : Node(T)) : Node(T) 65 | left_size = t.left.nil? ? 0 : t.left.as(Node).size 66 | right_size = t.right.nil? ? 0 : t.right.as(Node).size 67 | t.size = left_size + right_size + 1 68 | 69 | if t.rev 70 | t.left, t.right = t.right, t.left 71 | t.left.as(Node).rev ^= true if !t.left.nil? 72 | t.right.as(Node).rev ^= true if !t.right.nil? 73 | t.rev = false 74 | end 75 | t 76 | end 77 | 78 | private def merge_rec(l : Node(T)?, r : Node(T)?) : Node(T)? 79 | l = push(l) if !l.nil? 80 | r = push(r) if !r.nil? 81 | 82 | if l.nil? || r.nil? 83 | return r if l.nil? 84 | return l 85 | end 86 | 87 | m, n = l.size, r.size 88 | if @rnd.next_int % (m + n) < m 89 | l.right = merge_rec(l.right, r) 90 | push(l) 91 | else 92 | r.left = merge_rec(l, r.left) 93 | push(r) 94 | end 95 | end 96 | 97 | # Merges two trees by O(log n). This method returns self, so several calls can be chained. 98 | # 99 | # ``` 100 | # left = RandomizedBinarySearchTree(Int32).new 101 | # right = RandomizedBinarySearchTree(Int32).new 102 | # 103 | # [4, 5].each_with_index { |e, i| left.insert(i, e) } 104 | # [1, 2, 3].each_with_index { |e, i| right.insert(i, e) } 105 | # 106 | # left.merge(right) 107 | # 108 | # right.find(0) # => 4 109 | # right.find(1) # => 5 110 | # left.find(2) # => 1 111 | # left.find(3) # => 2 112 | # left.find(4) # => 3 113 | # ``` 114 | def merge(other : RandomizedBinarySearchTree(T)) 115 | @root = merge_rec(@root, other.@root) 116 | other.root = nil 117 | 118 | self 119 | end 120 | 121 | private def split_rec(k : Int32, t : Node(T)? = @root) 122 | t = push t if !t.nil? 123 | return {nil, nil} if t.nil? 124 | left_size = t.left.nil? ? 0 : t.left.as(Node(T)).size 125 | if k <= left_size 126 | l, r = split_rec(k, t.left) 127 | t.left = r 128 | {l, push(t)} 129 | else 130 | l, r = split_rec(k - left_size - 1, t.right) 131 | t.right = l 132 | {push(t), r} 133 | end 134 | end 135 | 136 | # Splits a tree to [0, index) and [index, n) by O(log n). 137 | # After this method called, a receiver tree is empty. 138 | # 139 | # ``` 140 | # tree = RandomizedBinarySearchTree(Int32).new 141 | # 142 | # [1, 2, 3, 4, 5].each_with_index { |e, i| tree.insert(i, e) } 143 | # 144 | # left, right = tree.split(3) 145 | # 146 | # left.find(0) # => 1 147 | # left.find(1) # => 2 148 | # left.find(2) # => 3 149 | # right.find(0) # => 4 150 | # right.find(1) # => 5 151 | # ``` 152 | def split(index : Int32) 153 | left_root, right_root = split_rec(index, @root) 154 | left = RandomizedBinarySearchTree(T).new(left_root) 155 | right = RandomizedBinarySearchTree(T).new(right_root) 156 | @root = nil 157 | {left, right} 158 | end 159 | 160 | # Inserts a value by O(log n). This method returns self, so several calls can be chained. 161 | # 162 | # ``` 163 | # tree = RandomizedBinarySearchTree(Int32).new 164 | # tree.insert(0, 1) 165 | # ``` 166 | def insert(index : Int32, value : T) 167 | node = find_rec(index, @root) 168 | return self if !node.nil? && node.key == index 169 | left, right = split_rec(index) 170 | t = merge_rec(left, Node.new(index, value)) 171 | t = merge_rec(t, right) 172 | @root = t.nil? ? t : push(t) 173 | 174 | self 175 | end 176 | 177 | # Erases a value by O(log n). This method returns self, so several calls can be chained. 178 | # 179 | # ``` 180 | # tree = RandomizedBinarySearchTree(Int32).new 181 | # tree.insert(0, 1) 182 | # 183 | # tree.erase(0) 184 | # ``` 185 | def erase(index : Int32) 186 | node = find_rec(index, @root) 187 | return self if node.nil? || node.key != index 188 | tmp, c = split_rec(index + 1, @root) 189 | a, b = split_rec(index, tmp) 190 | @root = merge_rec(a, c) 191 | @root = push(@root.as(Node(T))) if !@root.nil? 192 | 193 | self 194 | end 195 | 196 | # Updates a value by O(log n). This method returns self, so several calls can be chained. 197 | # 198 | # ``` 199 | # tree = RandomizedBinarySearchTree(Int32).new 200 | # tree.insert(0, 1) 201 | # 202 | # tree.update(0, 2) 203 | # ``` 204 | def update(index : Int32, value : T) 205 | node = find_rec(index, @root) 206 | return self if node.nil? || node.key != index 207 | tmp, c = split_rec(index + 1, @root) 208 | a, b = split_rec(index, tmp) 209 | @root = merge_rec(merge_rec(a, Node(T).new(index, value)), c) 210 | @root = push(@root.as(Node(T))) if !@root.nil? 211 | 212 | self 213 | end 214 | 215 | private def find_rec(index : Int32, t : Node(T)?) : Node(T)? 216 | return nil if t.nil? 217 | push(t) 218 | 219 | left_size = t.left.nil? ? 0 : t.left.as(Node(T)).size 220 | if index < left_size 221 | find_rec(index, t.left) 222 | elsif left_size == index 223 | t 224 | else 225 | find_rec(index - left_size - 1, t.right) 226 | end 227 | end 228 | 229 | # Returns a value by O(log n). 230 | # 231 | # ``` 232 | # tree = RandomizedBinarySearchTree(Int32).new 233 | # tree.insert(0, 1) 234 | # 235 | # tree.find(0) # => 1 236 | # ``` 237 | def find(index : Int32) : T? 238 | result = find_rec(index, @root) 239 | return nil if result.nil? 240 | result.value 241 | end 242 | 243 | # Reverses values in [left_id, right_id) by O(log n). This method returns self, so several calls can be chained. 244 | # 245 | # ``` 246 | # tree = RandomizedBinarySearchTree(Int32).new 247 | # 248 | # [1, 2, 3, 4, 5].each_with_index { |e, i| tree.insert(i, e) } 249 | # 250 | # tree.reverse(1, 4) 251 | # 252 | # tree.find(0) # => 1 253 | # tree.find(1) # => 4 254 | # tree.find(2) # => 3 255 | # tree.find(3) # => 2 256 | # tree.find(4) # => 5 257 | # ``` 258 | def reverse(left_id : Int32, right_id : Int32) 259 | tmp, c = split_rec(right_id) 260 | a, b = split_rec(left_id, tmp) 261 | b.as(Node(T)).rev ^= true if !b.nil? 262 | merge_rec(merge_rec(a, b), c) 263 | 264 | self 265 | end 266 | end 267 | end 268 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/randomized_meldable_heap.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A randomized meldable heap is a priority queue allowed merging heaps 3 | # by supporting internal method called meld. 4 | class RandomizedMeldableHeap(T) 5 | # :nodoc: 6 | class Node(T) 7 | property value : T 8 | property left : Node(T)? 9 | property right : Node(T)? 10 | 11 | def initialize(@value : T) 12 | end 13 | end 14 | 15 | # :nodoc: 16 | property root : Node(T)? 17 | 18 | @rng : Crystalg::Random::Xor128 19 | @size : Int32 20 | 21 | # Creates a new `RandomizedMeldableHeap(T)`. The `order` parameter must be `:min` or `:max`. 22 | def initialize(@order = :min, seed : UInt64 = 123456789) 23 | Helper.assert(@order == :min || @order == :max) 24 | @rng = Crystalg::Random::Xor128.new(seed) 25 | @root = nil 26 | @size = 0 27 | end 28 | 29 | # :nodoc: 30 | def meld(q1 : Node(T)?, q2 : Node(T)?) 31 | return q2 if q1.nil? 32 | return q1 if q2.nil? 33 | q1, q2 = q2, q1 if @order == :min && q2.value < q1.value 34 | q1, q2 = q2, q1 if @order == :max && q1.value < q2.value 35 | 36 | if @rng.get % 2 == 0 37 | q1.left = meld(q1.left, q2) 38 | else 39 | q1.right = meld(q1.right, q2) 40 | end 41 | q1 42 | end 43 | 44 | # Returns number of elements in a heap. 0 if a heap is empty. `O(1)`. 45 | # 46 | # ``` 47 | # heap = RandomizedMeldableHeap(Int32).new 48 | # 49 | # heap.size # => 0 50 | # heap.push(1).size # => 1 51 | # ``` 52 | def size : Int32 53 | @size 54 | end 55 | 56 | # Pushes a new value to heap. `O(log n)` 57 | # 58 | # ``` 59 | # heap = RandomizedMeldableHeap(Int32).new 60 | # heap.push(2) 61 | # heap.top # => 2 62 | # ``` 63 | def push(value : T) 64 | @root = meld(Node(T).new(value), @root) 65 | return if @root.nil? 66 | @size += 1 67 | 68 | self 69 | end 70 | 71 | # Pops the highest priority value from heap. `O(log n)`. 72 | # 73 | # ``` 74 | # heap = RandomizedMeldableHeap(Int32).new 75 | # 76 | # heap.push(3).push(2).push(1) 77 | # heap.pop 78 | # heap.top # => 2 79 | # ``` 80 | def pop 81 | return if @root.nil? 82 | @root = meld(@root.as(Node(T)).left, @root.as(Node(T)).right) 83 | @size -= 1 84 | 85 | self 86 | end 87 | 88 | # Returns the higheset priority value or nil if heap is empty. `O(1)`. 89 | # 90 | # ``` 91 | # heap = RandomizedMeldableHeap(Int32).new 92 | # 93 | # heap.top # => nil 94 | # heap.push(1).top # => 1 95 | # ``` 96 | def top 97 | @root.as(Node(T)).value if !@root.nil? 98 | end 99 | 100 | private def remove_rec(node : Node(T)?, value : T) : Node(T)? 101 | return nil if node.nil? 102 | return node if @order == :min && value < node.value 103 | return node if @order == :max && node.value < value 104 | while !node.nil? && node.value == value 105 | node = meld(node.left, node.right) 106 | end 107 | return nil if node.nil? 108 | node.left = remove_rec(node.left, value) 109 | node.right = remove_rec(node.right, value) 110 | node 111 | end 112 | 113 | # Removes all values equal a parameter from heap. `O(k log n)`. `k` is number of removed elements. 114 | # 115 | # ``` 116 | # heap = RandomizedMeldableHeap(Int32).new 117 | # 118 | # [10, 1, 2, 2, 2, 11, 2].each { |e| heap.push(e) } 119 | # 120 | # heap.remove(2) 121 | # 122 | # heap.top # => 1 123 | # heap.pop.top # => 10 124 | # heap.pop.top # => 11 125 | # heap.pop.top # => nil 126 | # ``` 127 | def remove(value : T) 128 | @root = remove_rec(@root, value) 129 | self 130 | end 131 | 132 | # Adds all elements of the meldable heap Q passed as parameter to this heap, and then emptying Q. `O(log n)`. 133 | # 134 | # ``` 135 | # heap1 = RandomizedMeldableHeap(Int32).new 136 | # heap2 = RandomizedMeldableHeap(Int32).new 137 | # [1, 2, 3].each { |e| heap1.push(e) } 138 | # [4, 5, 6].each { |e| heap2.push(e) } 139 | # 140 | # heap1.absorb(heap2) 141 | # 142 | # heap2.top # => nil 143 | # 144 | # heap1.top # => 1 145 | # heap1.pop.top # => 2 146 | # heap1.pop.top # => 3 147 | # heap1.pop.top # => 4 148 | # heap1.pop.top # => 5 149 | # heap1.pop.top # => 6 150 | # heap1.pop.top # => nil 151 | # ``` 152 | def absorb(other : RandomizedMeldableHeap(T)) 153 | @root = meld(@root, other.root) 154 | other.root = nil 155 | self 156 | end 157 | end 158 | end 159 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/segment_tree.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | class SegmetTree(T) 3 | getter size : Int32 4 | 5 | def initialize(@size) 6 | @n = 1 7 | while @n < @size 8 | @n *= 2 9 | end 10 | @value = Array(T).new(@n * 2 + 1, T.zero) 11 | @delta = Array(T).new(@n * 2 + 1, T.zero) 12 | end 13 | 14 | private def child_index(k : Int32) : Tuple(Int32, Int32) 15 | {k * 2 + 1, k * 2 + 2} 16 | end 17 | 18 | private def propagate(k : Int32) 19 | @value[k] += @delta[k] 20 | if k + 1 < @n 21 | left, right = child_index(k) 22 | @delta[left] += @delta[k] 23 | @delta[right] += @delta[k] 24 | end 25 | @delta[k] = T.zero 26 | end 27 | 28 | private def add(a, b, v, k, l, r) 29 | propagate k 30 | return if r <= a || b <= l 31 | if a <= l && r <= b 32 | @delta[k] = @delta[k] + v 33 | propagate k 34 | else 35 | left_child, right_child = child_index(k) 36 | mid = ((l + r) / 2).to_i 37 | add(a, b, v, left_child, l, mid) 38 | add(a, b, v, right_child, mid, r) 39 | @value[k] = Math.min(@value[left_child], @value[right_child]) 40 | end 41 | end 42 | 43 | private def min(a, b, k, l, r) 44 | propagate k 45 | return T::MAX if r <= a || b <= l 46 | return @value[k] if a <= l && r <= b 47 | left_child, right_child = child_index(k) 48 | mid = ((l + r) / 2).to_i 49 | left_result = min(a, b, left_child, l, mid) 50 | right_result = min(a, b, right_child, mid, r) 51 | Math.min(left_result, right_result) 52 | end 53 | 54 | def add(a, b, v) 55 | add(a, b, v, 0, 0, @size) 56 | end 57 | 58 | def min(a, b) 59 | min(a, b, 0, 0, @size) 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/skew_heap.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A skew heap is a priority queue allowed merging heaps. 3 | class SkewHeap(T) 4 | private class Node(T) 5 | property left : Node(T)? 6 | property right : Node(T)? 7 | getter value : T 8 | 9 | def initialize(@value) 10 | @left = nil 11 | @right = nil 12 | end 13 | end 14 | 15 | # :nodoc: 16 | setter root : Node(T)? 17 | @root : Node(T)? = nil 18 | 19 | private def meld(a : Node(T)?, b : Node(T)?) : Node(T)? 20 | return b if a.nil? 21 | return a if b.nil? 22 | a, b = b, a if a.value > b.value 23 | a.right = meld(a.right, b) 24 | a.left, a.right = a.right, a.left 25 | a 26 | end 27 | 28 | # Pushes a new value to heap. `O(log n)` 29 | # 30 | # ``` 31 | # heap = SkewHeap(Int32).new 32 | # heap.push(2) 33 | # heap.top # => 2 34 | # ``` 35 | def push(x) 36 | @root = 37 | if @root.nil? 38 | Node(T).new x 39 | else 40 | meld(@root.as(Node(T)), Node(T).new x) 41 | end 42 | 43 | self 44 | end 45 | 46 | # Returns the higheset priority value or nil if heap is empty. `O(1)`. 47 | # 48 | # ``` 49 | # heap = SkewHeap(Int32).new 50 | # 51 | # heap.top # => nil 52 | # heap.push(1).top # => 1 53 | # ``` 54 | def top 55 | @root.try &.value 56 | end 57 | 58 | # Pops the highest priority value from heap. `O(log n)`. 59 | # 60 | # ``` 61 | # heap = SkewHeap(Int32).new 62 | # 63 | # heap.push(3).push(2).push(1) 64 | # heap.pop 65 | # heap.top # => 2 66 | # ``` 67 | def pop 68 | return self if @root.nil? 69 | tmp = @root.as(Node(T)) 70 | @root = meld(tmp.left, tmp.right) 71 | 72 | self 73 | end 74 | 75 | # Adds all elements of the meldable heap Q passed as parameter to this heap, and then emptying Q. `O(log n)`. 76 | # 77 | # ``` 78 | # heap1 = SkewHeap(Int32).new 79 | # heap2 = SkewHeap(Int32).new 80 | # [1, 2, 3].each { |e| heap1.push(e) } 81 | # [4, 5, 6].each { |e| heap2.push(e) } 82 | # 83 | # heap1.absorb(heap2) 84 | # 85 | # heap2.top # => nil 86 | # 87 | # heap1.top # => 1 88 | # heap1.pop.top # => 2 89 | # heap1.pop.top # => 3 90 | # heap1.pop.top # => 4 91 | # heap1.pop.top # => 5 92 | # heap1.pop.top # => 6 93 | # heap1.pop.top # => nil 94 | # ``` 95 | def absorb(other : SkewHeap(T)) 96 | @root = meld(@root, other.@root) 97 | other.root = nil 98 | 99 | self 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/skip_list.cr: -------------------------------------------------------------------------------- 1 | require "../random/xor128" 2 | 3 | module Crystalg::DataStructures 4 | class SkipList 5 | private class Node 6 | getter value : Int32 7 | getter level : Int32 8 | property right : Node? 9 | property down : Node? 10 | 11 | def initialize(@value, @level, @right = nil, @down = nil) 12 | end 13 | 14 | def insert_to_right(new_node : Node) 15 | old = @right 16 | @right = new_node 17 | new_node.right = old 18 | end 19 | end 20 | 21 | @rng : Crystalg::Random::Xor128 22 | @origin : Node 23 | 24 | def initialize(@max_level : Int32, seed : UInt64 = 123456789) 25 | @rng = Crystalg::Random::Xor128.new(seed) 26 | level = @max_level 27 | @origin = Node.new(Int32::MIN, level) 28 | current = @origin 29 | while 0 < level 30 | level = level - 1 31 | current.down = Node.new(Int32::MIN, level) 32 | current = current.down.as(Node) 33 | end 34 | end 35 | 36 | def includes?(value : Int32) 37 | value == upper_bound(value, @max_level).@value 38 | end 39 | 40 | def insert(value : Int32) 41 | level = generate_level 42 | current = upper_bound(value, level) 43 | loop do 44 | if current.level <= level 45 | current.insert_to_right Node.new(value, current.level) 46 | end 47 | return if current.level == 0 48 | current.down = Node.new(value, current.level - 1) 49 | current = current.down.as(Node) 50 | end 51 | end 52 | 53 | private def upper_bound(value : Int32, level : Int32) : Node 54 | current = @origin 55 | while 0 < current.level 56 | while level < current.level 57 | current = current.down.as(Node) 58 | Helper.assert(!current.nil?) 59 | end 60 | 61 | unless current.nil? 62 | right = current.right 63 | break if right.nil? || right.value < value 64 | current = right 65 | end 66 | end 67 | current 68 | end 69 | 70 | private def generate_level 71 | (@rng.get & ((1 << @max_level) - 1)).to_i32 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/stack.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | # A stack is a first-in-last-out data structure. In a FILO data structure, 3 | # the first element added to the queue will be the last one to be removed. 4 | # 5 | # ``` 6 | # stack = Stack(Int32).new 7 | # stack.push(1).push(2).push(3) 8 | # 9 | # puts stack.pop! # => 3 10 | # puts stack.pop! # => 2 11 | # puts stack.pop! # => 1 12 | # ``` 13 | class Stack(T) 14 | def initialize 15 | @array = Array(T).new 16 | end 17 | 18 | def push(val : T) 19 | @array << val 20 | self 21 | end 22 | 23 | def pop 24 | @array.pop? 25 | self 26 | end 27 | 28 | def pop! : T? 29 | result = @array.last? 30 | @array.pop? 31 | result 32 | end 33 | 34 | def top : T? 35 | @array.last? 36 | end 37 | 38 | def empty? 39 | @array.empty? 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/crystalg/data_structures/union_find.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::DataStructures 2 | class UnionFind 3 | getter size : Int32 4 | 5 | def initialize(@size) 6 | @data = Array(Int32).new(@size, -1) 7 | end 8 | 9 | def unite(x : NodeID, y : NodeID) 10 | x = root(x) 11 | y = root(y) 12 | if x != y 13 | x, y = y, x if @data[y] < @data[x] 14 | @data[x] += @data[y] 15 | @data[y] = x 16 | end 17 | end 18 | 19 | def same?(x : NodeID, y : NodeID) 20 | root(x) == root(y) 21 | end 22 | 23 | def size(x : NodeID) 24 | @data[root(x)].abs 25 | end 26 | 27 | private def root(x : NodeID) 28 | @data[x] < 0 ? x : (@data[x] = root(@data[x])) 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /src/crystalg/geometry/circle.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | class Circle(T) 5 | getter center : Point(T) 6 | getter radius : T 7 | 8 | def initialize(@center, @radius) 9 | end 10 | 11 | def ==(other : self) 12 | center == other.center && radius === other.radius 13 | end 14 | 15 | def contain?(target) 16 | (target - center).norm.sign radius <= T.zero 17 | end 18 | 19 | # returns number of the common tangents 20 | def intersection(other) 21 | dist = center.distance other.center 22 | return 4 if dist > radius + other.radius 23 | return 3 if dist == radius + other.radius 24 | return 2 if dist > (radius - other.radius).abs 25 | return 1 if dist == (radius - other.radius).abs 26 | 0 27 | end 28 | 29 | def intersection_points(line) 30 | return Array(Point(T)).new if line.distance(center) <=> radius > 0 31 | q = line.project center 32 | t = (center - q).norm 33 | d = (radius * radius - t * t).sqrt 34 | base = line.direction - line.position 35 | result = Array(Point(T)).new 36 | result << q + base * (d / base.norm) 37 | result << q - base * (d / base.norm) 38 | result 39 | end 40 | 41 | def intersection_points(other : self) 42 | result = Array(Point(T)).new 43 | return result if (center - other.center).norm > (radius + other.radius) ** 2 44 | theta = Math.atan2(other.center.y - center.y, other.center.x - center.x) 45 | dist = center.distance other.center 46 | alpha = Math.acos((dist ** 2 + radius ** 2 - other.radius ** 2) / (2 * dist * radius)) 47 | result << Point.new(center.x + radius * Math.cos(theta + alpha), center.y + radius * Math.sin(theta + alpha)) 48 | result << Point.new(center.x + radius * Math.cos(theta - alpha), center.y + radius * Math.sin(theta - alpha)) 49 | result 50 | end 51 | 52 | def intersection_area(other) 53 | r1, r2 = Math.min(radius, other.radius), Math.max(radius, other.radius) 54 | dist = (center - other.center).norm 55 | return Math::PI * r1 ** 2 if (dist <=> r2 - r1) <= 0 56 | return 0.0 if (dist <=> r2 + r1) >= 0 57 | rc = dist ** 2 + r1 ** 2 - r2 ** 2 / (2 * dist) 58 | theta = Math.acos(rc / r1) 59 | phi = Math.acos((dist - rc) / r2) 60 | r1 ** 2 * theta + r2 ** 2 * phi - dist * r1 * Math.sin(theta) 61 | end 62 | 63 | def circumscribed_circle(a, b) 64 | q = (a + b) / 2 65 | Circle(T).new(q, (a - q).norm) 66 | end 67 | 68 | def self.circumscribed_circle(p, q, r) 69 | a, b = (q - p) * 2, (r - p) * 2 70 | c = Point(T).new(p.dot(p) - q.dot(q), p.dot(p) - r.dot(r)) 71 | tmp = Point(T).new(a.y * c.y - b.y * c.x, b.x * c.x - a.x * c.y) / a.cross b 72 | Circle(T).new(tmp, p.distance tmp) 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /src/crystalg/geometry/extensions.cr: -------------------------------------------------------------------------------- 1 | EPS = 1e-8 2 | 3 | struct Float 4 | include Comparable(Float) 5 | 6 | def +(other : Float) 7 | if (self + other).abs < EPS * (self.abs + other.abs) 8 | 0.as Float 9 | else 10 | self + other 11 | end 12 | end 13 | 14 | def <=>(other : Float) 15 | if (self < other - EPS) 16 | -1 17 | elsif (self > other + EPS) 18 | 1 19 | else 20 | 0 21 | end 22 | end 23 | 24 | def ===(other : Float) 25 | (self <=> other) == 0 26 | end 27 | 28 | def sign : Int 29 | self <=> 0.as(Float) 30 | end 31 | 32 | def sqrt 33 | Math.sqrt Math.max(self, 0.0) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /src/crystalg/geometry/geometry.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | # a -> b -> c 5 | enum CCW 6 | COUNTER_CLOCKWISE = 1 7 | CLOCKWISE = -1 8 | ONLINE_BACK = 2 # c--a--b 9 | ONLINE_FRONT = -2 # a--b--c 10 | ON_SEGMENT = 0 # a--c--b 11 | end 12 | 13 | def counter_clockwise(a : Point, b : Point, c : Point) : CCW 14 | b = b - a 15 | c = c - a 16 | return CCW::COUNTER_CLOCKWISE if b.cross(c) > 0 17 | return CCW::CLOCKWISE if b.cross(c) < 0 18 | return CCW::ONLINE_BACK if b.dot(c) < 0 19 | return CCW::ONLINE_FRONT if b.norm < c.norm 20 | CCW::ON_SEGMENT 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/crystalg/geometry/line.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | class Line(T) 5 | getter position : Point(T) 6 | getter direction : Point(T) 7 | 8 | def initialize(@position, @direction) 9 | end 10 | 11 | def project(point) 12 | base = direction - position 13 | position + base * ((point - position).dot (base / base.dot base)) 14 | end 15 | 16 | def reflect(q) 17 | q + (project(q) - q) * 2 18 | end 19 | 20 | def is_parallel?(other) 21 | (direction - position).cross(other.direction - other.position) == 0 22 | end 23 | 24 | def is_orthogonal?(other) 25 | (direction - position).dot(other.direction - other.position) == 0 26 | end 27 | 28 | def is_intersection?(other) 29 | !is_parallel? other 30 | end 31 | 32 | def distance(point) 33 | v = direction - position 34 | v.cross(point - position).abs / v.norm 35 | end 36 | 37 | def intersection_point(other) 38 | vector = direction - position 39 | other_vector = other.direction - other.position 40 | position + vector * (other_vector.cross(other.position - position) / other_vector.cross vector) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /src/crystalg/geometry/point.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | class Point(T) 5 | include Comparable(Point(T)) 6 | 7 | getter x : T, y : T 8 | 9 | def initialize(@x : T, @y : T) 10 | end 11 | 12 | def +(other : self) 13 | Point.new(x + other.x, y + other.y) 14 | end 15 | 16 | def -(other : self) 17 | Point.new(x + (-other.x), y + (-other.y)) 18 | end 19 | 20 | def *(other) 21 | Point.new(x * other, y * other) 22 | end 23 | 24 | def /(other) 25 | Point.new(x / other, y / other) 26 | end 27 | 28 | def <=>(other) 29 | if x != other.x 30 | x <=> other.x 31 | else 32 | y <=> other.y 33 | end 34 | end 35 | 36 | def ==(other) 37 | x === other.x && y === other.y 38 | end 39 | 40 | def norm 41 | (x * x + y * y).sqrt.as(T) 42 | end 43 | 44 | def distance(other) 45 | (self - other).norm 46 | end 47 | 48 | def dot(other) 49 | x * other.x + y * other.y 50 | end 51 | 52 | def cross(other) 53 | x * other.y - y * other.x 54 | end 55 | 56 | def rotate(radian, pivot = Point.new(0, 0)) 57 | Point.new( 58 | LibM.cos(r) * (x - pivot.x) - LibM.sin(r) * (y - pivot.y) + pivot.x, 59 | LibM.sin(r) * (x - pivot.x) + LibM.cos(r) * (y - pivot.y) + pivot.y) 60 | end 61 | 62 | def arg 63 | LibM.atan(y/x) if x.sign > 0 64 | LibM.atan(y/x) + PI if x.sign < 0 65 | PI / 2.0.as Float if y.sign > 0 66 | 3.0 * PI / 2.0.as Float if y.sign < 0 67 | 0 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /src/crystalg/geometry/polygon.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | class Polygon(T) 5 | def initialize(*points : Point(T)) 6 | @points = points.to_a 7 | end 8 | 9 | def initialize(@points : Array(Point(T))) 10 | end 11 | 12 | def size 13 | @points.size 14 | end 15 | 16 | def prv(i) 17 | cur(i - 1) 18 | end 19 | 20 | def cur(i) 21 | @points[i % @points.size] 22 | end 23 | 24 | def nxt(i) 25 | cur(i + 1) 26 | end 27 | 28 | def [](i) 29 | @points[i] 30 | end 31 | 32 | def ==(other : self) 33 | this, that = self.@points, other.@points 34 | return false if this.size != that.size 35 | this.sort == that.sort 36 | end 37 | 38 | def is_convex? 39 | @points.each_with_index do |e, i| 40 | return false if counter_clockwise(prv(i), cur(i), nxt(i)) == CCW::CLOCKWISE 41 | end 42 | true 43 | end 44 | 45 | enum Containment 46 | OUT = 0 47 | IN = 1 48 | ON = 2 49 | end 50 | 51 | def contain(target : Point(T)) : Containment 52 | is_contain = false 53 | @points.each_with_index do |e, i| 54 | a, b = cur(i) - target, nxt(i) - target 55 | a, b = b, a if a.y > b.y 56 | is_contain ^= true if a.y <= 0 && 0 < b.y && a.cross(b) < 0 57 | return Containment::ON if a.cross(b) == 0 && a.dot(b) <= 0 58 | end 59 | is_contain ? Containment::IN : Containment::OUT 60 | end 61 | 62 | def area 63 | result = T.zero 64 | @points.each_with_index do |e, i| 65 | result += (e.x - nxt(i).x) * (e.y + nxt(i).y) 66 | end 67 | result.abs / 2.0 68 | end 69 | 70 | def convex_cut(line : Line(T)) 71 | pos, dir = line.position, line.direction 72 | result = Array(Point(T)).new 73 | @points.each_with_index do |e, i| 74 | vec = dir - pos 75 | side = Segment(T).new(e, nxt i) 76 | result << e if counter_clockwise(pos, dir, e) != CCW::CLOCKWISE 77 | # TODO : bugfix 78 | result << side.intersection_point(Segment(T).new(pos, dir)) if side.is_intersection? Segment(T).new(line.position, line.direction) 79 | end 80 | Polygon.new(result) 81 | end 82 | 83 | def convex_hull 84 | points = @points 85 | points.sort 86 | result = Array(Point(T)).new 87 | (0...points.size).each do |i| 88 | while result.size > 1 89 | tail1 = result[result.size - 1] 90 | tail2 = result[result.size - 2] 91 | (tail1 - tail2).cross(points[i] - tail1) 92 | break if (tail1 - tail2).cross(points[i] - tail1) < 0 93 | result.pop 94 | end 95 | result << points[i] 96 | end 97 | 98 | t = result.size 99 | (0..points.size - 2).reverse_each do |i| 100 | tail1 = result[result.size - 1] 101 | tail2 = result[result.size - 2] 102 | while result.size > t 103 | tail1 = result[result.size - 1] 104 | tail2 = result[result.size - 2] 105 | break if (tail1 - tail2).cross(points[i] - tail1) < 0 106 | result.pop 107 | end 108 | result << points[i] 109 | end 110 | result.pop 111 | Polygon.new(result) 112 | end 113 | 114 | def diameter 115 | qs = convex_hull 116 | n = qs.size 117 | 118 | return 0.0 if n == 2 119 | 120 | i = j = 0 121 | (0...n).each do |k| 122 | i = k if qs[k] < qs[i] 123 | j = k if qs[j] < qs[k] 124 | end 125 | 126 | result = 0_f64 127 | si, sj = i, j 128 | while i != sj && j != si 129 | result = Math.max(result, qs[i].distance qs[j]) 130 | if (qs.nxt(i) - qs.cur(i)).cross(qs.nxt(j) - qs.cur(j)) < 0 131 | i = (i + 1) % n 132 | else 133 | j = (j + 1) % n 134 | end 135 | end 136 | result 137 | end 138 | end 139 | end 140 | -------------------------------------------------------------------------------- /src/crystalg/geometry/segment.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Crystalg::Geometry 4 | class Segment(T) 5 | getter position : Point(T) 6 | getter direction : Point(T) 7 | 8 | def initialize(@position, @direction) 9 | end 10 | 11 | def on?(c) 12 | counter_clockwise(position, direction, c) == CCW::ON_SEGMENT 13 | end 14 | 15 | def is_parallel?(other) 16 | (direction - position).cross(other.direction - other.position) == 0 17 | end 18 | 19 | def is_overlap?(other) 20 | is_parallel(other) && (on other.position || on other.direction || other.on position || other.on direction) 21 | end 22 | 23 | def distance(point : Point(T)) 24 | a, b, c = position, direction, point 25 | return c.distance a if (b - a).dot(c - a) < 0 26 | return c.distance b if (a - b).dot(c - b) < 0 27 | (b - a).cross(c - a).abs / b.distance a 28 | end 29 | 30 | def distance(other) 31 | return 0.0 if is_intersection? other 32 | Math.min( 33 | Math.min(distance(other.position), distance other.direction), 34 | Math.min(other.distance(position), other.distance direction) 35 | ) 36 | end 37 | 38 | def is_intersection?(other) 39 | a, b, c, d = position, direction, other.position, other.direction 40 | counter_clockwise(a, b, c).value * counter_clockwise(a, b, d).value <= 0 && 41 | counter_clockwise(c, d, a).value * counter_clockwise(c, d, b).value <= 0 42 | end 43 | 44 | def intersection_point(other) 45 | q = other.direction - other.position 46 | d1 = q.cross(position - other.position).abs 47 | d2 = q.cross(direction - other.position).abs 48 | position + (direction - position) * (d1 / (d1 + d2)) 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /src/crystalg/graph/connected_components/articulation_points.cr: -------------------------------------------------------------------------------- 1 | require "./context" 2 | 3 | module Crystalg::Graph::ConnectedComponents 4 | module ArticulationPoints 5 | private def articulation_points_dfs(u : NodeID, ctx : Context, prev : NodeID = -1) 6 | ctx.used[u] = true 7 | ctx.order[u] = ctx.lowlink[u] = ctx.k 8 | ctx.k += 1 9 | 10 | adjacent_nodes(u).each do |target_id, _target_cost| 11 | if !ctx.used[target_id] 12 | ctx.parent[target_id] = u 13 | articulation_points_dfs(target_id, ctx, u) 14 | ctx.lowlink[u] = Math.min(ctx.lowlink[u], ctx.lowlink[target_id]) 15 | elsif target_id != prev 16 | ctx.lowlink[u] = Math.min(ctx.lowlink[u], ctx.order[target_id]) 17 | end 18 | end 19 | end 20 | 21 | def articulation_points : Array(NodeID) 22 | ctx = Context.new(@size) 23 | 24 | count = 0 25 | result = Array(NodeID).new 26 | articulation_points_dfs(0, ctx) 27 | (0...@size).each do |i| 28 | count += 1 if ctx.parent[i] == 0 && i != 0 29 | if ctx.parent[i] > 0 && ctx.lowlink[i] >= ctx.order[ctx.parent[i]] 30 | result << ctx.parent[i] 31 | end 32 | end 33 | result << 0 if count >= 2 34 | result.sort!.uniq! 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/crystalg/graph/connected_components/bridges.cr: -------------------------------------------------------------------------------- 1 | require "./context" 2 | 3 | module Crystalg::Graph::ConnectedComponents 4 | module Bridges(T) 5 | private def bridge_dfs(u : NodeID, bridges : Array(Edge(T)), ctx : Context, prev : NodeID = -1) 6 | ctx.used[u] = true 7 | ctx.order[u] = ctx.lowlink[u] = ctx.k 8 | ctx.k += 1 9 | 10 | adjacent_nodes(u).each do |target_node_id, target_cost| 11 | if !ctx.used[target_node_id] 12 | bridge_dfs(target_node_id, bridges, ctx, u) 13 | ctx.lowlink[u] = Math.min(ctx.lowlink[u], ctx.lowlink[target_node_id]) 14 | if ctx.order[u] < ctx.lowlink[target_node_id] 15 | left = Math.min(u, target_node_id) 16 | right = Math.max(u, target_node_id) 17 | bridges << Edge.new(left, right, target_cost) 18 | end 19 | elsif target_node_id != prev 20 | ctx.lowlink[u] = Math.min(ctx.lowlink[u], ctx.order[target_node_id]) 21 | end 22 | end 23 | end 24 | 25 | def bridges 26 | ctx = Context.new(@size) 27 | bridges = Array(Edge(T)).new 28 | bridge_dfs(0, bridges, ctx) 29 | bridges 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/crystalg/graph/connected_components/context.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Graph::ConnectedComponents 2 | private class Context 3 | property k, used, order, lowlink, parent 4 | 5 | # size is number of nodes 6 | def initialize(size : Int32) 7 | @k = 0 8 | @used = Array(Bool).new(size, false) 9 | @order = Array(Int32).new(size, 0) 10 | @lowlink = Array(Int32).new(size, 0) 11 | @parent = Array(Int32).new(size, -1) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /src/crystalg/graph/connected_components/cycle_detection.cr: -------------------------------------------------------------------------------- 1 | require "../*" 2 | 3 | module Crystalg::Graph::ConnectedComponents 4 | module CycleDetection 5 | private def dfs(u : Int32, used : Array(Int32), flag : Bool) : Bool 6 | return flag if used[u] == 1 || flag 7 | used[u] = 2 8 | adjacent_nodes(u).each do |target_node_id, target_cost| 9 | return true if used[target_node_id] == 2 10 | flag ||= dfs(target_node_id, used, flag) if used[target_node_id] == 0 11 | end 12 | used[u] = 1 13 | flag 14 | end 15 | 16 | def has_cycle? 17 | used = Array(Int32).new(@size, 0) 18 | flag = false 19 | (0...@size).each { |node_id| flag ||= dfs(node_id, used, flag) } 20 | flag 21 | end 22 | 23 | # bellman ford 24 | def has_negative_cycle? 25 | dist = Array(Int32).new(@size, 0) 26 | (0...@size).each do |i| 27 | edges.each do |edge| 28 | if dist[edge.target] > dist[edge.source] + edge.cost 29 | dist[edge.target] = dist[edge.source] + edge.cost 30 | return true if i == @size - 1 31 | end 32 | end 33 | end 34 | false 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/crystalg/graph/directed_graph.cr: -------------------------------------------------------------------------------- 1 | require "./connected_components/*" 2 | require "./shortest_path/*" 3 | 4 | module Crystalg::Graph 5 | # C: type of cost 6 | class DirectedGraph(C) < Graph(C) 7 | getter size : Int32 8 | 9 | def initialize(@size : Int32) 10 | @graph = Array(Array(Tuple(NodeID, C))).new(@size) { 11 | Array(Tuple(NodeID, C)).new 12 | } 13 | end 14 | 15 | def add(edge : Edge(C)) 16 | @graph[edge.source] << {edge.target, edge.cost} 17 | end 18 | 19 | def adjacent_nodes(node_id : NodeID) : Array(Tuple(C, NodeID)) 20 | @graph[node_id].map do |e| 21 | {e[0], e[1]} 22 | end 23 | end 24 | 25 | def edges : Array(Edge(C)) 26 | result = Array(Edge(C)).new 27 | (0...@size).each do |node_id| 28 | node_edges = adjacent_nodes(node_id).map do |target_id, cost| 29 | Edge(C).new(node_id, target_id, cost) 30 | end 31 | result.concat(node_edges) 32 | end 33 | result.uniq! 34 | end 35 | 36 | def topological_sort : Array(NodeID) 37 | used = Array(Bool).new(@size, false) 38 | order = Array(NodeID).new 39 | (0...@size).each do |i| 40 | topological_sort used, order, i if !used[i] 41 | end 42 | order.reverse! 43 | end 44 | 45 | private def topological_sort(used : Array(Bool), order : Array(NodeID), u : NodeID) 46 | used[u] = true 47 | adjacent_nodes(u).each do |target_id, _cost| 48 | topological_sort(used, order, target_id) if !used[target_id] 49 | end 50 | order << u 51 | end 52 | 53 | include ConnectedComponents::CycleDetection 54 | include ShortestPath::Dijkstra(C) 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /src/crystalg/graph/edge.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Graph 2 | class Edge(T) 3 | include Comparable(Edge(T)) 4 | 5 | getter source, target, cost 6 | 7 | def initialize(@source : NodeID, @target : NodeID, @cost : T) 8 | end 9 | 10 | def <=>(other : Edge(T)) 11 | if cost != other.cost 12 | cost <=> other.cost 13 | elsif source != other.source 14 | source <=> other.source 15 | else 16 | target <=> other.target 17 | end 18 | end 19 | 20 | def ==(other : Edge(T)) 21 | (source == other.source || source == other.target) && 22 | (target == other.source || target == other.target) && 23 | cost == other.cost 24 | end 25 | 26 | def ===(other : Edge(T)) 27 | source == other.source && target == other.target && cost == other.cost 28 | end 29 | end 30 | 31 | class FlowEdge(U) 32 | getter source, target, capacity 33 | 34 | def initialize(@source : NodeID, @target : NodeID, @capacity : U) 35 | end 36 | end 37 | 38 | class WeightedFlowEdge(T, U) 39 | getter source, target, cost, capacity 40 | 41 | def initialize(@source : NodeID, @target : NodeID, @cost : T, @capacity : U) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /src/crystalg/graph/flow/dinic.cr: -------------------------------------------------------------------------------- 1 | require "../../data_structures/queue" 2 | require "../flow_graph" 3 | 4 | module Crystalg::Graph 5 | class Dinic(C) 6 | def initialize(@graph : FlowGraph(C)) 7 | @iter = Array(NodeID).new(@graph.size, 0) 8 | @level = Array(Int32).new(@graph.size, -1) 9 | end 10 | 11 | def max_flow(source : NodeID, target : NodeID) 12 | flow = C.zero 13 | loop do 14 | bfs(source) 15 | return flow if @level[target] < 0 16 | @iter.fill(0) 17 | while (f = dfs(source, target, C::MAX)) > C.zero 18 | flow += f 19 | end 20 | end 21 | end 22 | 23 | private def bfs(source : NodeID) 24 | @level.fill(-1) 25 | queue = Queue(Int32).new 26 | @level[source] = 0 27 | queue.push source 28 | until (node_id = queue.pop!).nil? 29 | @graph.adjacent_nodes(node_id).each do |target_id, capacity| 30 | if capacity > C.zero && @level[target_id] < 0 31 | @level[target_id] = @level[node_id] + 1 32 | queue.push(target_id) 33 | end 34 | end 35 | end 36 | end 37 | 38 | private def dfs(v : NodeID, target : NodeID, flow : C) : C 39 | return flow if v == target 40 | nodes = @graph.adjacent_nodes(v) 41 | while @iter[v] < nodes.size 42 | next_id, capacity, _rev = nodes[@iter[v]] 43 | if capacity > C.zero && @level[v] < @level[next_id] 44 | d = dfs(next_id, target, Math.min(flow, capacity)) 45 | return @graph.flow(v, @iter[v], d) if d > C.zero 46 | end 47 | @iter[v] += 1 48 | end 49 | C.zero 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /src/crystalg/graph/flow/ford_fulkerson.cr: -------------------------------------------------------------------------------- 1 | require "../flow_graph" 2 | 3 | module Crystalg::Graph 4 | # C: type of capacity 5 | class FordFulkerson(C) 6 | def initialize(@graph : FlowGraph(C)) 7 | @used = Array(Bool).new(@graph.size, false) 8 | end 9 | 10 | def max_flow(source : NodeID, target : NodeID) 11 | flow = C.zero 12 | loop do 13 | @used.fill(false) 14 | f = dfs(source, target, C::MAX) 15 | return flow if f == C.zero 16 | flow += f 17 | end 18 | end 19 | 20 | def dfs(node_id : NodeID, target : NodeID, flow : C) : C 21 | return flow if node_id == target 22 | @used[node_id] = true 23 | @graph.adjacent_nodes(node_id).each_with_index do |node, i| 24 | next_id, capacity = node 25 | if !@used[next_id] && capacity > C.zero 26 | d = dfs(next_id, target, Math.min(flow, capacity)) 27 | return @graph.flow(node_id, i, d) if d > C.zero 28 | end 29 | end 30 | C.zero 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /src/crystalg/graph/flow/hopcroft_karp.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Graph 2 | class HopcroftKarp 3 | @left_size : Int32 4 | @right_size : Int32 5 | @edge_size : Int32 6 | @last : Array(Int32) 7 | @prev : Array(Int32) 8 | @head : Array(Int32) 9 | @match : Array(Int32) 10 | @dist : Array(Int32) 11 | @used : Array(Bool) 12 | @visited : Array(Bool) 13 | 14 | def initialize(@left_size : Int32, @right_size : Int32) 15 | @edge_size = 0 16 | @last = Array.new(@left_size, -1) 17 | @head = Array(Int32).new 18 | @prev = Array(Int32).new 19 | @match = Array(Int32).new(@right_size, -1) 20 | @dist = Array(Int32).new(@left_size, -1) 21 | @used = Array(Bool).new(@left_size, false) 22 | @visited = Array(Bool).new(@left_size, false) 23 | end 24 | 25 | def add_edge(left_id : Int32, right_id : Int32) 26 | @head << right_id 27 | @prev << @last[left_id] 28 | @last[left_id] = @edge_size 29 | @edge_size += 1 30 | end 31 | 32 | def bipartite_matching 33 | @used.fill(false) 34 | @match.fill(-1) 35 | flow = 0 36 | loop do 37 | bfs 38 | @visited.fill(false) 39 | f = 0 40 | (0...@left_size).each do |u| 41 | if !@used[u] && dfs(u) 42 | f += 1 43 | end 44 | end 45 | return flow if f == 0 46 | flow += f 47 | end 48 | end 49 | 50 | private def bfs 51 | queue = Array(Int32).new 52 | @dist.fill(-1) 53 | (0...@left_size).each do |u| 54 | if !@used[u] 55 | queue << u 56 | @dist[u] = 0 57 | end 58 | end 59 | 60 | (0...queue.size).each do |i| 61 | u1 = queue[i] 62 | e = @last[u1] 63 | while e >= 0 64 | u2 = @match[@head[e]] 65 | if u2 >= 0 && @dist[u2] < 0 66 | @dist[u2] = @dist[u1] + 1 67 | queue << u2 68 | end 69 | e = @prev[e] 70 | end 71 | end 72 | end 73 | 74 | private def dfs(u1 : Int32) : Bool 75 | @visited[u1] = true 76 | e = @last[u1] 77 | while e >= 0 78 | v = @head[e] 79 | u2 = @match[v] 80 | if u2 < 0 || (!@visited[u2] && @dist[u2] == @dist[u1] + 1 && dfs(u2)) 81 | @match[v] = u1 82 | return (@used[u1] = true) 83 | end 84 | e = @prev[e] 85 | end 86 | false 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /src/crystalg/graph/flow_graph.cr: -------------------------------------------------------------------------------- 1 | require "../graph" 2 | 3 | module Crystalg::Graph 4 | # C: type of capacity 5 | class FlowGraph(C) 6 | getter size 7 | 8 | def initialize(@size : Int32) 9 | @graph = Array(Array(Tuple(NodeID, C, Int32))).new(@size) { 10 | Array(Tuple(NodeID, C, Int32)).new 11 | } 12 | end 13 | 14 | def add(edge : FlowEdge(C)) 15 | @graph[edge.source] << {edge.target, edge.capacity, @graph[edge.target].size} 16 | @graph[edge.target] << {edge.source, C.zero, @graph[edge.source].size - 1} 17 | end 18 | 19 | def adjacent_nodes(node_id : NodeID) : Array(Tuple(NodeID, C, Int32)) 20 | @graph[node_id].map do |target_id, capacity, rev| 21 | {target_id, capacity, rev} 22 | end 23 | end 24 | 25 | def flow(v : NodeID, index : Int32, f : C) : C 26 | e = @graph[v][index] 27 | r = @graph[e[0]][e[2]] 28 | @graph[v][index] = {e[0], e[1] - f, e[2]} 29 | @graph[e[0]][e[2]] = {r[0], r[1] + f, r[2]} 30 | f 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /src/crystalg/graph/graph.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Graph 2 | alias NodeID = Int32 3 | 4 | abstract class Graph(C) 5 | abstract def size : Int32 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/crystalg/graph/shortest_path/dijkstra.cr: -------------------------------------------------------------------------------- 1 | require "../graph" 2 | 3 | module Crystalg::Graph::ShortestPath 4 | module Dijkstra(C) 5 | def dijkstra(start : NodeID) : Array(Tuple(C, NodeID?)?) 6 | que = PriorityQueue(Tuple(C, NodeID)).new 7 | result = Array(Tuple(C, NodeID?)?).new(@size, nil) 8 | 9 | start_state = {0, start} 10 | que.push(start_state) 11 | result[start] = {0, nil} 12 | 13 | until (current_state = que.pop!).nil? 14 | current_cost, node_id = current_state 15 | adjacent_nodes(node_id).each do |target_id, target_cost| 16 | is_visited = !result[target_id].nil? 17 | cost = current_cost + target_cost 18 | 19 | next if is_visited && gte?(cost, result[target_id]) 20 | 21 | result[target_id] = {cost, node_id} 22 | que.push({cost, target_id}) 23 | end 24 | end 25 | result 26 | end 27 | 28 | private def gte?(cost_to_target : C, target_result : Tuple(C, NodeID?)?) 29 | target_node_result = target_result.as(Tuple(C, NodeID?)) 30 | target_node_result[0] <= cost_to_target 31 | end 32 | 33 | def get_dijkstra_path(node_id : NodeID, dijkstra_result : Array(Tuple(C, NodeID?)?)) : Array(NodeID) 34 | path = [] of NodeID 35 | return path if dijkstra_result[node_id].nil? 36 | 37 | until node_id.nil? 38 | Helper.assert(!dijkstra_result[node_id].nil?) 39 | 40 | path << node_id 41 | _cost, prev_node_id = dijkstra_result[node_id].as(Tuple(C, NodeID?)) 42 | node_id = prev_node_id 43 | end 44 | path.reverse! 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src/crystalg/graph/spanning_tree/kruskal.cr: -------------------------------------------------------------------------------- 1 | require "../graph" 2 | require "../../data_structures/*" 3 | 4 | module Crystalg::Graph::SpanningTree 5 | module Kruskal(C) 6 | def kruskal : Array(Edge(C)) 7 | union_find = UnionFind.new(@size) 8 | result = Array(Edge(C)).new 9 | 10 | edges.sort.each do |edge| 11 | if !union_find.same?(edge.source, edge.target) 12 | union_find.unite(edge.source, edge.target) 13 | result << edge 14 | end 15 | end 16 | result 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /src/crystalg/graph/undirected_graph.cr: -------------------------------------------------------------------------------- 1 | require "./connected_components/*" 2 | require "./spanning_tree/*" 3 | 4 | module Crystalg::Graph 5 | # C: type of cost 6 | class UndirectedGraph(C) < Graph(C) 7 | getter size : Int32 8 | 9 | def initialize(@size : Int32) 10 | @graph = Array(Array(Tuple(NodeID, C))).new(@size) { 11 | Array(Tuple(NodeID, C)).new 12 | } 13 | end 14 | 15 | def add(edge : Edge(C)) 16 | @graph[edge.source] << {edge.target, edge.cost} 17 | @graph[edge.target] << {edge.source, edge.cost} 18 | end 19 | 20 | def adjacent_nodes(node_id : NodeID) : Array(Tuple(NodeID, C)) 21 | @graph[node_id].map do |e| 22 | {e[0], e[1]} 23 | end 24 | end 25 | 26 | def edges : Array(Edge(C)) 27 | result = Array(Edge(C)).new 28 | (0...@size).each do |node_id| 29 | adjacent_nodes(node_id).each do |target_id, cost| 30 | result << Edge(C).new(node_id, target_id, cost) if node_id < target_id 31 | end 32 | end 33 | result.uniq! 34 | end 35 | 36 | include ConnectedComponents::ArticulationPoints 37 | include ConnectedComponents::Bridges(C) 38 | include SpanningTree::Kruskal(C) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /src/crystalg/helper.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | module Crystalg::Helper 3 | def self.assert(pred : Bool) 4 | return if pred 5 | raise "Error: you've found a bug. Please open an issue, including source code that will allow us to reproduce the bug: https://github.com/TobiasGSmollett/crystalg/issues" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/carmichael.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | def carmichael(n) 3 | result = 1 4 | n /= 2 if n % 8 == 0 5 | (2..n).each do |d| 6 | if n % d == 0 7 | y = d - 1 8 | n /= d 9 | while n % d == 0 10 | n /= d 11 | y *= d 12 | end 13 | result = lcm(result, y) 14 | end 15 | end 16 | result 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/euclid.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | def gcd(a, b) 3 | while b != 0 4 | a, b = b, (a % b).to_i 5 | end 6 | a.abs 7 | end 8 | 9 | def lcm(a, b) 10 | (a / gcd(a, b) * b).abs 11 | end 12 | 13 | # returns {gcd(a,b), x, y} such that gcd(a,b) == a*x + b*y 14 | def extgcd(a, b) 15 | x, y, u, v = 0, 1, 1, 0 16 | while a != 0 17 | q = (b / a).to_i 18 | x, u = u, x - q * u 19 | y, v = v, y - q * v 20 | a, b = b - q * a, a 21 | end 22 | {b, x, y} 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/euler_phi.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | # count the totatives of n that is the positive integers 3 | # less than or equal to n that are relatively prime to n 4 | def phi(n) 5 | res = n 6 | i = 2 7 | while i * i <= n 8 | if (n % i == 0) 9 | while n % i == 0 10 | n = n / i 11 | end 12 | res -= res / i 13 | end 14 | i += 1 15 | end 16 | res -= res / n if n > 1 17 | res 18 | end 19 | 20 | def phi_list(n) 21 | result = (0..n).to_a 22 | (1..n).each do |i| 23 | j = 2 * i 24 | while j <= n 25 | result[j] -= result[i] 26 | j += i 27 | end 28 | end 29 | result 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/mobius.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | def mobius(n) 3 | result = 1 4 | (2..n).each do |d| 5 | return 0 if n % (d * d) == 0 6 | if n % d == 0 7 | n /= d 8 | result *= -1 9 | end 10 | end 11 | result 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/mod.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | module Mod 3 | def self.mod(a, m) 4 | (a = a % m) >= 0 ? a : a + m 5 | end 6 | 7 | def self.inverse(a, m) 8 | raise "precondition: self > 0" if m <= 0 9 | raise "precondition: gcd(self, m) == 1" if gcd(a, m) != 1 10 | extgcd(a, m).x.mod m 11 | end 12 | 13 | def self.pow(y, exp, mod) 14 | result = 1 15 | while 0 < exp 16 | result = result * y % mod if (exp & 1) != 0 17 | y = y &* y % mod 18 | exp = exp >> 1 19 | end 20 | result 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/prime_number.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | def divisor(n) 3 | result = Array(Int32).new 4 | (1..Math.sqrt(n).to_i).each do |i| 5 | if (n % i == 0) 6 | result << i 7 | result << (n / i).to_i if i != n / i 8 | end 9 | end 10 | result 11 | end 12 | 13 | def prime?(n) 14 | i = 2 15 | while i * i <= n 16 | return false if n % i == 0 17 | i += 1 18 | end 19 | n != 1 20 | end 21 | 22 | def prime_factorize(n) 23 | result = Hash(Int32, Int32).new 24 | 25 | (2..Math.sqrt(n).to_i).each do |i| 26 | count = 0 27 | while n % i == 0 28 | count += 1 29 | n = (n / i).to_i 30 | end 31 | result[i] = count if count > 0 32 | end 33 | result[n] = 1 if n != 1 34 | result 35 | end 36 | 37 | def sieve_of_eratosthenes(n) 38 | result = Array(Bool).new(n + 1, true) 39 | result[0] = result[1] = false 40 | (2..Math.sqrt(n).to_i).each do |i| 41 | if (result[i] == true) 42 | (i*i..n).step(i).each { |i| result[j] = false } 43 | end 44 | end 45 | result 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src/crystalg/number_theory/stern_brocot_tree.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::NumberTheory 2 | struct Fraction 3 | getter numerator : Int32 4 | getter denominator : Int32 5 | 6 | def initialize(@numerator, @denominator) 7 | end 8 | end 9 | 10 | class SternBrocotTree 11 | private struct Node 12 | getter left : Fraction 13 | getter right : Fraction 14 | getter middle 15 | 16 | def initialize(@left, @right) 17 | end 18 | 19 | def middle 20 | Fraction.new( 21 | left.numerator + right.numerator, 22 | left.denominator + right.denominator 23 | ) 24 | end 25 | end 26 | 27 | private def rec(x, range, result) 28 | middle = range.middle 29 | return if middle.numerator + middle.denominator > x 30 | rec(x, Node.new(range.left, middle), result) 31 | result << middle 32 | rec(x, Node.new(middle, range.right), result) 33 | end 34 | 35 | def run(height) 36 | left, right = Fraction.new(0, 1), Fraction.new(1, 0) 37 | result = Array(Fraction).new 38 | rec(height, Node.new(left, right), result) 39 | result 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/crystalg/random/xor128.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Random 2 | class Xor128 3 | @seed : Array(UInt64) 4 | 5 | def initialize(s : UInt64) 6 | @seed = (1..4).map do |i| 7 | s = 1812433253_u64 &* (s ^ (s >> 30)) + i 8 | end 9 | end 10 | 11 | def get : UInt64 12 | t = (@seed[0] ^ (@seed[0] << 11)) 13 | @seed[0], @seed[1], @seed[2] = @seed[1], @seed[2], @seed[3] 14 | @seed[3] = (@seed[3] ^ (@seed[3] >> 19)) ^ (t ^ (t >> 8)) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/crystalg/strings/aho_corasick.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Strings 2 | class AhoCorasick 3 | class Node 4 | property parent : Int32 5 | property link : Int32 6 | property char : Char 7 | property is_leaf : Bool 8 | 9 | def initialize 10 | @parent = 0 11 | @link = -1 12 | @char = '\0' 13 | @is_leaf = false 14 | @children = Array(Int32).new(128, -1) 15 | @next = Array(Int32).new(128, -1) 16 | end 17 | end 18 | 19 | property size : Int32 20 | property nodes : Array(Node) 21 | ROOT = 0 22 | 23 | def initialize(max_node) 24 | @size = 0 25 | @nodes = Array(Node).new(max_node) { Node.new } 26 | @nodes[ROOT].link = ROOT 27 | @nodes[ROOT].parent = -1 28 | end 29 | 30 | def add(str) 31 | cur = ROOT 32 | str.each_char do |ch| 33 | c = ch.bytes.first 34 | if @nodes[cur].@children[c] == -1 35 | @size += 1 36 | @nodes[@size].parent = cur 37 | @nodes[@size].char = ch 38 | @nodes[cur].@children[c] = @size 39 | end 40 | cur = @nodes[cur].@children[c] 41 | end 42 | @nodes[cur].is_leaf = true 43 | end 44 | 45 | def failure(id) 46 | if @nodes[id].link == -1 47 | if @nodes[id].parent == ROOT 48 | @nodes[id].link = ROOT 49 | else 50 | @nodes[id].link = goto(failure(@nodes[id].parent), @nodes[id].char) 51 | end 52 | end 53 | @nodes[id].link 54 | end 55 | 56 | def goto(id, char) 57 | c = char.bytes.first 58 | if @nodes[id].@next[c] == -1 59 | if @nodes[id].@children[c] != -1 60 | @nodes[id].@next[c] = @nodes[id].@children[c] 61 | elsif id == ROOT 62 | @nodes[id].@next[c] = ROOT 63 | else 64 | @nodes[id].@next[c] = goto(failure(id), char) 65 | end 66 | end 67 | @nodes[id].@next[c] 68 | end 69 | 70 | def contain?(target : String) 71 | cur = ROOT 72 | target.each_char do |ch| 73 | cur = @nodes[cur].@children[ch.bytes.first] 74 | return false if cur < 0 75 | end 76 | @nodes[cur].is_leaf 77 | end 78 | 79 | def match_suffix?(target : String) 80 | cur = ROOT 81 | target.each_char { |ch| cur = goto(cur, ch) } 82 | @nodes[cur].is_leaf 83 | end 84 | 85 | def match_prefixes(target : String) : Array(String) 86 | cur = ROOT 87 | target.each_char do |ch| 88 | cur = @nodes[cur].@children[ch.bytes.first] 89 | return [] of String if cur < 0 90 | end 91 | result = [] of String 92 | que = [{cur, target}] 93 | loop do 94 | return result if que.empty? 95 | cur, acc = que.shift 96 | now = @nodes[cur] 97 | result << acc if now.is_leaf 98 | now.@children.each do |child| 99 | next if child < 0 100 | next_char = @nodes[child].char 101 | que << {child, acc + next_char} 102 | end 103 | end 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /src/crystalg/strings/baker_bird.cr: -------------------------------------------------------------------------------- 1 | require "../*" 2 | 3 | module Crystalg::Strings 4 | class BakerBird 5 | def initialize(@text : Array(String)) 6 | size = @text.reduce(0) { |acc, str| acc + str.size } 7 | @aho_corasick = AhoCorasick.new(size) 8 | end 9 | 10 | def search(pattern) 11 | pattern.each { |row| @aho_corasick.add row } 12 | acc = Array(Int32).new 13 | pattern.each do |str| 14 | node_id = 0 15 | str.each_char do |char| 16 | node_id = @aho_corasick.goto node_id, char 17 | acc << node_id if @aho_corasick.@nodes[node_id].is_leaf 18 | end 19 | end 20 | 21 | til = @text[0].size 22 | td = Array(Array(Int32)).new(til) { Array(Int32).new(@text.size, 0) } 23 | 24 | @text.each_with_index do |row, i| 25 | node_id = 0 26 | row.each_char_with_index do |e, j| 27 | node_id = @aho_corasick.goto node_id, @text[i][j] 28 | td[til - j - 1][i] = node_id 29 | end 30 | end 31 | 32 | result = Array(Tuple(Int32, Int32)).new 33 | a = Array(Int32).new(acc.size + @text.size + 2, -1) 34 | sl = acc.size + @text.size + 1 35 | (0...til).each do |i| 36 | s = acc.dup 37 | s << -1 38 | 39 | (0...@text.size).each { |j| s << td[i][j] } 40 | j = -1 41 | (0...sl).each do |k| 42 | while j >= 0 && s[k] != s[j] 43 | j = a[j] 44 | end 45 | j += 1 46 | a[k + 1] = j 47 | end 48 | (acc.size + 1..sl).each do |k| 49 | result << {k - acc.size * 2 - 1, til - i - pattern[0].size} if a[k] == acc.size 50 | end 51 | end 52 | result 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /src/crystalg/strings/kmp.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Strings 2 | def kmp(target : String, pattern : String) : Array(Int32) 3 | # initialize 4 | n = Array(Int32).new(pattern.size + 1, 0) 5 | j, n[0] = -1, -1 6 | (0...pattern.size).each do |i| 7 | while j >= 0 && pattern[i] != pattern[j] 8 | j = n[j] 9 | end 10 | j = j + 1 11 | n[i + 1] = j 12 | end 13 | 14 | result = Array(Int32).new 15 | j = 0 16 | (0...target.size).each do |i| 17 | while j >= 0 && target[i] != pattern[j] 18 | j = n[j] 19 | end 20 | j += 1 21 | if j == pattern.size 22 | result << i - pattern.size + 1 23 | j = n[j] 24 | end 25 | end 26 | result 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/crystalg/strings/rolling_hash.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Strings 2 | class RollingHash 3 | private PRIME = 1000000007 4 | 5 | def initialize(@str : String) 6 | @pow = Array(Int64).new(@str.size + 1) 7 | @phash = Array(Int64).new(@str.size + 1) 8 | @pow << 1_i64 9 | @phash << 0_i64 10 | @str.each_char_with_index do |ch, i| 11 | @phash << ch.bytes.first.to_i64 &+ @phash[i] &* PRIME 12 | @pow << @pow[i] &* PRIME 13 | end 14 | end 15 | 16 | def hash(t) 17 | t.chars.reduce(0_i64) { |acc, ch| ch.bytes.first.to_i64 &+ acc &* PRIME } 18 | end 19 | 20 | def hash(b, e) 21 | @phash[e] &- @phash[b] &* @pow[e - b] 22 | end 23 | 24 | def count(t) 25 | w = t.size 26 | result = 0 27 | if w < @str.size 28 | h = hash t 29 | result = result &+ (0..@str.size - w).count { |i| hash(i, i + w) == h } 30 | end 31 | result 32 | end 33 | 34 | def lcp(i, j) 35 | l = 0 36 | r = @str.size - Math.max(i, j) + 1 37 | while l + 1 < r 38 | m = (l + r) >> 1 39 | if hash(i, i + m) == hash(j, j + m) 40 | l = m 41 | else 42 | r = m 43 | end 44 | end 45 | l 46 | end 47 | 48 | private def compare(i, j) 49 | k = lcp i, j 50 | if i + k >= @str.size 51 | -1 52 | elsif j + k >= @str.size 53 | 1 54 | elsif @str[i + k] == @str[j + k] 55 | 0 56 | else 57 | @str[i + k] < @str[j + k] ? -1 : 1 58 | end 59 | end 60 | 61 | def get_suffix_array 62 | suffix_array = (0...@str.size + 1).to_a 63 | suffix_array.sort { |a, b| compare a, b } 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /src/crystalg/strings/suffix_array.cr: -------------------------------------------------------------------------------- 1 | module Crystalg::Strings 2 | class SuffixArray 3 | getter suffix_array : Array(Int32) 4 | getter rank : Array(Int32) 5 | 6 | def initialize(@target : String) 7 | @target += '\0' 8 | @suffix_array = (0...@target.size).to_a 9 | @rank = @target.chars.map { |char| char.bytes.first.to_i32 } 10 | @lcp = Array(Int32).new(@target.size, 0) 11 | end 12 | 13 | def construct 14 | n = @target.size 15 | 16 | # suffix array in O(n log^2 n) 17 | len = 1 18 | while len < n 19 | tmp = Array(Int64).new(n, 0_i64) 20 | (0...n).each do |i| 21 | tmp[i] = (@rank[i].to_i64 << 32) + (i + len < n ? @rank[i + len] + 1 : 0) 22 | end 23 | 24 | @suffix_array = @suffix_array.sort { |a, b| tmp[a] <=> tmp[b] } 25 | 26 | (0...n).each do |i| 27 | j = @suffix_array[i] 28 | k = @suffix_array[i - 1] 29 | @rank[j] = 30 | if i > 0 && tmp[k] == tmp[j] 31 | @rank[k] 32 | else 33 | i 34 | end 35 | end 36 | len *= 2 37 | end 38 | 39 | # longest common prefixes array in O(n) 40 | h = 0 41 | (0...n).each do |i| 42 | if @rank[i] + 1 < n 43 | j = @suffix_array[@rank[i] + 1] 44 | while Math.max(i, j) + h < n && @target[i + h] == @target[j + h] 45 | h += 1 46 | end 47 | @lcp[@rank[i]] = h 48 | h -= 1 if h > 0 49 | end 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /src/crystalg/version.cr: -------------------------------------------------------------------------------- 1 | module Crystalg 2 | VERSION = "0.1.0" 3 | end 4 | --------------------------------------------------------------------------------