├── run_all.sh ├── config.cpp ├── run_accuracy.sh ├── run_or.sh ├── run_twitter.sh ├── mylib.cpp ├── run_dblp.sh ├── CMakeLists.txt ├── run_lj.sh ├── run_wiki.sh ├── run_webs.sh ├── README.md ├── graph.h ├── heap.h ├── rng.h ├── Makefile ├── constrain.h ├── constrain_ratio.h ├── config.h ├── constrain_linear.h ├── mylib.h ├── agenda.cpp └── LICENSE /run_all.sh: -------------------------------------------------------------------------------- 1 | sudo apt install libopenblas-dev liblapack-dev libarpack2-dev libsuperlu-dev libboost-all-dev 2 | -------------------------------------------------------------------------------- /config.cpp: -------------------------------------------------------------------------------- 1 | #include "mylib.h" 2 | #include "config.h" 3 | 4 | 5 | Config config; 6 | Result result; 7 | 8 | bool exists_test(const std::string &name) { 9 | ifstream f(name.c_str()); 10 | if (f.good()) { 11 | f.close(); 12 | return true; 13 | } 14 | else { 15 | f.close(); 16 | return false; 17 | } 18 | } 19 | 20 | void assert_file_exist(string desc, string name) { 21 | 22 | if (!exists_test(name)) { 23 | cerr << desc << " " << name << " not find " << endl; 24 | exit(1); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /run_accuracy.sh: -------------------------------------------------------------------------------- 1 | cmake . 2 | 3 | make 4 | 5 | rate=(0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9) 6 | ## Agenda 7 | # for rt in "${rate[@]}" 8 | # do 9 | # rm /home/zulun/Project/data/dblp/lazyup.txt 10 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate 1 --timewin 10 --with_idx --shuffle --esf ${rt} --check_size 10 11 | # ./agenda calc-acc --prefix ../data/ --dataset dblp --esf ${rt} 12 | # done 13 | ## Fora 14 | for rt in "${rate[@]}" 15 | do 16 | rm /home/zulun/Project/data/dblp/fora.txt 17 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate 4 --timewin 10 --with_idx --shuffle --esf ${rt} --check_size 10 18 | ./agenda calc-acc --prefix ../data/ --dataset dblp --esf ${rt} 19 | done -------------------------------------------------------------------------------- /run_or.sh: -------------------------------------------------------------------------------- 1 | cmake . 2 | 3 | make 4 | 5 | rate=(0.125 0.25 0.5 1 2 4 8) 6 | 7 | ## Agenda 8 | for rt in "${rate[@]}" 9 | do 10 | ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset orkutt --lambdaq 0.1 --rate ${rt} --timewin 1000 --with_idx 11 | done 12 | 13 | ### Fora free 14 | # for rt in "${rate[@]}" 15 | # do 16 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset orkutt --lambdaq 0.1 --rate 1 --timewin 1000 17 | # done 18 | 19 | ### Fora+ index 20 | 21 | for rt in "${rate[@]}" 22 | do 23 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset orkutt --lambdaq 0.1 --rate ${rt} --timewin 1000 --with_idx 24 | done 25 | 26 | ### Resacc 27 | 28 | # for rt in "${rate[@]}" 29 | # do 30 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset orkutt --lambdaq 0.1 --rate 1 --timewin 1000 31 | # done -------------------------------------------------------------------------------- /run_twitter.sh: -------------------------------------------------------------------------------- 1 | cmake . 2 | 3 | make 4 | 5 | rate=(0.125 0.25 0.5 1 2 4 8) 6 | 7 | # ## Agenda 8 | # for rt in "${rate[@]}" 9 | # do 10 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset twitter --lambdaq 0.01 --rate ${rt} --timewin 10000 --with_idx 11 | # done 12 | 13 | ### Fora free 14 | # for rt in "${rate[@]}" 15 | # do 16 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset twitter --lambdaq 0.01 --rate 1 --timewin 10000 17 | # done 18 | 19 | ### Fora+ index 20 | 21 | 22 | 23 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset twitter --lambdaq 0.01 --rate 0.125 --timewin 10000 --with_idx 24 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset twitter --lambdaq 0.01 --rate 0.25 --timewin 10000 --with_idx 25 | 26 | ### Resacc 27 | 28 | # for rt in "${rate[@]}" 29 | # do 30 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset twitter --lambdaq 0.01 --rate 1 --timewin 10000 31 | # done 32 | -------------------------------------------------------------------------------- /mylib.cpp: -------------------------------------------------------------------------------- 1 | #include "mylib.h" 2 | 3 | 4 | template 5 | string toStr(T t) { 6 | stringstream ss; 7 | ss << t; 8 | return ss.str(); 9 | } 10 | 11 | string __n_variable(string t, int n) { 12 | t = t + ','; 13 | int i = 0; 14 | if (n) for (; i < SIZE(t) && n; i++) if (t[i] == ',') n--; 15 | n = i; 16 | for (; t[i] != ','; i++); 17 | t = t.substr((unsigned long) n, (unsigned long) (i - n)); 18 | trim(t); 19 | if (t[0] == '"') return ""; 20 | return t + "="; 21 | } 22 | 23 | int Counter::cnt[1000] = {0}; 24 | 25 | vector Timer::timeUsed; 26 | vector Timer::timeUsedDesc; 27 | vector Timer::time_one_time; 28 | 29 | #ifndef WIN32 30 | #ifdef __CYGWIN__ 31 | 32 | //CYGWIN 33 | uint64 rdtsc() { 34 | uint64 t0; 35 | asm volatile("rdtsc" : "=A"(t0)); 36 | return t0; 37 | } 38 | 39 | #else 40 | //LINUX 41 | uint64 rdtsc(void) 42 | { 43 | unsigned a, d; 44 | //asm("cpuid"); 45 | asm volatile("rdtsc" : "=a" (a), "=d" (d)); 46 | return (((uint64)a) | (((uint64)d) << 32)); 47 | } 48 | #endif 49 | #endif 50 | 51 | 52 | -------------------------------------------------------------------------------- /run_dblp.sh: -------------------------------------------------------------------------------- 1 | 2 | # ./agenda build --prefix ./data/ --dataset dblp --epsilon 0.5 --beta 1 --alter_idx 3 | # ./agenda build --prefix ./data/ --dataset dblp --epsilon 0.5 --beta 5 --baton 4 | # ./agenda build --prefix ./data/ --dataset dblp --epsilon 0.5 --beta 1 5 | 6 | cmake . 7 | 8 | make 9 | 10 | rate=(0.125 0.25 0.5 1 2 4 8) 11 | ## Agenda 12 | for rt in "${rate[@]}" 13 | do 14 | ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate ${rt} --timewin 10 --with_idx 15 | done 16 | 17 | ### Fora 18 | for rt in "${rate[@]}" 19 | do 20 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate ${rt} --timewin 10 21 | done 22 | 23 | ## Fora+ 24 | 25 | for rt in "${rate[@]}" 26 | do 27 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate ${rt} --timewin 10 --with_idx 28 | done 29 | 30 | ### Resacc 31 | 32 | for rt in "${rate[@]}" 33 | do 34 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset dblp --lambdaq 10 --rate ${rt} --timewin 10 35 | done -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(fora) 2 | # Specify the minimum version for CMake 3 | cmake_minimum_required(VERSION 2.8) 4 | 5 | #SET(CMAKE_CXX_FLAGS "-std=c++11 -O3 -Wall") 6 | SET(CMAKE_CXX_FLAGS "-std=c++11 -O3 -DNDEBUG -w -pthread -lboost_serialization -lboost_filesystem -lboost_system") 7 | #SET(CMAKE_CXX_FLAGS "-std=c++11 -O3 -w -pthread") 8 | 9 | 10 | find_package(Boost REQUIRED unit_test_framework filesystem system date_time program_options) 11 | #find_package(Threads) 12 | 13 | #set(HEADER algo.h build_oracle.h config.h graph.h head.h heap.h mylib.h query.h) 14 | #set(PPRLIB mylib.cpp config.cpp) 15 | 16 | # Set the output folder where your program will be created 17 | set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}) 18 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) 19 | set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) 20 | 21 | # The following folder will be included 22 | include_directories("${PROJECT_SOURCE_DIR}") 23 | find_package(Armadillo REQUIRED) 24 | include_directories(${ARMADILLO_INCLUDE_DIRS}) 25 | 26 | #add_library(mylib ${PROJECT_SOURCE_DIR}/mylib.cpp ${PROJECT_SOURCE_DIR}/mylib.h) 27 | #add_library(config ${PROJECT_SOURCE_DIR}/config.cpp ${PROJECT_SOURCE_DIR}/config.h) 28 | 29 | add_executable(agenda ${PROJECT_SOURCE_DIR}/agenda.cpp ${PROJECT_SOURCE_DIR}/mylib.cpp ${PROJECT_SOURCE_DIR}/config.cpp) 30 | #add_executable(HubPPR hubppr.cpp ${PPRLIB} ${HEADER}) 31 | 32 | target_link_libraries(agenda pthread boost_serialization boost_filesystem boost_system ${ARMADILLO_LIBRARIES}) -------------------------------------------------------------------------------- /run_lj.sh: -------------------------------------------------------------------------------- 1 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --query_size 20 --timewin 1036 --with_idx 2 | 3 | # for ((j=80; j<=320; j=j+80)) 4 | # do 5 | # echo $j 6 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --query_size $j --timewin 1036 --with_idx 7 | # done 8 | cmake . 9 | 10 | make 11 | 12 | rate=(0.125 0.25 0.5 1 2 4 8) 13 | # ./agenda test_linear --algo lazyup --lambdaq 0.1 --lambdau 0.3 --timewin 1000 --prefix ../data/ --dataset livejournal --with_idx 14 | 15 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 0.125 --timewin 1000 --with_idx 16 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 0.25 --timewin 1000 --with_idx 17 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 0.5 --timewin 1000 --with_idx 18 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 2 --timewin 1000 --with_idx 19 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 4 --timewin 1000 --with_idx 20 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate 8 --timewin 1000 --with_idx 21 | 22 | 23 | ### Fora 24 | for rt in "${rate[@]}" 25 | do 26 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate ${rt} --timewin 1000 27 | done 28 | 29 | ### Fora+ 30 | 31 | for rt in "${rate[@]}" 32 | do 33 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate ${rt} --timewin 1000 --with_idx 34 | done 35 | 36 | ### Resacc 37 | 38 | for rt in "${rate[@]}" 39 | do 40 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset livejournal --lambdaq 0.1 --rate ${rt} --timewin 1000 41 | done -------------------------------------------------------------------------------- /run_wiki.sh: -------------------------------------------------------------------------------- 1 | 2 | # ./agenda build --prefix ../data/ --dataset wiki --epsilon 0.5 --beta 1 --alter_idx 3 | # ./agenda build --prefix ../data/ --dataset wiki --epsilon 0.5 --beta 5 --baton 4 | # ./agenda build --prefix ../data/ --dataset wiki --epsilon 0.5 --beta 1 5 | 6 | ./agenda generate-ss-query --prefix ../data/ --dataset wiki --query_size 1000 7 | ./agenda gen-update --prefix ../data/ --dataset wiki --query_size 1000 8 | 9 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 80 --timewin 4 --with_idx 10 | 11 | 12 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 20 --timewin 4 --with_idx 13 | 14 | # for ((j=80; j<=320; j=j+80)) 15 | # do 16 | # echo $j 17 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size $j --timewin 4 --with_idx 18 | # done 19 | 20 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 380 --timewin 4 --with_idx 21 | 22 | 23 | 24 | 25 | 26 | # ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 20 --timewin 428 --with_idx 27 | 28 | # for ((j=80; j<=320; j=j+80)) 29 | # do 30 | # echo $j 31 | # ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size $j --timewin 428 --with_idx 32 | # done 33 | 34 | # ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 380 --timewin 428 --with_idx 35 | 36 | # ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 20 --timewin 12 37 | # for ((j=80; j<=320; j=j+80)) 38 | # do 39 | # echo $j 40 | # ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size $j --timewin 12 41 | # done 42 | # ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 380 --timewin 12 43 | 44 | # ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 20 --timewin 49 --with_idx 45 | # for ((j=80; j<=320; j=j+80)) 46 | # do 47 | # echo $j 48 | # ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size $j --timewin 49 --with_idx 49 | # done 50 | 51 | # ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset wiki --query_size 380 --timewin 49 --with_idx 52 | 53 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 1 --alter_idx 54 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 5 --baton 55 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 1 56 | 57 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 1 --alter_idx 58 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 5 --baton 59 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 1 60 | 61 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 1 --alter_idx 62 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 5 --baton 63 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 1 64 | 65 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 1 --alter_idx 66 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 5 --baton 67 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 1 -------------------------------------------------------------------------------- /run_webs.sh: -------------------------------------------------------------------------------- 1 | 2 | # ./agenda build --prefix ./data/ --dataset webstanford --epsilon 0.5 --beta 1 --alter_idx 3 | # ./agenda build --prefix ./data/ --dataset webstanford --epsilon 0.5 --beta 5 --baton 4 | # ./agenda build --prefix ./data/ --dataset webstanford --epsilon 0.5 --beta 1 5 | 6 | # ./agenda generate-ss-query --prefix ./data/ --dataset webstanford --query_size 1000 7 | # ./agenda gen-update --prefix ./data/ --dataset webstanford --query_size 1000 8 | 9 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 80 --timewin 4 --with_idx 10 | 11 | 12 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 20 --timewin 4 --with_idx 13 | 14 | # for ((j=80; j<=320; j=j+80)) 15 | # do 16 | # echo $j 17 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size $j --timewin 4 --with_idx 18 | # done 19 | 20 | # ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 380 --timewin 4 --with_idx 21 | 22 | 23 | 24 | 25 | 26 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 20 --timewin 428 --with_idx 27 | 28 | for ((j=80; j<=320; j=j+80)) 29 | do 30 | echo $j 31 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size $j --timewin 428 --with_idx 32 | done 33 | 34 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 380 --timewin 428 --with_idx 35 | 36 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 20 --timewin 12 37 | for ((j=80; j<=320; j=j+80)) 38 | do 39 | echo $j 40 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size $j --timewin 12 41 | done 42 | ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 380 --timewin 12 43 | 44 | ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 20 --timewin 49 --with_idx 45 | for ((j=80; j<=320; j=j+80)) 46 | do 47 | echo $j 48 | ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size $j --timewin 49 --with_idx 49 | done 50 | 51 | ./agenda dynamic-ss --algo fora --alter_idx --epsilon 0.5 --prefix ../data/ --dataset webstanford --query_size 380 --timewin 49 --with_idx 52 | 53 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 1 --alter_idx 54 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 5 --baton 55 | # ./agenda build --prefix ../data/ --dataset dblp --epsilon 0.5 --beta 1 56 | 57 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 1 --alter_idx 58 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 5 --baton 59 | # ./agenda build --prefix ../data/ --dataset livejournal --epsilon 0.5 --beta 1 60 | 61 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 1 --alter_idx 62 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 5 --baton 63 | # ./agenda build --prefix ../data/ --dataset orkutt --epsilon 0.5 --beta 1 64 | 65 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 1 --alter_idx 66 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 5 --baton 67 | # ./agenda build --prefix ../data/ --dataset twitter --epsilon 0.5 --beta 1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Tested Environment 2 | - Ubuntu 16 3 | - C++ 11 4 | - GCC 5.4 5 | - Boost 6 | - cmake 7 | 8 | ## Install the library 9 | ### Install some essential library 10 | ```sh 11 | $ sudo apt install libopenblas-dev liblapack-dev libarpack2-dev libsuperlu-dev libboost-all-dev 12 | ``` 13 | ### Install armadillo 14 | ```sh 15 | $ git clone https://gitlab.com/conradsnicta/armadillo-code.git 16 | $ cd armadillo-code/ 17 | $ cmake . 18 | $ sudo make install 19 | ``` 20 | ### Install ensmallen 21 | ```sh 22 | $ git clone https://github.com/mlpack/ensmallen.git 23 | $ cd ensmallen 24 | $ mkdir build 25 | $ cd build 26 | $ cmake .. 27 | $ sudo make install 28 | ``` 29 | 30 | ## Compile 31 | ```sh 32 | $ cmake . 33 | $ make 34 | ``` 35 | 36 | # For temporary test of optimal response time measurements 37 | ```sh 38 | $ bash run_webs.sh 39 | ``` 40 | 41 | ## Parameters 42 | ```sh 43 | ./agenda action_name --algo [options] 44 | ``` 45 | - action: 46 | - query: static SSPPR query 47 | - build: build index, for FORA only 48 | - dynamic-ss: dynamic SSPPR query 49 | - algo: which algorithm you prefer to run 50 | - baton: Baton 51 | - fora: FORA 52 | - partup: Agenda with partial update 53 | - lazyup: Agenda with lazy update 54 | - resacc: ResAcc 55 | - options 56 | - --prefix \ 57 | - --epsilon \ 58 | - --dataset \ 59 | - --query_size \ 60 | - --update_size \ 61 | - --with_idx 62 | - --beta: controls the trade-off between random walk and forward push 63 | 64 | 65 | 66 | ## Data 67 | The example data format is in `./data/webstanford/` folder. The data for DBLP, Pokec, Orkut, LiveJournal, Twitter are not included here for size limitation reason. You can find them online. 68 | 69 | ## Generate workloads 70 | Generate query files for the graph data. Each line contains a node id. 71 | 72 | ```sh 73 | $ ./agenda generate-ss-query --prefix --dataset --query_size 74 | ``` 75 | 76 | ```sh 77 | $ ./agenda gen-update --prefix --dataset --query_size 78 | ``` 79 | 80 | - Example: 81 | 82 | ```sh 83 | $ ./agenda generate-ss-query --prefix ./data/ --dataset webstanford --query_size 1000 84 | ``` 85 | 86 | ## Indexing 87 | Construct index files for the graph data using a single core. 88 | 89 | - Example 90 | 91 | For FORA index: 92 | ```sh 93 | $ ./agenda build --prefix ./data/ --dataset webstanford --epsilon 0.5 94 | ``` 95 | For Baton and Agenda index: 96 | ```sh 97 | $ ./agenda build --prefix ./data/ --dataset webstanford --epsilon 0.5 --baton 98 | ``` 99 | 100 | ## Query 101 | Process queries. 102 | 103 | ```sh 104 | $ ./agenda --algo --prefix --dataset --result_dir --epsilon --query_size --update_size [--with-idx --exact] 105 | ``` 106 | 107 | - Example: 108 | 109 | For SSPPR query on static graphs 110 | 111 | ```sh 112 | // FORA 113 | $ ./agenda query --algo fora --prefix ./data/ --dataset webstanford --epsilon 0.5 --query_size 200 114 | 115 | // FORA+ 116 | $ ./agenda query --algo fora --prefix ./data/ --dataset webstanford --epsilon 0.5 --query_size 200 --with_idx 117 | 118 | // Agenda 119 | $ ./agenda query --algo genda --prefix ./data/ --dataset webstanford --epsilon 0.5 --query_size 200 --with_idx 120 | ``` 121 | 122 | For SSPPR query on dynamic graphs: 123 | ```sh 124 | // FORA 125 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 200 --update_size 200 --with_idx 126 | 127 | // FORA+ 128 | ./agenda dynamic-ss --algo fora --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 200 --update_size 200 129 | 130 | // Baton 131 | ./agenda dynamic-ss --algo baton --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 200 --update_size 200 --with_idx 132 | 133 | // ResAcc 134 | $ ./agenda dynamic-ss --algo resacc --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 200 --update_size 200 --with_idx 135 | 136 | // Agenda 137 | $ ./agenda dynamic-ss --algo lazyup --epsilon 0.5 --prefix ./data/ --dataset webstanford --query_size 200 --update_size 200 --with_idx 138 | 139 | 140 | ``` 141 | 142 | 143 | -------------------------------------------------------------------------------- /graph.h: -------------------------------------------------------------------------------- 1 | #ifndef __GRAPH_H__ 2 | #define __GRAPH_H__ 3 | 4 | #include "mylib.h" 5 | #include "config.h" 6 | 7 | class Graph { 8 | public: 9 | 10 | vector> g; 11 | vector> gr; 12 | string data_folder; 13 | 14 | //vector global_ppr; 15 | 16 | // node rank[100] = 0, means node 100 has first rank 17 | vector node_rank; 18 | // node_score[0] 19 | vector node_score; 20 | 21 | //node order 0 = [100, 34.5], most important node is 100 with score 34.5 22 | vector> node_order; 23 | vector loc; 24 | 25 | 26 | // the tele ratio for random walk 27 | double alpha; 28 | 29 | static bool cmp(const pair &t1, const pair &t2) { 30 | return t1.second > t2.second; 31 | } 32 | 33 | int n; 34 | long long m; 35 | 36 | Graph(string data_folder) { 37 | INFO("sub constructor"); 38 | this->data_folder = data_folder; 39 | this->alpha = ALPHA_DEFAULT; 40 | if(config.action != GEN_SS_QUERY&&config.action != CALCULATE_ACCURACY) 41 | init_graph(); 42 | else 43 | init_nm(); 44 | cout << "init graph n: " << this->n << " m: " << this->m << endl; 45 | } 46 | 47 | 48 | void init_nm() { 49 | string attribute_file = data_folder + FILESEP + "attribute.txt"; 50 | assert_file_exist("attribute file", attribute_file); 51 | ifstream attr(attribute_file); 52 | string line1, line2; 53 | char c; 54 | while (true) { 55 | attr >> c; 56 | if (c == '=') break; 57 | } 58 | attr >> n; 59 | while (true) { 60 | attr >> c; 61 | if (c == '=') break; 62 | } 63 | attr >> m; 64 | } 65 | 66 | void init_graph() { 67 | init_nm(); 68 | g = vector>(n, vector()); 69 | gr = vector>(n, vector()); 70 | string graph_file = data_folder + FILESEP + "graph.txt"; 71 | assert_file_exist("ab_values", graph_file); 72 | FILE *fin = fopen(graph_file.c_str(), "r"); 73 | int t1, t2; 74 | while (fscanf(fin, "%d%d", &t1, &t2) != EOF) { 75 | assert(t1 < n); 76 | assert(t2 < n); 77 | if(t1 == t2) continue; 78 | 79 | g[t1].push_back(t2); 80 | gr[t2].push_back(t1); 81 | 82 | } 83 | } 84 | 85 | 86 | double get_avg_degree() const { 87 | return double(m) / double(n); 88 | } 89 | 90 | 91 | }; 92 | 93 | 94 | 95 | static void init_parameter(Config &config, const Graph &graph) { 96 | // init the bwd delta, fwd delta etc 97 | 98 | //INFO("init parameters", graph.n); 99 | config.delta = 1.0 / graph.n; 100 | config.pfail = 1.0 / graph.n; 101 | 102 | config.dbar = double(graph.m) / double(graph.n); // average degree 103 | 104 | 105 | } 106 | 107 | static void set_optimal_beta(Config &config, const Graph &graph) { 108 | // init the bwd delta, fwd delta etc 109 | 110 | //INFO("init parameters", graph.n); 111 | double theta=0.8; 112 | double epsilon_f=config.epsilon*(1-config.sigma); 113 | double K=(2+epsilon_f)*log(2/config.pfail)/config.delta/epsilon_f/epsilon_f; 114 | double C_2=K*config.query_size; 115 | double C_1=graph.m*config.query_size/config.alpha/10+2*5*config.update_size*double(graph.n)/(1-theta)/config.epsilon/config.delta/config.alpha/config.alpha/K; 116 | config.beta=sqrt(C_2/C_1)/4; 117 | INFO(double(graph.n)); 118 | INFO(config.epsilon,config.delta,config.alpha,(1-theta),K); 119 | INFO(C_1,C_2,graph.m*config.query_size/config.alpha/10,2*5*config.update_size*double(graph.n)/(1-theta)/config.epsilon/config.delta/config.alpha/config.alpha/K); 120 | INFO(config.beta); 121 | 122 | } 123 | 124 | static void set_optimal_beta_onehop(Config &config, const Graph &graph) { 125 | double theta=0.8; 126 | double epsilon_f=config.epsilon*(1-config.sigma); 127 | double K=(2+epsilon_f)*log(2/config.pfail)/config.delta/epsilon_f/epsilon_f; 128 | double C_2=K*config.query_size; 129 | double C_1=graph.m*config.query_size/config.alpha/10+2*5*config.update_size*double(graph.n)/(1-theta)/config.epsilon/config.delta/config.alpha/config.alpha/K; 130 | config.beta=sqrt(C_2/C_1)/4; 131 | INFO(double(graph.n)); 132 | INFO(config.epsilon,config.delta,config.alpha,(1-theta),K); 133 | INFO(C_1,C_2,graph.m*config.query_size/config.alpha/10,2*5*config.update_size*double(graph.n)/(1-theta)/config.epsilon/config.delta/config.alpha/config.alpha/K); 134 | INFO(config.beta); 135 | 136 | } 137 | 138 | 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /heap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by tyz on 2015/11/24. 3 | // 4 | 5 | #ifndef PPR_HEAP_H 6 | #define PPR_HEAP_H 7 | 8 | 9 | /* 10 | * C++ Program to Implement Binary Heap 11 | */ 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | /* 20 | * Class Declaration 21 | */ 22 | template> 23 | class BinaryHeap { 24 | private: 25 | vector> heap; 26 | vector heap_idx; 27 | 28 | int left(int parent) { 29 | int l = 2 * parent + 1; 30 | if (l < int(heap.size())) 31 | return l; 32 | else 33 | return -1; 34 | } 35 | 36 | 37 | int right(int parent) { 38 | int r = 2 * parent + 2; 39 | if (r < int(heap.size())) 40 | return r; 41 | else 42 | return -1; 43 | } 44 | 45 | int parent(int child) { 46 | int p = (child - 1) / 2; 47 | if (child == 0) 48 | return -1; 49 | else 50 | return p; 51 | } 52 | 53 | 54 | void heapswap(int x, int y) { 55 | swap(heap_idx[heap[x].second], heap_idx[heap[y].second]); 56 | swap(heap[x], heap[y]); 57 | } 58 | 59 | void heapifyup(int in) { 60 | while (true) { 61 | int pin = parent(in); 62 | // if smaller than parent then swap 63 | if (in >= 0 && pin >= 0 && comp(heap[in].first, heap[pin].first)) { 64 | heapswap(in, pin); 65 | in = pin; 66 | } 67 | else 68 | break; 69 | } 70 | } 71 | 72 | 73 | void heapifydown(int in) { 74 | while (true) { 75 | int child = left(in); 76 | int child1 = right(in); 77 | // child point to smaller one 78 | if (child >= 0 && child1 >= 0 && comp(heap[child1].first, heap[child].first)) { 79 | child = child1; 80 | } 81 | // if child is smaller, then swap 82 | if (child > 0 && comp(heap[child].first, heap[in].first)) { 83 | heapswap(in, child); 84 | in = child; 85 | } 86 | else { 87 | break; 88 | } 89 | } 90 | } 91 | 92 | Compare comp; 93 | // comp return true means more close to root 94 | public: 95 | BinaryHeap(int maxn, Compare _comp = std::less()) { 96 | heap_idx = vector((unsigned long) maxn + 10, -1); 97 | comp = _comp; 98 | // cout << comp(1, 2) << endl; 99 | // cout << comp(2, 1) << endl; 100 | } 101 | 102 | map as_map() { 103 | map rtn; 104 | for (auto item: heap) { 105 | rtn[item.second] = item.first; 106 | } 107 | return rtn; 108 | }; 109 | 110 | vector>& get_elements(){ 111 | return heap; 112 | } 113 | 114 | T get_value(int idx) { 115 | return heap[heap_idx[idx]].first; 116 | }; 117 | 118 | void insert(int index, T element) { 119 | heap_idx[index] = (int) heap.size(); 120 | heap.push_back(MP(element, index)); 121 | heapifyup(int(heap.size()) - 1); 122 | } 123 | 124 | void delete_top() { 125 | if (heap.size() == 0) { 126 | cout << "Heap is Empty" << endl; 127 | return; 128 | } 129 | heapswap(0, (int) (heap.size() - 1)); 130 | heap_idx[heap.back().second] = -1; 131 | heap.pop_back(); 132 | heapifydown(0); 133 | //cout << "Element Deleted" << endl; 134 | } 135 | 136 | void modify(int index, T newvalue) { 137 | int idx = heap_idx[index]; 138 | if (comp(newvalue, heap[idx].first)) { 139 | heap[idx].first = newvalue; 140 | heapifyup(idx); 141 | } 142 | else { 143 | heap[idx].first = newvalue; 144 | heapifydown(idx); 145 | } 146 | } 147 | 148 | pair extract_top() { 149 | return heap.front(); 150 | } 151 | 152 | void display() { 153 | cout << "Heap --> "; 154 | for (auto p:heap) { 155 | cout << p.first << " "; 156 | } 157 | cout << endl; 158 | 159 | } 160 | 161 | int size() { 162 | return int(heap.size()); 163 | } 164 | 165 | void clear() { 166 | // heap.clear(); 167 | while (size()) 168 | delete_top(); 169 | } 170 | 171 | // return true is has index 172 | bool has_idx(int idx) { 173 | return heap_idx[idx] != -1; 174 | } 175 | 176 | void verify() { 177 | for (int child = 0; child < heap.size(); ++child) { 178 | int p = parent(child); 179 | if (p >= 0) 180 | // child cannot be smaller than parent 181 | assert (!comp(heap[child].first, heap[p].first)); 182 | 183 | } 184 | } 185 | }; 186 | 187 | 188 | #endif //PPR_HEAP_H 189 | -------------------------------------------------------------------------------- /rng.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // The code in this file is free and unencumbered software released 5 | // into the public domain. 6 | // 7 | // . 8 | // 9 | 10 | #ifndef RNG_H 11 | #define RNG_H 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #if defined(_MSC_VER) 18 | /* Microsoft C/C++-compatible compiler 19 | * Adaptive implementations 20 | */ 21 | #include 22 | #define _rdtsc() __rdtsc() 23 | 24 | #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) 25 | /* GCC-compatible compiler, targeting x86/x86-64 26 | * NO implementation needed 27 | */ 28 | #include 29 | 30 | #elif defined(__GNUC__) && defined(__ARM_NEON__) 31 | /* GCC-compatible compiler, targeting ARM with NEON 32 | * Adaptive implementations 33 | */ 34 | #include 35 | 36 | #elif defined(__GNUC__) && defined(__IWMMXT__) 37 | /* GCC-compatible compiler, targeting ARM with WMMX 38 | * Adaptive implementations 39 | */ 40 | #include 41 | 42 | #elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) 43 | /* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX 44 | * Adaptive implementations 45 | */ 46 | #include 47 | 48 | #elif defined(__GNUC__) && defined(__SPE__) 49 | /* GCC-compatible compiler, targeting PowerPC with SPE 50 | * Adaptive implementations 51 | */ 52 | #include 53 | 54 | #endif 55 | 56 | namespace rng { 57 | 58 | // 59 | // Bitwise circular left shift. 60 | // 61 | static inline std::uint64_t 62 | rotl(const std::uint64_t x, int k) 63 | { 64 | return (x << k) | (x >> (64 - k)); 65 | } 66 | 67 | // 68 | // A simple random seed generator based on the entropy coming from the 69 | // system thread/process scheduler. This is rather slow but seeds are 70 | // normally generated very infrequently. 71 | // 72 | struct tsc_seed 73 | { 74 | using result_type = std::uint64_t; 75 | 76 | result_type operator()() 77 | { 78 | std::uint64_t base = _rdtsc(); 79 | std::uint64_t seed = base & 0xff; 80 | for (int i = 1; i < 8; i++) { 81 | std::this_thread::yield(); 82 | seed |= ((_rdtsc() - base) & 0xff) << (i << 3); 83 | } 84 | return seed; 85 | } 86 | }; 87 | 88 | // 89 | // A random seed generator based on std::random_device. 90 | // 91 | struct random_device_seed 92 | { 93 | using result_type = std::uint64_t; 94 | 95 | result_type operator()() 96 | { 97 | std::random_device rd; 98 | if (sizeof(result_type) > sizeof(std::random_device::result_type)) 99 | return rd() | (result_type{rd()} << 32); 100 | else 101 | return rd(); 102 | } 103 | }; 104 | 105 | // 106 | // A random number generator with 64-bit internal state. It is based on 107 | // the code from here: http://xoroshiro.di.unimi.it/splitmix64.c 108 | // 109 | struct rng64 110 | { 111 | using result_type = std::uint64_t; 112 | 113 | std::uint64_t state; 114 | 115 | rng64(std::uint64_t seed = 1) : state{seed} {} 116 | 117 | result_type operator()() 118 | { 119 | std::uint64_t z = (state += UINT64_C(0x9E3779B97F4A7C15)); 120 | z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); 121 | z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB); 122 | return z ^ (z >> 31); 123 | } 124 | }; 125 | 126 | // 127 | // A random number generator with 128-bit internal state. It is based on 128 | // the code from here: http://xoroshiro.di.unimi.it/xoroshiro128plus.c 129 | // 130 | struct rng128 131 | { 132 | using result_type = std::uint64_t; 133 | 134 | std::uint64_t state[2]; 135 | 136 | rng128(std::uint64_t seed[2]) : state{seed[0], seed[1]} {} 137 | 138 | rng128(std::uint64_t s0, std::uint64_t s1) : state{s0, s1} {} 139 | 140 | rng128(std::uint64_t seed = 1) 141 | { 142 | rng64 seeder(seed); 143 | state[0] = seeder(); 144 | state[1] = seeder(); 145 | } 146 | 147 | result_type operator()() 148 | { 149 | const uint64_t s0 = state[0]; 150 | uint64_t s1 = state[1]; 151 | const uint64_t value = s0 + s1; 152 | 153 | s1 ^= s0; 154 | state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); 155 | state[1] = rotl(s1, 36); 156 | 157 | return value; 158 | } 159 | 160 | // This is the jump function for the generator. It is equivalent 161 | // to 2 ^ 64 calls to next(); it can be used to generate 2 ^ 64 162 | // non-overlapping subsequences for parallel computations. 163 | void jump() 164 | { 165 | static const std::uint64_t j[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; 166 | 167 | std::uint64_t s0 = 0, s1 = 0; 168 | for (std::size_t i = 0; i < sizeof j / sizeof j[0]; i++) { 169 | for (int b = 0; b < 64; b++) { 170 | if ((j[i] & UINT64_C(1) << b) != 0) { 171 | s0 ^= state[0]; 172 | s1 ^= state[1]; 173 | } 174 | operator()(); 175 | } 176 | } 177 | 178 | state[0] = s0; 179 | state[1] = s1; 180 | } 181 | }; 182 | 183 | } // namespace rng 184 | 185 | #endif // RNG_H -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | 7 | .PHONY : default_target 8 | 9 | # Allow only one "make -f Makefile2" at a time, but pass parallelism. 10 | .NOTPARALLEL: 11 | 12 | 13 | #============================================================================= 14 | # Special targets provided by cmake. 15 | 16 | # Disable implicit rules so canonical targets will work. 17 | .SUFFIXES: 18 | 19 | 20 | # Remove some rules from gmake that .SUFFIXES does not remove. 21 | SUFFIXES = 22 | 23 | .SUFFIXES: .hpux_make_needs_suffix_list 24 | 25 | 26 | # Suppress display of executed commands. 27 | $(VERBOSE).SILENT: 28 | 29 | 30 | # A target that is always out of date. 31 | cmake_force: 32 | 33 | .PHONY : cmake_force 34 | 35 | #============================================================================= 36 | # Set environment variables for the build. 37 | 38 | # The shell in which to execute make rules. 39 | SHELL = /bin/sh 40 | 41 | # The CMake executable. 42 | CMAKE_COMMAND = /usr/bin/cmake 43 | 44 | # The command to remove a file. 45 | RM = /usr/bin/cmake -E remove -f 46 | 47 | # Escaping for special characters. 48 | EQUALS = = 49 | 50 | # The top-level source directory on which CMake was run. 51 | CMAKE_SOURCE_DIR = /home/zulun/Project/Agenda 52 | 53 | # The top-level build directory on which CMake was run. 54 | CMAKE_BINARY_DIR = /home/zulun/Project/Agenda 55 | 56 | #============================================================================= 57 | # Targets provided globally by CMake. 58 | 59 | # Special rule for the target rebuild_cache 60 | rebuild_cache: 61 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 62 | /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 63 | .PHONY : rebuild_cache 64 | 65 | # Special rule for the target rebuild_cache 66 | rebuild_cache/fast: rebuild_cache 67 | 68 | .PHONY : rebuild_cache/fast 69 | 70 | # Special rule for the target edit_cache 71 | edit_cache: 72 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." 73 | /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. 74 | .PHONY : edit_cache 75 | 76 | # Special rule for the target edit_cache 77 | edit_cache/fast: edit_cache 78 | 79 | .PHONY : edit_cache/fast 80 | 81 | # The main all target 82 | all: cmake_check_build_system 83 | $(CMAKE_COMMAND) -E cmake_progress_start /home/zulun/Project/Agenda/CMakeFiles /home/zulun/Project/Agenda/CMakeFiles/progress.marks 84 | $(MAKE) -f CMakeFiles/Makefile2 all 85 | $(CMAKE_COMMAND) -E cmake_progress_start /home/zulun/Project/Agenda/CMakeFiles 0 86 | .PHONY : all 87 | 88 | # The main clean target 89 | clean: 90 | $(MAKE) -f CMakeFiles/Makefile2 clean 91 | .PHONY : clean 92 | 93 | # The main clean target 94 | clean/fast: clean 95 | 96 | .PHONY : clean/fast 97 | 98 | # Prepare targets for installation. 99 | preinstall: all 100 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 101 | .PHONY : preinstall 102 | 103 | # Prepare targets for installation. 104 | preinstall/fast: 105 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 106 | .PHONY : preinstall/fast 107 | 108 | # clear depends 109 | depend: 110 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 111 | .PHONY : depend 112 | 113 | #============================================================================= 114 | # Target rules for targets named agenda 115 | 116 | # Build rule for target. 117 | agenda: cmake_check_build_system 118 | $(MAKE) -f CMakeFiles/Makefile2 agenda 119 | .PHONY : agenda 120 | 121 | # fast build rule for target. 122 | agenda/fast: 123 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/build 124 | .PHONY : agenda/fast 125 | 126 | agenda.o: agenda.cpp.o 127 | 128 | .PHONY : agenda.o 129 | 130 | # target to build an object file 131 | agenda.cpp.o: 132 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/agenda.cpp.o 133 | .PHONY : agenda.cpp.o 134 | 135 | agenda.i: agenda.cpp.i 136 | 137 | .PHONY : agenda.i 138 | 139 | # target to preprocess a source file 140 | agenda.cpp.i: 141 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/agenda.cpp.i 142 | .PHONY : agenda.cpp.i 143 | 144 | agenda.s: agenda.cpp.s 145 | 146 | .PHONY : agenda.s 147 | 148 | # target to generate assembly for a file 149 | agenda.cpp.s: 150 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/agenda.cpp.s 151 | .PHONY : agenda.cpp.s 152 | 153 | config.o: config.cpp.o 154 | 155 | .PHONY : config.o 156 | 157 | # target to build an object file 158 | config.cpp.o: 159 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/config.cpp.o 160 | .PHONY : config.cpp.o 161 | 162 | config.i: config.cpp.i 163 | 164 | .PHONY : config.i 165 | 166 | # target to preprocess a source file 167 | config.cpp.i: 168 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/config.cpp.i 169 | .PHONY : config.cpp.i 170 | 171 | config.s: config.cpp.s 172 | 173 | .PHONY : config.s 174 | 175 | # target to generate assembly for a file 176 | config.cpp.s: 177 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/config.cpp.s 178 | .PHONY : config.cpp.s 179 | 180 | mylib.o: mylib.cpp.o 181 | 182 | .PHONY : mylib.o 183 | 184 | # target to build an object file 185 | mylib.cpp.o: 186 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/mylib.cpp.o 187 | .PHONY : mylib.cpp.o 188 | 189 | mylib.i: mylib.cpp.i 190 | 191 | .PHONY : mylib.i 192 | 193 | # target to preprocess a source file 194 | mylib.cpp.i: 195 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/mylib.cpp.i 196 | .PHONY : mylib.cpp.i 197 | 198 | mylib.s: mylib.cpp.s 199 | 200 | .PHONY : mylib.s 201 | 202 | # target to generate assembly for a file 203 | mylib.cpp.s: 204 | $(MAKE) -f CMakeFiles/agenda.dir/build.make CMakeFiles/agenda.dir/mylib.cpp.s 205 | .PHONY : mylib.cpp.s 206 | 207 | # Help Target 208 | help: 209 | @echo "The following are some of the valid targets for this Makefile:" 210 | @echo "... all (the default if no target is provided)" 211 | @echo "... clean" 212 | @echo "... depend" 213 | @echo "... rebuild_cache" 214 | @echo "... edit_cache" 215 | @echo "... agenda" 216 | @echo "... agenda.o" 217 | @echo "... agenda.i" 218 | @echo "... agenda.s" 219 | @echo "... config.o" 220 | @echo "... config.i" 221 | @echo "... config.s" 222 | @echo "... mylib.o" 223 | @echo "... mylib.i" 224 | @echo "... mylib.s" 225 | .PHONY : help 226 | 227 | 228 | 229 | #============================================================================= 230 | # Special targets to cleanup operation of make. 231 | 232 | # Special rule to run CMake to check the build system integrity. 233 | # No rule that depends on this can have commands that come from listfiles 234 | # because they might be regenerated. 235 | cmake_check_build_system: 236 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 237 | .PHONY : cmake_check_build_system 238 | 239 | -------------------------------------------------------------------------------- /constrain.h: -------------------------------------------------------------------------------- 1 | 2 | // Example implementation of an objective function class for linear regression 3 | // and usage of the L-BFGS optimizer. 4 | // 5 | // Compilation: 6 | // g++ example.cpp -o example -O3 -larmadillo 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include "algo.h" 13 | #include "graph.h" 14 | #include "heap.h" 15 | #include "config.h" 16 | 17 | #include 18 | using namespace std; 19 | int iteration=0; 20 | // class LinearRegressionFunction 21 | // { 22 | // public: 23 | 24 | // LinearRegressionFunction(arma::mat& X, arma::vec& y) : X(X), y(y) { } 25 | 26 | // double EvaluateWithGradient(const arma::mat& theta, arma::mat& gradient) 27 | // { 28 | // const arma::vec tmp = X.t() * theta - y; 29 | // gradient = 2 * X * tmp; 30 | // return arma::dot(tmp,tmp); 31 | // } 32 | 33 | // private: 34 | 35 | // const arma::mat& X; 36 | // const arma::vec& y; 37 | // }; 38 | 39 | class ConstrainedFunctionType 40 | { 41 | public: 42 | //We set \Tilde{t}_q = a \beta_1\beta_2+b\beta_1+\frac{c}{\beta_1} 43 | // Return the objective function f(x) for the given x. 44 | double a,b,c,d; 45 | bool plot = false; 46 | void calculate_para(arma::mat x){ 47 | 48 | double tau0 = qtau1*x(0,0)/config.omega; 49 | double epsilon = config.epsilon/config.theta; 50 | double tau1 = qtau2*(1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega/ 51 | (x(0,0)*config.edges*(x(0,1)*config.nodes*config.rbmax+1)); 52 | double tau2 = qtau3*config.alpha*config.nodes/(x(0,0)*config.edges); 53 | double tau3 = utau1*x(0,1)*config.nodes*config.alpha*config.rbmax/config.edges; 54 | 55 | a = config.edges*(config.nodes*config.rbmax*tau1)/ 56 | ((1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega); 57 | 58 | 59 | 60 | b = config.edges*tau1/((1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega)+ 61 | config.edges*tau2/(config.alpha*config.nodes); 62 | 63 | c = config.omega*tau0; 64 | 65 | d = config.edges*tau3/(config.nodes*config.alpha*config.rbmax); 66 | 67 | // std::cout << "tau0 is " <0){ 94 | 95 | fx = (config.lambda_u*(config.mv_update.second+t_u*t_u)+config.lambda_q*(config.mv_query.second+t_q*t_q))/ 96 | ((1-config.lambda_u*t_u-config.lambda_q*t_q)*2)+t_q; 97 | y = fx; 98 | }else if(1-config.lambda_u*t_u-config.lambda_q*t_q==0){ 99 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q+0.1; 100 | 101 | }else{ 102 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q; 103 | y = -fx; 104 | } 105 | // } 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | //*** Output for visualization 114 | 115 | // if(plot == false){ 116 | // string filename = "/home/zulun/some_test/para.txt"; 117 | // ofstream queryfile(filename, ios::app); 118 | // queryfile<0){ 204 | return (config.lambda_u*t_u+config.lambda_q*t_q-1)*10; 205 | break; 206 | } 207 | else{ 208 | return 0; 209 | break; 210 | } 211 | 212 | case 1: if (t_q-config.response_t>0){ 213 | return (t_q-config.response_t)*100; 214 | break; 215 | } 216 | else{ 217 | return 0; 218 | break; 219 | } 220 | case 2: if (-x(0,0)>0){ 221 | return (-x(0,0))*100; 222 | break; 223 | } 224 | else{ 225 | return 0; 226 | break; 227 | } 228 | case 3: if (-x(0,1)>0){ 229 | return (-x(0,1))*100; 230 | break; 231 | } 232 | else{ 233 | return 0; 234 | break; 235 | } 236 | } 237 | 238 | }; 239 | 240 | // Evaluate the gradient of constraint i at the parameters x, storing the 241 | // result in the given matrix g. If the constraint is not satisfied, the 242 | // gradient should be set in such a way that the gradient points in the 243 | // direction where the constraint would be satisfied. 244 | void GradientConstraint(const size_t i, const arma::mat& x, arma::mat& g){ 245 | switch (i){ 246 | case 0: g = {config.lambda_q*(a*x(0,1)+b-c/(x(0,0)*x(0,0))),config.lambda_q*a*x(0,0)-config.lambda_u*d/(x(0,1)*x(0,1))}; 247 | break; 248 | case 1: g = {a*x(0,1)+b-c/(x(0,0)*x(0,0)),a*x(0,0)}; 249 | break; 250 | case 2: g = {-1,0}; 251 | break; 252 | case 3: g = {0,-1}; 253 | break; 254 | } 255 | }; 256 | 257 | 258 | }; 259 | 260 | pair improve_throughput() 261 | { 262 | 263 | arma::mat x,original; 264 | x = {1.0, 1.0}; 265 | original = x; 266 | ConstrainedFunctionType f; 267 | f.calculate_para(original); 268 | 269 | ens::AugLagrangian optimizer(1500,0.25,10); 270 | optimizer.Optimize(f, x); 271 | // output the log file 272 | string filename = config.graph_location + "result.txt"; 273 | ofstream queryfile(filename, ios::app); 274 | char str[50]; 275 | time_t now = time(NULL); 276 | strftime(str, 50, "%x %X", localtime(&now)); 277 | queryfile << str<(x(0,0), x(0,1)); 291 | } 292 | -------------------------------------------------------------------------------- /constrain_ratio.h: -------------------------------------------------------------------------------- 1 | // Example implementation of an objective function class for linear regression 2 | // and usage of the L-BFGS optimizer. 3 | // 4 | // Compilation: 5 | // g++ example.cpp -o example -O3 -larmadillo 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include "algo.h" 12 | #include "graph.h" 13 | #include "heap.h" 14 | #include "config.h" 15 | 16 | #include 17 | using namespace std; 18 | int iteration=0; 19 | // class LinearRegressionFunction 20 | // { 21 | // public: 22 | 23 | // LinearRegressionFunction(arma::mat& X, arma::vec& y) : X(X), y(y) { } 24 | 25 | // double EvaluateWithGradient(const arma::mat& theta, arma::mat& gradient) 26 | // { 27 | // const arma::vec tmp = X.t() * theta - y; 28 | // gradient = 2 * X * tmp; 29 | // return arma::dot(tmp,tmp); 30 | // } 31 | 32 | // private: 33 | 34 | // const arma::mat& X; 35 | // const arma::vec& y; 36 | // }; 37 | 38 | class ConstrainedFunctionType 39 | { 40 | public: 41 | //We set \Tilde{t}_q = a \beta_1\beta_2+b\beta_1+\frac{c}{\beta_1} 42 | // Return the objective function f(x) for the given x. 43 | double a,b,c,d; 44 | bool plot = false; 45 | void calculate_para(arma::mat x){ 46 | if(config.algo == LAZYUP){ 47 | double tau0 = qtau1*x(0,0)/config.omega; 48 | double epsilon = config.epsilon/config.theta; 49 | double tau1 = qtau2*(1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega/ 50 | (x(0,0)*config.edges*(x(0,1)*config.nodes*config.rbmax+1)); 51 | double tau2 = qtau3*config.alpha*config.nodes/(x(0,0)*config.edges); 52 | double tau3 = utau1*x(0,1)*config.nodes*config.alpha*config.rbmax/config.edges; 53 | 54 | a = config.edges*(config.nodes*config.rbmax*tau1)/ 55 | ((1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega); 56 | 57 | 58 | 59 | b = config.edges*tau1/((1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega)+ 60 | config.edges*tau2/(config.alpha*config.nodes); 61 | 62 | c = config.omega*tau0; 63 | 64 | d = config.edges*tau3/(config.nodes*config.alpha*config.rbmax); 65 | }else if(config.algo == FORA){ 66 | 67 | 68 | } 69 | // std::cout << "tau0 is " <0){ 96 | 97 | fx = (config.lambda_u*(config.mv_update.second+t_u*t_u)+config.lambda_q*(config.mv_query.second+t_q*t_q))/ 98 | ((1-config.lambda_u*t_u-config.lambda_q*t_q)*2)+t_q; 99 | y = fx; 100 | }else if(1-config.lambda_u*t_u-config.lambda_q*t_q==0){ 101 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q+0.1; 102 | 103 | }else{ 104 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q; 105 | y = -fx; 106 | } 107 | // } 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | //*** Output for visualization 116 | 117 | // if(plot == false){ 118 | // string filename = "/home/zulun/some_test/para.txt"; 119 | // ofstream queryfile(filename, ios::app); 120 | // queryfile<0){ 206 | return (config.lambda_u*t_u+config.lambda_q*t_q-1)*10; 207 | break; 208 | } 209 | else{ 210 | return 0; 211 | break; 212 | } 213 | case 1: if (-x(0,0)>0){ 214 | return (-x(0,0))*100000; 215 | break; 216 | } 217 | else{ 218 | return 0; 219 | break; 220 | } 221 | case 2: if (-x(0,1)>0){ 222 | return (-x(0,1))*100000; 223 | break; 224 | } 225 | else{ 226 | return 0; 227 | break; 228 | } 229 | // case 3: if (t_q-config.response_t>0){ 230 | // return (t_q-config.response_t)*100; 231 | // break; 232 | // } 233 | // else{ 234 | // return 0; 235 | // break; 236 | // } 237 | } 238 | 239 | }; 240 | 241 | // Evaluate the gradient of constraint i at the parameters x, storing the 242 | // result in the given matrix g. If the constraint is not satisfied, the 243 | // gradient should be set in such a way that the gradient points in the 244 | // direction where the constraint would be satisfied. 245 | void GradientConstraint(const size_t i, const arma::mat& x, arma::mat& g){ 246 | switch (i){ 247 | case 0: g = {config.lambda_q*(a*x(0,1)+b-c/(x(0,0)*x(0,0))),config.lambda_q*a*x(0,0)-config.lambda_u*d/(x(0,1)*x(0,1))}; 248 | break; 249 | // case 1: g = {a*x(0,1)+b-c/(x(0,0)*x(0,0)),a*x(0,0)}; 250 | // break; 251 | case 1: g = {-1,0}; 252 | break; 253 | case 2: g = {0,-1}; 254 | break; 255 | } 256 | }; 257 | 258 | 259 | }; 260 | 261 | pair improve_throughput() 262 | { 263 | 264 | arma::mat x,original; 265 | x = {1.0, 1.0}; 266 | original = x; 267 | ConstrainedFunctionType f; 268 | f.calculate_para(original); 269 | 270 | ens::AugLagrangian optimizer(1500,0.25,10); 271 | optimizer.Optimize(f, x); 272 | // output the log file 273 | string filename = config.graph_location + "result.txt"; 274 | ofstream queryfile(filename, ios::app); 275 | char str[50]; 276 | time_t now = time(NULL); 277 | strftime(str, 50, "%x %X", localtime(&now)); 278 | queryfile << str<(x(0,0), x(0,1)); 292 | } -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | 5 | #ifdef WIN32 6 | #define FILESEP "\\" 7 | #else 8 | #define FILESEP "/" 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using namespace boost; 24 | using namespace boost::property_tree; 25 | 26 | 27 | const double ALPHA_DEFAULT = 0.2; 28 | 29 | const int NUM_OF_QUERY = 20; 30 | 31 | const string QUERY = "query"; 32 | const string GEN_SS_QUERY = "generate-ss-query"; 33 | const string TOPK = "topk"; 34 | const string BUILD = "build"; 35 | const string TEST_LINEAR = "test_linear"; 36 | const string GEN_EXACT_TOPK = "gen-exact-topk"; 37 | //const string ASSVERSION = "version"; 38 | const string BATCH_TOPK = "batch-topk"; 39 | const string GEN_UPDATE = "gen-update"; 40 | const string DYNAMIC_SS = "dynamic-ss"; 41 | const string DYNAMIC_TOPK = "dynamic-topk"; 42 | const string DYNAMIC_ONEHOP = "dynamic-onehop"; 43 | const string DYNAMIC_HYBRID = "dynamic-hybrid"; 44 | const string CALCULATE_ACCURACY = "calc-acc"; 45 | const string COMPARE_NO_UPDATE = "comp-no-up"; 46 | 47 | const string BIPPR = "bippr"; 48 | const string FORA = "fora"; 49 | const string FORA_NO_INDEX = "foran"; 50 | const string BATON = "baton"; 51 | const string FWDPUSH = "fwdpush"; 52 | const string MC = "montecarlo"; 53 | const string HUBPPR = "hubppr"; 54 | const string PARTUP = "partup"; 55 | const string LAZYUP = "lazyup"; 56 | const string RESACC = "resacc"; 57 | const string SPEEDPPR = "speedppr"; 58 | const string FORA_AND_BATON = "fora+baton"; 59 | const string GENDA = "genda"; 60 | 61 | const int MC_QUERY = 1; 62 | const int BIPPR_QUERY = 2; 63 | const int FORA_QUERY = 3; 64 | const int HUBPPR_QUERY = 4; 65 | const int FWD_LU = 5; 66 | const int RONDOM_WALK = 6; 67 | const int SOURCE_DIST = 7; 68 | const int SORT_MAP = 8; 69 | const int BWD_LU = 9; 70 | const int PI_QUERY = 10; 71 | const int REBUILD_INDEX = 13; 72 | 73 | const double RG_COST = 1; 74 | 75 | // 0.2 for webstanford, 0.15 for dblp, 0.126 for pokec, 0.128 for LP, 0.097 for orkut 76 | // const double SG_PUSH_COST = 0.125; 77 | // const double SG_RW_COST = 1.0; 78 | 79 | const double SG_RW_COST = 8.0; 80 | 81 | const int DQUERY = 0; 82 | const int DUPDATE = 1; 83 | const int DSSQUERY = 2; 84 | const int DTOPKQUERY = 3; 85 | const int DOHQUERY = 4; 86 | 87 | #ifdef WIN32 88 | const string parent_folder = "../../"; 89 | #else 90 | const string parent_folder = string("./") + FILESEP; 91 | #endif 92 | 93 | typedef pair, map> HubBwdidx; 94 | // pi residual 95 | typedef pair HubBwdidxWithResidual; 96 | 97 | // typedef pair, unordered_map> Bwdidx; 98 | typedef pair, iMap> ReversePushidx; 99 | typedef pair, iMap> Bwdidx; 100 | typedef pair, iMap> Fwdidx; 101 | typedef pair, iMap> Reuseidx; 102 | 103 | 104 | typedef std::vector< std::vector > RwIdx; //random walk idx 105 | 106 | class Config { 107 | public: 108 | string graph_alias; 109 | string graph_location; 110 | 111 | string action = ""; // query/generate index, etc.. 112 | 113 | string prefix = "d:\\dropbox\\research\\data\\"; 114 | 115 | string version = "vector"; 116 | 117 | string exe_result_dir = parent_folder; 118 | 119 | string get_graph_folder() { 120 | return prefix + graph_alias + FILESEP; 121 | } 122 | bool multithread = false; 123 | bool with_rw_idx = false; 124 | bool with_baton = false; 125 | bool shuffle = false; 126 | bool exact = false; 127 | bool reuse = false; 128 | bool power_iteration=false; 129 | bool adaptive=false; 130 | bool alter_idx=false; 131 | bool opt = false; 132 | bool remap = false; 133 | bool force_rebuild = false; 134 | bool balanced = false; 135 | bool with_fora = false; 136 | bool no_rebuild = false; 137 | // int num_rw = 10; 138 | 139 | double omega; // 1/omega omega = # of random walk 140 | double rmax; // identical to r_max 141 | 142 | string distribution = "poisson"; 143 | double lambda_q = 30; //ratio of query 144 | double lambda_u = 200; //ratio of update 145 | double rate = 1.0; //ratio of query/update 146 | double simulation_time = 10.0; //simulation time 147 | int runs = 1;//multiple runs 148 | int linear_runs = 5; 149 | double test_beta1 = 1.0; 150 | double beta1 = 0.1, beta2 = 3.0; //the optimization parameters 151 | bool test_throughput = false; //true when test the throuput, otherwise test the response time 152 | double response_t = 0.5; 153 | double e_sf = 0; 154 | unsigned int query_size = 200; 155 | unsigned int update_size = 200; 156 | unsigned int check_size = 10; 157 | unsigned int check_from = 0; 158 | 159 | 160 | unsigned int max_iter_num = 100; 161 | 162 | double pfail = 0; 163 | double dbar = 0; 164 | double epsilon = 0.5; 165 | double delta = 0; 166 | double beta = 1.0; 167 | double sigma = 0.5; 168 | double errorlimiter = 1.0; 169 | double insert_ratio = 1.0; 170 | double rbmax = 1; 171 | double theta; 172 | double n = 2.0; 173 | int nodes, edges; 174 | int show_each; 175 | 176 | long graph_n = 0; 177 | pair mv_query, mv_update; 178 | unsigned int k = 500; 179 | double ppr_decay_alpha = 0.77; 180 | 181 | double rw_cost_ratio = 8.0;//8.0; 182 | 183 | double rmax_scale = 1.0; 184 | double multithread_param = 1.0; 185 | 186 | string algo; 187 | 188 | double alpha = ALPHA_DEFAULT; 189 | 190 | string exact_pprs_folder; 191 | 192 | unsigned int hub_space_consum = 1; 193 | 194 | ptree get_data() { 195 | ptree data; 196 | data.put("graph_alias", graph_alias); 197 | data.put("action", action); 198 | data.put("alpha", alpha); 199 | data.put("pfail", pfail); 200 | data.put("epsilon", epsilon); 201 | data.put("delta", delta); 202 | data.put("idx", with_rw_idx); 203 | // data.put("avg-idx-count", num_rw); 204 | data.put("k", k); 205 | data.put("rand-walk & push cost ratio", rw_cost_ratio); 206 | data.put("query-size", query_size); 207 | data.put("algo", algo); 208 | data.put("rmax", rmax); 209 | data.put("rmax-scale", rmax_scale); 210 | data.put("omega", omega); 211 | data.put("result-dir", exe_result_dir); 212 | return data; 213 | } 214 | }; 215 | 216 | class Result { 217 | public: 218 | int n; 219 | long long m; 220 | double avg_query_time; 221 | 222 | double total_mem_usage; 223 | double total_time_usage; 224 | 225 | double num_randwalk; 226 | double num_rw_idx_use; 227 | double hit_idx_ratio; 228 | 229 | double randwalk_time; 230 | double randwalk_time_ratio; 231 | 232 | double propagation_time; 233 | double propagation_time_ratio; 234 | 235 | double source_dist_time; 236 | double source_dist_time_ratio; 237 | 238 | double topk_sort_time; 239 | double topk_sort_time_ratio; 240 | 241 | // double topk_precision; 242 | double topk_max_abs_err; 243 | double topk_avg_abs_err; 244 | double topk_max_relative_err; 245 | double topk_avg_relative_err; 246 | double topk_precision; 247 | double topk_recall; 248 | // double topk_max_add_err; 249 | // double topk_avg_add_err; 250 | int real_topk_source_count; 251 | 252 | ptree get_data() { 253 | ptree data; 254 | data.put("n", n); 255 | data.put("m", m); 256 | data.put("avg query time(s/q)", avg_query_time); 257 | 258 | data.put("total memory usage(MB)", total_mem_usage); 259 | 260 | data.put("total time usage(s)", total_time_usage); 261 | data.put("total time on rand-walks(s)", randwalk_time); 262 | data.put("total time on propagation(s)", propagation_time); 263 | // data.put("total time on source distribution(s)", source_dist_time); 264 | data.put("total time on sorting top-k ppr(s)", topk_sort_time); 265 | 266 | 267 | data.put("total time ratio on rand-walks(%)", randwalk_time_ratio); 268 | data.put("total time ratio on propagation(%)", propagation_time_ratio); 269 | // data.put("total time ratio on source distribution(%)", source_dist_time_ratio); 270 | // data.put("total time ratio on sorting top-k ppr(%)", topk_sort_time_ratio); 271 | 272 | data.put("total number of rand-walks", num_randwalk); 273 | data.put("total number of rand-walk idx used", num_rw_idx_use); 274 | data.put("total usage ratio of rand-walk idx", hit_idx_ratio); 275 | 276 | // data.put("avg topk precision", topk_precision); 277 | data.put("topk max absolute error", topk_max_abs_err/real_topk_source_count); 278 | data.put("topk avg absolute error", topk_avg_abs_err/real_topk_source_count); 279 | data.put("topk max relative error", topk_max_relative_err/real_topk_source_count); 280 | data.put("topk avg relative error", topk_avg_relative_err/real_topk_source_count); 281 | data.put("topk precision", topk_precision/real_topk_source_count); 282 | data.put("topk recall", topk_recall/real_topk_source_count); 283 | return data; 284 | } 285 | 286 | }; 287 | 288 | extern Config config; 289 | extern Result result; 290 | 291 | bool exists_test(const std::string &name); 292 | 293 | void assert_file_exist(string desc, string name); 294 | 295 | namespace Saver { 296 | static string get_current_time_str() { 297 | time_t rawtime; 298 | struct tm *timeinfo; 299 | char buffer[80]; 300 | 301 | time(&rawtime); 302 | timeinfo = localtime(&rawtime); 303 | 304 | strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo); 305 | std::string str(buffer); 306 | 307 | return str; 308 | 309 | } 310 | 311 | static string get_time_path() { 312 | // using namespace boost::posix_time; 313 | // auto tm = second_clock::local_time(); 314 | if(!boost::algorithm::ends_with(config.exe_result_dir, FILESEP)) 315 | config.exe_result_dir += FILESEP; 316 | config.exe_result_dir += "execution/"; 317 | if(!boost::filesystem::exists(config.exe_result_dir)){ 318 | boost::filesystem::path dir(config.exe_result_dir); 319 | boost::filesystem::create_directories(dir); 320 | } 321 | 322 | string filename = config.graph_alias+"."+config.action+"."+config.algo; 323 | if(config.algo == "assppr") 324 | filename = filename + "." + to_string((int)config.rw_cost_ratio); 325 | 326 | string idx_flag = config.with_rw_idx?"with_idx":"without_idx"; 327 | filename = filename+"."+idx_flag+"."; 328 | filename += "k-"+to_string(config.k)+"."; 329 | filename += "rmax-"+to_string(config.rmax_scale); 330 | 331 | return config.exe_result_dir + filename; 332 | // return config.exe_result_dir + to_iso_string(tm); 333 | } 334 | 335 | static ptree combine; 336 | 337 | static void init() { 338 | combine.put("start_time", get_current_time_str()); 339 | } 340 | 341 | 342 | static void save_json(Config &config, Result &result, vector args) { 343 | ofstream fout(get_time_path() + ".json"); 344 | string command_line = ""; 345 | for (int i = 1; i < args.size(); i++) { 346 | command_line += " " + args[i]; 347 | } 348 | combine.put("end_time", get_current_time_str()); 349 | combine.put("command_line", command_line); 350 | combine.put_child("config", config.get_data()); 351 | combine.put_child("result", result.get_data()); 352 | ptree timer; 353 | for (int i = 0; i < (int) Timer::timeUsed.size(); i++) { 354 | if (Timer::timeUsed[i] > 0) { 355 | timer.put(to_str(i), Timer::timeUsed[i] / TIMES_PER_SEC); 356 | } 357 | } 358 | combine.put_child("timer", timer); 359 | 360 | write_json(fout, combine, true); 361 | } 362 | }; 363 | 364 | 365 | #endif 366 | -------------------------------------------------------------------------------- /constrain_linear.h: -------------------------------------------------------------------------------- 1 | 2 | // Example implementation of an objective function class for linear regression 3 | // and usage of the L-BFGS optimizer. 4 | // 5 | // Compilation: 6 | // g++ example.cpp -o example -O3 -larmadillo 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include "algo.h" 13 | #include "graph.h" 14 | #include "heap.h" 15 | #include "config.h" 16 | 17 | #include 18 | using namespace std; 19 | int iteration=0; 20 | // class LinearRegressionFunction 21 | // { 22 | // public: 23 | 24 | // LinearRegressionFunction(arma::mat& X, arma::vec& y) : X(X), y(y) { } 25 | 26 | // double EvaluateWithGradient(const arma::mat& theta, arma::mat& gradient) 27 | // { 28 | // const arma::vec tmp = X.t() * theta - y; 29 | // gradient = 2 * X * tmp; 30 | // return arma::dot(tmp,tmp); 31 | // } 32 | 33 | // private: 34 | 35 | // const arma::mat& X; 36 | // const arma::vec& y; 37 | // }; 38 | 39 | class ConstrainedFunctionType 40 | { 41 | public: 42 | //We set \Tilde{t}_q = a \beta_1\beta_2+b\beta_1+\frac{c}{\beta_1} 43 | // Return the objective function f(x) for the given x. 44 | double qq, uu; 45 | double complexity[5] = {}; 46 | bool plot = false; 47 | void calculate_para(arma::mat x){ 48 | string ab_values = config.graph_location + "linear_values.txt"; 49 | cout< get_qu(const arma::mat& var){ 91 | double complexity_scale[5] = {}; 92 | double epsilon = config.epsilon/config.theta; 93 | complexity_scale[0] = config.omega/var(0,0); 94 | complexity_scale[1] = (config.lambda_u*var(0,0)*config.edges*(var(0,1)*config.nodes*config.rbmax+1))/ 95 | (config.lambda_q*(1-config.theta)*epsilon*config.delta*config.nodes*pow(config.alpha,2)*config.omega); 96 | complexity_scale[2] = (var(0,0)*config.edges)/(config.alpha); 97 | complexity_scale[3] = config.edges/(var(0,1)*config.nodes*config.alpha*config.rbmax); 98 | complexity_scale[4] = config.nodes; 99 | double t_q = 0; 100 | double t_u = 0; 101 | alist[4] = 1; 102 | blist[4] = 0; 103 | for(int i = 0; i < 3; i++){ 104 | t_q = t_q+(alist[i]*complexity_scale[i]+blist[i])*tau[i]; 105 | } 106 | for(int j = 3; j < 5; j++){ 107 | t_u = t_u+(alist[j]*complexity_scale[j]+blist[j])*tau[j]; 108 | } 109 | 110 | return pair(t_q,t_u); 111 | 112 | } 113 | double Evaluate(const arma::mat& x){ 114 | iteration++; 115 | double t_q,t_u; 116 | t_q = get_qu(x).first; 117 | t_u = get_qu(x).second; 118 | 119 | double y; 120 | // INFO(t_q); 121 | // INFO(t_u); 122 | // if(config.test_throughput==true){ 123 | // // ***Optimize the lambda_q 124 | // double fx = (2*(config.response_t-t_q)*(1-config.lambda_u*t_u)-config.lambda_u*(config.mv_update.second+t_u*t_u))/ 125 | // (config.mv_query.second+2*config.response_t*t_q-t_q*t_q); 126 | // y = -fx; 127 | 128 | // }else{ 129 | // ***Optimize the response time 130 | double fx; 131 | if(1-config.lambda_u*t_u-config.lambda_q*t_q>0){ 132 | 133 | fx = (config.lambda_u*(config.mv_update.second+t_u*t_u)+config.lambda_q*(config.mv_query.second+t_q*t_q))/ 134 | ((1-config.lambda_u*t_u-config.lambda_q*t_q)*2)+t_q; 135 | y = fx; 136 | }else if(1-config.lambda_u*t_u-config.lambda_q*t_q==0){ 137 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q+0.1; 138 | 139 | }else{ 140 | fx = 1-config.lambda_u*t_u-config.lambda_q*t_q; 141 | y = -fx; 142 | } 143 | // } 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | //*** Output for visualization 152 | 153 | // if(plot == false){ 154 | // string filename = "/home/zulun/some_test/para.txt"; 155 | // ofstream queryfile(filename, ios::app); 156 | // queryfile<0){ 233 | return (config.lambda_u*t_u+config.lambda_q*t_q-1)*1000; 234 | break; 235 | } 236 | else{ 237 | return 0; 238 | break; 239 | } 240 | case 1: if (-x(0,0)>0){ 241 | return (-x(0,0))*1000; 242 | break; 243 | } 244 | else{ 245 | return 0; 246 | break; 247 | } 248 | case 2: if (-x(0,1)>0){ 249 | return (-x(0,1))*1000; 250 | break; 251 | } 252 | else{ 253 | return 0; 254 | break; 255 | } 256 | // case 3: if (t_q-config.response_t>0){ 257 | // return (t_q-config.response_t)*100; 258 | // break; 259 | // } 260 | // else{ 261 | // return 0; 262 | // break; 263 | // } 264 | 265 | } 266 | 267 | }; 268 | 269 | // Evaluate the gradient of constraint i at the parameters x, storing the 270 | // result in the given matrix g. If the constraint is not satisfied, the 271 | // gradient should be set in such a way that the gradient points in the 272 | // direction where the constraint would be satisfied. 273 | void GradientConstraint(const size_t i, const arma::mat& x, arma::mat& g){ 274 | arma::mat dbeta1,dbeta2; 275 | 276 | double eps = 1e-8; 277 | dbeta1 = {x(0,0)+eps, x(0,1)}; 278 | dbeta2 = {x(0,0), x(0,1)+eps}; 279 | double t_q,t_u; 280 | t_q = get_qu(x).first; 281 | t_u = get_qu(x).second; 282 | 283 | double fx, fxd1, fxd2, fx_r,fxd1_r, fxd2_r; 284 | //***Optimize the response time 285 | fx = config.lambda_u*t_u+config.lambda_q*t_q-1; 286 | fx_r = t_q-config.response_t; 287 | 288 | double dt_q,dt_u; 289 | dt_q = get_qu(dbeta1).first; 290 | dt_u = get_qu(dbeta1).second; 291 | 292 | fxd1 = config.lambda_u*dt_u+config.lambda_q*dt_q-1; 293 | fxd1_r = dt_q-config.response_t; 294 | 295 | dt_q = get_qu(dbeta2).first; 296 | dt_u = get_qu(dbeta2).second; 297 | fxd2 = config.lambda_u*dt_u+config.lambda_q*dt_q-1; 298 | fxd2_r = dt_q-config.response_t; 299 | switch (i){ 300 | case 0: g = {(fxd1 - fx)/eps, (fxd2 - fx)/eps}; 301 | break; 302 | // case 1: g = {(fxd1_r - fx_r)/eps, (fxd2_r - fx_r)/eps}; 303 | // break; 304 | case 1: g = {-1,0}; 305 | break; 306 | case 2: g = {0,-1}; 307 | break; 308 | } 309 | }; 310 | 311 | 312 | }; 313 | 314 | pair improve_throughput() 315 | { 316 | 317 | arma::mat x,original; 318 | x = {1.0, 1.0}; 319 | original = x; 320 | ConstrainedFunctionType f; 321 | f.calculate_para(original); 322 | 323 | ens::AugLagrangian optimizer(100,0.25,10); 324 | optimizer.Optimize(f, x); 325 | // output the log file 326 | string filename = config.graph_location + "result.txt"; 327 | ofstream queryfile(filename, ios::app); 328 | char str[50]; 329 | time_t now = time(NULL); 330 | strftime(str, 50, "%x %X", localtime(&now)); 331 | queryfile << str<(x(0,0), x(0,1)); 347 | } 348 | -------------------------------------------------------------------------------- /mylib.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYLIB_H__ 2 | #define __MYLIB_H__ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | //#include 11 | //#include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | //#include 25 | #include 26 | //#include 27 | //#include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | using namespace std; 42 | typedef unsigned int uint; 43 | typedef unsigned char uint8; 44 | typedef long long int64; 45 | typedef unsigned long long uint64; 46 | typedef pair ipair; 47 | typedef pair dpair; 48 | #define MP make_pair 49 | #define F first 50 | #define S second 51 | 52 | 53 | #ifndef TIMES_PER_SEC 54 | #define TIMES_PER_SEC (1.0e9) 55 | #endif 56 | 57 | typedef char int8; 58 | typedef unsigned char uint8; 59 | typedef long long int64; 60 | typedef unsigned long long uint64; 61 | 62 | #define SIZE(t) (int)(t.size()) 63 | #define ALL(t) (t).begin(), (t).end() 64 | #define FOR(i, n) for(int (i)=0; (i)<((int)(n)); (i)++) 65 | 66 | 67 | typedef pair ipair; 68 | 69 | const int MAXN = 1000000; 70 | 71 | const int VectorDefaultSize=20; 72 | const int TOPNUM = 1; 73 | 74 | 75 | template 76 | class iVector 77 | { 78 | public: 79 | unsigned int m_size; 80 | _T* m_data; 81 | unsigned int m_num; 82 | 83 | void free_mem() 84 | { 85 | delete[] m_data; 86 | } 87 | 88 | iVector() 89 | { 90 | //printf("%d\n",VectorDefaultSize); 91 | m_size = VectorDefaultSize; 92 | m_data = new _T[VectorDefaultSize]; 93 | m_num = 0; 94 | } 95 | iVector( unsigned int n ) 96 | { 97 | if ( n == 0 ) 98 | { 99 | n = VectorDefaultSize; 100 | } 101 | // printf("iVector allocate: %d\n",n); 102 | m_size = n; 103 | m_data = new _T[m_size]; 104 | m_num = 0; 105 | } 106 | void push_back( _T d ) 107 | { 108 | if ( m_num == m_size ) 109 | { 110 | re_allocate( m_size*2 ); 111 | } 112 | m_data[m_num] = d ; 113 | m_num++; 114 | } 115 | void push_back( const _T* p, unsigned int len ) 116 | { 117 | while ( m_num + len > m_size ) 118 | { 119 | re_allocate( m_size*2 ); 120 | } 121 | memcpy( m_data+m_num, p, sizeof(_T)*len ); 122 | m_num += len; 123 | } 124 | 125 | void re_allocate( unsigned int size ) 126 | { 127 | if ( size < m_num ) 128 | { 129 | return; 130 | } 131 | _T* tmp = new _T[size]; 132 | memcpy( tmp, m_data, sizeof(_T)*m_num ); 133 | m_size = size; 134 | delete[] m_data; 135 | m_data = tmp; 136 | } 137 | void Sort() 138 | { 139 | if ( m_num < 20 ) 140 | { 141 | int k ; 142 | _T tmp; 143 | for ( int i = 0 ; i < m_num-1 ; ++i ) 144 | { 145 | k = i ; 146 | for ( int j = i+1 ; j < m_num ; ++j ) 147 | if ( m_data[j] < m_data[k] ) k = j ; 148 | if ( k != i ) 149 | { 150 | tmp = m_data[i]; 151 | m_data[i] = m_data[k]; 152 | m_data[k] = tmp; 153 | } 154 | } 155 | } 156 | else sort( m_data, m_data+m_num ); 157 | } 158 | void unique() 159 | { 160 | if ( m_num == 0 ) return; 161 | Sort(); 162 | unsigned int j = 0; 163 | for ( unsigned int i = 0 ; i < m_num ; ++i ) 164 | if ( !(m_data[i] == m_data[j]) ) 165 | { 166 | ++j; 167 | if ( j != i ) m_data[j] = m_data[i]; 168 | } 169 | m_num = j+1; 170 | } 171 | int BinarySearch( _T& data ) 172 | { 173 | for ( int x = 0 , y = m_num-1 ; x <= y ; ) 174 | { 175 | int p = (x+y)/2; 176 | if ( m_data[p] == data ) return p; 177 | if ( m_data[p] < data ) x = p+1; 178 | else y = p-1; 179 | } 180 | return -1; 181 | } 182 | void clean() 183 | { 184 | m_num = 0; 185 | } 186 | void assign( iVector& t ) 187 | { 188 | m_num = t.m_num; 189 | m_size = t.m_size; 190 | delete[] m_data; 191 | m_data = t.m_data; 192 | } 193 | 194 | bool remove( _T& x ) 195 | { 196 | for ( int l = 0 , r = m_num ; l < r ; ) 197 | { 198 | int m = (l+r)/2; 199 | 200 | if ( m_data[m] == x ) 201 | { 202 | m_num--; 203 | if ( m_num > m ) memmove( m_data+m, m_data+m+1, sizeof(_T)*(m_num-m) ); 204 | return true; 205 | } 206 | else if ( m_data[m] < x ) l = m+1; 207 | else r = m; 208 | } 209 | return false; 210 | } 211 | 212 | void sorted_insert( _T& x ) 213 | { 214 | if ( m_num == 0 ) 215 | { 216 | push_back( x ); 217 | return; 218 | } 219 | 220 | if ( m_num == m_size ) re_allocate( m_size*2 ); 221 | 222 | int l,r; 223 | 224 | for ( l = 0 , r = m_num ; l < r ; ) 225 | { 226 | int m = (l+r)/2; 227 | if ( m_data[m] < x ) l = m+1; 228 | else r = m; 229 | } 230 | 231 | if ( l < m_num && m_data[l] == x ) 232 | { 233 | //printf("Insert Duplicate....\n"); 234 | //cout< l ) 240 | { 241 | memmove( m_data+l+1, m_data+l, sizeof(_T)*(m_num-l) ); 242 | } 243 | m_num++; 244 | m_data[l] = x; 245 | } 246 | } 247 | 248 | bool remove_unsorted( _T& x ) 249 | { 250 | for ( int m = 0 ; m < m_num ; ++m ) 251 | { 252 | if ( m_data[m] == x ) 253 | { 254 | m_num--; 255 | if ( m_num > m ) memcpy( m_data+m, m_data+m+1, sizeof(_T)*(m_num-m) ); 256 | return true; 257 | } 258 | } 259 | return false; 260 | } 261 | 262 | _T& operator[]( unsigned int i ) 263 | { 264 | //if ( i < 0 || i >= m_num ) 265 | //{ 266 | // printf("iVector [] out of range!!!\n"); 267 | //} 268 | return m_data[i]; 269 | } 270 | //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 271 | //close range check for [] in iVector if release 272 | 273 | }; 274 | 275 | 276 | 277 | 278 | template 279 | struct iMap 280 | { 281 | _T* m_data; 282 | int m_num; 283 | int cur; 284 | iVector occur; 285 | _T nil; 286 | iMap() 287 | { 288 | m_data = NULL; 289 | m_num = 0; 290 | //nil = std::make_pair((long)-9,(long)-9); 291 | //nil = 1073741834; 292 | } 293 | iMap(int size){ 294 | initialize(size); 295 | } 296 | void free_mem() 297 | { 298 | delete[] m_data; 299 | occur.free_mem(); 300 | } 301 | 302 | void initialize( int n ) 303 | { 304 | occur.re_allocate(n); 305 | occur.clean(); 306 | m_num = n; 307 | nil = -9; 308 | if ( m_data != NULL ) 309 | delete[] m_data; 310 | m_data = new _T[m_num]; 311 | for ( int i = 0 ; i < m_num ; ++i ) 312 | m_data[i] = nil; 313 | cur = 0; 314 | } 315 | void clean() 316 | { 317 | //cout<<"clean"<= m_num ) 357 | //{ 358 | // printf("iMap get out of range!!!\n"); 359 | // return -8; 360 | //} 361 | return m_data[p]; 362 | } 363 | _T& operator[]( int p ) 364 | { 365 | //if ( i < 0 || i >= m_num ) 366 | //{ 367 | // printf("iVector [] out of range!!!\n"); 368 | //} 369 | return m_data[p]; 370 | } 371 | void erase( int p ) 372 | { 373 | //if ( p < 0 || p >= m_num ) 374 | //{ 375 | // printf("iMap get out of range!!!\n"); 376 | //} 377 | m_data[p] = nil; 378 | cur--; 379 | } 380 | bool notexist( int p ) 381 | { 382 | return m_data[p] == nil ; 383 | } 384 | bool exist( int p ) 385 | { 386 | return !(m_data[p] == nil); 387 | } 388 | void insert( int p , _T d ) 389 | { 390 | //if ( p < 0 || p >= m_num ) 391 | //{ 392 | // printf("iMap insert out of range!!!\n"); 393 | //} 394 | if ( m_data[p] == nil ) 395 | { 396 | occur.push_back( p ); 397 | cur++; 398 | } 399 | m_data[p] = d; 400 | } 401 | void inc( int p ) 402 | { 403 | //if ( m_data[p] == nil ) 404 | //{ 405 | // printf("inc some unexisted point\n"); 406 | //} 407 | m_data[p]++; 408 | } 409 | void inc( int p , int x ) 410 | { 411 | //if ( m_data[p] == nil ) 412 | //{ 413 | // printf("inc some unexisted point\n"); 414 | //} 415 | m_data[p] += x; 416 | } 417 | void dec( int p ) 418 | { 419 | //if ( m_data[p] == nil ) 420 | //{ 421 | // printf("dec some unexisted point\n" ); 422 | //} 423 | m_data[p]--; 424 | } 425 | //close range check when release!!!!!!!!!!!!!!!!!!!! 426 | }; 427 | 428 | 429 | static inline string <rim(string &s) { 430 | s.erase(s.begin(), find_if(s.begin(), s.end(), not1(ptr_fun(isspace)))); 431 | return s; 432 | } 433 | 434 | static inline string &rtrim(string &s) { 435 | s.erase(find_if(s.rbegin(), s.rend(), not1(ptr_fun(isspace))).base(), s.end()); 436 | return s; 437 | } 438 | 439 | static inline string &trim(string &s) { return ltrim(rtrim(s)); } 440 | 441 | string __n_variable(string t, int n); 442 | 443 | #define __expand_nv(x) __n_variable(t, x)<< t##x << " " 444 | 445 | 446 | template 447 | void ___debug(string t, T0 t0, ostream &os) { 448 | os << __expand_nv(0); 449 | } 450 | 451 | template 452 | void ___debug(string t, T0 t0, T1 t1, ostream &os) { 453 | os << __expand_nv(0) << __expand_nv(1); 454 | } 455 | 456 | template 457 | void ___debug(string t, T0 t0, T1 t1, T2 t2, ostream &os) { 458 | os << __expand_nv(0) << __expand_nv(1) << __expand_nv(2); 459 | } 460 | 461 | template 462 | void ___debug(string t, T0 t0, T1 t1, T2 t2, T3 t3, ostream &os) { 463 | os << __expand_nv(0) << __expand_nv(1) << __expand_nv(2) << __expand_nv(3); 464 | } 465 | 466 | template 467 | void ___debug(string t, T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, ostream &os) { 468 | os << __expand_nv(0) << __expand_nv(1) << __expand_nv(2) << __expand_nv(3) << __expand_nv(4); 469 | } 470 | 471 | template 472 | void ___debug(string t, deque t0, ostream &os) { 473 | os << __n_variable(t, 0); 474 | FOR(i, SIZE(t0))os << t0[i] << " "; 475 | } 476 | 477 | template 478 | void ___debug(string t, vector t0, ostream &os) { 479 | os << __n_variable(t, 0); 480 | FOR(i, SIZE(t0))os << t0[i] << " "; 481 | } 482 | 483 | template 484 | void ___debug(string t, vector > t0, ostream &os) { 485 | os << __n_variable(t, 0); 486 | FOR(i, SIZE(t0))os << t0[i].F << "," << t0[i].S << " "; 487 | } 488 | 489 | #define RUN_TIME(...) { int64 t=rdtsc(); __VA_ARGS__; t=rdtsc()-t; cout<< #__VA_ARGS__ << " : " << t/TIMES_PER_SEC <<"s"< 520 | string toStr(T t); 521 | 522 | 523 | class Counter { 524 | public: 525 | static int cnt[1000]; 526 | int myid = 0; 527 | 528 | Counter(int id = 0) { 529 | myid = id; 530 | cnt[id]++; 531 | } 532 | 533 | void add(int x) { 534 | cnt[myid] += x; 535 | } 536 | 537 | ~Counter() { 538 | } 539 | 540 | static void show() { 541 | for (int i = 0; i < 1000; i++) 542 | if (cnt[i] > 0) 543 | INFO("Counter", i, cnt[i]); 544 | } 545 | }; 546 | 547 | 548 | uint64 rdtsc(); 549 | 550 | static double get_duration(std::chrono::steady_clock::time_point startTime){ 551 | return std::chrono::duration_cast(std::chrono::steady_clock::now() - startTime).count()/ TIMES_PER_SEC; 552 | } 553 | 554 | class Timer { 555 | public: 556 | static vector timeUsed; 557 | static vector timeUsedDesc; 558 | static vector time_one_time; 559 | int id; 560 | std::chrono::steady_clock::time_point startTime; 561 | bool showOnDestroy; 562 | 563 | Timer(int id, string desc = "", bool showOnDestroy = false) { 564 | this->id = id; 565 | while ((int) timeUsed.size() <= id) { 566 | timeUsed.push_back(0); 567 | time_one_time.push_back(0); 568 | timeUsedDesc.push_back(""); 569 | } 570 | timeUsedDesc[id] = desc; 571 | startTime = std::chrono::steady_clock::now(); 572 | this->showOnDestroy = showOnDestroy; 573 | } 574 | 575 | static double used(int id) { 576 | return timeUsed[id] / TIMES_PER_SEC; 577 | } 578 | static double used_one_time(int id) { 579 | return time_one_time[id] / TIMES_PER_SEC; 580 | } 581 | 582 | ~Timer() { 583 | auto duration = std::chrono::duration_cast(std::chrono::steady_clock::now() - startTime).count(); 584 | if (showOnDestroy) { 585 | cout << "time spend on " << timeUsedDesc[id] << ":" << duration / TIMES_PER_SEC << "s" << endl; 586 | } 587 | timeUsed[id] += duration; 588 | time_one_time[id] = duration; 589 | } 590 | 591 | static void show(bool debug = false) { 592 | if (debug) { TRACE("### Timer"); 593 | } 594 | else { 595 | INFO("### Timer"); 596 | } 597 | if((int) timeUsed.size()>11){ 598 | auto total = timeUsed[11] / TIMES_PER_SEC + timeUsed[3] / TIMES_PER_SEC; 599 | } 600 | for (int i = 0; i < (int) timeUsed.size(); i++) { 601 | if (timeUsed[i] > 0) { 602 | char str[100]; 603 | sprintf(str, "%.6lf", timeUsed[i] / TIMES_PER_SEC); 604 | string s = str; 605 | if ((int) s.size() < 15) s = " " + s; 606 | char t[100]; 607 | memset(t, 0, sizeof t); 608 | sprintf(t, "%4d %s %s", i, s.c_str(), timeUsedDesc[i].c_str()); 609 | if (debug) { TRACE(t); 610 | } 611 | else { 612 | INFO(t); 613 | } 614 | } 615 | } 616 | double total; 617 | for (int i = 1; i < (int) timeUsed.size(); i++) { 618 | if (timeUsed[i] > 0) { 619 | total+= timeUsed[i] / TIMES_PER_SEC; 620 | } 621 | } 622 | //INFO(total); 623 | } 624 | 625 | static void reset(int id){ 626 | timeUsed[id] = 0; 627 | } 628 | 629 | static void clearAll() { 630 | timeUsed.clear(); 631 | timeUsedDesc.clear(); 632 | } 633 | }; 634 | 635 | 636 | static vector combine_args(int argc, char **argv) { 637 | vector args; 638 | for (int i = 0; i < argc; ++i) { 639 | args.push_back(argv[i]); 640 | } 641 | return args; 642 | } 643 | 644 | static string to_str(double t) { 645 | stringstream ss; 646 | ss << t; 647 | return ss.str(); 648 | } 649 | 650 | inline bool file_exists_test(const std::string &name) { 651 | ifstream f(name.c_str()); 652 | if (f.good()) { 653 | f.close(); 654 | return true; 655 | } else { 656 | f.close(); 657 | return false; 658 | } 659 | } 660 | 661 | static string replace(std::string str, const std::string &from, const std::string &to) { 662 | //original string will not be modified 663 | size_t start_pos = str.find(from); 664 | if (start_pos == std::string::npos) 665 | return str; 666 | str.replace(start_pos, from.length(), to); 667 | return str; 668 | } 669 | 670 | // unit is kilobyte (KB) 671 | inline int get_proc_memory(){ 672 | struct rusage r_usage; 673 | getrusage(RUSAGE_SELF,&r_usage); 674 | return r_usage.ru_maxrss; 675 | } 676 | 677 | const string Green = "\033[0;32m"; 678 | const string Reset = "\033[0m"; 679 | const string Red = "\033[0;31m"; 680 | 681 | 682 | static string get_current_time_str() { 683 | time_t rawtime; 684 | struct tm *timeinfo; 685 | char buffer[80]; 686 | 687 | time(&rawtime); 688 | timeinfo = localtime(&rawtime); 689 | 690 | strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo); 691 | std::string str(buffer); 692 | 693 | return str; 694 | } 695 | 696 | static void program_start(int argc, char **argv) { 697 | 698 | cout << Green << "--------------start------------" << get_current_time_str() << Reset << endl; 699 | string combine = ""; 700 | for (int i = 1; i < argc; i++) { 701 | combine += argv[i]; 702 | combine += " "; 703 | } 704 | cout << Green << "args:" << combine << Reset << endl; 705 | } 706 | 707 | static void program_stop() { 708 | cout << Red << "--------------stop------------" << get_current_time_str() << Reset << endl; 709 | cout << endl; 710 | cout << endl; 711 | cout << endl; 712 | 713 | } 714 | 715 | 716 | #ifndef NDEBUG 717 | # define ASSERTMSG(condition, message) \ 718 | do { \ 719 | if (! (condition)) { \ 720 | std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \ 721 | << " line " << __LINE__ << ": " << message << std::endl; \ 722 | std::exit(EXIT_FAILURE); \ 723 | } \ 724 | } while (false) 725 | #else 726 | # define ASSERTMSG(condition, message) do { } while (false) 727 | #endif 728 | 729 | #endif //__MYLIB_H__ 730 | -------------------------------------------------------------------------------- /agenda.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define _CRT_SECURE_NO_DEPRECATE 3 | #define HEAD_INFO 4 | 5 | #include "mylib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "graph.h" 18 | #include "config.h" 19 | #include "algo.h" 20 | #include "query.h" 21 | #include "build.h" 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | using namespace std::chrono; 32 | 33 | using namespace boost; 34 | using namespace boost::property_tree; 35 | 36 | using namespace std; 37 | 38 | 39 | string get_time_path() { 40 | using namespace boost::posix_time; 41 | auto tm = second_clock::local_time(); 42 | #ifdef WIN32 43 | return "../../execution/" + to_iso_string(tm); 44 | #else 45 | return parent_folder+FILESEP+"execution/" + to_iso_string(tm); 46 | #endif 47 | } 48 | 49 | #include 50 | 51 | namespace po = boost::program_options; 52 | 53 | 54 | using namespace std; 55 | 56 | int main(int argc, char *argv[]) { 57 | ios::sync_with_stdio(false); 58 | program_start(argc, argv); 59 | 60 | // this is main entry 61 | Saver::init(); 62 | srand(time(NULL)); 63 | config.graph_alias = "nethept"; 64 | for (int i = 0; i < argc; i++) { 65 | string help_str = "" 66 | "fora query --algo [options]\n" 67 | "fora topk --algo [options]\n" 68 | "fora batch-topk --algo [options]\n" 69 | "fora build [options]\n" 70 | "fora generate-ss-query [options]\n" 71 | "fora gen-exact-topk [options]\n" 72 | "fora\n" 73 | "\n" 74 | "algo: \n" 75 | " bippr\n" 76 | " montecarlo\n" 77 | " fora\n" 78 | " hubppr\n" 79 | "options: \n" 80 | " --prefix \n" 81 | " --epsilon \n" 82 | " --dataset \n" 83 | " --query_size \n" 84 | " --k \n" 85 | " --with_idx\n" 86 | " --hub_space \n" 87 | " --exact_ppr_path \n" 88 | " --rw_ratio \n" 89 | " --result_dir " 90 | " --rmax_scale \n"; 91 | 92 | if (string(argv[i]) == "--help") { 93 | cout << help_str << endl; 94 | exit(0); 95 | } 96 | } 97 | 98 | config.action = argv[1]; 99 | cout << "action: " << config.action << endl; 100 | 101 | // init graph first 102 | for (int i = 0; i < argc; i++) { 103 | if (string(argv[i]) == "--prefix") { 104 | config.prefix = argv[i + 1]; 105 | } 106 | if (string(argv[i]) == "--dataset") { 107 | config.graph_alias = argv[i + 1]; 108 | } 109 | } 110 | if(config.graph_alias=="webstanford"){ 111 | config.show_each=20; 112 | 113 | }else{ 114 | config.show_each=1; 115 | 116 | } 117 | for (int i = 0; i < argc; i++) { 118 | string arg = argv[i]; 119 | if (arg == "--algo") { 120 | config.algo = string(argv[i + 1]); 121 | }else if (arg == "--epsilon") { 122 | config.epsilon = atof(argv[i + 1]); 123 | INFO(config.epsilon); 124 | }else if (arg == "--lambdaq") { 125 | config.lambda_q = atof(argv[i + 1]); 126 | INFO(config.lambda_q); 127 | }else if (arg == "--distribution") { 128 | config.distribution = string(argv[i + 1]); 129 | INFO(config.distribution); 130 | }else if (arg == "--esf") { 131 | config.e_sf = atof(argv[i + 1]); 132 | INFO(config.e_sf); 133 | }else if (arg == "--rate") { 134 | config.rate = atof(argv[i + 1]); 135 | INFO(config.rate); 136 | }else if (arg == "--lambdau") { 137 | config.lambda_u = atof(argv[i + 1]); 138 | INFO(config.lambda_u); 139 | }else if (arg == "--responsetime") { 140 | config.response_t = atof(argv[i + 1]); 141 | INFO(config.response_t); 142 | }else if (arg == "--timewin") { 143 | config.simulation_time = atof(argv[i + 1]); 144 | INFO(config.simulation_time); 145 | }else if (arg == "--runs") { 146 | config.runs = atof(argv[i + 1]); 147 | }else if(arg == "--throughput"){ 148 | config.test_throughput = true; 149 | }else if(arg == "--multithread"){ 150 | config.multithread = true; 151 | }else if(arg == "--shuffle"){ 152 | config.shuffle = true; 153 | } 154 | else if(arg == "--result_dir"){ 155 | config.exe_result_dir = string(argv[i + 1]); 156 | } 157 | else if( arg == "--exact_ppr_path"){ 158 | config.exact_pprs_folder = string(argv[i + 1]); 159 | }else if(arg == "--with_idx"){ 160 | config.with_rw_idx = true; 161 | } 162 | else if(arg == "--rmax_scale"){ 163 | config.rmax_scale = atof(argv[i+1]); 164 | } 165 | else if (arg == "--query_size"){ 166 | config.query_size = atoi(argv[i+1]); 167 | } 168 | else if (arg == "--update_size"){ 169 | config.update_size = atoi(argv[i+1]); 170 | } 171 | else if (arg == "--check_size"){ 172 | config.check_size = atoi(argv[i+1]); 173 | INFO(config.check_size); 174 | } 175 | else if (arg == "--check_from"){ 176 | config.check_from = atoi(argv[i+1]); 177 | } 178 | else if(arg == "--hub_space"){ 179 | config.hub_space_consum = atoi(argv[i+1]); 180 | } 181 | else if (arg == "--version"){ 182 | config.version = argv[i+1]; 183 | } 184 | else if(arg == "--k"){ 185 | config.k = atoi(argv[i+1]); 186 | } 187 | else if(arg == "--rw_ratio"){ 188 | config.rw_cost_ratio = atof(argv[i + 1]); 189 | } 190 | else if (arg == "--prefix" || arg == "--dataset") { 191 | // pass 192 | } 193 | else if (arg == "--baton"){ 194 | config.with_baton = true; 195 | }else if (arg == "--exact"){ 196 | config.exact = true; 197 | } 198 | else if (arg == "--reuse"){ 199 | config.reuse = true; 200 | } 201 | else if (arg == "--beta"){ 202 | config.beta = atof(argv[i + 1]); 203 | } 204 | else if (arg == "--n"){ 205 | config.n = atof(argv[i + 1]); 206 | } 207 | else if (arg == "--power_iter"){ 208 | config.power_iteration=true; 209 | } 210 | else if (arg == "--adapt"){ 211 | config.adaptive=true; 212 | } 213 | else if (arg == "--alter_idx"){ 214 | config.alter_idx=true; 215 | } 216 | else if(arg == "--opt"){ 217 | config.opt = true; 218 | } 219 | else if(arg == "--balanced"){ 220 | config.balanced = true; 221 | } 222 | else if(arg == "--errorlimiter"){ 223 | config.errorlimiter = atof(argv[i + 1]); 224 | } 225 | else if(arg == "--with_fora"){ 226 | config.with_fora = true; 227 | } 228 | else if(arg == "--no_rebuild"){ 229 | config.no_rebuild = true; 230 | } 231 | else if(arg == "--graph_n"){ 232 | config.graph_n = atoi(argv[i+1]); 233 | } 234 | else if(arg == "--insert_ratio"){ 235 | config.insert_ratio = atof(argv[i + 1]); 236 | } 237 | else if (arg.substr(0, 2) == "--") { 238 | cerr << "command not recognize " << arg << endl; 239 | exit(1); 240 | } 241 | } 242 | 243 | INFO(config.version); 244 | vector possibleAlgo = {BIPPR, FORA, BATON, FWDPUSH, MC, HUBPPR, PARTUP, LAZYUP, GENDA, RESACC}; 245 | if(config.algo==BATON||config.algo==PARTUP||config.algo==LAZYUP||config.algo==GENDA){ 246 | config.with_baton = true; 247 | } 248 | 249 | if(config.with_fora){ 250 | config.with_baton = false; 251 | } 252 | 253 | INFO(config.action); 254 | 255 | srand (time(NULL)); 256 | if (config.action == QUERY) { 257 | auto f = find(possibleAlgo.begin(), possibleAlgo.end(), config.algo); 258 | assert (f != possibleAlgo.end()); 259 | if(f == possibleAlgo.end()){ 260 | INFO("Wrong algo param: ", config.algo); 261 | exit(1); 262 | } 263 | 264 | config.graph_location = config.get_graph_folder(); 265 | Graph graph(config.graph_location); 266 | INFO("load graph finish"); 267 | init_parameter(config, graph); 268 | 269 | INFO("finihsed initing parameters"); 270 | INFO(graph.n, graph.m); 271 | 272 | // if(config.multithread){ 273 | // init_multi_setting(graph.n); 274 | // } 275 | 276 | if(config.with_rw_idx) 277 | deserialize_idx(); 278 | INFO(rw_idx.size()); 279 | query(graph); 280 | 281 | //cout << Timer::used(RONDOM_WALK)*1000/double(rw_count) << "ms" << " for each random walk" < list_query = generate_query_workload_with_timestamp(config.lambda_q, config.simulation_time, DQUERY,graph); 322 | if(config.with_rw_idx) 323 | deserialize_idx(); 324 | 325 | topk(graph,list_query); 326 | cout<<"Cycle: "< list_query = generate_query_workload_with_timestamp(config.lambda_q, config.simulation_time, DQUERY,graph); 418 | 419 | vector list_update = generate_query_workload_with_timestamp(config.lambda_u, config.simulation_time, DUPDATE,graph); 420 | merge_dynamic_workload(list_query, list_update); 421 | 422 | // cout << "listqqqq:" << list_query[1000].init_time<< "listuuu"<< list_update.size()<> updates; 430 | regenerate_updates(graph, updates,list_update); 431 | dynamic_ssquery_origin(graph, list_query, list_update,updates); 432 | } 433 | LeastSquare query1(w_query1,a_query1); 434 | LeastSquare query2(w_query2,a_query2); 435 | LeastSquare query3(w_query3,a_query3); 436 | LeastSquare update1(w_update1,a_update1); 437 | LeastSquare update2(w_update2,a_update2); 438 | string filename = config.graph_location + "linear_values.txt"; 439 | ofstream queryfile(filename, ios::app); 440 | queryfile< list_query = generate_query_workload_with_timestamp(config.lambda_q, config.simulation_time, DQUERY,graph); 505 | 506 | vector list_update = generate_query_workload_with_timestamp(config.lambda_u, config.simulation_time, DUPDATE,graph); 507 | merge_dynamic_workload(list_query, list_update); 508 | 509 | // cout << "listqqqq:" << list_query[1000].init_time<< "listuuu"<< list_update.size()<> updates; 517 | regenerate_updates(graph, updates,list_update); 518 | 519 | dynamic_ssquery_origin(graph, list_query, list_update,updates); 520 | if(ori_finished==false){ 521 | 522 | INFO(final_throughput_ori.back()); 523 | INFO(config.lambda_q); 524 | INFO(l_ori); 525 | INFO(r_ori); 526 | if(final_response_time_ori.back()>0 && final_response_time_ori.back() <= config.response_t){ 527 | if(throughput_ori < final_throughput_ori.back()) throughput_ori=final_throughput_ori.back(); 528 | l_ori = config.lambda_q + 1; 529 | }else{ 530 | r_ori = config.lambda_q - 1; 531 | } 532 | final_throughput_ori.pop_back(); 533 | 534 | } 535 | 536 | 537 | if(l_ori > r_ori){ 538 | cout<<"Original throughput finished!!!!!!!!!!!!!!! : "<0 && final_response_time.back() <= config.response_t){ 552 | if(throughput < final_throughput.back()) throughput=final_throughput.back(); 553 | l = config.lambda_q + 1; 554 | }else{ 555 | r = config.lambda_q - 1; 556 | } 557 | final_throughput.pop_back(); 558 | } 559 | if(l> r){ 560 | cout<<"improved throughput finished!!!!!!!!!!!!!!! : "< list_query = generate_query_workload_with_timestamp(config.lambda_q, config.simulation_time, DQUERY,graph); 613 | 614 | vector list_update = generate_query_workload_with_timestamp(config.lambda_u, config.simulation_time, DUPDATE,graph); 615 | vector> updates; 616 | regenerate_updates(graph, updates,list_update); 617 | 618 | // if(config.graph_alias=="wiki"){ 619 | // list_query = load_query_workload_with_timestamp(DQUERY); 620 | // list_update = load_update_workload_with_timestamp(graph, updates, DUPDATE); 621 | // } 622 | // cout<<"list_query[i].init_time"< algos = {FORA,LAZYUP}; 714 | vector> exact_ppr_result; 715 | // std::string exact_path = "result/"+config.graph_alias+"/"+"exact"+".txt"; 716 | // std::string result_path = "result/"+config.graph_alias+"/"+"C_accuracy"+".txt"; 717 | config.graph_location = config.get_graph_folder(); 718 | std::string exact_path = config.graph_location +"/exact.txt";; 719 | std::string result_path = config.graph_location +"/C_accuracy.txt"; 720 | 721 | 722 | 723 | ofstream result_file(result_path, ios::app); 724 | // ofstream result_file; 725 | // result_file.open(result_path); 726 | 727 | 728 | Graph graph(config.graph_location); 729 | if(access(exact_path.c_str(), NULL)==-1){ 730 | cerr<<"Exact Load error!"<> algo_ppr_result; 743 | load_ppr_result(algo_ppr_result, prefix); 744 | INFO(algo); 745 | calc_accuracy(algo_ppr_result, exact_ppr_result, result_file, graph.n); 746 | result_file<<" esf ="<< config.e_sf<<"end"< 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The GNU General Public License is a free, copyleft license for 12 | software and other kinds of works. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | the GNU General Public License is intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. We, the Free Software Foundation, use the 19 | GNU General Public License for most of our software; it applies also to 20 | any other work released this way by its authors. You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | them if you wish), that you receive source code or can get it if you 27 | want it, that you can change the software or use pieces of it in new 28 | free programs, and that you know you can do these things. 29 | 30 | To protect your rights, we need to prevent others from denying you 31 | these rights or asking you to surrender the rights. Therefore, you have 32 | certain responsibilities if you distribute copies of the software, or if 33 | you modify it: responsibilities to respect the freedom of others. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must pass on to the recipients the same 37 | freedoms that you received. You must make sure that they, too, receive 38 | or can get the source code. And you must show them these terms so they 39 | know their rights. 40 | 41 | Developers that use the GNU GPL protect your rights with two steps: 42 | (1) assert copyright on the software, and (2) offer you this License 43 | giving you legal permission to copy, distribute and/or modify it. 44 | 45 | For the developers' and authors' protection, the GPL clearly explains 46 | that there is no warranty for this free software. For both users' and 47 | authors' sake, the GPL requires that modified versions be marked as 48 | changed, so that their problems will not be attributed erroneously to 49 | authors of previous versions. 50 | 51 | Some devices are designed to deny users access to install or run 52 | modified versions of the software inside them, although the manufacturer 53 | can do so. This is fundamentally incompatible with the aim of 54 | protecting users' freedom to change the software. The systematic 55 | pattern of such abuse occurs in the area of products for individuals to 56 | use, which is precisely where it is most unacceptable. Therefore, we 57 | have designed this version of the GPL to prohibit the practice for those 58 | products. If such problems arise substantially in other domains, we 59 | stand ready to extend this provision to those domains in future versions 60 | of the GPL, as needed to protect the freedom of users. 61 | 62 | Finally, every program is threatened constantly by software patents. 63 | States should not allow patents to restrict development and use of 64 | software on general-purpose computers, but in those that do, we wish to 65 | avoid the special danger that patents applied to a free program could 66 | make it effectively proprietary. To prevent this, the GPL assures that 67 | patents cannot be used to render the program non-free. 68 | 69 | The precise terms and conditions for copying, distribution and 70 | modification follow. 71 | 72 | TERMS AND CONDITIONS 73 | 74 | 0. Definitions. 75 | 76 | "This License" refers to version 3 of the GNU General Public License. 77 | 78 | "Copyright" also means copyright-like laws that apply to other kinds of 79 | works, such as semiconductor masks. 80 | 81 | "The Program" refers to any copyrightable work licensed under this 82 | License. Each licensee is addressed as "you". "Licensees" and 83 | "recipients" may be individuals or organizations. 84 | 85 | To "modify" a work means to copy from or adapt all or part of the work 86 | in a fashion requiring copyright permission, other than the making of an 87 | exact copy. The resulting work is called a "modified version" of the 88 | earlier work or a work "based on" the earlier work. 89 | 90 | A "covered work" means either the unmodified Program or a work based 91 | on the Program. 92 | 93 | To "propagate" a work means to do anything with it that, without 94 | permission, would make you directly or secondarily liable for 95 | infringement under applicable copyright law, except executing it on a 96 | computer or modifying a private copy. Propagation includes copying, 97 | distribution (with or without modification), making available to the 98 | public, and in some countries other activities as well. 99 | 100 | To "convey" a work means any kind of propagation that enables other 101 | parties to make or receive copies. Mere interaction with a user through 102 | a computer network, with no transfer of a copy, is not conveying. 103 | 104 | An interactive user interface displays "Appropriate Legal Notices" 105 | to the extent that it includes a convenient and prominently visible 106 | feature that (1) displays an appropriate copyright notice, and (2) 107 | tells the user that there is no warranty for the work (except to the 108 | extent that warranties are provided), that licensees may convey the 109 | work under this License, and how to view a copy of this License. If 110 | the interface presents a list of user commands or options, such as a 111 | menu, a prominent item in the list meets this criterion. 112 | 113 | 1. Source Code. 114 | 115 | The "source code" for a work means the preferred form of the work 116 | for making modifications to it. "Object code" means any non-source 117 | form of a work. 118 | 119 | A "Standard Interface" means an interface that either is an official 120 | standard defined by a recognized standards body, or, in the case of 121 | interfaces specified for a particular programming language, one that 122 | is widely used among developers working in that language. 123 | 124 | The "System Libraries" of an executable work include anything, other 125 | than the work as a whole, that (a) is included in the normal form of 126 | packaging a Major Component, but which is not part of that Major 127 | Component, and (b) serves only to enable use of the work with that 128 | Major Component, or to implement a Standard Interface for which an 129 | implementation is available to the public in source code form. A 130 | "Major Component", in this context, means a major essential component 131 | (kernel, window system, and so on) of the specific operating system 132 | (if any) on which the executable work runs, or a compiler used to 133 | produce the work, or an object code interpreter used to run it. 134 | 135 | The "Corresponding Source" for a work in object code form means all 136 | the source code needed to generate, install, and (for an executable 137 | work) run the object code and to modify the work, including scripts to 138 | control those activities. However, it does not include the work's 139 | System Libraries, or general-purpose tools or generally available free 140 | programs which are used unmodified in performing those activities but 141 | which are not part of the work. For example, Corresponding Source 142 | includes interface definition files associated with source files for 143 | the work, and the source code for shared libraries and dynamically 144 | linked subprograms that the work is specifically designed to require, 145 | such as by intimate data communication or control flow between those 146 | subprograms and other parts of the work. 147 | 148 | The Corresponding Source need not include anything that users 149 | can regenerate automatically from other parts of the Corresponding 150 | Source. 151 | 152 | The Corresponding Source for a work in source code form is that 153 | same work. 154 | 155 | 2. Basic Permissions. 156 | 157 | All rights granted under this License are granted for the term of 158 | copyright on the Program, and are irrevocable provided the stated 159 | conditions are met. This License explicitly affirms your unlimited 160 | permission to run the unmodified Program. The output from running a 161 | covered work is covered by this License only if the output, given its 162 | content, constitutes a covered work. This License acknowledges your 163 | rights of fair use or other equivalent, as provided by copyright law. 164 | 165 | You may make, run and propagate covered works that you do not 166 | convey, without conditions so long as your license otherwise remains 167 | in force. You may convey covered works to others for the sole purpose 168 | of having them make modifications exclusively for you, or provide you 169 | with facilities for running those works, provided that you comply with 170 | the terms of this License in conveying all material for which you do 171 | not control copyright. Those thus making or running the covered works 172 | for you must do so exclusively on your behalf, under your direction 173 | and control, on terms that prohibit them from making any copies of 174 | your copyrighted material outside their relationship with you. 175 | 176 | Conveying under any other circumstances is permitted solely under 177 | the conditions stated below. Sublicensing is not allowed; section 10 178 | makes it unnecessary. 179 | 180 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 181 | 182 | No covered work shall be deemed part of an effective technological 183 | measure under any applicable law fulfilling obligations under article 184 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 185 | similar laws prohibiting or restricting circumvention of such 186 | measures. 187 | 188 | When you convey a covered work, you waive any legal power to forbid 189 | circumvention of technological measures to the extent such circumvention 190 | is effected by exercising rights under this License with respect to 191 | the covered work, and you disclaim any intention to limit operation or 192 | modification of the work as a means of enforcing, against the work's 193 | users, your or third parties' legal rights to forbid circumvention of 194 | technological measures. 195 | 196 | 4. Conveying Verbatim Copies. 197 | 198 | You may convey verbatim copies of the Program's source code as you 199 | receive it, in any medium, provided that you conspicuously and 200 | appropriately publish on each copy an appropriate copyright notice; 201 | keep intact all notices stating that this License and any 202 | non-permissive terms added in accord with section 7 apply to the code; 203 | keep intact all notices of the absence of any warranty; and give all 204 | recipients a copy of this License along with the Program. 205 | 206 | You may charge any price or no price for each copy that you convey, 207 | and you may offer support or warranty protection for a fee. 208 | 209 | 5. Conveying Modified Source Versions. 210 | 211 | You may convey a work based on the Program, or the modifications to 212 | produce it from the Program, in the form of source code under the 213 | terms of section 4, provided that you also meet all of these conditions: 214 | 215 | a) The work must carry prominent notices stating that you modified 216 | it, and giving a relevant date. 217 | 218 | b) The work must carry prominent notices stating that it is 219 | released under this License and any conditions added under section 220 | 7. This requirement modifies the requirement in section 4 to 221 | "keep intact all notices". 222 | 223 | c) You must license the entire work, as a whole, under this 224 | License to anyone who comes into possession of a copy. This 225 | License will therefore apply, along with any applicable section 7 226 | additional terms, to the whole of the work, and all its parts, 227 | regardless of how they are packaged. This License gives no 228 | permission to license the work in any other way, but it does not 229 | invalidate such permission if you have separately received it. 230 | 231 | d) If the work has interactive user interfaces, each must display 232 | Appropriate Legal Notices; however, if the Program has interactive 233 | interfaces that do not display Appropriate Legal Notices, your 234 | work need not make them do so. 235 | 236 | A compilation of a covered work with other separate and independent 237 | works, which are not by their nature extensions of the covered work, 238 | and which are not combined with it such as to form a larger program, 239 | in or on a volume of a storage or distribution medium, is called an 240 | "aggregate" if the compilation and its resulting copyright are not 241 | used to limit the access or legal rights of the compilation's users 242 | beyond what the individual works permit. Inclusion of a covered work 243 | in an aggregate does not cause this License to apply to the other 244 | parts of the aggregate. 245 | 246 | 6. Conveying Non-Source Forms. 247 | 248 | You may convey a covered work in object code form under the terms 249 | of sections 4 and 5, provided that you also convey the 250 | machine-readable Corresponding Source under the terms of this License, 251 | in one of these ways: 252 | 253 | a) Convey the object code in, or embodied in, a physical product 254 | (including a physical distribution medium), accompanied by the 255 | Corresponding Source fixed on a durable physical medium 256 | customarily used for software interchange. 257 | 258 | b) Convey the object code in, or embodied in, a physical product 259 | (including a physical distribution medium), accompanied by a 260 | written offer, valid for at least three years and valid for as 261 | long as you offer spare parts or customer support for that product 262 | model, to give anyone who possesses the object code either (1) a 263 | copy of the Corresponding Source for all the software in the 264 | product that is covered by this License, on a durable physical 265 | medium customarily used for software interchange, for a price no 266 | more than your reasonable cost of physically performing this 267 | conveying of source, or (2) access to copy the 268 | Corresponding Source from a network server at no charge. 269 | 270 | c) Convey individual copies of the object code with a copy of the 271 | written offer to provide the Corresponding Source. This 272 | alternative is allowed only occasionally and noncommercially, and 273 | only if you received the object code with such an offer, in accord 274 | with subsection 6b. 275 | 276 | d) Convey the object code by offering access from a designated 277 | place (gratis or for a charge), and offer equivalent access to the 278 | Corresponding Source in the same way through the same place at no 279 | further charge. You need not require recipients to copy the 280 | Corresponding Source along with the object code. If the place to 281 | copy the object code is a network server, the Corresponding Source 282 | may be on a different server (operated by you or a third party) 283 | that supports equivalent copying facilities, provided you maintain 284 | clear directions next to the object code saying where to find the 285 | Corresponding Source. Regardless of what server hosts the 286 | Corresponding Source, you remain obligated to ensure that it is 287 | available for as long as needed to satisfy these requirements. 288 | 289 | e) Convey the object code using peer-to-peer transmission, provided 290 | you inform other peers where the object code and Corresponding 291 | Source of the work are being offered to the general public at no 292 | charge under subsection 6d. 293 | 294 | A separable portion of the object code, whose source code is excluded 295 | from the Corresponding Source as a System Library, need not be 296 | included in conveying the object code work. 297 | 298 | A "User Product" is either (1) a "consumer product", which means any 299 | tangible personal property which is normally used for personal, family, 300 | or household purposes, or (2) anything designed or sold for incorporation 301 | into a dwelling. In determining whether a product is a consumer product, 302 | doubtful cases shall be resolved in favor of coverage. For a particular 303 | product received by a particular user, "normally used" refers to a 304 | typical or common use of that class of product, regardless of the status 305 | of the particular user or of the way in which the particular user 306 | actually uses, or expects or is expected to use, the product. A product 307 | is a consumer product regardless of whether the product has substantial 308 | commercial, industrial or non-consumer uses, unless such uses represent 309 | the only significant mode of use of the product. 310 | 311 | "Installation Information" for a User Product means any methods, 312 | procedures, authorization keys, or other information required to install 313 | and execute modified versions of a covered work in that User Product from 314 | a modified version of its Corresponding Source. The information must 315 | suffice to ensure that the continued functioning of the modified object 316 | code is in no case prevented or interfered with solely because 317 | modification has been made. 318 | 319 | If you convey an object code work under this section in, or with, or 320 | specifically for use in, a User Product, and the conveying occurs as 321 | part of a transaction in which the right of possession and use of the 322 | User Product is transferred to the recipient in perpetuity or for a 323 | fixed term (regardless of how the transaction is characterized), the 324 | Corresponding Source conveyed under this section must be accompanied 325 | by the Installation Information. But this requirement does not apply 326 | if neither you nor any third party retains the ability to install 327 | modified object code on the User Product (for example, the work has 328 | been installed in ROM). 329 | 330 | The requirement to provide Installation Information does not include a 331 | requirement to continue to provide support service, warranty, or updates 332 | for a work that has been modified or installed by the recipient, or for 333 | the User Product in which it has been modified or installed. Access to a 334 | network may be denied when the modification itself materially and 335 | adversely affects the operation of the network or violates the rules and 336 | protocols for communication across the network. 337 | 338 | Corresponding Source conveyed, and Installation Information provided, 339 | in accord with this section must be in a format that is publicly 340 | documented (and with an implementation available to the public in 341 | source code form), and must require no special password or key for 342 | unpacking, reading or copying. 343 | 344 | 7. Additional Terms. 345 | 346 | "Additional permissions" are terms that supplement the terms of this 347 | License by making exceptions from one or more of its conditions. 348 | Additional permissions that are applicable to the entire Program shall 349 | be treated as though they were included in this License, to the extent 350 | that they are valid under applicable law. If additional permissions 351 | apply only to part of the Program, that part may be used separately 352 | under those permissions, but the entire Program remains governed by 353 | this License without regard to the additional permissions. 354 | 355 | When you convey a copy of a covered work, you may at your option 356 | remove any additional permissions from that copy, or from any part of 357 | it. (Additional permissions may be written to require their own 358 | removal in certain cases when you modify the work.) You may place 359 | additional permissions on material, added by you to a covered work, 360 | for which you have or can give appropriate copyright permission. 361 | 362 | Notwithstanding any other provision of this License, for material you 363 | add to a covered work, you may (if authorized by the copyright holders of 364 | that material) supplement the terms of this License with terms: 365 | 366 | a) Disclaiming warranty or limiting liability differently from the 367 | terms of sections 15 and 16 of this License; or 368 | 369 | b) Requiring preservation of specified reasonable legal notices or 370 | author attributions in that material or in the Appropriate Legal 371 | Notices displayed by works containing it; or 372 | 373 | c) Prohibiting misrepresentation of the origin of that material, or 374 | requiring that modified versions of such material be marked in 375 | reasonable ways as different from the original version; or 376 | 377 | d) Limiting the use for publicity purposes of names of licensors or 378 | authors of the material; or 379 | 380 | e) Declining to grant rights under trademark law for use of some 381 | trade names, trademarks, or service marks; or 382 | 383 | f) Requiring indemnification of licensors and authors of that 384 | material by anyone who conveys the material (or modified versions of 385 | it) with contractual assumptions of liability to the recipient, for 386 | any liability that these contractual assumptions directly impose on 387 | those licensors and authors. 388 | 389 | All other non-permissive additional terms are considered "further 390 | restrictions" within the meaning of section 10. If the Program as you 391 | received it, or any part of it, contains a notice stating that it is 392 | governed by this License along with a term that is a further 393 | restriction, you may remove that term. If a license document contains 394 | a further restriction but permits relicensing or conveying under this 395 | License, you may add to a covered work material governed by the terms 396 | of that license document, provided that the further restriction does 397 | not survive such relicensing or conveying. 398 | 399 | If you add terms to a covered work in accord with this section, you 400 | must place, in the relevant source files, a statement of the 401 | additional terms that apply to those files, or a notice indicating 402 | where to find the applicable terms. 403 | 404 | Additional terms, permissive or non-permissive, may be stated in the 405 | form of a separately written license, or stated as exceptions; 406 | the above requirements apply either way. 407 | 408 | 8. Termination. 409 | 410 | You may not propagate or modify a covered work except as expressly 411 | provided under this License. Any attempt otherwise to propagate or 412 | modify it is void, and will automatically terminate your rights under 413 | this License (including any patent licenses granted under the third 414 | paragraph of section 11). 415 | 416 | However, if you cease all violation of this License, then your 417 | license from a particular copyright holder is reinstated (a) 418 | provisionally, unless and until the copyright holder explicitly and 419 | finally terminates your license, and (b) permanently, if the copyright 420 | holder fails to notify you of the violation by some reasonable means 421 | prior to 60 days after the cessation. 422 | 423 | Moreover, your license from a particular copyright holder is 424 | reinstated permanently if the copyright holder notifies you of the 425 | violation by some reasonable means, this is the first time you have 426 | received notice of violation of this License (for any work) from that 427 | copyright holder, and you cure the violation prior to 30 days after 428 | your receipt of the notice. 429 | 430 | Termination of your rights under this section does not terminate the 431 | licenses of parties who have received copies or rights from you under 432 | this License. If your rights have been terminated and not permanently 433 | reinstated, you do not qualify to receive new licenses for the same 434 | material under section 10. 435 | 436 | 9. Acceptance Not Required for Having Copies. 437 | 438 | You are not required to accept this License in order to receive or 439 | run a copy of the Program. Ancillary propagation of a covered work 440 | occurring solely as a consequence of using peer-to-peer transmission 441 | to receive a copy likewise does not require acceptance. However, 442 | nothing other than this License grants you permission to propagate or 443 | modify any covered work. These actions infringe copyright if you do 444 | not accept this License. Therefore, by modifying or propagating a 445 | covered work, you indicate your acceptance of this License to do so. 446 | 447 | 10. Automatic Licensing of Downstream Recipients. 448 | 449 | Each time you convey a covered work, the recipient automatically 450 | receives a license from the original licensors, to run, modify and 451 | propagate that work, subject to this License. You are not responsible 452 | for enforcing compliance by third parties with this License. 453 | 454 | An "entity transaction" is a transaction transferring control of an 455 | organization, or substantially all assets of one, or subdividing an 456 | organization, or merging organizations. If propagation of a covered 457 | work results from an entity transaction, each party to that 458 | transaction who receives a copy of the work also receives whatever 459 | licenses to the work the party's predecessor in interest had or could 460 | give under the previous paragraph, plus a right to possession of the 461 | Corresponding Source of the work from the predecessor in interest, if 462 | the predecessor has it or can get it with reasonable efforts. 463 | 464 | You may not impose any further restrictions on the exercise of the 465 | rights granted or affirmed under this License. For example, you may 466 | not impose a license fee, royalty, or other charge for exercise of 467 | rights granted under this License, and you may not initiate litigation 468 | (including a cross-claim or counterclaim in a lawsuit) alleging that 469 | any patent claim is infringed by making, using, selling, offering for 470 | sale, or importing the Program or any portion of it. 471 | 472 | 11. Patents. 473 | 474 | A "contributor" is a copyright holder who authorizes use under this 475 | License of the Program or a work on which the Program is based. The 476 | work thus licensed is called the contributor's "contributor version". 477 | 478 | A contributor's "essential patent claims" are all patent claims 479 | owned or controlled by the contributor, whether already acquired or 480 | hereafter acquired, that would be infringed by some manner, permitted 481 | by this License, of making, using, or selling its contributor version, 482 | but do not include claims that would be infringed only as a 483 | consequence of further modification of the contributor version. For 484 | purposes of this definition, "control" includes the right to grant 485 | patent sublicenses in a manner consistent with the requirements of 486 | this License. 487 | 488 | Each contributor grants you a non-exclusive, worldwide, royalty-free 489 | patent license under the contributor's essential patent claims, to 490 | make, use, sell, offer for sale, import and otherwise run, modify and 491 | propagate the contents of its contributor version. 492 | 493 | In the following three paragraphs, a "patent license" is any express 494 | agreement or commitment, however denominated, not to enforce a patent 495 | (such as an express permission to practice a patent or covenant not to 496 | sue for patent infringement). To "grant" such a patent license to a 497 | party means to make such an agreement or commitment not to enforce a 498 | patent against the party. 499 | 500 | If you convey a covered work, knowingly relying on a patent license, 501 | and the Corresponding Source of the work is not available for anyone 502 | to copy, free of charge and under the terms of this License, through a 503 | publicly available network server or other readily accessible means, 504 | then you must either (1) cause the Corresponding Source to be so 505 | available, or (2) arrange to deprive yourself of the benefit of the 506 | patent license for this particular work, or (3) arrange, in a manner 507 | consistent with the requirements of this License, to extend the patent 508 | license to downstream recipients. "Knowingly relying" means you have 509 | actual knowledge that, but for the patent license, your conveying the 510 | covered work in a country, or your recipient's use of the covered work 511 | in a country, would infringe one or more identifiable patents in that 512 | country that you have reason to believe are valid. 513 | 514 | If, pursuant to or in connection with a single transaction or 515 | arrangement, you convey, or propagate by procuring conveyance of, a 516 | covered work, and grant a patent license to some of the parties 517 | receiving the covered work authorizing them to use, propagate, modify 518 | or convey a specific copy of the covered work, then the patent license 519 | you grant is automatically extended to all recipients of the covered 520 | work and works based on it. 521 | 522 | A patent license is "discriminatory" if it does not include within 523 | the scope of its coverage, prohibits the exercise of, or is 524 | conditioned on the non-exercise of one or more of the rights that are 525 | specifically granted under this License. You may not convey a covered 526 | work if you are a party to an arrangement with a third party that is 527 | in the business of distributing software, under which you make payment 528 | to the third party based on the extent of your activity of conveying 529 | the work, and under which the third party grants, to any of the 530 | parties who would receive the covered work from you, a discriminatory 531 | patent license (a) in connection with copies of the covered work 532 | conveyed by you (or copies made from those copies), or (b) primarily 533 | for and in connection with specific products or compilations that 534 | contain the covered work, unless you entered into that arrangement, 535 | or that patent license was granted, prior to 28 March 2007. 536 | 537 | Nothing in this License shall be construed as excluding or limiting 538 | any implied license or other defenses to infringement that may 539 | otherwise be available to you under applicable patent law. 540 | 541 | 12. No Surrender of Others' Freedom. 542 | 543 | If conditions are imposed on you (whether by court order, agreement or 544 | otherwise) that contradict the conditions of this License, they do not 545 | excuse you from the conditions of this License. If you cannot convey a 546 | covered work so as to satisfy simultaneously your obligations under this 547 | License and any other pertinent obligations, then as a consequence you may 548 | not convey it at all. For example, if you agree to terms that obligate you 549 | to collect a royalty for further conveying from those to whom you convey 550 | the Program, the only way you could satisfy both those terms and this 551 | License would be to refrain entirely from conveying the Program. 552 | 553 | 13. Use with the GNU Affero General Public License. 554 | 555 | Notwithstanding any other provision of this License, you have 556 | permission to link or combine any covered work with a work licensed 557 | under version 3 of the GNU Affero General Public License into a single 558 | combined work, and to convey the resulting work. The terms of this 559 | License will continue to apply to the part which is the covered work, 560 | but the special requirements of the GNU Affero General Public License, 561 | section 13, concerning interaction through a network will apply to the 562 | combination as such. 563 | 564 | 14. Revised Versions of this License. 565 | 566 | The Free Software Foundation may publish revised and/or new versions of 567 | the GNU General Public License from time to time. Such new versions will 568 | be similar in spirit to the present version, but may differ in detail to 569 | address new problems or concerns. 570 | 571 | Each version is given a distinguishing version number. If the 572 | Program specifies that a certain numbered version of the GNU General 573 | Public License "or any later version" applies to it, you have the 574 | option of following the terms and conditions either of that numbered 575 | version or of any later version published by the Free Software 576 | Foundation. If the Program does not specify a version number of the 577 | GNU General Public License, you may choose any version ever published 578 | by the Free Software Foundation. 579 | 580 | If the Program specifies that a proxy can decide which future 581 | versions of the GNU General Public License can be used, that proxy's 582 | public statement of acceptance of a version permanently authorizes you 583 | to choose that version for the Program. 584 | 585 | Later license versions may give you additional or different 586 | permissions. However, no additional obligations are imposed on any 587 | author or copyright holder as a result of your choosing to follow a 588 | later version. 589 | 590 | 15. Disclaimer of Warranty. 591 | 592 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 593 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 594 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 595 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 596 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 597 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 598 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 599 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 600 | 601 | 16. Limitation of Liability. 602 | 603 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 604 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 605 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 606 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 607 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 608 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 609 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 610 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 611 | SUCH DAMAGES. 612 | 613 | 17. Interpretation of Sections 15 and 16. 614 | 615 | If the disclaimer of warranty and limitation of liability provided 616 | above cannot be given local legal effect according to their terms, 617 | reviewing courts shall apply local law that most closely approximates 618 | an absolute waiver of all civil liability in connection with the 619 | Program, unless a warranty or assumption of liability accompanies a 620 | copy of the Program in return for a fee. 621 | 622 | END OF TERMS AND CONDITIONS 623 | 624 | How to Apply These Terms to Your New Programs 625 | 626 | If you develop a new program, and you want it to be of the greatest 627 | possible use to the public, the best way to achieve this is to make it 628 | free software which everyone can redistribute and change under these terms. 629 | 630 | To do so, attach the following notices to the program. It is safest 631 | to attach them to the start of each source file to most effectively 632 | state the exclusion of warranty; and each file should have at least 633 | the "copyright" line and a pointer to where the full notice is found. 634 | 635 | {one line to give the program's name and a brief idea of what it does.} 636 | Copyright (C) {year} {name of author} 637 | 638 | This program is free software: you can redistribute it and/or modify 639 | it under the terms of the GNU General Public License as published by 640 | the Free Software Foundation, either version 3 of the License, or 641 | (at your option) any later version. 642 | 643 | This program is distributed in the hope that it will be useful, 644 | but WITHOUT ANY WARRANTY; without even the implied warranty of 645 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 646 | GNU General Public License for more details. 647 | 648 | You should have received a copy of the GNU General Public License 649 | along with this program. If not, see . 650 | 651 | Also add information on how to contact you by electronic and paper mail. 652 | 653 | If the program does terminal interaction, make it output a short 654 | notice like this when it starts in an interactive mode: 655 | 656 | {project} Copyright (C) {year} {fullname} 657 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 658 | This is free software, and you are welcome to redistribute it 659 | under certain conditions; type `show c' for details. 660 | 661 | The hypothetical commands `show w' and `show c' should show the appropriate 662 | parts of the General Public License. Of course, your program's commands 663 | might be different; for a GUI interface, you would use an "about box". 664 | 665 | You should also get your employer (if you work as a programmer) or school, 666 | if any, to sign a "copyright disclaimer" for the program, if necessary. 667 | For more information on this, and how to apply and follow the GNU GPL, see 668 | . 669 | 670 | The GNU General Public License does not permit incorporating your program 671 | into proprietary programs. If your program is a subroutine library, you 672 | may consider it more useful to permit linking proprietary applications with 673 | the library. If this is what you want to do, use the GNU Lesser General 674 | Public License instead of this License. But first, please read 675 | . 676 | ======= 677 | MIT License 678 | 679 | Copyright (c) 2022 ZulunZhu 680 | 681 | Permission is hereby granted, free of charge, to any person obtaining a copy 682 | of this software and associated documentation files (the "Software"), to deal 683 | in the Software without restriction, including without limitation the rights 684 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 685 | copies of the Software, and to permit persons to whom the Software is 686 | furnished to do so, subject to the following conditions: 687 | 688 | The above copyright notice and this permission notice shall be included in all 689 | copies or substantial portions of the Software. 690 | 691 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 692 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 693 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 694 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 695 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 696 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 697 | SOFTWARE. 698 | >>>>>>> 013ff970ecb651ca564886e29749130802d75156 699 | --------------------------------------------------------------------------------