AnaHiePro is a module that allows solving various tasks of systems analysis using the Analytic Hierarchy Process (AHP).
AnaHiePro is a Python module designed to simplify the decision-making process by using the Analytic Hierarchy Process (AHP) method. This method allows you to structure complex problems in the form of a hierarchical model consisting of goals, criteria, and alternatives. AnaHiePro automatically calculates global priorities for the entire hierarchy.
The module provides a recursive traversal of the hierarchical tree, starting from the leaf nodes and moving up to the root. Each level of the hierarchy is processed by multiplying the matrix of local child vectors by the global parent vector, which allows you to determine the weight of each element at all levels. This makes AnaHiePro an ideal tool for analyzing complex systems and making informed decisions in a variety of fields, including business, project management, scientific research, and more.
Open the terminal window and write the following command:
pip install anahiepro
After loading you can use all AnaHiePro's functionality, down below you can see the simplest way of using AnaHiePro.
from anahiepro.nodes import Problem, Criteria, Alternative
from anahiepro.models.model import Model
problem = Problem("Example Problem")
list_of_criterias = [
Criteria("Citeria_1"),
Criteria("Citeria_2"),
Criteria("Citeria_3")
]
alternatives = [
Alternative("Alternative_1"),
Alternative("Alternative_2")
]
model = Model(problem, list_of_criterias, alternatives)
print(model.show())
PairwiseComparisonMatrix
represents the pairwise comparison matrix. A pairwise comparison matrix is a tool used in decision-making processes. It helps compare different options or criteria by evaluating them in pairs. Each element of the matrix represents the comparison result between two options or criteria.
Method Name | Description |
---|---|
__init__(self, size, matrix) |
Initialize a pairwise comparison matrix with the given size or given matrix. |
set_comparison(self, i, j, value) |
Set the comparison value for the given indices. Might raise the ValueError exception when you try to set diagonal values to value, that not equal 1 . |
set_matrix(self, matrix) |
Set the entire matrix, ensuring it is a valid pairwise comparison matrix. Might raise the ValueError if the matrix is not consistent or not valid. |
get_matrix(self) |
Returns the current pairwise comparison matrix. |
calculate_priority_vector(self) |
Calculate the priority vector from the pairwise comparison matrix. |
calculate_consistency_ratio(self) |
Calculate the consistency ratio of the pairwise comparison matrix. |
__getitem__(self, key) |
Returns the value at the specified index in the matrix. |
__setitem__(self, key, value) |
Set the value at the specified index in the matrix. |
from anahiepro.pairwise import PairwiseComparisonMatrix
matrix = [
[1, 2, 3],
[1/2, 1, 2],
[1/3, 1/2, 1]
]
pairwise_matrix = PairwiseComparisonMatrix(matrix=matrix)
print(pairwise_matrix.get_matrix())
print("Consistency ratio:", pairwise_matrix.calculate_consistency_ratio())
print("Priority vector:", pairwise_matrix.calculate_priority_vector())
Output:
[[1. 2. 3. ]
[0.5 1. 2. ]
[0.33333333 0.5 1. ]]
Consistency ratio: 0.007933373029552656
Priority vector: [0.84679693 0.46601031 0.25645536]
AnaHiePro has three types of nodes: Problem, Criteria (also DummyCriteria, which use for normalizing a model) and Alternative. All of them is inherited from abstract class Node
.
NOTE: And we want to mentioned that each class which is inhereted from
Node
has an id field.
As we mentioned before Node
is a basic class for Problem
, Criteria
and Alternative
. Down below you can see all Node
's methods:
Method Name | Description |
---|---|
__init__(self, name, parents, children, id, pcm) |
Initialize the Node object with given name , list of its parents , list of its children , identifier (id ) and pcm. |
get_name(self) |
Returns the name of the node. |
get_parents(self) |
Returns list of parents for the node. |
get_children(self) |
Returns list of childrens for the node. |
get_key(self) |
Returns the tuple object, which consists of name of a node and its id. |
add_child(self, child) |
Add child to the list of children. |
show(self) |
Returns str object which represent all relations between nodes. |
compare(self, key: tuple) |
Compare the node with a given key, where key is a tuple object which has size that equal 2. key[0] is a name of node and key[1] is an identifier of the node. |
create_pcm(self) |
Create a pairwise comparison matrix (PCM) object for the node which shape is equal number of node's childrens. |
set_matrix(self, matrix) |
Attach given PCM to the node. If the self.pcm does not exist call the create_pcm method than checks if the shape of given matrix matchs, raise VlalueError if does not otherwise attach it. |
set_comparison(self, i, j, value) |
Set given value to the right place. Other words it is a wrapper above the PairwiseComparisonMatrix 's set_comparison method. |
get_priority_vector(self) |
Wrapper above PairwiseComparisonMatrix's get_priority_vector` method. |
get_consistency_ratio(self) |
Wrapper above PairwiseComparisonMatrix's get_consistency_ratio` method. |
get_pcm(self) |
Returns the pairwise comparison matrix of the node. |
__eq__(self, value) |
Compare two Node 's instance. |
def show(self) |
Show the node and its children in a hierarchical structure. |
__copy__(self) |
Copy the node. |
Problem
is a class that represents the ptoblem, which user want to solve. This class inherits form Node
and has the same methods as his parrent, except of this it overrides some methods.
Method Name | Description |
---|---|
__init__(self, name, children, pcm) |
Initialize the Problem object with given name , list of its childern and pairwise comparison matrix. |
Rest methods are the same as in Node
class.
Criteria
represents the criteria which will be used for selection. This class inherits form Node
and has the same methods as his parrent, except of this it overrides some methods.
Method Name | Description |
---|---|
__init__(self, name, children, pcm) |
Initialize the Criteria object with given name , list of its childern and pairwise comparison matrix. |
Rest methods are the same as in Node
class.
DummyCriteria
class that inherited from Criteria
it is used for normalizing problem in VaryDepthModel
.
Alternative
represents alternatives between which the selection is happened. Scince Alternative
is the final node in hierarchy it have not children, so that the self.pcm
field for it is deleted.
Method Name | Description |
---|---|
__init__(self, name) |
Initialize the Alternative object with given name . |
create_pcm(self) |
Does not implemented for reasons which were mentioned. |
set_matrix(self, matrix) |
Does not implemented and raise NotImplementedError exception. |
`set_comparison(self, i, j, value) | Does not implemented and raise NotImplementedError exception. |
Rest methods are the same as in Node
class.
from anahiepro.nodes import Problem, Criteria, Alternative
# Create instance of each classes.
problem = Problem("Example Problem")
criteria1 = Criteria("Criteria_1")
criteria2 = Criteria("Criteria_2")
alternative1 = Alternative("Alternative_1")
alternative2 = Alternative("Alternative_2")
# Lincing each instances.
problem.add_child(criteria1)
problem.add_child(criteria2)
criteria1.add_child(alternative1)
criteria1.add_child(alternative2)
criteria2.add_child(alternative1)
criteria2.add_child(alternative2)
# Print the problem hierarchy.
print(problem.show())
Output:
+Example Problem
+--Criteria_1
+----Alternative_1
+----Alternative_2
+--Criteria_2
+----Alternative_1
+----Alternative_2
AnaHiePro has two types of models that you can use for automatic solve setted problem - Model
and VaryDepthModel
.
This two classes are called for solve different types of problem. To be honest VaryDepthModel
is used for problems with different depth such as at the image down below.
At that time the Model
can solve problems which have hierarchy with the same depth of each children for them (look at the next picture).
Each model classes, which AnaHiePro has, have the methods which is described down below.
Method Name | Description |
---|---|
__init__(self, problem: Problem, criterias, alternatives: list) |
Initialize the model with a problem, criteria, and alternatives. Also checks if the criterias has correct format, type and for Model - if the depth of the criterias hierarchy is the same depth. |
get_problem(self) |
Return the problem instance. |
get_alternatives(self) |
Return the list of alternatives. |
get_criterias_name_ids(self) |
Get the names and IDs of the criteria. |
find_criteria(self, key: tuple) |
Find criteria by (name, id) tuple. |
attach_criteria_pcm(self, key: tuple, pcm) |
Attach a pairwise comparison matrix to the criteria identified by the key. |
__getitem__(self, key: tuple) |
Get the criteria identified by the key. |
solve(self, showAlternatives=False) |
Solve the model to calculate the global priority vector. |
show(self) |
Display the problem. |
Model
and VaryDepthModel
can take the next format of the criterias in their __init__
method:
criterias = [Criteria(children=[Criteria()]),
Criteria(children=[Criteria()]),
Criteria(children=[Criteria()])]
or
criterias = [
{Criteria(): [
{Criteria(): None}
]},
{Criteria(): [
{Criteria(): None}
]},
{Criteria(): [
{Criteria(): None}
]}
]
Another formats of the criterias
param is not added (except of empty list).
Here you can see the simplest way how to create Model
instance:
from anahiepro.nodes import Problem, Criteria, Alternative
from anahiepro.models.model import Model
problem = Problem("Example Problem")
list_of_criterias = [
Criteria("Citeria_1", children=[
Criteria("Criteria_4")
]),
Criteria("Citeria_2", children=[
Criteria("Criteria_5")
]),
Criteria("Citeria_3", children=[
Criteria("Criteria_5")
]),
]
alternatives = [
Alternative("Alternative_1"),
Alternative("Alternative_2")
]
model = Model(problem, list_of_criterias, alternatives)
print(model.show())
Output:
+Example Problem
+--Citeria_1
+----Criteria_4
+------Alternative_1
+------Alternative_2
+--Citeria_2
+----Criteria_5
+------Alternative_1
+------Alternative_2
+--Citeria_3
+----Criteria_5
+------Alternative_1
+------Alternative_2
Now let's see how it works for VaryDepthModel
:
from anahiepro.nodes import Problem, Criteria, Alternative
from anahiepro.models.vary_depth_model import VaryDepthModel
problem = Problem("Example Problem")
list_of_criterias = [
Criteria("Citeria_1", children=[
Criteria("Criteria_4")
]),
Criteria("Citeria_2", children=[
Criteria("Criteria_5")
]),
Criteria("Citeria_3"), # <- Here Criteria_3 does not have children.
]
alternatives = [
Alternative("Alternative_1"),
Alternative("Alternative_2")
]
model = VaryDepthModel(problem, list_of_criterias, alternatives)
print(model.show())
Output:
+Example Problem
+--Citeria_1
+----Criteria_4
+------Alternative_1
+------Alternative_2
+--Citeria_2
+----Criteria_5
+------Alternative_1
+------Alternative_2
+--DummyCriteria0
+----Citeria_3
+------Alternative_1
+------Alternative_2
So, as you can see from the out put VaryDepthModel
normalize the hierarchy of problem. And, yes, you can use VaryDepthModel
with the example for Model
class.
from anahiepro.nodes import Problem, Criteria, Alternative
from anahiepro.models.model import Model
problem = Problem("Example Problem", pcm=[[1, 2, 1/2],
[1/2, 1, 1/7],
[2, 7, 1]])
list_of_criterias = [
Criteria("Citeria_1", pcm=[[1, 2, 4],
[1/2, 1, 3],
[1/4, 1/3, 1]]),
Criteria("Citeria_2", pcm=[[1, 2, 1/5],
[1/2, 1, 3],
[5, 1/3, 1]]),
Criteria("Citeria_3", pcm=[[1, 1/3, 3],
[3, 1, 3],
[1/3, 1/3, 1]]),
]
alternatives = [
Alternative("Alternative_1"),
Alternative("Alternative_2"),
Alternative("Alternative_3")
]
model = Model(problem, list_of_criterias, alternatives)
print("Global vector without alternatives:")
print(model.solve())
print("Global vector with alternatives:")
print(model.solve(showAlternatives=True))
Output:
Global vector without alternatives:
[0.64557092 0.88998852 0.15336415]
Global vector with alternatives:
[(Alternative_1, np.float64(0.6455709201621959)), (Alternative_2, np.float64(0.8899885172373624)), (Alternative_3, np.float64(0.15336414859759606))]
- @danylevych - Idea & Initial work