Repository: FormalLanguageConstrainedPathQuerying/CFPQ_Data (language: python)

Issue:
Replace GTgraph with networkx graph generator 
Is it possible to replace GTgraph (which is currently used to generate synthetic graphs) with generators from [networkx](https://networkx.github.io/).
redis_rdf deprecated



Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index b483d688..86794fc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+# IDEA
+.idea
+
 # Byte-compiled / optimized / DLL files
 __pycache__/
 *.py[cod]
@@ -120,4 +123,4 @@ log
 tmp.txt
 
 # MacOS directory structure meta
-/**/.DS_Store
\ No newline at end of file
+/**/.DS_Store
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 00000000..797be343
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,514 @@
+[MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-whitelist=
+
+# Specify a score threshold to be exceeded before program exits with error.
+fail-under=10.0
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+init-hook='import sys; sys.path.append("/path/to/root")'
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use.
+jobs=8
+
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=invalid-name,
+        missing-module-docstring,
+        too-many-locals,
+        import-error,
+        too-many-instance-attributes
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[REPORTS]
+
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'error', 'warning', 'refactor', and 'convention'
+# which contain the number of messages in each category, as well as 'statement'
+# which is the total number of statements analyzed. This score is used by the
+# global evaluation report (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages.
+reports=no
+
+# Activate the evaluation score.
+score=yes
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=no
+
+# This flag controls whether the implicit-str-concat should generate a warning
+# on implicit string concatenation in sequences defined over several lines.
+check-str-concat-over-line-jumps=no
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains the private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[BASIC]
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style.
+#argument-rgx=
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style.
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+          bar,
+          baz,
+          toto,
+          tutu,
+          tata
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+bad-names-rgxs=
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style.
+#class-attribute-rgx=
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-
+# style.
+#class-rgx=
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style.
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style.
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+           j,
+           k,
+           ex,
+           Run,
+           _
+
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+good-names-rgxs=
+
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style.
+#inlinevar-rgx=
+
+# Naming style matching correct method names.
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style.
+#method-rgx=
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style.
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style.
+#variable-rgx=
+
+
+[LOGGING]
+
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style=old
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid defining new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+          _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore.
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+      XXX,
+      TODO
+
+# Regular expression of note tags to take in consideration.
+#notes-rgx=
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis). It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+# List of decorators that change the signature of a decorated function.
+signature-mutators=
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+                      __new__,
+                      setUp,
+                      __post_init__
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+                  _fields,
+                  _replace,
+                  _source,
+                  _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=cls
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method.
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr=5
+
+# Maximum number of branch for function / method body.
+max-branches=12
+
+# Maximum number of locals for function / method body.
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body.
+max-returns=6
+
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[IMPORTS]
+
+# List of modules that can be imported at any level, not just the top level
+# one.
+allow-any-import-level=
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=optparse,tkinter.tix
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled).
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled).
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled).
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+# Couples of modules and preferred modules, separated by a comma.
+preferred-modules=
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "BaseException, Exception".
+overgeneral-exceptions=BaseException,
+                       Exception
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..43b49573
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+language: python
+cache: pip
+jobs:
+  include:
+    - name: "Docker"
+      services:
+        - docker
+      python: "3.8.0"
+      script:
+        - docker build -t cfpq_data .
+        - docker run -it --rm -v "$PWD":/CFPQ_Data cfpq_data python3 -m pytest -vv -s  tests/
+    - name: "Linux"
+      os: linux
+      python: "3.8.0"
+    - name: "MacOS"
+      os: osx
+      osx_image: xcode12u
+      language: shell
+    - name: "Windows"
+      os: windows
+      language: shell
+      before_install:
+        - choco install python --version 3.8.0
+        - choco install jdk8
+        - cmd.exe //c "RefreshEnv.cmd"
+        - python -m pip install --upgrade pip
+      env: PATH=/c/Python38:/c/Python38/Scripts:$PATH
+install:
+  - pip3 install --upgrade pip
+  - pip3 install -r requirements.txt
+script: python3 -m pytest -vv -s tests/ || python -m pytest -vv -s tests/ || Python38 -m pytest -vv -s tests/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..4bfe5df2
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+FROM ubuntu:latest
+
+RUN apt -y update && \
+    apt-get -y install software-properties-common && \
+    add-apt-repository ppa:deadsnakes/ppa && \
+    apt -y install \
+    python3.8 \
+    python3-pip \
+    git \
+    openjdk-8-jdk
+
+COPY . /CFPQ_Data
+
+WORKDIR /CFPQ_Data
+RUN pip3 install -r requirements.txt
diff --git a/cfpq_data/__init__.py b/cfpq_data/__init__.py
new file mode 100644
index 00000000..12f1eb08
--- /dev/null
+++ b/cfpq_data/__init__.py
@@ -0,0 +1,19 @@
+"""
+Graphs and grammars for experimental analysis of context-free path querying algorithms
+
+- RDF: Class for loading fixed versions of real-world RDF files
+- MemoryAliases: Class for loading real-world data for points-to analysis of C code
+- WorstCase: Class for generating graphs with two cycles
+- SparseGraph: Class for generating graphs with NetworkX to emulate sparse data
+- ScaleFree: Class for generating graphs by using the Barab'asi-Albert model of scale-free networks
+- FullGraph: Class for generating cycle graphs, all edges of which are labeled with the same token
+- LUBM: Class for generating Lehigh University Benchmark graphs
+"""
+
+from cfpq_data.src.graphs.full_graph import FullGraph
+from cfpq_data.src.graphs.lubm_graph import LUBM
+from cfpq_data.src.graphs.memory_aliases_graph import MemoryAliases
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.graphs.scale_free_graph import ScaleFree
+from cfpq_data.src.graphs.sparse_graph import SparseGraph
+from cfpq_data.src.graphs.worst_case_graph import WorstCase
diff --git a/cfpq_data/config.py b/cfpq_data/config.py
new file mode 100644
index 00000000..88f38681
--- /dev/null
+++ b/cfpq_data/config.py
@@ -0,0 +1,11 @@
+import json
+from pathlib import Path
+
+PACKAGE_NAME = 'cfpq_data'
+
+MAIN_FOLDER = Path(__file__).parent
+
+with open(MAIN_FOLDER / 'release_notes.json', 'r') as input_file:
+    RELEASE_INFO = json.load(input_file)
+
+PACKAGE_VERSION = RELEASE_INFO['version']
diff --git a/tools/redis-rdf/src/__init__.py b/cfpq_data/data/.gitkeep
similarity index 100%
rename from tools/redis-rdf/src/__init__.py
rename to cfpq_data/data/.gitkeep
diff --git a/tools/redis-rdf/src/utils/__init__.py b/cfpq_data/data/FullGraph/.gitkeep
similarity index 100%
rename from tools/redis-rdf/src/utils/__init__.py
rename to cfpq_data/data/FullGraph/.gitkeep
diff --git a/cfpq_data/data/FullGraph/Grammars/.gitkeep b/cfpq_data/data/FullGraph/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/FullGraph/Grammars/A_star0.txt b/cfpq_data/data/FullGraph/Grammars/A_star0.txt
similarity index 90%
rename from data/FullGraph/Grammars/A_star0.txt
rename to cfpq_data/data/FullGraph/Grammars/A_star0.txt
index 3b7aabbe..419b335b 100644
--- a/data/FullGraph/Grammars/A_star0.txt
+++ b/cfpq_data/data/FullGraph/Grammars/A_star0.txt
@@ -1,3 +1,3 @@
-s
-A
+s
+A
 s -> A s | eps
\ No newline at end of file
diff --git a/data/FullGraph/Grammars/A_star1.txt b/cfpq_data/data/FullGraph/Grammars/A_star1.txt
similarity index 88%
rename from data/FullGraph/Grammars/A_star1.txt
rename to cfpq_data/data/FullGraph/Grammars/A_star1.txt
index 50374e35..1413d6f2 100644
--- a/data/FullGraph/Grammars/A_star1.txt
+++ b/cfpq_data/data/FullGraph/Grammars/A_star1.txt
@@ -1,3 +1,3 @@
-s
-A
+s
+A
 s -> s s | A
\ No newline at end of file
diff --git a/data/FullGraph/Grammars/A_star2.txt b/cfpq_data/data/FullGraph/Grammars/A_star2.txt
similarity index 92%
rename from data/FullGraph/Grammars/A_star2.txt
rename to cfpq_data/data/FullGraph/Grammars/A_star2.txt
index bf7a7bbf..9a66dae9 100644
--- a/data/FullGraph/Grammars/A_star2.txt
+++ b/cfpq_data/data/FullGraph/Grammars/A_star2.txt
@@ -1,3 +1,3 @@
-s
-A
+s
+A
 s -> s s | s s s | A
\ No newline at end of file
diff --git a/cfpq_data/data/FullGraph/Graphs/.gitkeep b/cfpq_data/data/FullGraph/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/LUBM/.gitkeep b/cfpq_data/data/LUBM/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/LUBM/Grammars/.gitkeep b/cfpq_data/data/LUBM/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/LUBM/Graphs/.gitkeep b/cfpq_data/data/LUBM/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/MemoryAliases/.gitkeep b/cfpq_data/data/MemoryAliases/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/MemoryAliases/Grammars/.gitkeep b/cfpq_data/data/MemoryAliases/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/MemoryAliases/Grammars/g1.txt b/cfpq_data/data/MemoryAliases/Grammars/g1.txt
similarity index 100%
rename from data/MemoryAliases/Grammars/g1.txt
rename to cfpq_data/data/MemoryAliases/Grammars/g1.txt
diff --git a/data/MemoryAliases/Grammars/g2.txt b/cfpq_data/data/MemoryAliases/Grammars/g2.txt
similarity index 100%
rename from data/MemoryAliases/Grammars/g2.txt
rename to cfpq_data/data/MemoryAliases/Grammars/g2.txt
diff --git a/cfpq_data/data/MemoryAliases/Graphs/.gitkeep b/cfpq_data/data/MemoryAliases/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/MemoryAliases/Graphs/Apache_httpd_2.2.18_pointsto_graph_meta.json b/cfpq_data/data/MemoryAliases/Graphs/Apache_httpd_2.2.18_pointsto_graph_meta.json
new file mode 100644
index 00000000..6059c1b7
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/Apache_httpd_2.2.18_pointsto_graph_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "Apache_httpd_2.2.18_pointsto_graph.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 1721418,
+    "edges": 1510411,
+    "size of file": 138037427
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/PostgreSQL_8.3.9_pointsto_graph_meta.json b/cfpq_data/data/MemoryAliases/Graphs/PostgreSQL_8.3.9_pointsto_graph_meta.json
new file mode 100644
index 00000000..aab67c5d
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/PostgreSQL_8.3.9_pointsto_graph_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "PostgreSQL_8.3.9_pointsto_graph.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 5203419,
+    "edges": 4678543,
+    "size of file": 429924717
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/arch_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/arch_afterInline.txt_meta.json
new file mode 100644
index 00000000..b42b44f9
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/arch_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "arch_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3448422,
+    "edges": 2970242,
+    "size of file": 278669103
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/block_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/block_afterInline.txt_meta.json
new file mode 100644
index 00000000..16d46b13
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/block_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "block_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3423234,
+    "edges": 2951393,
+    "size of file": 276869199
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/bzip2.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/bzip2.txt_meta.json
new file mode 100644
index 00000000..608a69d7
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/bzip2.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "bzip2.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 632,
+    "edges": 556,
+    "size of file": 45432
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/crypto_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/crypto_afterInline.txt_meta.json
new file mode 100644
index 00000000..e39dc097
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/crypto_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "crypto_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3464970,
+    "edges": 2988387,
+    "size of file": 280248585
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/drivers_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/drivers_afterInline.txt_meta.json
new file mode 100644
index 00000000..39d877ca
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/drivers_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "drivers_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 4273803,
+    "edges": 3707769,
+    "size of file": 346720743
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/fs_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/fs_afterInline.txt_meta.json
new file mode 100644
index 00000000..f5eaedac
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/fs_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "fs_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 4177416,
+    "edges": 3609373,
+    "size of file": 337856145
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/gzip.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/gzip.txt_meta.json
new file mode 100644
index 00000000..90ae0aac
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/gzip.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "gzip.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 2687,
+    "edges": 2293,
+    "size of file": 199239
+}
diff --git a/cfpq_data/data/MemoryAliases/Graphs/init_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/init_afterInline.txt_meta.json
new file mode 100644
index 00000000..cf02c9ad
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/init_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "init_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 2446224,
+    "edges": 2112809,
+    "size of file": 197676888
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/ipc_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/ipc_afterInline.txt_meta.json
new file mode 100644
index 00000000..ef1bb224
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/ipc_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "ipc_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3401022,
+    "edges": 2931498,
+    "size of file": 275033440
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/kernel_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/kernel_afterInline.txt_meta.json
new file mode 100644
index 00000000..e2c5a115
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/kernel_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "kernel_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 11254434,
+    "edges": 9484213,
+    "size of file": 886162222
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/lib_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/lib_afterInline.txt_meta.json
new file mode 100644
index 00000000..6b4d0bb5
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/lib_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "lib_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3401355,
+    "edges": 2931880,
+    "size of file": 275060825
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/ls.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/ls.txt_meta.json
new file mode 100644
index 00000000..f1ca5a85
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/ls.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "ls.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 1687,
+    "edges": 1453,
+    "size of file": 126329
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/mm_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/mm_afterInline.txt_meta.json
new file mode 100644
index 00000000..c57d80b6
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/mm_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "mm_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 2538243,
+    "edges": 2191079,
+    "size of file": 205010253
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/net_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/net_afterInline.txt_meta.json
new file mode 100644
index 00000000..88f49404
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/net_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "net_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 4039470,
+    "edges": 3500141,
+    "size of file": 327815218
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/pr.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/pr.txt_meta.json
new file mode 100644
index 00000000..38ac87df
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/pr.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "pr.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 815,
+    "edges": 692,
+    "size of file": 59629
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/security_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/security_afterInline.txt_meta.json
new file mode 100644
index 00000000..e0d46668
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/security_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "security_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3479982,
+    "edges": 3003326,
+    "size of file": 281698638
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/sound_afterInline.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/sound_afterInline.txt_meta.json
new file mode 100644
index 00000000..1a40cc79
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/sound_afterInline.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "sound_afterInline.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 3528861,
+    "edges": 3049732,
+    "size of file": 285856817
+}
\ No newline at end of file
diff --git a/cfpq_data/data/MemoryAliases/Graphs/wc.txt_meta.json b/cfpq_data/data/MemoryAliases/Graphs/wc.txt_meta.json
new file mode 100644
index 00000000..222f0888
--- /dev/null
+++ b/cfpq_data/data/MemoryAliases/Graphs/wc.txt_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "wc.txt.xml",
+    "path": "data/MemoryAliases/Graphs",
+    "version": "0.0.0",
+    "vertices": 332,
+    "edges": 269,
+    "size of file": 23679
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/.gitkeep b/cfpq_data/data/RDF/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/RDF/Grammars/.gitkeep b/cfpq_data/data/RDF/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/RDF/Grammars/g1.txt b/cfpq_data/data/RDF/Grammars/g1.txt
new file mode 100644
index 00000000..69839996
--- /dev/null
+++ b/cfpq_data/data/RDF/Grammars/g1.txt
@@ -0,0 +1,3 @@
+s
+SCO SCO_R T T_R
+s -> SCO_R s SCO | T_R s T | SCO_R SCO | T_R T
diff --git a/cfpq_data/data/RDF/Grammars/g2.txt b/cfpq_data/data/RDF/Grammars/g2.txt
new file mode 100644
index 00000000..18e7327f
--- /dev/null
+++ b/cfpq_data/data/RDF/Grammars/g2.txt
@@ -0,0 +1,3 @@
+s
+SCO_R SCO T_R T
+s -> SCO_R s SCO | SCO
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Grammars/geo.txt b/cfpq_data/data/RDF/Grammars/geo.txt
new file mode 100644
index 00000000..39059bf2
--- /dev/null
+++ b/cfpq_data/data/RDF/Grammars/geo.txt
@@ -0,0 +1,3 @@
+s
+BT BT_R
+s -> BT s BT_R | BT BT_R
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/.gitkeep b/cfpq_data/data/RDF/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/RDF/Graphs/atom-primitive_meta.json b/cfpq_data/data/RDF/Graphs/atom-primitive_meta.json
new file mode 100644
index 00000000..c3414ebf
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/atom-primitive_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "atom-primitive.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 291,
+    "edges": 425,
+    "size of file": 48884
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/biomedical-mesure-primitive_meta.json b/cfpq_data/data/RDF/Graphs/biomedical-mesure-primitive_meta.json
new file mode 100644
index 00000000..2acceb4c
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/biomedical-mesure-primitive_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "biomedical-mesure-primitive.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 341,
+    "edges": 459,
+    "size of file": 53057
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/core_meta.json b/cfpq_data/data/RDF/Graphs/core_meta.json
new file mode 100644
index 00000000..1f8c47a1
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/core_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "core.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 1323,
+    "edges": 2752,
+    "size of file": 270846
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/eclass_514en_meta.json b/cfpq_data/data/RDF/Graphs/eclass_514en_meta.json
new file mode 100644
index 00000000..246fbef7
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/eclass_514en_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "eclass_514en.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 239111,
+    "edges": 360248,
+    "size of file": 40191953
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/enzyme_meta.json b/cfpq_data/data/RDF/Graphs/enzyme_meta.json
new file mode 100644
index 00000000..afd97c79
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/enzyme_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "enzyme.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 48815,
+    "edges": 86543,
+    "size of file": 8806602
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/foaf_meta.json b/cfpq_data/data/RDF/Graphs/foaf_meta.json
new file mode 100644
index 00000000..cb6ab74a
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/foaf_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "foaf.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 256,
+    "edges": 631,
+    "size of file": 44209
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/funding_meta.json b/cfpq_data/data/RDF/Graphs/funding_meta.json
new file mode 100644
index 00000000..293a9c07
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/funding_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "funding.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 778,
+    "edges": 1086,
+    "size of file": 131564
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/generations_meta.json b/cfpq_data/data/RDF/Graphs/generations_meta.json
new file mode 100644
index 00000000..2f208e1e
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/generations_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "generations.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 129,
+    "edges": 273,
+    "size of file": 13826
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/geospecies_meta.json b/cfpq_data/data/RDF/Graphs/geospecies_meta.json
new file mode 100644
index 00000000..33e66862
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/geospecies_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "geospecies.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 450609,
+    "edges": 2201532,
+    "size of file": 187133434
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/go-hierarchy_meta.json b/cfpq_data/data/RDF/Graphs/go-hierarchy_meta.json
new file mode 100644
index 00000000..28fa0ef8
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/go-hierarchy_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "go-hierarchy.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 45007,
+    "edges": 490109,
+    "size of file": 38888638
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/go_meta.json b/cfpq_data/data/RDF/Graphs/go_meta.json
new file mode 100644
index 00000000..f88efa36
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/go_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "go.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 582929,
+    "edges": 1437437,
+    "size of file": 164749424
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/pathways_meta.json b/cfpq_data/data/RDF/Graphs/pathways_meta.json
new file mode 100644
index 00000000..9c763cae
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/pathways_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "pathways.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 6238,
+    "edges": 12363,
+    "size of file": 1305842
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/people_pets_meta.json b/cfpq_data/data/RDF/Graphs/people_pets_meta.json
new file mode 100644
index 00000000..d97243bc
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/people_pets_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "people_pets.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 337,
+    "edges": 640,
+    "size of file": 40375
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/pizza_meta.json b/cfpq_data/data/RDF/Graphs/pizza_meta.json
new file mode 100644
index 00000000..919b4e00
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/pizza_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "pizza.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 671,
+    "edges": 1980,
+    "size of file": 126939
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/skos_meta.json b/cfpq_data/data/RDF/Graphs/skos_meta.json
new file mode 100644
index 00000000..523c75b6
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/skos_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "skos.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 144,
+    "edges": 252,
+    "size of file": 28966
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/taxonomy-hierarchy_meta.json b/cfpq_data/data/RDF/Graphs/taxonomy-hierarchy_meta.json
new file mode 100644
index 00000000..a7ac3b2c
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/taxonomy-hierarchy_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "taxonomy-hierarchy.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 2112625,
+    "edges": 32876289,
+    "size of file": 2425286037
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/taxonomy_meta.json b/cfpq_data/data/RDF/Graphs/taxonomy_meta.json
new file mode 100644
index 00000000..900e95e9
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/taxonomy_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "taxonomy.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 5728398,
+    "edges": 14922125,
+    "size of file": 1293836336
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/travel_meta.json b/cfpq_data/data/RDF/Graphs/travel_meta.json
new file mode 100644
index 00000000..0c483151
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/travel_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "travel.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 131,
+    "edges": 277,
+    "size of file": 17169
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/univ-bench_meta.json b/cfpq_data/data/RDF/Graphs/univ-bench_meta.json
new file mode 100644
index 00000000..470ffe9d
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/univ-bench_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "univ-bench.owl",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 179,
+    "edges": 293,
+    "size of file": 14433
+}
\ No newline at end of file
diff --git a/cfpq_data/data/RDF/Graphs/wine_meta.json b/cfpq_data/data/RDF/Graphs/wine_meta.json
new file mode 100644
index 00000000..7a0b94ab
--- /dev/null
+++ b/cfpq_data/data/RDF/Graphs/wine_meta.json
@@ -0,0 +1,8 @@
+{
+    "name": "wine.rdf",
+    "path": "data/RDF/Graphs",
+    "version": "0.0.0",
+    "vertices": 733,
+    "edges": 1839,
+    "size of file": 78225
+}
\ No newline at end of file
diff --git a/cfpq_data/data/ScaleFree/.gitkeep b/cfpq_data/data/ScaleFree/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/ScaleFree/Grammars/.gitkeep b/cfpq_data/data/ScaleFree/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/ScaleFree/Grammars/an_bm_cm_dn.txt b/cfpq_data/data/ScaleFree/Grammars/an_bm_cm_dn.txt
similarity index 100%
rename from data/ScaleFree/Grammars/an_bm_cm_dn.txt
rename to cfpq_data/data/ScaleFree/Grammars/an_bm_cm_dn.txt
diff --git a/cfpq_data/data/ScaleFree/Graphs/.gitkeep b/cfpq_data/data/ScaleFree/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/SparseGraph/.gitkeep b/cfpq_data/data/SparseGraph/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/SparseGraph/Grammars/.gitkeep b/cfpq_data/data/SparseGraph/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/SparseGraph/Grammars/SG.txt b/cfpq_data/data/SparseGraph/Grammars/SG.txt
new file mode 100644
index 00000000..fa75e92c
--- /dev/null
+++ b/cfpq_data/data/SparseGraph/Grammars/SG.txt
@@ -0,0 +1,3 @@
+s
+A_R A
+s -> A_R A | A_R s A
diff --git a/cfpq_data/data/SparseGraph/Graphs/.gitkeep b/cfpq_data/data/SparseGraph/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/WorstCase/.gitkeep b/cfpq_data/data/WorstCase/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/data/WorstCase/Grammars/.gitkeep b/cfpq_data/data/WorstCase/Grammars/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/WorstCase/Grammars/Brackets.txt b/cfpq_data/data/WorstCase/Grammars/Brackets.txt
similarity index 91%
rename from data/WorstCase/Grammars/Brackets.txt
rename to cfpq_data/data/WorstCase/Grammars/Brackets.txt
index 9f1c4c9a..284a8113 100644
--- a/data/WorstCase/Grammars/Brackets.txt
+++ b/cfpq_data/data/WorstCase/Grammars/Brackets.txt
@@ -1,3 +1,3 @@
-s
-A B
+s
+A B
 s -> A s B | A B
\ No newline at end of file
diff --git a/cfpq_data/data/WorstCase/Graphs/.gitkeep b/cfpq_data/data/WorstCase/Graphs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/release_notes.json b/cfpq_data/release_notes.json
new file mode 100644
index 00000000..8c0767c4
--- /dev/null
+++ b/cfpq_data/release_notes.json
@@ -0,0 +1,47 @@
+{
+  "version": "0.0.0",
+  "RDF": {
+    "atom-primitive": "12tY-PRFGs51WOtlkWW-WlY9tRBjg3PXd",
+    "biomedical-mesure-primitive": "1NvmSbs75zWN_I9p_wLhrsza757cvhXPs",
+    "core": "1Qa-jqExT43AmY7S2TPHg0vp3EmSF732d",
+    "eclass_514en": "1Wc4z7oR8DsZ7yPJwERGtUmLm5PV3UeNZ",
+    "enzyme": "1oF2rfeGhrgIfK-Mf-hSUz7PrvZHcfZbv",
+    "foaf": "1KTVJq59BfgQxJcPM4Jv7TSqGhEzfj3qh",
+    "funding": "1Hzj5BHz4N00P8RhriRNYoszpGLHjxjLE",
+    "generations": "1AeaE4Vq57Lgm4-_0NKQVNaZ-LsKWSUu_",
+    "geospecies": "1cIskhK_hP5qYQ8zSfIDJI7dMPOcw-5VY",
+    "go-hierarchy": "131tO2DpNTmCR309e5usP7fCBDt0Ztb29",
+    "go": "1Pn1BGwhoiIDsb6fFp4QaJmcSewn2BGuD",
+    "pathways": "1uTybJMkitcEiZLdN1du4jn5IsetjpqgX",
+    "people_pets": "1_pqQP85XzaMdSFGR24kj5VILsq3y6SFY",
+    "pizza": "1zHEhhmy7evsarSScuZfW1eRVsxXlLGt3",
+    "skos": "14kqPKPjUyIQwe0muJTmNRboFcqRsvCKa",
+    "taxonomy-hierarchy": "1BazxlQZxWOYmcqsWzZExBoPMlMi-8NFV",
+    "taxonomy": "1u1RNOe6bgauEv4O6HPWzQcx3f8FDU3MT",
+    "travel": "1r9FtzUgLw-RMV8i8LqITpQyiJk63aqyK",
+    "univ-bench": "1Ar5M50iD5URszbbKUI2hS4dlJzigYyfA",
+    "wine": "1lGf1N4poMHMOEDGovIS5opGsPbCPHeZJ"
+  },
+  "MemoryAliases": {
+    "Apache_httpd_2.2.18_pointsto_graph": "12EC1ygETIT1XFoMiqYPSaD9gmLY49aOC",
+    "arch_afterInline": "1LW-mSzSOGwr0q-euqaDiGaqtFkwd5y8_",
+    "block_afterInline": "1dBuAgoksdmOEnB5g0J2jgOAw5M2ErPHu",
+    "bzip2": "1L9lytXXftpzPG7u1uqLHH799h8HWuq4Q",
+    "crypto_afterInline": "1fh-fgvnPdpwE_PVWa3NouvA8sJ1BC_Om",
+    "drivers_afterInline": "1XdTEujSToK492zESnMv5pEqJUGpdKp6c",
+    "fs_afterInline": "1u8DGGIfNewzFCEeblMphOPxzJx_jDn9r",
+    "gzip": "1VY2x2giq3RNZjalYkO_imNnWtWvrUs6E",
+    "init_afterInline": "1dEM7MJUmwNfsAZMx4Q_bcqeAIQ1HU17t",
+    "ipc_afterInline": "1qsHz9XPeaDrGqZDePz6i9RgBNGCh85TY",
+    "kernel_afterInline": "1Oi1RpYRnYkVF92EXsBaoHEgCGydRUDWg",
+    "lib_afterInline": "1wjIaV7gng2H06JBbNkE1XSaUVPty_Amg",
+    "ls": "1GH3-ClTb_f6wf5Kehh-pg4H9AnbeQ9cn",
+    "mm_afterInline": "1V4QzXUZBtRaB9XFAZzSahxcbvxyKa8XN",
+    "net_afterInline": "1PU8pcDUxDXUuKe8FzRDpqHbrV_EmSxbl",
+    "PostgreSQL_8.3.9_pointsto_graph": "1__5K0F-uDeYuTumiLsegPE4AwS8qDHI5",
+    "pr": "1eO79LgXdf3k4djN-npeMWLWrVxArYozA",
+    "security_afterInline": "1TY206_ikpQL35AuWP_6KqAdxPGQQfKLN",
+    "sound_afterInline": "1KdolYE4XB929vXpv8ISu8xNtGM4UmacC",
+    "wc": "1dQD5zbsj7FvpCJ0dh1LoH9cfdMTb3mcm"
+  }
+}
diff --git a/cfpq_data/src/__init__.py b/cfpq_data/src/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/src/graphs/__init__.py b/cfpq_data/src/graphs/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/src/graphs/full_graph.py b/cfpq_data/src/graphs/full_graph.py
new file mode 100644
index 00000000..76ac028c
--- /dev/null
+++ b/cfpq_data/src/graphs/full_graph.py
@@ -0,0 +1,91 @@
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Dict, Tuple, Union, Optional
+
+import rdflib
+from tqdm import tqdm
+
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import add_graph_dir
+
+FULL_GRAPH_TO_GEN = [
+    10, 50, 100, 200, 500,
+    1000, 2000, 5000, 10000, 25000, 50000, 80000
+]
+
+
+class FullGraph(RDF):
+    """
+    FullGraph — cycle graph, all edges are labeled with the same token
+
+    - graphs: already built graphs
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str, int],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> FullGraph:
+        """
+        Builds FullGraph instance by number of vertices in the graph
+
+        :param args: args[0] - number of vertices in the graph
+        :type args: int
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: FullGraph instance
+        :rtype: FullGraph
+        """
+
+        if isinstance(args[0], int):
+            vertices_number = int(args[0])
+            path_to_graph = gen_cycle_graph(add_graph_dir('FullGraph'), vertices_number)
+            graph = FullGraph.load_from_rdf(path_to_graph)
+        else:
+            source = args[0]
+            if source_file_format == 'txt':
+                graph = cls.load_from_txt(source, config)
+            else:
+                graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+
+def gen_cycle_graph(destination_folder: Path, vertices_number: int) -> Path:
+    """
+    Generates one cycle graph with specified number of vertices
+
+    :param destination_folder: directory to save the graph
+    :type destination_folder: Path
+    :param vertices_number: number of vertices in the graph
+    :type vertices_number: int
+    :return: path to generated graph
+    :rtype: Path
+    """
+
+    output_graph = rdflib.Graph()
+
+    edges = list()
+
+    for i in range(0, vertices_number - 1):
+        edges.append((i, 'A', i + 1))
+
+    edges.append((vertices_number - 1, 'A', 0))
+
+    for subj, pred, obj in tqdm(edges, desc=f'fullgraph_{vertices_number} generation'):
+        add_rdf_edge(subj, pred, obj, output_graph)
+
+    target = destination_folder / f'fullgraph_{vertices_number}.xml'
+    write_to_rdf(target, output_graph)
+
+    return target
diff --git a/cfpq_data/src/graphs/graph_interface.py b/cfpq_data/src/graphs/graph_interface.py
new file mode 100644
index 00000000..135e1fa3
--- /dev/null
+++ b/cfpq_data/src/graphs/graph_interface.py
@@ -0,0 +1,60 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from pathlib import Path
+from typing import Union, Dict, Any
+
+
+class IGraph(ABC):
+    """
+    Generic graph interface
+
+    """
+
+    @classmethod
+    @abstractmethod
+    def build(cls, *args: Any) -> IGraph:
+        """
+        Builds graph by arguments
+
+        :param args: various arguments
+        :type args: Any
+        :return: built graph
+        :rtype: IGraph
+        """
+
+    @abstractmethod
+    def save(self,
+             destination: Union[Path, str],
+             destination_file_format: str = 'rdf',
+             config: Dict[str, str] = None) -> Path:
+        """
+        Saves graph with specified destination_file_format and edge configuration
+
+        :param destination: path to save the graph
+        :type destination: Optional[Union[Path, str]]
+        :param destination_file_format: graph source_file_format
+        :type destination_file_format: str
+        :param config: edges configuration
+        :type config: Dict[str, str]
+        :return: path to saved graph
+        :rtype: Path
+        """
+
+    @abstractmethod
+    def get_metadata(self) -> Dict[str, str]:
+        """
+        Generates graph metadata
+
+        :return: metadata
+        :rtype: Dict[str, str]
+        """
+
+    @abstractmethod
+    def save_metadata(self) -> Path:
+        """
+        Saves metadata to specified file
+
+        :return: path to file with graph metadata
+        :rtype: Path
+        """
diff --git a/cfpq_data/src/graphs/lubm_graph.py b/cfpq_data/src/graphs/lubm_graph.py
new file mode 100644
index 00000000..7cf19113
--- /dev/null
+++ b/cfpq_data/src/graphs/lubm_graph.py
@@ -0,0 +1,136 @@
+from __future__ import annotations
+
+import os
+import shutil
+import subprocess
+from pathlib import Path
+from typing import Dict, Tuple, Union, Optional
+
+import rdflib
+import wget
+from tqdm import tqdm
+
+from cfpq_data.config import MAIN_FOLDER
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import add_graph_dir
+
+LUBM_URL = 'http://swat.cse.lehigh.edu/projects/lubm/uba1.7.zip'
+MAX_FILES_PER_UNI = 30
+
+
+class LUBM(RDF):
+    """
+    LUBM - Lehigh University Benchmark graph
+
+    - graphs: already built graphs
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str, int],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> LUBM:
+        """
+        Builds LUBM instance by number of generated graphs to create one LUBM graph
+
+        :param args: args[0] - number of generated graphs or path
+        :type args: Union[int, Tuple[int, int]]
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: LUBM instance
+        :rtype: LUBM
+        """
+
+        if isinstance(args[0], int):
+            number_of_generated_graphs = args[0]
+            path_to_graph = gen_lubm_graph(add_graph_dir('LUBM'), number_of_generated_graphs)
+            graph = LUBM.load_from_rdf(path_to_graph)
+        else:
+            source = args[0]
+            if source_file_format == 'txt':
+                graph = cls.load_from_txt(source, config)
+            else:
+                graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+
+def gen_lubm_graph(destination_folder: Path, count: int) -> Path:
+    """
+    Generates LUBM graph by specified number of generated graphs to create one LUBM graph
+
+    :param destination_folder: directory to save the graph
+    :type destination_folder: Path
+    :param count: number of generated graphs
+    :type count: int
+    :return: path to generated graph
+    :rtype: Path
+    """
+
+    arch = MAIN_FOLDER / 'data' / 'LUBM' / 'uba.zip'
+    univ_dir = MAIN_FOLDER / 'data' / 'LUBM' / 'univ'
+    if not os.path.exists(univ_dir):
+        wget.download(url=LUBM_URL, out=str(arch))
+        shutil.unpack_archive(filename=str(arch), extract_dir=str(univ_dir))
+        os.remove(arch)
+    subprocess.run(
+        'java ' +
+        '-cp ' +
+        'classes ' +
+        'edu.lehigh.swat.bench.uba.Generator ' +
+        '-univ ' +
+        f'{count} ' +
+        '-onto ' +
+        'http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl',
+        cwd=str(univ_dir),
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        check=True,
+        shell=True
+    )
+
+    output_graph = rdflib.Graph()
+
+    triples = list()
+
+    vertices = dict()
+    next_id = 0
+
+    generated_graphs = \
+        os.listdir(MAIN_FOLDER / 'data' / 'LUBM') + \
+        os.listdir(univ_dir)  # for Windows
+
+    for tmp_graph_path in generated_graphs:
+        if 'University' not in tmp_graph_path:
+            continue
+
+        tmp_graph_path = f"{MAIN_FOLDER / 'data' / 'LUBM'}/{tmp_graph_path}"
+        tmp_graph = rdflib.Graph()
+        tmp_graph.parse(tmp_graph_path)
+
+        for subj, pred, obj in tmp_graph:
+            for tmp in [subj, obj]:
+                if tmp not in vertices:
+                    vertices[tmp] = next_id
+                    next_id += 1
+            triples.append((vertices[subj], pred, vertices[obj]))
+
+        os.remove(tmp_graph_path)
+
+    for subj, pred, obj in tqdm(triples, desc=f'lubm_{count} generation'):
+        add_rdf_edge(subj, pred, obj, output_graph, reverse=True)
+
+    target = destination_folder / f'lubm_{count}.xml'
+
+    write_to_rdf(target, output_graph)
+
+    return target
diff --git a/cfpq_data/src/graphs/memory_aliases_graph.py b/cfpq_data/src/graphs/memory_aliases_graph.py
new file mode 100644
index 00000000..1b8701f6
--- /dev/null
+++ b/cfpq_data/src/graphs/memory_aliases_graph.py
@@ -0,0 +1,18 @@
+from pathlib import Path
+from typing import Dict, Tuple
+
+from cfpq_data.config import RELEASE_INFO
+from cfpq_data.src.graphs.rdf_graph import RDF
+
+
+class MemoryAliases(RDF):
+    """
+    MemoryAliases — real-world data for points-to analysis of C code
+
+    - graphs: already built graphs
+    - graph_keys: reserved graph names
+    - config: default edge configuration
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+    graph_keys: Dict[str, str] = RELEASE_INFO['MemoryAliases']
diff --git a/cfpq_data/src/graphs/rdf_graph.py b/cfpq_data/src/graphs/rdf_graph.py
new file mode 100644
index 00000000..e21a6131
--- /dev/null
+++ b/cfpq_data/src/graphs/rdf_graph.py
@@ -0,0 +1,322 @@
+from __future__ import annotations
+
+import json
+import os
+from pathlib import Path
+from typing import Optional, Tuple, Any, List, Dict, Union
+
+import rdflib
+
+from cfpq_data.config import RELEASE_INFO, MAIN_FOLDER
+from cfpq_data.src.graphs.graph_interface import IGraph
+from cfpq_data.src.utils.rdf_graphs_downloader import download_data
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import unpack_graph
+
+
+class RDF(IGraph):
+    """
+    RDF — fixed versions of real-world RDF files (links are provided for updating purposes only!)
+
+    - graphs: already built graphs
+    - graph_keys: reserved graph names
+    - config: default edge configuration
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+    graph_keys: Dict[str, str] = RELEASE_INFO['RDF']
+
+    def __init__(self):
+        """
+        Generic constructor
+
+        - type: type of graph instance
+        - store: stored rdflib graph
+        - path: absolute path to graph
+        - dirname: absolute path to graph directory
+        - basename: graph file
+        - vertices_number: number of vertices in the graph
+        - edges_number: number of edges in the graph
+        - file_size: size of graph file, in bytes
+        - file_name: name of graph file
+        - file_extension: extension of graph file
+        """
+
+        self.type: Optional[str] = None
+
+        self.store: Optional[rdflib.Graph] = None
+
+        self.path: Optional[Path] = None
+        self.dirname: Optional[Path] = None
+        self.basename: Optional[str] = None
+
+        self.vertices_number: Optional[int] = None
+        self.edges_number: Optional[int] = None
+
+        self.file_size: Optional[int] = None
+        self.file_name: Optional[str] = None
+        self.file_extension: Optional[str] = None
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> RDF:
+        """
+        An RDF graph builder
+
+        :param args: args[0] - path to graph or reserved graph name, args[1] (optional) - graph file extension
+        :type args: Union[Path, str]
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: RDF graph instance
+        :rtype: RDF
+        """
+
+        source = args[0]
+
+        if source_file_format == 'txt':
+            graph = cls.load_from_txt(source, config)
+        else:
+            graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+    @classmethod
+    def load(cls,
+             source: Union[Path, str],
+             source_file_format: str = 'rdf',
+             config: Optional[Dict[str, str]] = None) -> RDF:
+        """
+        Loads RDF graph from specified source with specified source_file_format
+
+        :param source: graph source
+        :type source: Optional[Union[Path, str]]
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: loaded graph
+        :rtype: RDF
+        """
+
+        if source_file_format == 'txt':
+            rdf_graph = cls.load_from_txt(source, config)
+        else:
+            rdf_graph = cls.load_from_rdf(source)
+
+        return rdf_graph
+
+    def save(self,
+             destination: Union[Path, str],
+             destination_file_format: str = 'rdf',
+             config: Optional[Dict[str, str]] = None) -> Path:
+        """
+        Saves RDF graph to destination with specified destination_file_format and edge configuration
+
+        :param destination: path to save the graph
+        :type destination: Optional[Union[Path, str]]
+        :param destination_file_format: graph format
+        :type destination_file_format: str
+        :param config: edges configuration
+        :type config: Optional[Dict[str, str]]
+        :return: path to saved graph
+        :rtype: Path
+        """
+
+        if destination is None:
+            destination = MAIN_FOLDER / 'data' / self.type / 'Graphs' / self.basename
+
+        if destination_file_format == 'txt':
+            self.save_to_txt(destination, config)
+        else:
+            self.save_to_rdf(destination)
+        return destination
+
+    def get_metadata(self) -> Dict[str, str]:
+        """
+        Generates RDF graph metadata
+
+        :return: metadata
+        :rtype: Dict[str, str]
+        """
+
+        return {
+            'name': str(self.basename),
+            'path': str(self.path),
+            'version': RELEASE_INFO['version'],
+            'vertices': self.vertices_number,
+            'edges': self.edges_number,
+            'size of file': self.file_size
+        }
+
+    def save_metadata(self) -> Path:
+        """
+        Saves metadata to specified file
+
+        :return: path to file with graph metadata
+        :rtype: Path
+        """
+
+        metadata_file_path = self.dirname / f'{self.file_name}_meta.json'
+
+        with open(metadata_file_path, 'w') as metadata_file:
+            json.dump(self.get_metadata(), metadata_file, indent=4)
+
+        return metadata_file_path
+
+    def get_triples(self) -> List[Tuple[Any, Any, Any]]:
+        """
+        Returns edges as list of triples (subject, predicate, object)
+
+        :return: edges
+        :rtype: List[Tuple[Any, Any, Any]]
+        """
+
+        triples = list()
+
+        for subj, pred, obj in self.store:
+            triples.append((subj, pred, obj))
+
+        return triples
+
+    @classmethod
+    def load_from_rdf(cls, source: Path = None) -> RDF:
+        """
+        Loads RDF graph from specified source with rdf format
+
+        :param source: graph source
+        :type source: Path
+        :return: loaded graph
+        :rtype: RDF
+        """
+
+        if hasattr(cls, 'graph_keys') and source in cls.graph_keys:
+            graph_name = source[:]
+            download_data(cls.__name__, graph_name, cls.graph_keys[graph_name])
+            source = unpack_graph(cls.__name__, graph_name)
+
+        graph = cls()
+
+        graph.type = cls.__name__
+
+        graph.store = rdflib.Graph()
+        graph.store.parse(location=str(source), format='xml')
+
+        graph.path = Path(source)
+        graph.dirname = Path(os.path.dirname(source))
+        graph.basename = os.path.basename(source)
+
+        graph.vertices_number = len(graph.store.all_nodes())
+        graph.edges_number = len(graph.store)
+
+        graph.file_size = os.path.getsize(source)
+        graph.file_name, graph.file_extension = os.path.splitext(graph.basename)
+
+        return graph
+
+    @classmethod
+    def load_from_txt(cls,
+                      source: Path = None,
+                      config: Optional[Dict[str, str]] = None) -> RDF:
+        """
+        Loads RDF graph from specified source with txt format
+
+        :param source: graph source
+        :type source: Path
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: loaded graph
+        :rtype: RDF
+        """
+
+        tmp_graph = rdflib.Graph()
+
+        if config is None:
+            config = dict()
+
+            with open(source, 'r') as input_file:
+                for edge in input_file:
+                    s, p, o = edge.strip('\n').split(' ')
+                    p_text = p
+                    if not p.startswith('http'):
+                        p_text = f'http://yacc/rdf-schema#{p_text}'
+                    config[p] = p_text
+
+        with open(source, 'r') as input_file:
+            for edge in input_file:
+                s, p, o = edge.strip('\n').split(' ')
+                add_rdf_edge(s, config[p], o, tmp_graph)
+
+        write_to_rdf(Path('tmp.xml'), tmp_graph)
+
+        graph = cls.load_from_rdf(Path('tmp.xml'))
+
+        # os.remove('tmp.xml')
+
+        return graph
+
+    def save_to_rdf(self, destination: Path) -> Path:
+        """
+        Saves RDF graph to destination rdf file
+
+        :param destination: path to save the graph
+        :type destination: Path
+        :return: path to saved graph
+        :rtype: Path
+        """
+
+        write_to_rdf(destination, self.store)
+        return destination
+
+    def save_to_txt(self,
+                    destination: Path,
+                    config: Optional[Dict[str, str]] = None) -> Path:
+        """
+        Saves RDF graph to destination txt file with specified edge configuration
+
+        :param destination: path to save the graph
+        :type destination: Path
+        :param config: edges configuration
+        :type config: Optional[Dict[str, str]]
+        :return: path to saved graph
+        :rtype: Path
+        """
+
+        vertices = dict()
+        edges = dict()
+        next_id = 0
+        triples = list()
+
+        if config is None:
+            config = dict()
+
+            for subj, pred, obj in self.store:
+                p_text = str(pred)
+                config[p_text] = p_text
+
+        for subj, pred, obj in self.store:
+            for tmp in [subj, obj]:
+                if tmp not in vertices:
+                    vertices[tmp] = next_id
+                    next_id += 1
+
+            p_text = str(pred)
+            if p_text in config:
+                edges[p_text] = config[p_text]
+            else:
+                edges[p_text] = 'other'
+
+            triples.append((vertices[subj], edges[str(pred)], vertices[obj]))
+
+        with open(destination, 'w') as output_file:
+            for s, p, o in triples:
+                output_file.write(f'{s} {p} {o}\n')
+
+        return destination
diff --git a/cfpq_data/src/graphs/scale_free_graph.py b/cfpq_data/src/graphs/scale_free_graph.py
new file mode 100644
index 00000000..55ef1529
--- /dev/null
+++ b/cfpq_data/src/graphs/scale_free_graph.py
@@ -0,0 +1,135 @@
+from __future__ import annotations
+
+from itertools import product
+from pathlib import Path
+from typing import Tuple, Dict, Union, Optional
+
+import numpy as np
+import rdflib
+from tqdm import tqdm
+
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import add_graph_dir
+
+SCALE_FREE_GRAPH_TO_GEN = list(product(
+    [100, 500, 2500, 10000],
+    [1, 3, 5, 10]
+))
+
+
+class ScaleFree(RDF):
+    """
+    ScaleFree — graphs generated by using the Barab'asi-Albert model of scale-free networks
+
+    - graphs: already built graphs
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str, int],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> ScaleFree:
+        """
+        Builds ScaleFree graph instance by number of vertices and degree of vertex
+
+        - args[0] - number of vertices in the graph or path
+        - args[1] - degree of the vertex in the graph (if args[0] is not a path)
+
+        :param args: arguments
+        :type args: int
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: ScaleFree graph instance
+        :rtype: ScaleFree
+        """
+
+        if len(args) > 1:
+            vertices_number = args[0]
+            vertices_degree = args[1]
+
+            path_to_graph = gen_scale_free_graph(add_graph_dir('ScaleFree'),
+                                                 vertices_number,
+                                                 vertices_degree)
+
+            graph = ScaleFree.load_from_rdf(path_to_graph)
+        else:
+            source = args[0]
+            if source_file_format == 'txt':
+                graph = cls.load_from_txt(source, config)
+            else:
+                graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+
+def gen_scale_free_graph(destination_folder: Path,
+                         vertices_number: int,
+                         vertices_degree: int,
+                         labels: Tuple[str, ...] = ('A', 'B', 'C', 'D')
+                         ) -> Path:
+    """
+    Generates scale free graph
+
+    :param destination_folder: directory to save the graph
+    :type destination_folder: Path
+    :param vertices_number: number of vertices in the graph
+    :type vertices_number: int
+    :param vertices_degree: degree of a vertex in the graph
+    :type vertices_degree: int
+    :param labels: edge labels in the graph
+    :type labels: Tuple[str, ...]
+    :return: path to generated graph
+    :rtype: Path
+    """
+
+    g = {
+        i: [(j, np.random.choice(labels)) for j in range(vertices_degree)]
+        for i in range(vertices_degree)
+    }
+
+    degree = [3] * vertices_degree
+
+    for i in range(vertices_degree, vertices_number):
+        to_vertices = np.random.choice(
+            range(i),
+            size=vertices_degree,
+            replace=False,
+            p=np.array(degree) / sum(degree)
+        )
+
+        g[i] = []
+        degree.append(0)
+        for to in to_vertices:
+            label = np.random.choice(labels)
+            g[i].append((to, label))
+            degree[to] += 1
+            degree[i] += 1
+
+    output_graph = rdflib.Graph()
+
+    edges = list()
+
+    for v in g:
+        for to in g[v]:
+            edges.append((v, to[1], to[0]))
+
+    for subj, pred, obj in tqdm(
+            edges,
+            desc=f'scale_free_graph_{vertices_number}_{vertices_degree} generation'
+    ):
+        add_rdf_edge(subj, pred, obj, output_graph)
+
+    target = destination_folder / f'scale_free_graph_{vertices_number}_{vertices_degree}.xml'
+
+    write_to_rdf(target, output_graph)
+
+    return target
diff --git a/cfpq_data/src/graphs/sparse_graph.py b/cfpq_data/src/graphs/sparse_graph.py
new file mode 100644
index 00000000..23932f55
--- /dev/null
+++ b/cfpq_data/src/graphs/sparse_graph.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Dict, Tuple, Union, Optional
+
+import networkx as nx
+import rdflib
+from tqdm import tqdm
+
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import add_graph_dir
+
+SPARSE_GRAPH_TO_GEN = [
+    [5000, 0.001],
+    [10000, 0.001],
+    [10000, 0.01],
+    [10000, 0.1],
+    [20000, 0.001],
+    [40000, 0.001],
+    [80000, 0.001]
+]
+
+
+class SparseGraph(RDF):
+    """
+    SparseGraph — graphs generated with NetworkX to emulate sparse data
+
+    - graphs: already built graphs
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str, int],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> SparseGraph:
+        """
+        Build SparseGraph instance by number of vertices in probability of edge existence
+
+        - args[0] - number of vertices in the graph
+        - args[1] - probability of edge existence in the graph
+
+        :param args: arguments
+        :type args: int
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: SparseGraph instance
+        :rtype: SparseGraph
+        """
+
+        if len(args) > 1:
+            vertices_number = args[0]
+            edge_probability = args[1]
+
+            path_to_graph = gen_sparse_graph(add_graph_dir('SparseGraph'),
+                                             vertices_number,
+                                             edge_probability
+                                             )
+
+            graph = SparseGraph.load_from_rdf(path_to_graph)
+        else:
+            source = args[0]
+            if source_file_format == 'txt':
+                graph = cls.load_from_txt(source, config)
+            else:
+                graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+
+def gen_sparse_graph(destination_folder: Path,
+                     vertices_number: int,
+                     edge_probability: float) -> Path:
+    """
+    Generates sparse graph
+
+    :param destination_folder: directory to save the graph
+    :type destination_folder: Path
+    :param vertices_number: number of vertices in the graph
+    :type vertices_number: int
+    :param edge_probability: probability of edge existence in the graph
+    :type edge_probability: float
+    :return: path to generated graph
+    :rtype: Path
+    """
+
+    tmp_graph = nx.generators.fast_gnp_random_graph(vertices_number, edge_probability)
+
+    output_graph = rdflib.Graph()
+
+    edges = list()
+
+    for v, to in tmp_graph.edges():
+        edges.append((v, 'A', to))
+        edges.append((v, 'AR', to))
+
+    for subj, pred, obj in tqdm(
+            edges,
+            desc=f'G{vertices_number}-{edge_probability} generation'
+    ):
+        add_rdf_edge(subj, pred, obj, output_graph)
+
+    target = destination_folder / f'G{vertices_number}-{edge_probability}.xml'
+
+    write_to_rdf(target, output_graph)
+
+    return target
diff --git a/cfpq_data/src/graphs/worst_case_graph.py b/cfpq_data/src/graphs/worst_case_graph.py
new file mode 100644
index 00000000..04928815
--- /dev/null
+++ b/cfpq_data/src/graphs/worst_case_graph.py
@@ -0,0 +1,97 @@
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Dict, Tuple, Union, Optional
+
+import rdflib
+from tqdm import tqdm
+
+from cfpq_data.src.graphs.rdf_graph import RDF
+from cfpq_data.src.utils.rdf_helper import write_to_rdf, add_rdf_edge
+from cfpq_data.src.utils.utils import add_graph_dir
+
+NUMBER_OF_WORST_CASES = 12
+
+
+class WorstCase(RDF):
+    """
+    WorstCase — graphs with two cycles
+
+    - graphs: already built graphs
+    """
+
+    graphs: Dict[Tuple[str, str], Path] = dict()
+
+    @classmethod
+    def build(cls,
+              *args: Union[Path, str],
+              source_file_format: str = 'rdf',
+              config: Optional[Dict[str, str]] = None) -> WorstCase:
+        """
+        Builds WorstCase graph instance by number of vertices in the graph
+
+        :param args: args[0] - number of vertices in the graph
+        :type args: int
+        :param source_file_format: graph format ('txt'/'rdf')
+        :type source_file_format: str
+        :param config: edge configuration
+        :type config: Optional[Dict[str, str]]
+        :return: WorstCase graph instance
+        :rtype:WorstCase
+        """
+
+        if isinstance(args[0], int):
+            vertices_number = int(args[0])
+            path_to_graph = gen_worst_case_graph(add_graph_dir('WorstCase'), vertices_number)
+            graph = WorstCase.load_from_rdf(path_to_graph)
+        else:
+            source = args[0]
+            if source_file_format == 'txt':
+                graph = cls.load_from_txt(source, config)
+            else:
+                graph = cls.load_from_rdf(source)
+
+        graph.save_metadata()
+
+        cls.graphs[(graph.basename, graph.file_extension)] = graph.path
+
+        return graph
+
+
+def gen_worst_case_graph(destination_folder: Path, vertices_number: int) -> Path:
+    """
+    Generates graphs with two cycles by number of vertices in the graph
+
+    :param destination_folder: directory to save the graph
+    :type destination_folder: Path
+    :param vertices_number: number of vertices in the graph
+    :type vertices_number: int
+    :return: path to generated graph
+    :rtype: Path
+    """
+
+    output_graph = rdflib.Graph()
+
+    first_cycle = int(vertices_number / 2) + 1
+
+    edges = list()
+
+    for i in range(0, first_cycle - 1):
+        edges.append((i, 'A', i + 1))
+
+    edges.append((first_cycle - 1, 'A', 0))
+    edges.append((first_cycle - 1, 'B', first_cycle))
+
+    for i in range(first_cycle, vertices_number - 1):
+        edges.append((i, 'B', i + 1))
+
+    edges.append((vertices_number - 1, 'B', first_cycle - 1))
+
+    for subj, pred, obj in tqdm(edges, desc=f'worstcase_{vertices_number} generation'):
+        add_rdf_edge(subj, pred, obj, output_graph)
+
+    target = destination_folder / f'worstcase_{vertices_number}.xml'
+
+    write_to_rdf(target, output_graph)
+
+    return target
diff --git a/cfpq_data/src/utils/__init__.py b/cfpq_data/src/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/cfpq_data/src/utils/rdf_graphs_downloader.py b/cfpq_data/src/utils/rdf_graphs_downloader.py
new file mode 100644
index 00000000..666cc99a
--- /dev/null
+++ b/cfpq_data/src/utils/rdf_graphs_downloader.py
@@ -0,0 +1,47 @@
+import requests
+from tqdm import tqdm
+
+from cfpq_data.src.utils.utils import add_graph_dir
+
+
+# TODO: rewrite to work with Google API
+def download_file_from_google_drive(file_id, destination):
+    download_file_prefix = 'https://docs.google.com/uc?export=download'
+
+    session = requests.Session()
+
+    response = session.get(download_file_prefix, params={'id': file_id}, stream=True)
+    token = get_confirm_token(response)
+
+    if token:
+        params = {'id': file_id, 'confirm': token}
+        response = session.get(download_file_prefix, params=params, stream=True)
+
+    save_response_content(response, destination)
+
+
+def get_confirm_token(response):
+    for key, value in response.cookies.items():
+        if key.startswith('download_warning'):
+            return value
+
+    return None
+
+
+def save_response_content(response, destination):
+    chunk_size = 32768
+
+    with open(destination, 'wb') as f:
+        for chunk in tqdm(response.iter_content(chunk_size), desc='Downloading'):
+            if chunk:  # filter out keep-alive new chunks
+                f.write(chunk)
+
+
+def download_data(graph_group, graph_name, graph_key):
+    dst = add_graph_dir(graph_group)
+
+    arch_dst = dst / f'{graph_name}.tar.xz'
+
+    download_file_from_google_drive(graph_key, arch_dst)
+
+    return dst
diff --git a/cfpq_data/src/utils/rdf_helper.py b/cfpq_data/src/utils/rdf_helper.py
new file mode 100644
index 00000000..89eb073b
--- /dev/null
+++ b/cfpq_data/src/utils/rdf_helper.py
@@ -0,0 +1,54 @@
+from pathlib import Path
+
+from rdflib import Graph, BNode, URIRef
+
+
+def write_to_rdf(target_path: Path, graph: Graph):
+    """
+    Saves the graph along the specified path
+
+    :param target_path: path where to save the graph
+    :type target_path: Path
+    :param graph: graph to be saved
+    :type graph: rdflib.Graph
+    :return: None
+    :rtype: None
+    """
+
+    graph.serialize(destination=str(target_path), format='xml')
+
+
+def add_rdf_edge(subj: int, pred: str, obj: int,
+                 rdf_graph: Graph,
+                 reverse: bool = False) -> None:
+    """
+    Add edge to RDF graph
+
+    :param subj: number of the starting vertex
+    :type subj: int
+    :param pred: the label of the edge to be added
+    :type pred: str
+    :param obj: number of the ending vertex
+    :type obj: int
+    :param rdf_graph: the graph to which the edge will be added
+    :type rdf_graph: rdflib.Graph
+    :param reverse: a label indicating whether to add a reverse edge to the graph
+    :type reverse: bool
+    :return: None
+    :rtype: None
+    """
+
+    s = BNode(f'id-{subj}')
+
+    p_text = str(pred)
+    if not p_text.startswith('http'):
+        p_text = f'http://yacc/rdf-schema#{p_text}'
+    p = URIRef(p_text)
+
+    o = BNode(f'id-{obj}')
+
+    rdf_graph.add((s, p, o))
+
+    if reverse is True:
+        pr = URIRef(str(p) + 'R')
+        rdf_graph.add((s, pr, o))
diff --git a/cfpq_data/src/utils/utils.py b/cfpq_data/src/utils/utils.py
new file mode 100644
index 00000000..d0656eb7
--- /dev/null
+++ b/cfpq_data/src/utils/utils.py
@@ -0,0 +1,82 @@
+import os
+import shutil
+from pathlib import Path
+from typing import List
+
+from cfpq_data.config import MAIN_FOLDER
+
+
+def __unpack_archive_listdir(target_dir: Path, arch: str) -> List[str]:
+    """
+    Returns a list of files from the archive
+
+    :param target_dir: folder where the archive will be unpacked
+    :type target_dir: Path
+    :param arch: path to archive
+    :type arch: str
+    :return: list of files from the archive
+    :rtype: List[str]
+    """
+
+    tmp = target_dir / 'tmp'
+    os.mkdir(tmp)
+    shutil.unpack_archive(arch, tmp)
+    result = os.listdir(tmp)
+    shutil.rmtree(tmp)
+    return result
+
+
+def unpack_graph(graph_group: str, graph_name: str) -> str:
+    """
+    Unpacks the graph to the desired folder
+
+    :param graph_group: graph group type
+    :type graph_group: str
+    :param graph_name: graph name
+    :type graph_name: str
+    :return: path to the unpacked graph
+    :rtype: str
+    """
+
+    to = MAIN_FOLDER / 'data' / graph_group / 'Graphs'
+
+    arch = to / f'{graph_name}.tar.xz'
+
+    shutil.unpack_archive(arch, to)
+
+    graph = __unpack_archive_listdir(to, arch)[0]
+
+    os.remove(arch)
+
+    return os.path.join(to, graph)
+
+
+def clean_dir(name: str) -> None:
+    """
+    Clears the specified folder
+
+    :param name: folder to clear
+    :type name: str
+    :return: None
+    :rtype: None
+    """
+
+    path = MAIN_FOLDER / 'data' / name / 'Graphs'
+    if os.path.isdir(path):
+        shutil.rmtree(path)
+    os.mkdir(path)
+
+
+def add_graph_dir(name: str) -> Path:
+    """
+    Creates a folder for the specified graph type
+
+    :param name: specified graph type
+    :type name: str
+    :return: path to folder for the specified graph type
+    :rtype: Path
+    """
+
+    dst = MAIN_FOLDER / 'data' / name / 'Graphs'
+    dst.mkdir(parents=True, exist_ok=True)
+    return dst
diff --git a/data/RDF/Grammars/g1.txt b/data/RDF/Grammars/g1.txt
deleted file mode 100644
index ccaf1c4d..00000000
--- a/data/RDF/Grammars/g1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-s
-SCO SCOR T TR
-s -> SCOR s SCO | TR s T | SCOR SCO | TR T
diff --git a/data/RDF/Grammars/g2.txt b/data/RDF/Grammars/g2.txt
deleted file mode 100644
index c9859759..00000000
--- a/data/RDF/Grammars/g2.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-s
-SCOR SCO TR T
-s -> SCOR s SCO | SCO
\ No newline at end of file
diff --git a/data/RDF/Grammars/geo.txt b/data/RDF/Grammars/geo.txt
deleted file mode 100644
index a2dad496..00000000
--- a/data/RDF/Grammars/geo.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-s
-BT BTR
-s -> BT s BTR | BT BTR
\ No newline at end of file
diff --git a/data/SparseGraph/Grammars/SG.txt b/data/SparseGraph/Grammars/SG.txt
deleted file mode 100644
index 04a7b925..00000000
--- a/data/SparseGraph/Grammars/SG.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-s
-AR A
-s -> AR A | AR s A
diff --git a/docs/README.md b/docs/README.md
index 7fec87c7..a5935269 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -3,47 +3,27 @@
 Graphs and grammars for experimental analysis of context-free path querying algorithms.
 
 ## Prerequirements
+
 * GCC
 * Python 3
 
-## How to start
-
-Just install requirements and run ```init.py```: 
+## Installing
 
+```shell
+python3 -m pip install cfpq_data
+python3
+>>> import cfpq_data
+>>> help(cfpq_data)
 ```
-pip3 install -r requirements.txt
-python3 init.py
-```
-
-This script downloads data (real-world RDF files) and [GTgraph](http://www.cse.psu.edu/~kxm85/software/GTgraph/), a suite of graph generators. After that, some synthetic graphs are generated with it.
-
-In order to download/update one specific part of the dataset run:
-```
-python3 init.py --update [GroupName]
-```
-Options for ```[GroupName]``` are ```rdf, scalefree, full, worstcase, sparse, memoryaliases```
-
-
-## Integration with graph DBs
 
-We provide a set of scripts to simplify data loading into some popular graph databases.
-
-### RedisGraph
-
-The dataset can be loaded to RedisGraph with ```tools/redis-rdf```, for example:
-```
-cd ./tools/redis-rdf
-python3 main.py --port [PORT] dir ../../data/Matrices/ScaleFree/
-python3 main.py --port [PORT] file ../../data/Matrices/RDF/foaf.rdf foaf
-```
-
-### Neo4j
+### Integration with Neo4j
 
 To load RDF data into Neo4j database one can use [Neosemantix plugin for Neo4j](https://neo4j.com/labs/nsmtx-rdf/).
 
 ## Dataset
 
-Set contains both real-world data and synthetic graphs for several specific cases. All graphs are represented in RDF format to unify loading process.
+Set contains both real-world data and synthetic graphs for several specific cases. All graphs are represented in RDF
+format to unify loading process.
 
 ### Query format
 
@@ -53,18 +33,19 @@ Queries are represented as context-free grammars in the following format:
 - Line 1: a set of terminal symbols delimited by spaces
 - The rest of the lines are productions in the form:
 
-     ```head -> body | body | ... | body```
+  ```head -> body | body | ... | body```
+
+  where each body can contain basic regular expression, allowed operators:
 
-    where each body can contain basic regular expression, allowed operators:
-    
     - The concatenation, the default operator, which can by represented either by a space or a dot (```.```)
     - The union, represented by ```|```
     - The ```?``` quantifier
     - The kleene star, represented by ```*```
-    
-    Epsilon symbol should be represented by ```eps```
+
+  Epsilon symbol should be represented by ```eps```
 
 Example query in such format:
+
 ```
 S
 a b
@@ -72,78 +53,146 @@ S -> a S b S
 S -> eps
 ```
 
-Grammar can be converted to CNF with ```tools/gramar_to_cnf```, which uses [pyformlang](https://pypi.org/project/pyformlang/) library to perform context-free grammar modifications.
+Grammar can be converted to CNF with ```src/tools/grammar2cnf```, which
+uses [pyformlang](https://pypi.org/project/pyformlang/) library to perform context-free grammar modifications.
+
+```
+$ python3 main.py grammar2cnf file [PATH_TO_GRAMMAR] --output [PATH_TO_OUTPUT]
+```
 
 ### Dataset structure
 
-Graphs and grammars can be found in  ```data``` — all graphs are divided into groups, which are placed in different directories. Each ```data/[GroupName]/Matrices``` contains graph descriptions and ```data/[GroupName]/Grammars``` — descriptions of queries. 
+Graphs and grammars can be found in  ```data``` — all graphs are divided into groups, which are placed in different
+directories. Each ```data/[GroupName]/Matrices``` contains graph descriptions and ```data/[GroupName]/Grammars``` —
+descriptions of queries.
 
 **```RDF```** — fixed versions of real-world RDF files (links are provided for updating purposes only!):
-- Small graphs is a set of popular semantic web ontologies. This set is introduced by Xiaowang Zhang in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743) :
-   - [skos](https://www.w3.org/2009/08/skos-reference/skos.rdf)
-   - [foaf](http://xmlns.com/foaf/0.1/)
-   - [wine](https://www.w3.org/TR/owl-guide/wine.rdf)
-   - [pizza](https://protege.stanford.edu/ontologies/pizza/pizza.owl)
-   - [generations](http://www.owl-ontologies.com/generations.owl)
-   - [travel](https://protege.stanford.edu/ontologies/travel.owl)
-   - [univ-bench](http://swat.cse.lehigh.edu/onto/univ-bench.owl)
-   - [people-pets](http://owl.man.ac.uk/tutorial/people+pets.rdf)
+
+- Small graphs is a set of popular semantic web ontologies. This set is introduced by Xiaowang Zhang
+  in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743) :
+    - [skos](https://www.w3.org/2009/08/skos-reference/skos.rdf)
+    - [foaf](http://xmlns.com/foaf/0.1/)
+    - [wine](https://www.w3.org/TR/owl-guide/wine.rdf)
+    - [pizza](https://protege.stanford.edu/ontologies/pizza/pizza.owl)
+    - [generations](http://www.owl-ontologies.com/generations.owl)
+    - [travel](https://protege.stanford.edu/ontologies/travel.owl)
+    - [univ-bench](http://swat.cse.lehigh.edu/onto/univ-bench.owl)
+    - [people-pets](http://owl.man.ac.uk/tutorial/people+pets.rdf)
 
 - Bigger graphs:
-   - **geospecies** – graph related to taxonomic hierarchy and geographical information of animal species, download here: <https://old.datahub.io/dataset/geospecies>. Introduced in ["An Experimental Study ofContext-Free Path Query Evaluation Methods"](https://dl.acm.org/doi/pdf/10.1145/3335783.3335791)
-   - a set of graphs from the **Uniprot** protein sequences database, download here: <ftp://ftp.uniprot.org/pub/databases/uniprot/current_release/rdf>
-       - **go**
-       - **go-hierarchy**
-       - **pathways**
-       - **taxonomy**
-       - **taxonomy-hierarchy**
-       - **core**
-       - **enzime**
-   - **eclass_514en** 
+    - **geospecies** – graph related to taxonomic hierarchy and geographical information of animal species, download
+      here: <http://rdf.geospecies.org/geospecies.rdf.gz>. Introduced
+      in ["An Experimental Study of Context-Free Path Query Evaluation Methods"](https://dl.acm.org/doi/pdf/10.1145/3335783.3335791)
+    - a set of graphs from the **Uniprot** protein sequences database, download
+      here: <ftp://ftp.uniprot.org/pub/databases/uniprot/current_release/rdf>
+        - **go**
+        - **go-hierarchy**
+        - **pathways**
+        - **taxonomy**
+        - **taxonomy-hierarchy**
+        - **core**
+        - **enzime**
+    - **eclass_514en**
 
 Grammars list contains the following variants of same-generation query over different relation tipes.
--  **g1** — same-generation query over _type_ and _subclass-of_ relations. Introduced in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743)
--  **g2** — same-generation query over _type_ and _subclass-of_ relations. Introduced in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743)
--  **geo** — same-generation query over _broader-transitive_ relation.
-  
-
-**```MemoryAliases```** — real-world data for points-to analysis of C code.
-  - First part is a dataset form [Graspan tool](https://github.com/Graspan/graspan-cpp). The original data is placed [here](https://drive.google.com/drive/folders/0B8bQanV_QfNkbDJsOWc2WWk4SkE?usp=sharing). This part is placed in ```Graspan``` folder.
-  - Second part is a part of dataset form ["Demand-driven alias analysis for C"](https://dl.acm.org/doi/10.1145/1328897.1328464). This part is placed in ```small``` folder.
-
-  Both grammars **g1** and **g2** specify the same language which is described in related papers. These two grammars were written in a different way in order to investigate dependencies on query specification format.
-
-**```WorstCase```** — graphs with two cylces; the query **Brackets** is a grammar for the language of correct bracket sequences.
 
-**```SparseGraph```** — graphs generated with [GTgraph](http://www.cse.psu.edu/~kxm85/software/GTgraph/) to emulate sparse data. The grammar provided is a variant of the same-generation query.
+- **g1** — same-generation query over _type_ and _subclass-of_ relations. Introduced
+  in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743)
+- **g2** — same-generation query over _type_ and _subclass-of_ relations. Introduced
+  in ["Context-Free Path Queries on RDF Graphs"](https://arxiv.org/abs/1506.00743)
+- **geo** — same-generation query over _broader-transitive_ relation.
 
-**```ScaleFree```** — graphs generated with [GTgraph](http://www.cse.psu.edu/~kxm85/software/GTgraph/) by using the Barab\'asi-Albert model of scale-free networks. Use with grammar **an_bm_cm_dn**, which is a query for _A<sub>n</sub>B<sub>m</sub>C<sub>m</sub>D<sub>n</sub>_ language.
-
-**```FullGraph```** — cycle graphs, all edges are labeled with the same token. Use with **A_star** queries, which produce full graph on that dataset.
-
-### Reference values
-
-Reference values for algorithms correctnes checking, which can be found in [reference_values.csv](./reference_values.csv), are in the following format: ```graph, grammar, control_sum```, where ```control_sum``` is the number of paths generated by non-terminals of the grammars.
+**```MemoryAliases```** — real-world data for points-to analysis of C code.
 
-Example of the ```FullGraph``` dataset reference values in such format:
-```
-fullgraph_10,A_star0,"{'s': 100}"
-fullgraph_100,A_star0,"{'s': 10000}"
-...
-```
+- First part is a dataset form [Graspan tool](https://github.com/Graspan/graspan-cpp). The original data is
+  placed [here](https://drive.google.com/drive/folders/0B8bQanV_QfNkbDJsOWc2WWk4SkE?usp=sharing). This part is placed
+  in ```Graspan``` folder.
+- Second part is a part of dataset
+  form ["Demand-driven alias analysis for C"](https://dl.acm.org/doi/10.1145/1328897.1328464). This part is placed
+  in ```small``` folder.
+
+Both grammars **g1** and **g2** specify the same language which is described in related papers. These two grammars were
+written in a different way in order to investigate dependencies on query specification format.
+
+**```WorstCase```** — graphs with two cylces; the query **Brackets** is a grammar for the language of correct bracket
+sequences.
+
+**```SparseGraph```** — graphs generated with [NetworkX](https://networkx.github.io/) to emulate sparse data. The
+grammar provided is a variant of the same-generation query.
+
+**```ScaleFree```** — graphs generated by using the Barab\'asi-Albert model of scale-free networks. Use with grammar **
+an_bm_cm_dn**, which is a query for _A<sub>n</sub>B<sub>m</sub>C<sub>m</sub>D<sub>n</sub>_ language.
+
+**```FullGraph```** — cycle graphs, all edges are labeled with the same token. Use with **A_star** queries, which
+produce full graph on that dataset.
+
+**```LUBM```** - the Lehigh University Benchmark graphs.
+
+### Graphs information
+
+#### RDF
+| Name | Vertices | Edges | Size of file (Bytes) |
+|:---|:---|:---|:---|
+| generations.owl | 129 | 273 | 13826 |
+| univ-bench.owl | 179 | 293 | 14433 |
+| travel.owl | 131 | 277 | 17169 |
+| skos.rdf | 144 | 252 | 28966 |
+| people_pets.rdf | 337 | 640 | 40375 |
+| foaf.rdf | 256 | 631 | 44209 |
+| atom-primitive.owl | 291 | 425 | 48884 |
+| biomedical-mesure-primitive.owl | 341 | 459 | 53057 |
+| wine.rdf | 733 | 1839 | 78225 |
+| pizza.owl | 671 | 1980 | 126939 |
+| funding.rdf | 778 | 1086 | 131564 |
+| core.owl | 1323 | 2752 | 270846 |
+| pathways.rdf | 6238 | 12363 | 1305842 |
+| enzyme.rdf | 48815 | 86543 | 8806602 |
+| go-hierarchy.owl | 45007 | 490109 | 38888638 |
+| eclass_514en.owl | 239111 | 360248 | 40191953 |
+| go.owl | 582929 | 1437437 | 164749424 |
+| geospecies.rdf | 450609 | 2201532 | 187133434 |
+| taxonomy.rdf | 5728398 | 14922125 | 1293836336 |
+| taxonomy-hierarchy.rdf | 2112625 | 32876289 | 2425286037 |
+
+#### MemoryAliases
+| Name | Vertices | Edges | Size of file (Bytes) |
+|:---|:---|:---|:---|
+| wc.txt.xml | 332 | 269 | 23679 |
+| bzip2.txt.xml | 632 | 556 | 45432 |
+| pr.txt.xml | 815 | 692 | 59629 |
+| ls.txt.xml | 1687 | 1453 | 126329 |
+| gzip.txt.xml | 2687 | 2293 | 199239 |
+| Apache_httpd_2.2.18_pointsto_graph.xml | 1721418 | 1510411 | 138037427 |
+| init_afterInline.txt.xml | 2446224 | 2112809 | 197676888 |
+| mm_afterInline.txt.xml | 2538243 | 2191079 | 205010253 |
+| ipc_afterInline.txt.xml | 3401022 | 2931498 | 275033440 |
+| lib_afterInline.txt.xml | 3401355 | 2931880 | 275060825 |
+| block_afterInline.txt.xml | 3423234 | 2951393 | 276869199 |
+| arch_afterInline.txt.xml | 3448422 | 2970242 | 278669103 |
+| crypto_afterInline.txt.xml | 3464970 | 2988387 | 280248585 |
+| security_afterInline.txt.xml | 3479982 | 3003326 | 281698638 |
+| sound_afterInline.txt.xml | 3528861 | 3049732 | 285856817 |
+| net_afterInline.txt.xml | 4039470 | 3500141 | 327815218 |
+| fs_afterInline.txt.xml | 4177416 | 3609373 | 337856145 |
+| drivers_afterInline.txt.xml | 4273803 | 3707769 | 346720743 |
+| PostgreSQL_8.3.9_pointsto_graph.xml | 5203419 | 4678543 | 429924717 |
+| kernel_afterInline.txt.xml | 11254434 | 9484213 | 886162222 |
 
 ## Papers on CFPQ
 
 List of CFPQ-related works. The list is not full, work in progress.
 
 ### Graph databases
+
 - M. Yannakakis. "Graph-theoretic methods in database theory".
 - P. Sevon and L. Eronen. "Subgraph queries by context-free grammars".
-- J. Kuijpers, G. Fletcher, N. Yakovets, and T. Lindaaker. "An experimental study of context-free path query evaluation methods".
-- H. Miao and A. Deshpande. "Understanding Data Science Lifecycle Provenance via Graph Segmentation and Summarization". 
+- J. Kuijpers, G. Fletcher, N. Yakovets, and T. Lindaaker. "An experimental study of context-free path query evaluation
+  methods".
+- H. Miao and A. Deshpande. "Understanding Data Science Lifecycle Provenance via Graph Segmentation and Summarization".
 - TBD
 
 ### Static code analysis
+
 - T. Reps. "Program analysis via graph reachability".
 - X. Zheng and R. Rugina. "Demand-driven alias analysis for C".
 - TBD
diff --git a/init.py b/init.py
deleted file mode 100644
index 8880b256..00000000
--- a/init.py
+++ /dev/null
@@ -1,339 +0,0 @@
-import lzma
-import tarfile
-import os
-import subprocess
-import shutil
-import urllib.request
-import requests
-import argparse
-import numpy as np
-from rdflib import Graph, URIRef, BNode
-from tools.rdf_helper import write_to_rdf, add_rdf_edge
-
-GT_GRAPH_URL = 'http://www.cse.psu.edu/~kxm85/software/GTgraph/GTgraph.tar.gz'
-GT_GRAPH_ARCH = './tools/GTgraph.tar.gz'
-
-MEMORY_ALIASES_DOWNLOAD_ID = '1gZA4x3Nep7IiRv5j3MZlZF7git2sTMEo'
-RDF_DOWNLOAD_ID = '1x4cELJ7kSwhqlLC0zrOcuxaF3c19qRnK'
-
-SPARSE_GRAPH_TO_GEN = [
-    [5000, 0.001],
-    [10000, 0.001],
-    [10000, 0.01],
-    [10000, 0.1],
-    [20000, 0.001],
-    [40000, 0.001],
-    [80000, 0.001],
-]
-
-FULL_GRAPH_TO_GEN = [
-    10, 50, 100, 200,
-    500, 1000, 2000,
-    5000, 10000, 25000,
-    50000, 80000,
-]
-
-NUMBER_OF_WORST_CASES = 12
-
-RDF = 'RDF'
-DATA_ROOT_DIR = './data/'
-MATRICES_DIR = 'Matrices'
-MEMORY_ALIASES = 'MemoryAliases'
-
-DATA_TO_UNPACK = {
-    MEMORY_ALIASES: MEMORY_ALIASES_DOWNLOAD_ID,
-    RDF: RDF_DOWNLOAD_ID
-}
-
-GT_GRAPH = './tools/GTgraph/random/GTgraph-random'
-TMP_FILE = 'tmp.txt'
-
-
-def download_file_from_google_drive(id, destination):
-    URL = 'https://docs.google.com/uc?export=download'
-
-    session = requests.Session()
-
-    response = session.get(URL, params={'id': id}, stream=True)
-    token = get_confirm_token(response)
-
-    if token:
-        params = {'id': id, 'confirm': token}
-        response = session.get(URL, params=params, stream=True)
-
-    save_response_content(response, destination)
-
-
-def get_confirm_token(response):
-    for key, value in response.cookies.items():
-        if key.startswith('download_warning'):
-            return value
-
-    return None
-
-
-def save_response_content(response, destination):
-    CHUNK_SIZE = 32768
-
-    with open(destination, 'wb') as f:
-        for chunk in response.iter_content(CHUNK_SIZE):
-            if chunk:  # filter out keep-alive new chunks
-                f.write(chunk)
-
-
-def download_data(graph_key):
-    print('Downloading from GDrive is started.')
-    dst = os.path.join(DATA_ROOT_DIR, graph_key, MATRICES_DIR)
-    clean_dir(dst)
-    arch_dst = os.path.join(dst + '.tar.xz')
-    print('Download archive to ' + arch_dst)
-    download_file_from_google_drive(DATA_TO_UNPACK[graph_key], arch_dst)
-    print('Downloading from GDrive is finished.')
-
-
-def unpack(file_from, path_to):
-    with lzma.open(file_from) as f:
-        with tarfile.open(fileobj=f) as tar:
-            tar.extractall(path_to)
-
-
-def install_gtgraph():
-    print('Installation of GTgraph is started.')
-    with urllib.request.urlopen(GT_GRAPH_URL) as response, open(
-        GT_GRAPH_ARCH, 'wb'
-    ) as out_file:
-        shutil.copyfileobj(response, out_file)
-    print('GTgraph is downloaded.')
-    tar = tarfile.open(GT_GRAPH_ARCH)
-    tar.extractall('./tools')
-    tar.close()
-
-    subprocess.run(
-        ['sed', '-i', 's/CC = icc/#CC = icc/g', './tools/GTgraph/Makefile.var']
-    )
-    subprocess.run(
-        ['sed', '-i', 's/#CC = gcc/CC = gcc/g', './tools/GTgraph/Makefile.var']
-    )
-    subprocess.run(['make', '-C', './tools/GTgraph'])
-    print('Installation of GTgraph is finished.')
-
-
-def to_file(filepath, graph):
-    with open(filepath, 'w') as out_file:
-        for t in graph:
-            s = t[0]
-            p = t[1]
-            o = t[2]
-            out_file.write('%s %s %s\n'%(s,p,o))
-
-def unpack_graphs(graph_key):
-    to = os.path.join(DATA_ROOT_DIR, graph_key)    
-    arch = os.path.join(to, '%s.tar.xz' % MATRICES_DIR)
-    print('Unpack ', arch, ' to ', to)
-    unpack(arch, to)
-
-
-def gen_sparse_graph(target_dir, vertices, prob):
-
-    subprocess.run([
-            GT_GRAPH,
-            '-t',
-            '0',
-            '-n',
-            '%s' % (vertices),
-            '-p',
-            '%s' % (prob),
-            '-o',
-            TMP_FILE,
-    ])
-
-    with open(TMP_FILE) as in_file:
-        output_graph = Graph()
-        target = os.path.join(target_dir, 'G%sk-%s' % (int(vertices / 1000), prob))
-        for l in in_file.readlines():
-            if l.startswith('a '):
-                a = l.split(' ')
-                lbl = 'A' if int(a[3]) % 2 == 0 else 'AR'
-                add_rdf_edge(a[1], lbl, a[2], output_graph)
-        write_to_rdf(target, output_graph)
-
-
-def gen_worst_case_graph(target_dir, vertices):
-    first_cycle = int(vertices / 2) + 1
-    output_graph = Graph()
-    target = os.path.join(target_dir, 'worstcase_%s' % (vertices))
-
-    for i in range(0, first_cycle - 1):
-        add_rdf_edge(i, 'A', i + 1, output_graph)
-
-    add_rdf_edge(first_cycle - 1, 'A', 0, output_graph)
-    add_rdf_edge(first_cycle - 1, 'B', first_cycle, output_graph)
-    for i in range(first_cycle, vertices - 1):
-        add_rdf_edge(i, 'B', i + 1, output_graph)
-
-    add_rdf_edge(vertices - 1, 'B', first_cycle - 1, output_graph)
-
-    write_to_rdf(target, output_graph)
-
-
-def gen_cycle_graph(target_dir, vertices):
-    output_graph = Graph()
-    target = os.path.join(target_dir, 'fullgraph_%s' % (vertices))
-
-    for i in range(0, vertices - 1):
-        add_rdf_edge(i, 'A', i + 1, output_graph)
-    add_rdf_edge(vertices - 1, 'A', 0, output_graph)
-
-    write_to_rdf(target, output_graph)
-
-
-def gen_scale_free_graph(target_dir, n, k, labels):
-    g = {i: [(j, np.random.choice(labels)) for j in range(k)] for i in range(k)}
-    degree = [3] * k
-
-    for i in range(k, n):
-        to_vertices = np.random.choice(
-            range(i), size=k, replace=False, p=np.array(degree) / sum(degree)
-        )
-
-        g[i] = []
-        degree.append(0)
-        for to in to_vertices:
-            label = np.random.choice(labels)
-            g[i].append((to, label))
-            degree[to] += 1
-            degree[i] += 1
-
-    output_graph = Graph()
-    target = os.path.join(target_dir, 'scale_free_graph_%s_%s') % (n, k)
-    for v in g:
-        for to in g[v]:
-            add_rdf_edge(v, to[1], to[0], output_graph)
-
-    write_to_rdf(target, output_graph)
-
-
-def clean_dir(path):
-    if os.path.isdir(path):
-        shutil.rmtree(path)
-    os.mkdir(path)
-
-
-def add_graph_dir(name):
-    matrices_dir = os.path.join(DATA_ROOT_DIR, name, MATRICES_DIR)
-    clean_dir(matrices_dir)
-    return matrices_dir
-
-
-def generate_all_sparse_graphs():
-    print('Sparse graphs generation is started.')
-    add_graph_dir('SparseGraph')
-    matrices_dir = add_graph_dir('SparseGraph')
-    for g in SPARSE_GRAPH_TO_GEN:
-        gen_sparse_graph(matrices_dir, g[0], g[1])
-    print('Sparse graphs generation is finished.')
-
-
-def generate_full_graphs():
-    print('Full graphs generation is started.')
-    matrices_dir = add_graph_dir('FullGraph')
-    for g in FULL_GRAPH_TO_GEN:
-        gen_cycle_graph(matrices_dir, g)
-    print('Full graphs generation is finished.')
-
-
-def generate_worst_case_graphs():
-    print('Worst case graphs generation is started.')
-    matrices_dir = add_graph_dir('WorstCase')
-    for n in range(2, NUMBER_OF_WORST_CASES):
-        gen_worst_case_graph(matrices_dir, 2 ** n)
-    print('Worst case graphs generation is finished.')
-
-
-def generate_scale_free_graphs():
-    print('Scale free graphs generation is started.')
-    matrices_dir = add_graph_dir('ScaleFree')
-    for k in 1, 3, 5, 10:
-        for n in 100, 500, 2500, 10000:
-            gen_scale_free_graph(matrices_dir, n, k, ['a', 'b', 'c', 'd'])
-    print('Scale free graphs generation is finished.')
-
-
-def gen_sierpinski_graph(target_dir, degree, predicates=['A']):
-    ''' Generates a Sierpinski Triangle graph. '''
-
-    def sierpinski(t, l, r, deg, preds, g):
-        ''' Core function for generating the Sierpinski Triangle. '''
-        if deg > 0:
-            lt = next(ids)
-            tr = next(ids)
-            rl = next(ids)
-            sierpinski(l, lt, rl, deg - 1, preds, g)
-            sierpinski(lt, t, tr, deg - 1, preds, g)
-            sierpinski(rl, tr, r, deg - 1, preds, g)
-        else:
-            add_edges(l, t, preds, g)
-            add_edges(t, r, preds, g)
-            add_edges(r, l, preds, g)
-
-    def add_edges(u, v, preds, g):
-        ''' Adds edges between vertices u and v for all predicates. '''
-        for p in preds:
-            g += [[u, p, v]]
-            g += [[v, p, u]]
-
-    def _idgen():
-        ''' Generates integer identifiers for vertices. '''
-        c = 4
-        while True:
-            yield c
-            c += 1
-
-    ids = _idgen()
-    graph = []
-    sierpinski(1, 2, 3, degree, predicates, graph)
-    with open(
-        os.path.join(target_dir, 'sierpinskigraph_%s.txt' % (degree)), 'w'
-    ) as out_file:
-        for triple in graph:
-            out_file.write('%s %s %s \n' % (triple[0], triple[1], triple[2]))
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='')
-    parser.add_argument(
-        '--update',
-        choices=[
-            'rdf', 'scalefree', 'full', 'worstcase', 'sparse', 'memoryaliases'
-        ],
-        required=False,
-        type=str,
-        help='partial dataset update',
-    )
-    args = parser.parse_args()
-
-    prt = args.update
-
-    if prt == 'rdf':
-        download_data(RDF)
-        unpack_graphs(RDF)
-    elif prt == 'memoryaliases':
-        download_data(MEMORY_ALIASES)
-        unpack_graphs(MEMORY_ALIASES)
-    elif prt == 'scalefree':
-        generate_scale_free_graphs()
-    elif prt == 'full':
-        generate_full_graphs()
-    elif prt == 'worstcase':
-        generate_worst_case_graphs()
-    elif prt == 'sparse':
-        generate_all_sparse_graphs()
-    else:
-        install_gtgraph()
-        for graph_key in DATA_TO_UNPACK:
-            download_data(graph_key)
-            unpack_graphs(graph_key)
-        generate_all_sparse_graphs()
-        generate_full_graphs()
-        generate_worst_case_graphs()
-        generate_scale_free_graphs()
diff --git a/meta_table_for_readme.py b/meta_table_for_readme.py
new file mode 100644
index 00000000..07f7b7dc
--- /dev/null
+++ b/meta_table_for_readme.py
@@ -0,0 +1,83 @@
+import glob
+import json
+
+from cfpq_data.config import RELEASE_INFO
+
+
+def rdf_dict():
+    data_rdf = dict()
+    names_rdf = RELEASE_INFO['RDF']
+    for name in names_rdf:
+        with open(f'./cfpq_data/data/RDF/Graphs/{name}_meta.json', 'r') as graph_info:
+            data_rdf[name] = json.load(graph_info)
+    return data_rdf
+
+
+def memoryaliases_dict():
+    data_memoryaliases = dict()
+    names_memoryaliases = RELEASE_INFO['MemoryAliases']
+    for name in names_memoryaliases:
+        name_of_file = glob.glob('./cfpq_data/data/MemoryAliases/Graphs/' + name + '*')[0]
+        with open(name_of_file, 'r') as graph_info:
+            data_memoryaliases[name] = json.load(graph_info)
+    return data_memoryaliases
+
+
+def create_table():
+    column_names = ["name", "vertices", "edges", "size of file"]
+    table_rdf = \
+        "| Name | Vertices | Edges | Size of file (Bytes) |\n" + \
+        "|:---|:---|:---|:---|\n"
+
+    table_memoryaliases = \
+        "| Name | Vertices | Edges | Size of file (Bytes) |\n" + \
+        "|:---|:---|:---|:---|\n"
+
+    rdf = rdf_dict()
+    memory_aliases = memoryaliases_dict()
+    names_rdf = RELEASE_INFO['RDF']
+    names_memoryaliases = RELEASE_INFO['MemoryAliases']
+
+    for name in sorted(names_rdf, key=lambda x: int(rdf[x]["size of file"])):
+        for column_name in column_names:
+            table_rdf += "| " + str(rdf[name][column_name]) + " "
+        table_rdf += "|\n"
+    for name in sorted(names_memoryaliases, key=lambda x: int(memory_aliases[x]["size of file"])):
+        for column_name in column_names:
+            table_memoryaliases += "| " + str(memory_aliases[name][column_name]) + " "
+        table_memoryaliases += "|\n"
+
+    with open('./docs/README.md', 'rt') as input_file:
+        lines = input_file.readlines()
+    with open('./docs/README.md', 'wt') as output_file:
+        for line in lines:
+            if "#### RDF" in line:
+                output_file.write(line)
+                output_file.write(table_rdf)
+                output_file.write("\n")
+                continue
+            elif "#### MemoryAliases" in line:
+                output_file.write(line)
+                output_file.write(table_memoryaliases)
+                output_file.write("\n")
+                continue
+            output_file.write(line)
+
+
+def clean_table():
+    flag = 0
+    with open('./docs/README.md', 'rt') as input_file:
+        lines = input_file.readlines()
+    with open('./docs/README.md', 'wt') as output_file:
+        for line in lines:
+            if "#### RDF" in line or "#### MemoryAliases" in line:
+                output_file.write(line)
+                flag = 1
+            if "### Reference values" in line:
+                flag = 0
+            if flag == 0:
+                output_file.write(line)
+
+
+clean_table()
+create_table()
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..374b58cb
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+    "setuptools>=42",
+    "wheel"
+]
+build-backend = "setuptools.build_meta"
diff --git a/reference_values.csv b/reference_values.csv
deleted file mode 100644
index 38b7378c..00000000
--- a/reference_values.csv
+++ /dev/null
@@ -1,87 +0,0 @@
-graph,grammar,control_sum
-fullgraph_10,A_star0,"{'s': 100}"
-fullgraph_100,A_star0,"{'s': 10000}"
-fullgraph_1000,A_star0,"{'s': 1000000}"
-fullgraph_200,A_star0,"{'s': 40000}"
-fullgraph_2000,A_star0,"{'s': 4000000}"
-fullgraph_50,A_star0,"{'s': 2500}"
-fullgraph_500,A_star0,"{'s': 250000}"
-fullgraph_5000,A_star0,"{'s': 25000000}"
-fullgraph_10,A_star1,"{'s': 100}"
-fullgraph_100,A_star1,"{'s': 10000}"
-fullgraph_1000,A_star1,"{'s': 1000000}"
-fullgraph_200,A_star1,"{'s': 40000}"
-fullgraph_2000,A_star1,"{'s': 4000000}"
-fullgraph_50,A_star1,"{'s': 2500}"
-fullgraph_500,A_star1,"{'s': 250000}"
-fullgraph_5000,A_star1,"{'s': 25000000}"
-fullgraph_10,A_star2,"{'s': 100}"
-fullgraph_100,A_star2,"{'s': 10000}"
-fullgraph_1000,A_star2,"{'s': 1000000}"
-fullgraph_200,A_star2,"{'s': 40000}"
-fullgraph_2000,A_star2,"{'s': 4000000}"
-fullgraph_50,A_star2,"{'s': 2500}"
-fullgraph_500,A_star2,"{'s': 250000}"
-fullgraph_5000,A_star2,"{'s': 25000000}"
-free_scale_graph_100_1,an_bm_cm_dn,"{'s': 0}"
-free_scale_graph_100_10,an_bm_cm_dn,"{'s': 1187}"
-free_scale_graph_100_3,an_bm_cm_dn,"{'s': 43}"
-free_scale_graph_100_5,an_bm_cm_dn,"{'s': 314}"
-free_scale_graph_10000_1,an_bm_cm_dn,"{'s': 28}"
-free_scale_graph_10000_10,an_bm_cm_dn,"{'s': 649360}"
-free_scale_graph_10000_3,an_bm_cm_dn,"{'s': 5441}"
-free_scale_graph_10000_5,an_bm_cm_dn,"{'s': 65560}"
-free_scale_graph_2500_1,an_bm_cm_dn,"{'s': 3}"
-free_scale_graph_2500_10,an_bm_cm_dn,"{'s': 86446}"
-free_scale_graph_2500_3,an_bm_cm_dn,"{'s': 1098}"
-free_scale_graph_2500_5,an_bm_cm_dn,"{'s': 12416}"
-free_scale_graph_500_1,an_bm_cm_dn,"{'s': 0}"
-free_scale_graph_500_10,an_bm_cm_dn,"{'s': 8122}"
-free_scale_graph_500_3,an_bm_cm_dn,"{'s': 551}"
-free_scale_graph_500_5,an_bm_cm_dn,"{'s': 1975}"
-worstcase_128,Brackets,"{'s': 4160}"
-worstcase_16,Brackets,"{'s': 72}"
-worstcase_256,Brackets,"{'s': 16512}"
-worstcase_32,Brackets,"{'s': 272}"
-worstcase_4,Brackets,"{'s': 6}"
-worstcase_512,Brackets,"{'s': 65792}"
-worstcase_64,Brackets,"{'s': 1056}"
-worstcase_8,Brackets,"{'s': 20}"
-geospeices,geo,"{'s': 226669749}"
-atom-primitive,GPPerf1,"{'s': 15447}"
-biomedical-mesure-primitive,GPPerf1,"{'s': 15156}"
-core,GPPerf1,"{'s': 316}"
-eclass_514en,GPPerf1,"{'s': 90994}"
-enzyme,GPPerf1,"{'s': 396}"
-foaf,GPPerf1,"{'s': 4118}"
-funding,GPPerf1,"{'s': 17610}"
-generations,GPPerf1,"{'s': 2164}"
-go-hierarchy,GPPerf1,"{'s': 588976}"
-go,GPPerf1,"{'s': 304070}"
-pathways,GPPerf1,"{'s': 884}"
-people_pets,GPPerf1,"{'s': 9472}"
-pizza,GPPerf1,"{'s': 56195}"
-skos,GPPerf1,"{'s': 799}"
-travel,GPPerf1,"{'s': 2499}"
-univ-bench,GPPerf1,"{'s': 2540}"
-wine,GPPerf1,"{'s': 66572}"
-atom-primitive,GPPerf2,"{'s': 122}"
-biomedical-mesure-primitive,GPPerf2,"{'s': 2856}"
-core,GPPerf2,"{'s': 214}"
-eclass_514en,GPPerf2,"{'s': 96163}"
-enzyme,GPPerf2,"{'s': 8163}"
-foaf,GPPerf2,"{'s': 10}"
-funding,GPPerf2,"{'s': 1158}"
-generations,GPPerf2,"{'s': 0}"
-go-hierarchy,GPPerf2,"{'s': 738937}"
-go,GPPerf2,"{'s': 334850}"
-pathways,GPPerf2,"{'s': 3117}"
-people_pets,GPPerf2,"{'s': 37}"
-pizza,GPPerf2,"{'s': 1262}"
-skos,GPPerf2,"{'s': 1}"
-travel,GPPerf2,"{'s': 63}"
-univ-bench,GPPerf2,"{'s': 81}"
-wine,GPPerf2,"{'s': 133}"
-G10k-0.001,SG,"{'s': 98545363}"
-G10k-0.01,SG,"{'s': 100000000}"
-G5k-0.001,SG,"{'s': 19960645}"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 759b4167..c9ef123c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,8 @@
 numpy
-rdflib
\ No newline at end of file
+rdflib
+tqdm
+networkx
+requests
+pytest
+setuptools
+wget
diff --git a/setup.py b/setup.py
new file mode 100644
index 00000000..b0a3c1f9
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,26 @@
+from pathlib import Path
+
+import setuptools
+
+with open(Path(__file__).parent / 'docs' / 'README.md', "r", encoding="utf-8") as fh:
+    long_description = fh.read()
+
+with open('requirements.txt') as f:
+    required = f.read().splitlines()
+
+setuptools.setup(
+    name='cfpq_data',
+    version='0.0.0',
+    description='Graphs and grammars for experimental analysis of context-free path querying algorithms',
+    long_description=long_description,
+    long_description_content_type='text/markdown',
+    packages=setuptools.find_packages(),
+    url='https://github.com/JetBrains-Research/CFPQ_Data',
+    license='Apache License 2.0',
+    author='Grigoriev Semyon',
+    author_email='rsdpisuy@gmail.com',
+    package_data={'': ['*.json'], 'cfpq_data': ['data/*/Grammars/*.txt']},
+    include_package_data=True,
+    python_requires='>=3.8',
+    install_requires=required
+)
diff --git a/tools/LUBM/README.md b/tools/LUBM/README.md
deleted file mode 100644
index 0dfe56ac..00000000
--- a/tools/LUBM/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# LUBM dataset
-
-## Folder structure
-- config.txt - configures mappings from IRI names to short string names (for our purposes)
-- download.sh - downloads and unzips the lubm generator from oficial website
-- generate.sh - generates dataset for 10 universities (this could be changed in the script: set -univ N)
-- prepare.py - prepares files names of the generated dataset (optional)
-- converter.py - convert set of database files to single file with mappings applied
-
-## Usage
-
-Download lubm java based generating tool. Run dataset generating for  10 universities, and then 
-generated database file with mapping for merged 3 universities (indicies 0..2) as an example.
-
-```
-$ bash download.sh
-$ bash generate.sh
-$ python3 converter.py univ\\University 3 config.txt
-```
diff --git a/tools/LUBM/config.txt b/tools/LUBM/config.txt
deleted file mode 100644
index fe290f9c..00000000
--- a/tools/LUBM/config.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#subOrganizationOf SO
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#worksFor WF
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#headOf HF
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#teacherOf TF
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#memberOf MF
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#advisor AD
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#takesCourse TC
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#publicationAuthor PA
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#undergraduateDegreeFrom UG
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#mastersDegreeFrom MD
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#doctoralDegreeFrom DD
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#emailAddress EA
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#name NM
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#researchInterest RI
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#telephone TP
-http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#teachingAssistantOf TA
\ No newline at end of file
diff --git a/tools/LUBM/converter.py b/tools/LUBM/converter.py
deleted file mode 100644
index b05c830f..00000000
--- a/tools/LUBM/converter.py
+++ /dev/null
@@ -1,91 +0,0 @@
-"""
-    RDF merger and converter for LUBM dataset.
-    Database is stored in files <prefix><id>_<sub_id>.owl
-    This files are merged for specified number of universities (ids range),
-    and edges are replaced with specified mapping.
-    Also vertices labels also replaces with integer based names.
-    
-    Usage:
-    - Create a conversion configuration file. Each line must contain an IRI,
-    a whitespace character and a string to replace the IRI by.
-    - Run converter.py <prefix> <count> <config>
-    - Result will have name <pefix><count><vertices count><indices count>.xml
-    
-    The graph will contain explicit inverted edges added an 'R'.
-    """
-
-import rdflib, sys, os
-
-URI_PREFIX = 'http://yacc/'
-MAX_FILES_PER_UNI = 30
-
-# RDF serialization
-def write_to_rdf(target, graph):
-    graph.serialize(target + '.xml', format='xml')
-
-# Edge addition (grapf constructing)
-def add_rdf_edge(subj, pred, obj, graph):
-    s = rdflib.BNode('id-%s' % (subj))
-    p = rdflib.URIRef(URI_PREFIX + pred)
-    o = rdflib.BNode('id-%s' % (obj))
-    graph.add((s, p, o))
-
-if len(sys.argv) < 3:
-    print('Usage: converter.py <prefix> <count> <config>')
-    exit()
-
-replace = {} # map for replacing predicates
-config = sys.argv[3]
-for l in open(config,'r').readlines():
-  pair = l.split(' ')
-  old = rdflib.URIRef(pair[0].strip(' '))
-  new = pair[1].strip('\n').strip(' ')
-  replace[old] = new
-
-print(replace)
-
-res = {}        # map from resources to integer ids
-next_id = 0     # id counter
-edges_count = 0 # Total edges
-
-graph = rdflib.Graph()
-prefix = sys.argv[1]
-count = int(sys.argv[2])
-
-processed = []
-notreplaced = set()
-
-for i in range(0,count):
-  for j in range(0,MAX_FILES_PER_UNI):
-    filename = prefix + str(i) + '_' + str(j) + '.owl'
-    try:
-      g = rdflib.Graph()
-      g.parse(filename)
-      
-      for s,p,o in g:
-        for r in [s,o]:
-          if r not in res:
-            res[r] = str(next_id)
-            next_id += 1
-
-        if p in replace:
-          add_rdf_edge(res[s], replace[p], res[o], graph)
-          add_rdf_edge(res[s], replace[p] + 'R', res[o], graph)
-          edges_count += 2
-        else:
-          add_rdf_edge(res[s], 'OTHER', res[o], graph)
-          edges_count += 1
-          notreplaced.add(p)
-
-      processed.append(filename)
-      print('Merged:', filename)
-    except Exception:
-      pass
-
-target = prefix + str(count) + 'v' + str(next_id) + 'e' + str(edges_count)  # output file
-write_to_rdf(target,graph)
-
-print('Total vertices:', next_id)
-print('Total edges:', edges_count)
-print('Processed files:\n', processed)
-print('Not replaced labels:', notreplaced)
diff --git a/tools/LUBM/download.sh b/tools/LUBM/download.sh
deleted file mode 100644
index c60235b8..00000000
--- a/tools/LUBM/download.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-wget http://swat.cse.lehigh.edu/projects/lubm/uba1.7.zip
-unzip uba1.7.zip -d univ
diff --git a/tools/LUBM/generate.sh b/tools/LUBM/generate.sh
deleted file mode 100644
index d7f60676..00000000
--- a/tools/LUBM/generate.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-cd univ
-java -cp classes edu.lehigh.swat.bench.uba.Generator -univ 10 -onto http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl
-cd ..
diff --git a/tools/LUBM/prepare.py b/tools/LUBM/prepare.py
deleted file mode 100644
index 2c028d1f..00000000
--- a/tools/LUBM/prepare.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import os, sys
-
-if len(sys.argv) < 2:
-    print('Usage: prepare.py <prefix> <new>')
-    exit()
-
-prefix = sys.argv[1]
-new = sys.argv[2]
-files = os.listdir()
-
-for f in files:
-  if f.startswith(prefix):
-    name = f.replace(prefix,new)
-    try:
-      os.rename(f, name)
-    except Exception:
-      print('Failed to rename file: ' + f + ' to ' + name)
diff --git a/tools/RDF_to_triple/convconfig b/tools/RDF_to_triple/convconfig
deleted file mode 100644
index 2009370f..00000000
--- a/tools/RDF_to_triple/convconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-http://www.w3.org/2000/01/rdf-schema#subClassOf SCO
-http://www.w3.org/1999/02/22-rdf-syntax-ns#type T
diff --git a/tools/RDF_to_triple/converter.py b/tools/RDF_to_triple/converter.py
deleted file mode 100644
index def25968..00000000
--- a/tools/RDF_to_triple/converter.py
+++ /dev/null
@@ -1,44 +0,0 @@
-"""
-RDF converter from popular formats (XML, Turtle, etc.) to simple triple
-format (.txt).
-
-Usage:
-- Create a conversion configuration file. Each line must contain an IRI, a
-  whitespace character and a string to replace the IRI by.
-- Run converter.py <data> <config>
-- Result will have the same name of the input data, with .txt extension.
-  The graph will contain explicit inverted edges added an 'R'.
-"""
-
-import rdflib, sys, os
-
-if len(sys.argv) < 2:
-	print('Usage: converter.py <data> <config>')
-	exit()
-
-replace = {} # map for replacing predicates
-config = sys.argv[2]
-for l in open(config,'r').readlines():
-	pair = l.split(' ')
-	old = rdflib.URIRef(pair[0].strip(' '))
-	new = pair[1].strip('\n').strip(' ')
-	replace[old] = new
-
-res = {}    # map from resources to integer ids
-next_id = 0 # id counter
-
-graph = rdflib.Graph()
-graph.parse(sys.argv[1])
-
-out = open(os.path.splitext(sys.argv[1])[0]+'.txt','w') # output file
-for s,p,o in graph:
-	for r in [s,o]:
-		if r not in res:
-			res[r] = str(next_id)
-			next_id += 1
-
-	if p in replace:
-		out.write(res[s]+' '+replace[p]+' ' +res[o]+'\n')
-		out.write(res[o]+' '+replace[p]+'R '+res[s]+'\n')
-	else:
-		out.write(res[s]+' OTHER '+res[o]+'\n')
diff --git a/tools/gen_RPQ/RDF_edge_stat.py b/tools/gen_RPQ/RDF_edge_stat.py
deleted file mode 100644
index 4b4073db..00000000
--- a/tools/gen_RPQ/RDF_edge_stat.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import rdflib, sys
-
-def get_labels_count (rdf):
-    d = {}
-    for s,p,o in rdf:     
-       d[p] = d.get(p,0) + 1
-    
-    sorted_d = [(k, v) for k, v in sorted(d.items(), key=lambda item: item[1])] 	
-    sorted_d.reverse()
-
-    return sorted_d
-
-def print_config(lst, path_to_config):
-    i = 0
-    with open(path_to_config,'w') as config:
-       for x in lst:
-           config.write(x[0] + ' ' + str(i) + '\n')
-           i = i + 1
-
-g = rdflib.Graph()
-
-g.parse(sys.argv[1])#, format="nt")
-
-r = get_labels_count (g)
-
-for x in r: 
-   print(x[0], ': ', x[1])
-
-print_config(r, sys.argv[2])
diff --git a/tools/gen_RPQ/README.md b/tools/gen_RPQ/README.md
deleted file mode 100644
index bd95be54..00000000
--- a/tools/gen_RPQ/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
- First step is edges investigation
- * Run  ```python3 RDF_edge_stat.py my_rdf.rdf my_config``` . Mapping from URIs to integers will be saved to my_config. You can use tid config for RDf to triples convertion using RDF_to_triple tool. Numbers of edges labelled with URIs will be printed in concole. 
- * Run ```python3 gen.py my_config n_URIs q_for_each_tpl result_root_dir```, where ```my_config``` is a config generated at the previous step, first ```n_URIs``` labels from config will be used to generate queryes, ```q_for_each_tpl``` queryes will be generated for each template.   
\ No newline at end of file
diff --git a/tools/gen_RPQ/gen.py b/tools/gen_RPQ/gen.py
deleted file mode 100644
index 92b77ad0..00000000
--- a/tools/gen_RPQ/gen.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import numpy, sys, os,  shutil
-
-templates = [(1, '%s*', 'q1'), (2, '%s %s*', 'q2'), (3, '%s %s* %s*', 'q3'), 
-             (2, '(%s | %s)*' , 'q4_2'), (3, '(%s | %s | %s)*', 'q4_3'), (4, '(%s | %s | %s | %s)*', 'q4_4'), (5, '(%s | %s | %s | %s | %s)*', 'q4_5'),
-             (3, '%s %s* %s', 'q5'), (2, '%s* %s*', 'q6'), (3, '%s %s %s*', 'q7'), (2, '%s? %s*', 'q8'),
-             (2, '(%s | %s)+', 'q9_2'), (3, '(%s | %s | %s)+', 'q9_3'), (4, '(%s | %s | %s | %s)+', 'q9_4'), (5, '(%s | %s | %s | %s | %s)+', 'q9_5'),
-             (3, '(%s | %s) %s*', 'q10_2'), (4, '(%s | %s | %s) %s*', 'q10_3'), (5, '(%s | %s | %s | %s) %s*', 'q10_4'), (6, '(%s | %s | %s | %s | %s) %s*', 'q10_5'),
-             (2, '%s %s', 'q11_2'), (3, '%s %s %s', 'q11_3'), (4, '%s %s %s %s', 'q11_4'), (5, '%s %s %s %s %s', 'q11_5'),
-             (4, '(%s %s)+ |  (%s %s)+', 'q_12'), (5, '(%s (%s %s)*)+ |  (%s %s)+', 'q_13'), (6, '(%s %s (%s %s)*)+  (%s | %s)*', 'q_14'),
-             (4, '(%s | %s)+ (%s | %s)+ ', 'q_15'), (5, '%s %s (%s | %s | %s)', 'q_16')]
-
-def gen (tpl, n, lst, k):
-    res = set()
-    while (len(res) < n):
-        perm = numpy.random.permutation(lst)
-        res.add(((tpl % tuple(perm[0:k])),tuple(perm[0:k])))
-    return res
-
-def gen_from_config(config, num_of_lalbels, num_of_queries):
-    lbls = [ l.split(' ')[1].rstrip() for l in open(config,'r').readlines()]
-    return [(tpl[2], gen (tpl[1], num_of_queries, lbls[0:num_of_lalbels], tpl[0])) for tpl in templates]
-
-def print_qs (qs, root_dir):
-    for qd in qs:
-        path = os.path.join(root_dir, qd[0])
-        if os.path.exists(path):
-           shutil.rmtree(path)
-        os.mkdir(path)
-        i = 0
-        for q in qd[1]:
-            with open(os.path.join(path,str(i)),'w') as out:
-                out.write('S\n')
-                out.write(' '.join(q[1]) + '\n')
-                out.write('S -> ' + q[0] + '\n')
-                i = i + 1
-
-r = gen_from_config(sys.argv[1],int(sys.argv[2]),int(sys.argv[3]))
-
-print_qs(r, sys.argv[4])
-
-for s in r:
-	for q in s:
-		print(q)
diff --git a/tools/grammar_to_cnf/README.md b/tools/grammar_to_cnf/README.md
deleted file mode 100644
index fb504332..00000000
--- a/tools/grammar_to_cnf/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-Loads context-free grammar and outputs it in CNF.
-
-Use the following input format:
-
-- Line 0:
-
-    ```
-    a set of variable symbols delimited by spaces,
-    the first one is the starting symbol
-    ```
-
-- Line 1:
-
-    ```
-    a set of terminal symbols delimited by spaces
-    ```
-
-- The rest of the lines are productions in the form:
-    
-    ```head -> body | body | ... | body```
-
-    where each body can contain basic regular expression, allowed operators:
-    
-    - The concatenation, the default operator, which can by represented either by a space or a dot (.)
-    
-    - The union, represented by ```|``` 
-
-    - The ```?``` quantifier
-    
-    - The kleene star, represented by ```*```
-    
-    Epsilon symbol should be represented by ```eps```
-
-
-To start run:
-```
-pip3 install -r requirements.txt
-python3 grammar_to_pyformlang.py PATH_TO_GRAMMAR -o PATH_TO_OUTPUT
-```
diff --git a/tools/grammar_to_cnf/examples/example.txt b/tools/grammar_to_cnf/examples/example.txt
deleted file mode 100644
index 11186ebd..00000000
--- a/tools/grammar_to_cnf/examples/example.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-S
-a b
-S -> a S b S
-S -> eps
\ No newline at end of file
diff --git a/tools/grammar_to_cnf/examples/example1.txt b/tools/grammar_to_cnf/examples/example1.txt
deleted file mode 100644
index 524c195c..00000000
--- a/tools/grammar_to_cnf/examples/example1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-S
-a b
-S -> a S b S | eps
\ No newline at end of file
diff --git a/tools/grammar_to_cnf/examples/example2.txt b/tools/grammar_to_cnf/examples/example2.txt
deleted file mode 100644
index 63cd236d..00000000
--- a/tools/grammar_to_cnf/examples/example2.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-S
-a b
-S -> (a S b)*
\ No newline at end of file
diff --git a/tools/grammar_to_cnf/grammar_to_cnf.py b/tools/grammar_to_cnf/grammar_to_cnf.py
deleted file mode 100644
index 5f974bb7..00000000
--- a/tools/grammar_to_cnf/grammar_to_cnf.py
+++ /dev/null
@@ -1,148 +0,0 @@
-from pyformlang.cfg import Production, Variable, Terminal, CFG, Epsilon
-from pyformlang.regular_expression import Regex
-import argparse
-import re
-
-EPS_SYM = 'eps'
-SUPPORTED_REGEX_CHARS = '.*()?|'
-
-# Counter function used to create unique variable names
-def get_new_var_num():
-    get_new_var_num.calls += 1
-    return get_new_var_num.calls
-get_new_var_num.calls = 0
-
-
-def regex_to_grammar_productions(regex, head, var_dict, terminal_dict):
-    _var_dict = {}
-    production_set = set()
-
-    # Getting an NFA from regex
-    enfa = regex.to_epsilon_nfa()
-    enfa = enfa.minimize()
-    transitions = enfa._transition_function._transitions
-
-    # Producing variables from NFA states
-    for state in enfa.states:
-        _var_dict[state] = Variable(
-            # Creating new CFG variable with unique name
-            '%s#REGEX#%s' % (head.value, get_new_var_num())
-        )
-
-    for head_state in transitions:
-        # Adding productions from head to start states
-        for start_state in enfa.start_states:
-            start_p = Production(head, [_var_dict[start_state]])
-            production_set.add(start_p)
-
-        # Getting productions from NFA transitions
-        for sym in list(transitions[head_state]):
-            body_state = transitions[head_state][sym]
-            inner_head = _var_dict[head_state]
-            inner_body = []
-
-            if sym in var_dict:
-                inner_body.append(var_dict[sym])
-            elif sym in terminal_dict:
-                inner_body.append(terminal_dict[sym])
-            elif sym == EPS_SYM:
-                inner_body.append(Epsilon())
-            else:
-                raise ValueError(f'''Symbol "{sym}" is not defined as
-                                 a terminal or a variable''')
-
-            inner_body.append(_var_dict[body_state])
-            production_set.add(
-                Production(inner_head, inner_body)
-            )
-
-            if transitions[head_state][sym] in enfa.final_states:
-                eps_p = Production(_var_dict[body_state], [])
-                production_set.add(eps_p)
-    return production_set
-
-
-def from_txt(lines):
-    var_dict = {}
-    terminal_dict = {}
-    production_set = set()
-
-    # variables
-    var_lst = lines[0].split()
-    start_var = Variable(var_lst[0])
-    for v in var_lst:
-        var_dict[v] = Variable(v)
-
-    # terminals
-    for t in lines[1].split():
-        terminal_dict[t] = Terminal(t)
-
-    # productions
-    for l in lines[2:]:
-        pr = l.split(' -> ')
-        head = var_dict[pr[0]]
-        body_str = pr[1].rstrip('\n')
-
-        # pyformlang doesn't accept '?' quantifier, transforming to alternative expression
-        body_str = body_str.replace('?',f'|{EPS_SYM}')
-
-        production_set |= regex_to_grammar_productions(
-            Regex(body_str),
-            head,
-            var_dict,
-            terminal_dict
-        )
-
-    cfg = CFG(
-        start_symbol=start_var, productions=production_set
-    )
-
-    print('Context-free grammar loaded.')
-    # DEBUG OUTPUT
-    # for w in list(cfg.get_words(5)):
-    #     print(w)
-    # print(cfg.start_symbol)
-    # print(f'Variables: {cfg.variables}')
-    # print(f'Terminals: {cfg.terminals}')
-    # print(f'Productions: {cfg.productions}')
-
-    return cfg
-
-
-def to_txt(cfg):
-    variables, productions, terminals = '', '', ''
-
-    for var in cfg.variables:
-        if var != cfg.start_symbol:
-            variables += f'{var.value} '
-    for ter in cfg.terminals:
-        terminals += f'{ter.value} '
-    for pr in cfg.productions:
-        head = pr.head.value
-        productions += (f'{head} -> ')
-        for sym in pr.body:
-            productions += f'{sym.value} '
-        productions += '\n'
-    return f'{cfg.start_symbol} {variables}\n{terminals}\n{productions}'
-
-
-def main():
-    parser = argparse.ArgumentParser(description='')
-    parser.add_argument('input',
-                        type=argparse.FileType('r')
-                        )
-    parser.add_argument("-o", "--output",
-                        help="Directs the output to a name of your choice",
-                        required=True
-                        )
-    args = parser.parse_args()
-
-    cfg = from_txt(args.input.readlines())
-    cfg = cfg.to_normal_form()
-    with open(args.output, 'w') as output_file:
-        output_file.write(to_txt(cfg))
-        print(f'Grammar in CNF written to {args.output}')
-
-
-if __name__ == "__main__":
-    main()
diff --git a/tools/grammar_to_cnf/requirements.txt b/tools/grammar_to_cnf/requirements.txt
deleted file mode 100644
index 5d05f5d9..00000000
--- a/tools/grammar_to_cnf/requirements.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-pyformlang
\ No newline at end of file
diff --git a/tools/graspan_to_rdf.py b/tools/graspan_to_rdf.py
deleted file mode 100644
index 493b9c7a..00000000
--- a/tools/graspan_to_rdf.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from os import listdir
-from os.path import isfile, join
-from rdf_helper import write_to_rdf, add_rdf_edge
-
-def convert_file(in_file_path, out_file_path):
-    output_graph = Graph()
-    with open(in_file_path) as in_file:       
-        for l in in_file.readlines():
-        	a = list(filter(None, l.split()))
-        	if len(a) > 0 and a[2][0] != '-':
-        		add_rdf_edge(a[0], a[2].upper(), a[1], output_graph)
-	
-    write_to_rdf(out_file_path, output_graph)
-
-def process_folder(folder):
-    onlyfiles = [f for f in listdir(folder) if isfile(join(folder, f))]
-
-    for file in onlyfiles:
-        print('Start: ' + file)
-        full_path = join(folder, file)
-        convert_file(full_path, full_path)
\ No newline at end of file
diff --git a/tools/rdf_helper.py b/tools/rdf_helper.py
deleted file mode 100644
index 17877f29..00000000
--- a/tools/rdf_helper.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from rdflib import Graph, URIRef, BNode
-
-URI_PREFIX = 'http://yacc/'
-
-# RDF serialization
-def write_to_rdf(target, graph):
-    graph.serialize(target + '.xml', format='xml')
-
-
-def add_rdf_edge(subj, pred, obj, graph):
-    s = BNode('id-%s' % (subj))
-    p = URIRef(URI_PREFIX + pred)
-    o = BNode('id-%s' % (obj))
-    graph.add((s, p, o))
\ No newline at end of file
diff --git a/tools/redis-rdf/README.md b/tools/redis-rdf/README.md
deleted file mode 100644
index 1258b3e0..00000000
--- a/tools/redis-rdf/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-### RDF loader in Redis Graph
-
-### Example of usage
-
-``` 
-$ python3 main.py file examples/graph.xml graph
-```
-``` 
-$ python3 main.py dir examples
-```
-
-### Help 
-
-``` 
-$ python3 main.py -h 
-```
diff --git a/tools/redis-rdf/examples/graph.xml b/tools/redis-rdf/examples/graph.xml
deleted file mode 100644
index d414c36d..00000000
--- a/tools/redis-rdf/examples/graph.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<rdf:RDF
-  xmlns:yacc="http://yacc/"
-  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
->
-  <rdf:Description rdf:about="http://yacc/A">
-    <yacc:parentOf>
-      <rdf:Description rdf:about="http://yacc/B">
-        <yacc:parentOf rdf:resource="http://yacc/C"/>
-      </rdf:Description>
-    </yacc:parentOf>
-  </rdf:Description>
-  <rdf:Description rdf:about="http://yacc/C">
-    <yacc:friendOf rdf:resource="http://yacc/B"/>
-    <yacc:parentOf rdf:resource="http://yacc/A"/>
-  </rdf:Description>
-</rdf:RDF>
diff --git a/tools/redis-rdf/main.py b/tools/redis-rdf/main.py
deleted file mode 100755
index df65a5d9..00000000
--- a/tools/redis-rdf/main.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/python3
-
-import os
-
-from src.redis_loader import load
-from argparse import ArgumentParser
-import logging
-
-
-def main():
-    parser = ArgumentParser('Load rdf into RedisGraph')
-
-    parser.add_argument('--host', help='redis host name', default='localhost')
-    parser.add_argument('--port', help='redis port', default=6379)
-
-    subparsers = parser.add_subparsers()
-
-    parser_file = subparsers.add_parser('file')
-    parser_file.add_argument('RDF_PATH', help='rdf graph path')
-    parser_file.add_argument('GRAPH_NAME', help='redis graph name')
-
-    parser_dir = subparsers.add_parser('dir')
-    parser_dir.add_argument('dir_path')
-
-    args = parser.parse_args()
-    # logging.disable(logging.WARNING)
-
-    if 'dir_path' in args:
-        for file in os.listdir(args.dir_path):
-            load(f'{args.dir_path}/{file}', file, args.host, args.port)
-    else:
-        load(args.RDF_PATH, args.GRAPH_NAME, args.host, args.port)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/tools/redis-rdf/requirements.txt b/tools/redis-rdf/requirements.txt
deleted file mode 100644
index b2d73034..00000000
--- a/tools/redis-rdf/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pandas
-tqdm==4.36.1
-rdflib==4.2.2
-redis==3.3.10
-git+https://github.com/RedisGraph/redisgraph-py.git@275cf4c7609a061e55b538e10efbc02c91c090e7
\ No newline at end of file
diff --git a/tools/redis-rdf/src/redis_loader/__init__.py b/tools/redis-rdf/src/redis_loader/__init__.py
deleted file mode 100644
index 5d173dba..00000000
--- a/tools/redis-rdf/src/redis_loader/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from .loader import load
\ No newline at end of file
diff --git a/tools/redis-rdf/src/redis_loader/graph.py b/tools/redis-rdf/src/redis_loader/graph.py
deleted file mode 100644
index 4f9f028e..00000000
--- a/tools/redis-rdf/src/redis_loader/graph.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import redisgraph
-
-
-class Graph(redisgraph.Graph):
-    def __init__(self, name, redis_con):
-        super().__init__(name, redis_con)
-
-    def commit_edges(self):
-        """
-        Create edges with existing nodes.
-        """
-        if len(self.nodes) == 0 and len(self.edges) == 0:
-            return None
-
-        query = 'MATCH '
-        for _, node in self.nodes.items():
-            query += str(node) + ','
-
-        # Discard leading comma.
-        if query[-1] is ',':
-            query = query[:-1]
-
-        query += ' CREATE '
-
-        query += ','.join([str(edge) for edge in self.edges])
-
-        # Discard leading comma.
-        if query[-1] is ',':
-            query = query[:-1]
-
-        return self.query(query)
-
-    def flush_edges(self):
-        """
-        Commit the edges and reset the edges and nodes to zero length
-        """
-        self.commit_edges()
-        self.nodes = {}
-        self.edges = []
diff --git a/tools/redis-rdf/src/redis_loader/loader.py b/tools/redis-rdf/src/redis_loader/loader.py
deleted file mode 100644
index fb3da145..00000000
--- a/tools/redis-rdf/src/redis_loader/loader.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import hashlib
-
-from redis import Redis
-from redisgraph import Node as RedisNode, Edge as RedisEdge
-from tqdm import tqdm
-
-from .graph import Graph as RedisGraph
-from .triplet_loader import load_rdf_graph
-
-BLOCK_SIZE = 100
-
-def make_node(value: str, alias=None):
-    return RedisNode(
-        label='Node', alias=alias, properties={
-            'value': value,
-            'sha256': hashlib.sha256(str(value).encode('utf-8')).hexdigest()
-        })
-
-def load_in_redis(rdf_graph, redis_graph: RedisGraph):
-    all_nodes = dict()
-
-    # Add all nodes from file to hash map
-    for subj, _, obj in rdf_graph:
-        all_nodes.setdefault(str(subj), make_node(str(subj)))
-        all_nodes.setdefault(str(obj), make_node(str(obj)))
-
-    print(f'{redis_graph.name}: Add all nodes to redis graph')
-    for k, v in tqdm(all_nodes.items()):
-        redis_graph.add_node(v)
-        if len(redis_graph.nodes) > BLOCK_SIZE:
-            redis_graph.flush()
-    redis_graph.flush()
-
-    # Create index over Nodes
-    redis_graph.query("CREATE INDEX ON :Node(sha256)")
-
-    print(f'{redis_graph.name}: Add edges to existing nodes')
-    for subj, pred, obj in tqdm(rdf_graph):
-        edge = RedisEdge(all_nodes[str(subj)], pred, all_nodes[str(obj)])
-        edge_r = RedisEdge(all_nodes[str(obj)], f'{pred}_r', all_nodes[str(subj)])
-        redis_graph.add_node(all_nodes[str(subj)])
-        redis_graph.add_node(all_nodes[str(obj)])
-        redis_graph.add_edge(edge)
-        redis_graph.add_edge(edge_r)
-        if len(redis_graph.edges) > BLOCK_SIZE:
-            redis_graph.flush_edges()
-    redis_graph.flush_edges()
-
-
-def load(rdf_file: str, redis_graph_name: str, redis_host: str, redis_port: int):
-    rdf_graph = load_rdf_graph(rdf_file)
-
-    redis_connector = Redis(host=redis_host, port=redis_port)
-    redis_graph = RedisGraph(redis_graph_name, redis_connector)
-
-    load_in_redis(rdf_graph, redis_graph)
diff --git a/tools/redis-rdf/src/redis_loader/triplet_loader.py b/tools/redis-rdf/src/redis_loader/triplet_loader.py
deleted file mode 100644
index 6add6e6f..00000000
--- a/tools/redis-rdf/src/redis_loader/triplet_loader.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import pathlib
-
-import rdflib
-
-
-def load_triplets(filename: str):
-    triplets = list()
-    with open(filename, mode='r') as file:
-        for line in file:
-            try:
-                subj, pred, obj = line[:-1].split()
-                triplets.append((subj, pred, obj))
-            except ValueError:
-                continue
-    return triplets
-
-
-def uri_to_name(identifier, rdf_graph: rdflib.Graph):
-    if isinstance(identifier, rdflib.URIRef):
-        prefix, namespace, name = rdf_graph.compute_qname(identifier)
-        return name
-    return identifier
-
-
-def load_rdf_graph(rdf_file: str):
-    rdf_graph = rdflib.Graph()
-    rdf_graph.load(rdf_file)
-    return list(map(lambda spo: (spo[0], uri_to_name(spo[1], rdf_graph), spo[2]), iter(rdf_graph)))


Test patch:
diff --git a/tests/FullGraph/conftest.py b/tests/FullGraph/conftest.py
new file mode 100644
index 00000000..0de4e668
--- /dev/null
+++ b/tests/FullGraph/conftest.py
@@ -0,0 +1,6 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[vertices for vertices in range(100, 1000, 100)])
+def num_of_vertices(request):
+    return request.param
diff --git a/tests/FullGraph/test_fullgraph.py b/tests/FullGraph/test_fullgraph.py
new file mode 100644
index 00000000..1d1a94d9
--- /dev/null
+++ b/tests/FullGraph/test_fullgraph.py
@@ -0,0 +1,29 @@
+import os
+
+from cfpq_data import FullGraph
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_fullgraph(num_of_vertices):
+    first_graph = FullGraph.build(num_of_vertices)
+    second_graph_path = first_graph.save('tmp')
+    second_graph = FullGraph.load_from_rdf(second_graph_path)
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
+
+
+def test_txt(num_of_vertices):
+    first_graph = FullGraph.build(num_of_vertices)
+    first_graph_path = first_graph.save('tmp1', 'txt')
+    second_graph = FullGraph.load_from_txt(first_graph_path)
+
+    os.remove(first_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tests/LUBM/conftest.py b/tests/LUBM/conftest.py
new file mode 100644
index 00000000..4173fae9
--- /dev/null
+++ b/tests/LUBM/conftest.py
@@ -0,0 +1,6 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[1, 2, 3])
+def num_of_vertices(request):
+    return request.param
diff --git a/tests/LUBM/test_lubm.py b/tests/LUBM/test_lubm.py
new file mode 100644
index 00000000..5d78e770
--- /dev/null
+++ b/tests/LUBM/test_lubm.py
@@ -0,0 +1,23 @@
+import os
+import sys
+
+from cfpq_data import LUBM
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_lubm(num_of_vertices):
+    if sys.platform == 'win32':
+        assert True
+    else:
+        first_graph = LUBM.build(num_of_vertices)
+        second_graph_path = first_graph.save('tmp')
+        second_graph = LUBM.load_from_rdf(second_graph_path)
+        os.remove(second_graph_path)
+
+        assert check_metadata(first_graph, second_graph)
diff --git a/tests/MemoryAliases/conftest.py b/tests/MemoryAliases/conftest.py
new file mode 100644
index 00000000..e6d3d3f8
--- /dev/null
+++ b/tests/MemoryAliases/conftest.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[
+    'bzip2'
+    , 'gzip'
+    , 'ls'
+    , 'pr'
+    , 'wc'
+])
+def ma_graph_name(request):
+    return request.param
diff --git a/tests/MemoryAliases/test_memoryaliases_graph.py b/tests/MemoryAliases/test_memoryaliases_graph.py
new file mode 100644
index 00000000..d3147a5b
--- /dev/null
+++ b/tests/MemoryAliases/test_memoryaliases_graph.py
@@ -0,0 +1,32 @@
+import os
+
+from cfpq_data import MemoryAliases
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_graph(ma_graph_name):
+    first_graph = MemoryAliases.build(ma_graph_name).save('tmp1')
+    first_graph_obj = MemoryAliases.build(first_graph)
+    second_graph = MemoryAliases.build(ma_graph_name).save('tmp2')
+    second_graph_obj = MemoryAliases.build(second_graph)
+
+    os.remove(first_graph)
+    os.remove(second_graph)
+
+    assert check_metadata(first_graph_obj, second_graph_obj)
+
+
+def test_txt(ma_graph_name):
+    first_graph = MemoryAliases.build(ma_graph_name)
+    first_graph_path = first_graph.save('tmp1', 'txt')
+    second_graph = MemoryAliases.load_from_txt(first_graph_path)
+
+    os.remove(first_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tests/RDF/conftest.py b/tests/RDF/conftest.py
new file mode 100644
index 00000000..94856245
--- /dev/null
+++ b/tests/RDF/conftest.py
@@ -0,0 +1,18 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[
+    'atom-primitive'
+    , 'biomedical-mesure-primitive'
+    , 'core'
+    , 'foaf'
+    , 'funding'
+    , 'generations'
+    , 'people_pets'
+    , 'skos'
+    , 'travel'
+    , 'univ-bench'
+    , 'wine'
+])
+def rdf_graph_name(request):
+    return request.param
diff --git a/tests/RDF/test_rdf.py b/tests/RDF/test_rdf.py
new file mode 100644
index 00000000..63a72268
--- /dev/null
+++ b/tests/RDF/test_rdf.py
@@ -0,0 +1,32 @@
+import os
+
+from cfpq_data import RDF
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_rdf(rdf_graph_name):
+    first_graph_path = RDF.build(rdf_graph_name).save('tmp1')
+    first_graph = RDF.build(first_graph_path)
+    second_graph_path = RDF.build(rdf_graph_name).save('tmp2')
+    second_graph = RDF.build(second_graph_path)
+
+    os.remove(first_graph_path)
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
+
+
+def test_txt(rdf_graph_name):
+    first_graph = RDF.build(rdf_graph_name)
+    first_graph_path = first_graph.save('tmp1.txt', 'txt')
+    second_graph = RDF.load_from_txt(first_graph_path)
+
+    os.remove(first_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tests/ScaleFree/conftest.py b/tests/ScaleFree/conftest.py
new file mode 100644
index 00000000..ae76454c
--- /dev/null
+++ b/tests/ScaleFree/conftest.py
@@ -0,0 +1,10 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[
+    (vertices_number, vertices_degree)
+    for vertices_number in range(100, 1000, 100)
+    for vertices_degree in range(3, 10)
+])
+def suit_scalefree(request):
+    return request.param
diff --git a/tests/ScaleFree/test_scalefree.py b/tests/ScaleFree/test_scalefree.py
new file mode 100644
index 00000000..6bb44055
--- /dev/null
+++ b/tests/ScaleFree/test_scalefree.py
@@ -0,0 +1,31 @@
+import os
+
+from cfpq_data import ScaleFree
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_scalefree(suit_scalefree):
+    vertices_number, vertices_degree = suit_scalefree
+    first_graph = ScaleFree.build(vertices_number, vertices_degree)
+    second_graph_path = first_graph.save('tmp')
+    second_graph = ScaleFree.load(second_graph_path)
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
+
+
+def test_txt(suit_scalefree):
+    vertices_number, vertices_degree = suit_scalefree
+    first_graph = ScaleFree.build(vertices_number, vertices_degree)
+    first_graph_path = first_graph.save('tmp1', 'txt')
+    second_graph = ScaleFree.load_from_txt(first_graph_path)
+
+    os.remove(first_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tests/SparseGraph/conftest.py b/tests/SparseGraph/conftest.py
new file mode 100644
index 00000000..bebebdd7
--- /dev/null
+++ b/tests/SparseGraph/conftest.py
@@ -0,0 +1,12 @@
+import pytest
+
+list_of_probabilities = (0.1, 0.2, 0.3, 0.4)
+
+
+@pytest.fixture(scope='session', params=[
+    (vertices_number, edge_probability)
+    for vertices_number in range(100, 600, 100)
+    for edge_probability in list_of_probabilities
+])
+def suit_sparsegraph(request):
+    return request.param
diff --git a/tests/SparseGraph/test_sparsegraph.py b/tests/SparseGraph/test_sparsegraph.py
new file mode 100644
index 00000000..3551fbbd
--- /dev/null
+++ b/tests/SparseGraph/test_sparsegraph.py
@@ -0,0 +1,31 @@
+import os
+
+from cfpq_data import SparseGraph
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_sparse(suit_sparsegraph):
+    vertices_number, edge_probability = suit_sparsegraph
+    first_graph = SparseGraph.build(vertices_number, edge_probability)
+    second_graph_path = first_graph.save('tmp')
+    second_graph = SparseGraph.load(second_graph_path)
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
+
+
+def test_txt(suit_sparsegraph):
+    vertices_number, edge_probability = suit_sparsegraph
+    first_graph = SparseGraph.build(vertices_number, edge_probability)
+    second_graph_path = first_graph.save('tmp', 'txt')
+    second_graph = SparseGraph.load_from_txt(second_graph_path)
+
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tests/WorstCase/conftest.py b/tests/WorstCase/conftest.py
new file mode 100644
index 00000000..0de4e668
--- /dev/null
+++ b/tests/WorstCase/conftest.py
@@ -0,0 +1,6 @@
+import pytest
+
+
+@pytest.fixture(scope='session', params=[vertices for vertices in range(100, 1000, 100)])
+def num_of_vertices(request):
+    return request.param
diff --git a/tests/WorstCase/test_worstcase.py b/tests/WorstCase/test_worstcase.py
new file mode 100644
index 00000000..085a44aa
--- /dev/null
+++ b/tests/WorstCase/test_worstcase.py
@@ -0,0 +1,29 @@
+import os
+
+from cfpq_data import WorstCase
+
+
+def check_metadata(first_graph, second_graph):
+    for field in ['vertices', 'edges']:
+        if first_graph.get_metadata()[field] != second_graph.get_metadata()[field]:
+            return False
+    return True
+
+
+def test_worstcase(num_of_vertices):
+    first_graph = WorstCase.build(num_of_vertices)
+    second_graph_path = first_graph.save('tmp')
+    second_graph = WorstCase.load_from_rdf(second_graph_path)
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
+
+
+def test_txt(num_of_vertices):
+    first_graph = WorstCase.build(num_of_vertices)
+    second_graph_path = first_graph.save('tmp', 'txt')
+    second_graph = WorstCase.load_from_txt(second_graph_path)
+
+    os.remove(second_graph_path)
+
+    assert check_metadata(first_graph, second_graph)
diff --git a/tools/redis-rdf/tests/test_load.py b/tools/redis-rdf/tests/test_load.py
deleted file mode 100644
index 44aaa5ac..00000000
--- a/tools/redis-rdf/tests/test_load.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import logging
-import random
-import string
-from unittest import TestCase
-
-from redis import Redis
-from redisgraph import Edge as RedisEdge
-
-from src.redis_loader.graph import Graph as RedisGraph
-from src.redis_loader.loader import load_in_redis, make_node
-from src.redis_loader.triplet_loader import load_rdf_graph
-
-
-def print_edge_with_alias(edge: RedisEdge, alias: str):
-    return f'{edge.src_node}-[{alias}: {edge.relation} {edge.toString()}]->{edge.dest_node}'
-
-
-class TestLoad(TestCase):
-    def setUp(self):
-        logging.disable(logging.WARNING)
-        self.redis_connector = Redis(host='localhost', port=6380)
-
-    def testLoadTxt(self):
-        self.loadAndCheck(load_rdf_graph('examples/graph.txt'))
-
-    def testLoadXml(self):
-        self.loadAndCheck(load_rdf_graph('examples/graph.xml'))
-
-    def loadAndCheck(self, rdf_graph):
-        redis_graph = RedisGraph(self.randomGraphName(), self.redis_connector)
-
-        # load
-        load_in_redis(rdf_graph, redis_graph)
-
-        # check every edge
-        for subj, pred, obj in rdf_graph:
-            self.assertTrue(self.checkEdgeExist(redis_graph, self.makeEdge(subj, pred, obj)))
-            self.assertTrue(self.checkEdgeExist(redis_graph, self.makeEdge(obj, f'{pred}_r', subj)))
-
-        # check total edges count
-        self.assertEqual(len(rdf_graph) * 2, self.countEdges(redis_graph))
-
-    @staticmethod
-    def makeEdge(subj, pred, obj):
-        return RedisEdge(make_node(str(subj), 'src'), pred, make_node(str(obj)), 'dst')
-
-    @staticmethod
-    def checkEdgeExist(redis_graph: RedisGraph, edge: RedisEdge):
-        query = f'MATCH {print_edge_with_alias(edge, "edge")} RETURN COUNT(edge)'
-        count = redis_graph.query(query).result_set[0][0]
-        return count > 0
-
-    @staticmethod
-    def countEdges(redis_graph: RedisGraph):
-        query = f'MATCH ()-[r]->() RETURN COUNT(r)'
-        return redis_graph.query(query).result_set[0][0]
-
-    @staticmethod
-    def randomGraphName():
-        letters = string.ascii_lowercase
-        return ''.join(random.choice(letters) for i in range(10))