├── .gitignore ├── compile.sh ├── merge.sh ├── relation.v ├── .travis.yml ├── distribution_functions.v ├── README.md ├── random_number_generation.v ├── main.v └── entity.v /.gitignore: -------------------------------------------------------------------------------- 1 | popgenerator 2 | popgenerator.v 3 | other_code.v 4 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./merge.sh 4 | 5 | v popgenerator.v 6 | -------------------------------------------------------------------------------- /merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -f other_code.v 4 | rm -f popgenerator.v 5 | 6 | ls *.v | grep -v "main.v" | xargs -I {} cat {} >> other_code.v 7 | cat main.v other_code.v >> popgenerator.v 8 | -------------------------------------------------------------------------------- /relation.v: -------------------------------------------------------------------------------- 1 | struct Relation { 2 | id_a int 3 | id_b int 4 | distance int 5 | } 6 | 7 | fn (r Relation) print() string { 8 | return r.id_a.str() + ' ' + r.id_b.str() + ' ' + r.distance.str() + '\n' 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: minimal 2 | 3 | before_install: 4 | - wget https://github.com/vlang/v/archive/master.zip 5 | - unzip master.zip 6 | - cd v-master 7 | - make 8 | - cd .. 9 | - chmod +x merge.sh 10 | - ./merge.sh 11 | 12 | script: 13 | - v-master/v popgenerator.v 14 | -------------------------------------------------------------------------------- /distribution_functions.v: -------------------------------------------------------------------------------- 1 | // #### population size along temporal space #### 2 | fn temporal_distribution(i int) int { 3 | x := f64(i) 4 | res := 10.0 * math.sin(0.01 * (x - 0.1)) + 20.0 5 | return int(math.round(res)) 6 | } 7 | 8 | // #### x structure along the social space #### 9 | fn x_distribution(i int) int { 10 | x := f64(i) 11 | res := 10.0 * math.sin(0.01 * (x - 0.1)) + 10.0 12 | return int(math.round(res)) 13 | } 14 | 15 | // #### y structure along the social space #### 16 | fn y_distribution(i int) int { 17 | x := f64(i) 18 | res := 10.0 * math.sin(0.01 * (x - 0.1)) + 10.0 19 | return int(math.round(res)) 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/nevrome/popgenerator.svg?token=vxsQ9RjxoGASGtX4Q8jc&branch=master)](https://travis-ci.com/nevrome/popgenerator) 2 | 3 | ## popgenerator 4 | 5 | popgenerator is a population network generator. 6 | 7 | ``` 8 | popgenerator 9 | ``` 10 | 11 | ## Installation 12 | 13 | ``` 14 | git clone git@github.com:nevrome/popgenerator.git 15 | wget https://github.com/vlang/v/archive/master.zip 16 | unzip master.zip 17 | cd v-master 18 | make 19 | cd .. 20 | chmod +x merge.sh 21 | ./merge.sh 22 | v-master/v popgenerator.v 23 | ``` 24 | 25 | ## Citation 26 | 27 | ``` 28 | @Manual{clemens_schmid_popgenerator_2019, 29 | title = {Popgenerator: A Population Network Generator}, 30 | author = {Clemens Schmid}, 31 | year = {2019} 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /random_number_generation.v: -------------------------------------------------------------------------------- 1 | fn random_integer(max int) int { 2 | return rand.next(max) 3 | } 4 | 5 | // https://www.geeksforgeeks.org/random-number-generator-in-arbitrary-probability-distribution-fashion/ 6 | // returns a random number from arr[] according to 7 | // distribution array defined by freq[]. n is size of arrays. 8 | fn random_integer_distribution(arr[] int, freq[] int, n int) int { 9 | // Create and fill prefix array 10 | mut prefix := [0; n] 11 | prefix[0] = freq[0] 12 | for i := 1; i < n; i++ { 13 | prefix[i] = prefix[i - 1] + freq[i] 14 | } 15 | // prefix[n-1] is sum of all frequencies. Generate a random number 16 | // with value from 1 to this sum 17 | r := (random_integer(prefix[n - 1])) + 1 18 | // Find index of ceiling of r in prefix arrat 19 | indexc := find_ceil(prefix, r, 0, n - 1) 20 | return arr[indexc] 21 | } 22 | 23 | // Utility function to find ceiling of r in arr[l..h] 24 | fn find_ceil(arr[] int, r int, l int, h int) int { 25 | mut mid := 0 26 | mut le := l 27 | mut he := h 28 | for { 29 | mid = (le + he) / 2 30 | if r > arr[mid] { le = mid + 1 } else { he = mid } 31 | if !(le < he) { break } 32 | } 33 | mut res := 0 34 | if arr[le] >= r { res = le } else { res = -1 } 35 | return res 36 | } 37 | -------------------------------------------------------------------------------- /main.v: -------------------------------------------------------------------------------- 1 | import rand 2 | import math 3 | import os 4 | import time 5 | 6 | fn main() { 7 | 8 | rand.seed(time.now().uni) 9 | 10 | // #### read input args #### 11 | input_config_file_path := os.args[1] 12 | output_pajek_file_path := os.args[2] 13 | 14 | // #### create parameter variables #### 15 | mut end_time := 0 16 | mut end_x := 0 17 | mut end_y := 0 18 | mut number_of_entities := 0 19 | mut neighbours_distance := 0 20 | 21 | // #### read config file #### 22 | input_config_file_content := os.read_file(input_config_file_path.trim_space()) or { 23 | println('failed to open $input_config_file_path') 24 | return 25 | } 26 | 27 | input_config_file_lines := input_config_file_content.split(';') 28 | config_number_lines := input_config_file_lines.len - 1 29 | 30 | for i := 0; i < config_number_lines; i++ { 31 | mut input_config_file_line := input_config_file_lines[i] 32 | mut config_values_array := input_config_file_line.split('=') 33 | mut name := config_values_array[0].trim_space() 34 | mut value := config_values_array[1].trim_space() 35 | 36 | println('$name = $value') 37 | 38 | if name == 'end_time' { 39 | end_time = value.int() 40 | } 41 | if name == 'end_x' { 42 | end_x = value.int() 43 | } 44 | if name == 'end_y' { 45 | end_y = value.int() 46 | } 47 | if name == 'number_of_entities' { 48 | number_of_entities = value.int() 49 | } 50 | if name == 'neighbours_distance' { 51 | neighbours_distance = value.int() 52 | } 53 | } 54 | 55 | // #### create sequences#### 56 | mut time_arr := [0; end_time] 57 | for i := 0; i < end_time; i++ { 58 | time_arr[i] = i 59 | } 60 | mut x_arr := [0; end_x] 61 | for i := 0; i < end_x; i++ { 62 | x_arr[i] = i 63 | } 64 | mut y_arr := [0; end_y] 65 | for i := 0; i < end_y; i++ { 66 | y_arr[i] = i 67 | } 68 | 69 | // #### calculate frequencies #### 70 | mut time_freq := [0; end_time] 71 | for i := 0; i < end_time; i++ { 72 | time_freq[i] = temporal_distribution(i) 73 | } 74 | mut x_freq := [0; end_x] 75 | for i := 0; i < end_x; i++ { 76 | x_freq[i] = x_distribution(i) 77 | } 78 | mut y_freq := [0; end_y] 79 | for i := 0; i < end_y; i++ { 80 | y_freq[i] = y_distribution(i) 81 | } 82 | 83 | // #### create entities #### 84 | mut entities := []Entity 85 | for entity_counter := 0; entity_counter < number_of_entities; entity_counter++ { 86 | // draw temporal coordinate 87 | entity_time := random_integer_distribution(time_arr, time_freq, end_time) 88 | // draw social coordinates 89 | entity_x := random_integer_distribution(x_arr, x_freq, end_x) 90 | entity_y := random_integer_distribution(y_arr, y_freq, end_y) 91 | // construct entities 92 | entities << Entity{ 93 | id: entity_counter, 94 | time: entity_time, 95 | x: entity_x, 96 | y: entity_y 97 | } 98 | } 99 | 100 | // endless social world 101 | //entities_cube := cubify_entities(entities, end_time, end_x, end_y) 102 | 103 | // social world with boundaries 104 | entities_cube := entities 105 | 106 | // #### determine relations #### 107 | mut relations := []Relation 108 | for entity_a in entities { 109 | for entity_b in entities_cube { 110 | if (entity_a.id != entity_b.id) && 111 | (entity_b.time <= entity_a.time + neighbours_distance) && 112 | (entity_b.time >= entity_a.time - neighbours_distance) && 113 | (entity_b.x <= entity_a.x + neighbours_distance) && 114 | (entity_b.x >= entity_a.x - neighbours_distance) && 115 | (entity_b.y <= entity_a.y + neighbours_distance) && 116 | (entity_b.y >= entity_a.y - neighbours_distance) { 117 | distance := int(math.sqrt( 118 | math.pow(f64(entity_a.time - entity_b.time), 2.0) + 119 | math.pow(f64(entity_a.x - entity_b.x), 2.0) + 120 | math.pow(f64(entity_a.y - entity_b.y), 2.0) 121 | )) 122 | relations << Relation{ 123 | id_a: entity_a.id, 124 | id_b: entity_b.id, 125 | distance: distance 126 | } 127 | } 128 | } 129 | } 130 | 131 | // #### save result #### 132 | output_pajek_file := os.create(output_pajek_file_path) or { 133 | println(error) 134 | return 135 | } 136 | output_pajek_file.write('*Network popgenerator_network \n') 137 | output_pajek_file.write('*Vertices $number_of_entities \n') 138 | for entity in entities { 139 | output_pajek_file.write(entity.print()) 140 | } 141 | output_pajek_file.write('*Edges \n') 142 | for relation in relations { 143 | output_pajek_file.write(relation.print()) 144 | } 145 | output_pajek_file.close() 146 | 147 | } 148 | -------------------------------------------------------------------------------- /entity.v: -------------------------------------------------------------------------------- 1 | struct Entity { 2 | id int 3 | time int 4 | x int 5 | y int 6 | } 7 | 8 | fn (e Entity) print() string { 9 | return e.id.str() + ' ' + e.time.str() + ' ' + e.x.str() + ' ' + e.y.str() + '\n' 10 | } 11 | 12 | // cubification function to enable endless world 13 | fn cubify_entities(entities []Entity, end_time int, end_x int, end_y int) []Entity { 14 | mut cubified_entities := []Entity 15 | for entity in entities { 16 | 17 | // top 18 | /* 19 | cubified_entities << Entity{ 20 | id: entity.id, 21 | time: entity.time + end_time, 22 | x: entity.x, 23 | y: entity.y 24 | } 25 | cubified_entities << Entity{ 26 | id: entity.id, 27 | time: entity.time + end_time, 28 | x: entity.x + end_x, 29 | y: entity.y 30 | } 31 | cubified_entities << Entity{ 32 | id: entity.id, 33 | time: entity.time + end_time, 34 | x: entity.x - end_x, 35 | y: entity.y 36 | } 37 | cubified_entities << Entity{ 38 | id: entity.id, 39 | time: entity.time + end_time, 40 | x: entity.x, 41 | y: entity.y + end_y 42 | } 43 | cubified_entities << Entity{ 44 | id: entity.id, 45 | time: entity.time + end_time, 46 | x: entity.x, 47 | y: entity.y - end_y 48 | } 49 | cubified_entities << Entity{ 50 | id: entity.id, 51 | time: entity.time + end_time, 52 | x: entity.x + end_x, 53 | y: entity.y + end_y 54 | } 55 | cubified_entities << Entity{ 56 | id: entity.id, 57 | time: entity.time + end_time, 58 | x: entity.x - end_x, 59 | y: entity.y - end_y 60 | } 61 | cubified_entities << Entity{ 62 | id: entity.id, 63 | time: entity.time + end_time, 64 | x: entity.x + end_x, 65 | y: entity.y - end_y 66 | } 67 | cubified_entities << Entity{ 68 | id: entity.id, 69 | time: entity.time + end_time, 70 | x: entity.x - end_x, 71 | y: entity.y + end_y 72 | } 73 | */ 74 | 75 | // middle 76 | cubified_entities << Entity{ 77 | id: entity.id, 78 | time: entity.time, 79 | x: entity.x, 80 | y: entity.y 81 | } 82 | cubified_entities << Entity{ 83 | id: entity.id, 84 | time: entity.time, 85 | x: entity.x + end_x, 86 | y: entity.y 87 | } 88 | cubified_entities << Entity{ 89 | id: entity.id, 90 | time: entity.time, 91 | x: entity.x - end_x, 92 | y: entity.y 93 | } 94 | cubified_entities << Entity{ 95 | id: entity.id, 96 | time: entity.time, 97 | x: entity.x, 98 | y: entity.y + end_y 99 | } 100 | cubified_entities << Entity{ 101 | id: entity.id, 102 | time: entity.time, 103 | x: entity.x, 104 | y: entity.y - end_y 105 | } 106 | cubified_entities << Entity{ 107 | id: entity.id, 108 | time: entity.time, 109 | x: entity.x + end_x, 110 | y: entity.y + end_y 111 | } 112 | cubified_entities << Entity{ 113 | id: entity.id, 114 | time: entity.time, 115 | x: entity.x - end_x, 116 | y: entity.y - end_y 117 | } 118 | cubified_entities << Entity{ 119 | id: entity.id, 120 | time: entity.time, 121 | x: entity.x + end_x, 122 | y: entity.y - end_y 123 | } 124 | cubified_entities << Entity{ 125 | id: entity.id, 126 | time: entity.time, 127 | x: entity.x - end_x, 128 | y: entity.y + end_y 129 | } 130 | 131 | // bottom 132 | /* 133 | cubified_entities << Entity{ 134 | id: entity.id, 135 | time: entity.time - end_time, 136 | x: entity.x, 137 | y: entity.y 138 | } 139 | cubified_entities << Entity{ 140 | id: entity.id, 141 | time: entity.time - end_time, 142 | x: entity.x + end_x, 143 | y: entity.y 144 | } 145 | cubified_entities << Entity{ 146 | id: entity.id, 147 | time: entity.time - end_time, 148 | x: entity.x - end_x, 149 | y: entity.y 150 | } 151 | cubified_entities << Entity{ 152 | id: entity.id, 153 | time: entity.time - end_time, 154 | x: entity.x, 155 | y: entity.y + end_y 156 | } 157 | cubified_entities << Entity{ 158 | id: entity.id, 159 | time: entity.time - end_time, 160 | x: entity.x, 161 | y: entity.y - end_y 162 | } 163 | cubified_entities << Entity{ 164 | id: entity.id, 165 | time: entity.time - end_time, 166 | x: entity.x + end_x, 167 | y: entity.y + end_y 168 | } 169 | cubified_entities << Entity{ 170 | id: entity.id, 171 | time: entity.time - end_time, 172 | x: entity.x - end_x, 173 | y: entity.y - end_y 174 | } 175 | cubified_entities << Entity{ 176 | id: entity.id, 177 | time: entity.time - end_time, 178 | x: entity.x + end_x, 179 | y: entity.y - end_y 180 | } 181 | cubified_entities << Entity{ 182 | id: entity.id, 183 | time: entity.time - end_time, 184 | x: entity.x - end_x, 185 | y: entity.y + end_y 186 | } 187 | */ 188 | 189 | } 190 | return cubified_entities 191 | } 192 | --------------------------------------------------------------------------------