Module trustML.assessment_methods.bayesiannetwork

Expand source code
import requests
from trustML.assessment_methods.assessmentmethod import AssessmentMethod
from json import dumps

class BayesianNetwork(AssessmentMethod):
    """Class that implements the trust assessment using a Bayesian network in DNE format,
    by using a BN model previously crafted and provided in the filepath specified in the
    configuration file. It requires to have the trust metrics already computed in the trust object.

    It also requires an active and listening server with the SSI-Assessment API-library 
    deployed (https://github.com/martimanzano/SSI-assessment). Its endpoint shall be 
    specified in the configuration file.
    """

    def __init__(self, additional_properties):
        """Retrieves the set of parameters required to perform the assessment through a BN
        (including the BN filepath and discretization intervals) from the additional properties
        retrieved from the configuration file and prepares the instance's attributes to perform
        the trustworthiness assessment using the SSI assessment library.

        Args:
            additional_properties (dict): [dictionary of parameters required by the assessment method,
            i.e., the BN's filepath, endpoint of the assessment service, 
            the BN node corresponding to the trustworthiness, and the discretization intervals to use]
        
        Raises:
            Exception: When assessed metrics and BN's binning intervals are not consistent
        """

        super().__init__()

        self.BN_path = additional_properties['bn_path']
        self.API_assessment_service = additional_properties['api_url']
        self.id_trust_node = additional_properties['id_trust_node']

        self.input_nodes = additional_properties['intervals_input_nodes']        
       
    def assess(self):
        """Calls the BN assessment service synchrounously to assess the BN node with name equal to the 
        "id_trust_node" attribute. Returns the result as a JSON formatted string containing the node's 
        probabilitiies.
        """

        input_names = [k for d in self.input_nodes for k in d.keys()]
        intervals_input_nodes = [k for d in self.input_nodes for k in d.values()]

        if not self.compare_config_assesssed_metrics_inputs(input_names):
            raise Exception("Validation error in config file: assessed metrics and BN's input binning intervals mismatch")

        input_values = []
        for input_name in input_names:
            input_values.append(self.trust.get_metrics_assessment_dict()[input_name])
                   
        api_response = requests.post(url=self.API_assessment_service, 
        json={'id_si': self.id_trust_node, 'input_names': input_names,'input_values': input_values, 'intervals_input_nodes': intervals_input_nodes, 'bn_path': self.BN_path})
        
        assessment_dict = api_response.json() 
        assessment_JSON = dumps(assessment_dict)

        return assessment_dict, assessment_JSON

    def compare_config_assesssed_metrics_inputs(self, inputNames):
        """Helper function to validate the binning intervals from the configuration dict.

        Returns:
            Boolean: True if binning intervals are consistent with the assessed metrics, False otherwise
        """
        assessed_metrics_list = [metric.__class__.__name__ for metric in self.trust.metrics]
    
        if set(inputNames).issubset(set(assessed_metrics_list)):
            return True
        return False
    
    def generate_trust_PDF(self, save_path):
        """Generates a PDF containing the graphical representation of the trustworthiness assessment
        with drill-down to the assessed metrics.

        First traverses the JSON assessment to collect all the data to be plotted in the lists
        "states_names", "element_names" and "probabilities". Then it iterates through every element
        and generates a PDF page with a stacked bar chart.

        Args:
            save_path (str): filepath to the PDF to generate
        """
        import matplotlib.pyplot as plt
        import numpy as np
        from matplotlib.backends.backend_pdf import PdfPages

        state_names = []
        element_names = []
        probabilities = []
        
        def traverse_hierarchy(element):
            # Extract metric name
            element_name = element['siname']
            element_names.append(element_name)

            # Extract states and probabilities
            states = []
            probs = []
            for state_prob in element['probsSICategories']:
                state = state_prob['idSICategory']
                probability = state_prob['probSICategory']
                states.append(state)
                probs.append(probability)

            state_names.append(states)
            probabilities.append(probs)
            
            # Traverse the "parentNodes" list recursively
            if 'parentNodes' in element:
                for parent in element['parentNodes']:
                    traverse_hierarchy(parent)

        # Start recursive traversal from the top-level element
        data = self.trust.trust_dict
        traverse_hierarchy(data)

        # Set up the plot
        # Plot each element in a separate plot
        with PdfPages(save_path) as pdf:
            for i, element_name in enumerate(element_names):
                fig, ax = plt.subplots(figsize=(2, 5))

                # Set up the plot
                num_states = len(state_names[i])
                ind = np.arange(1)
                width = 0.2

                # Plot the stacked bar
                bottom = 0
                for j in range(num_states):
                    prob = probabilities[i][j]
                    ax.bar(ind, prob, width, bottom=bottom, label=state_names[i][j])
                    bottom += prob

                # Customize the plot
                fig.suptitle('Trustworthiness assessment - Bayesian Network', fontsize=16)

                ax.set_ylabel('Probability')
                ax.set_title("Element: " + element_name)
                ax.set_xticks([])
                ax.legend(title='States', bbox_to_anchor=(1.05, 1))

                # to switch off the horizontal axis
                frame1 = fig.gca()
                frame1.axes.get_xaxis().set_visible(False)

                pdf.savefig(fig, bbox_inches='tight')

Classes

class BayesianNetwork (additional_properties)

Class that implements the trust assessment using a Bayesian network in DNE format, by using a BN model previously crafted and provided in the filepath specified in the configuration file. It requires to have the trust metrics already computed in the trust object.

It also requires an active and listening server with the SSI-Assessment API-library deployed (https://github.com/martimanzano/SSI-assessment). Its endpoint shall be specified in the configuration file.

Retrieves the set of parameters required to perform the assessment through a BN (including the BN filepath and discretization intervals) from the additional properties retrieved from the configuration file and prepares the instance's attributes to perform the trustworthiness assessment using the SSI assessment library.

Args

additional_properties : dict
[dictionary of parameters required by the assessment method,

i.e., the BN's filepath, endpoint of the assessment service, the BN node corresponding to the trustworthiness, and the discretization intervals to use]

Raises

Exception
When assessed metrics and BN's binning intervals are not consistent
Expand source code
class BayesianNetwork(AssessmentMethod):
    """Class that implements the trust assessment using a Bayesian network in DNE format,
    by using a BN model previously crafted and provided in the filepath specified in the
    configuration file. It requires to have the trust metrics already computed in the trust object.

    It also requires an active and listening server with the SSI-Assessment API-library 
    deployed (https://github.com/martimanzano/SSI-assessment). Its endpoint shall be 
    specified in the configuration file.
    """

    def __init__(self, additional_properties):
        """Retrieves the set of parameters required to perform the assessment through a BN
        (including the BN filepath and discretization intervals) from the additional properties
        retrieved from the configuration file and prepares the instance's attributes to perform
        the trustworthiness assessment using the SSI assessment library.

        Args:
            additional_properties (dict): [dictionary of parameters required by the assessment method,
            i.e., the BN's filepath, endpoint of the assessment service, 
            the BN node corresponding to the trustworthiness, and the discretization intervals to use]
        
        Raises:
            Exception: When assessed metrics and BN's binning intervals are not consistent
        """

        super().__init__()

        self.BN_path = additional_properties['bn_path']
        self.API_assessment_service = additional_properties['api_url']
        self.id_trust_node = additional_properties['id_trust_node']

        self.input_nodes = additional_properties['intervals_input_nodes']        
       
    def assess(self):
        """Calls the BN assessment service synchrounously to assess the BN node with name equal to the 
        "id_trust_node" attribute. Returns the result as a JSON formatted string containing the node's 
        probabilitiies.
        """

        input_names = [k for d in self.input_nodes for k in d.keys()]
        intervals_input_nodes = [k for d in self.input_nodes for k in d.values()]

        if not self.compare_config_assesssed_metrics_inputs(input_names):
            raise Exception("Validation error in config file: assessed metrics and BN's input binning intervals mismatch")

        input_values = []
        for input_name in input_names:
            input_values.append(self.trust.get_metrics_assessment_dict()[input_name])
                   
        api_response = requests.post(url=self.API_assessment_service, 
        json={'id_si': self.id_trust_node, 'input_names': input_names,'input_values': input_values, 'intervals_input_nodes': intervals_input_nodes, 'bn_path': self.BN_path})
        
        assessment_dict = api_response.json() 
        assessment_JSON = dumps(assessment_dict)

        return assessment_dict, assessment_JSON

    def compare_config_assesssed_metrics_inputs(self, inputNames):
        """Helper function to validate the binning intervals from the configuration dict.

        Returns:
            Boolean: True if binning intervals are consistent with the assessed metrics, False otherwise
        """
        assessed_metrics_list = [metric.__class__.__name__ for metric in self.trust.metrics]
    
        if set(inputNames).issubset(set(assessed_metrics_list)):
            return True
        return False
    
    def generate_trust_PDF(self, save_path):
        """Generates a PDF containing the graphical representation of the trustworthiness assessment
        with drill-down to the assessed metrics.

        First traverses the JSON assessment to collect all the data to be plotted in the lists
        "states_names", "element_names" and "probabilities". Then it iterates through every element
        and generates a PDF page with a stacked bar chart.

        Args:
            save_path (str): filepath to the PDF to generate
        """
        import matplotlib.pyplot as plt
        import numpy as np
        from matplotlib.backends.backend_pdf import PdfPages

        state_names = []
        element_names = []
        probabilities = []
        
        def traverse_hierarchy(element):
            # Extract metric name
            element_name = element['siname']
            element_names.append(element_name)

            # Extract states and probabilities
            states = []
            probs = []
            for state_prob in element['probsSICategories']:
                state = state_prob['idSICategory']
                probability = state_prob['probSICategory']
                states.append(state)
                probs.append(probability)

            state_names.append(states)
            probabilities.append(probs)
            
            # Traverse the "parentNodes" list recursively
            if 'parentNodes' in element:
                for parent in element['parentNodes']:
                    traverse_hierarchy(parent)

        # Start recursive traversal from the top-level element
        data = self.trust.trust_dict
        traverse_hierarchy(data)

        # Set up the plot
        # Plot each element in a separate plot
        with PdfPages(save_path) as pdf:
            for i, element_name in enumerate(element_names):
                fig, ax = plt.subplots(figsize=(2, 5))

                # Set up the plot
                num_states = len(state_names[i])
                ind = np.arange(1)
                width = 0.2

                # Plot the stacked bar
                bottom = 0
                for j in range(num_states):
                    prob = probabilities[i][j]
                    ax.bar(ind, prob, width, bottom=bottom, label=state_names[i][j])
                    bottom += prob

                # Customize the plot
                fig.suptitle('Trustworthiness assessment - Bayesian Network', fontsize=16)

                ax.set_ylabel('Probability')
                ax.set_title("Element: " + element_name)
                ax.set_xticks([])
                ax.legend(title='States', bbox_to_anchor=(1.05, 1))

                # to switch off the horizontal axis
                frame1 = fig.gca()
                frame1.axes.get_xaxis().set_visible(False)

                pdf.savefig(fig, bbox_inches='tight')

Ancestors

Methods

def assess(self)

Calls the BN assessment service synchrounously to assess the BN node with name equal to the "id_trust_node" attribute. Returns the result as a JSON formatted string containing the node's probabilitiies.

Expand source code
def assess(self):
    """Calls the BN assessment service synchrounously to assess the BN node with name equal to the 
    "id_trust_node" attribute. Returns the result as a JSON formatted string containing the node's 
    probabilitiies.
    """

    input_names = [k for d in self.input_nodes for k in d.keys()]
    intervals_input_nodes = [k for d in self.input_nodes for k in d.values()]

    if not self.compare_config_assesssed_metrics_inputs(input_names):
        raise Exception("Validation error in config file: assessed metrics and BN's input binning intervals mismatch")

    input_values = []
    for input_name in input_names:
        input_values.append(self.trust.get_metrics_assessment_dict()[input_name])
               
    api_response = requests.post(url=self.API_assessment_service, 
    json={'id_si': self.id_trust_node, 'input_names': input_names,'input_values': input_values, 'intervals_input_nodes': intervals_input_nodes, 'bn_path': self.BN_path})
    
    assessment_dict = api_response.json() 
    assessment_JSON = dumps(assessment_dict)

    return assessment_dict, assessment_JSON
def compare_config_assesssed_metrics_inputs(self, inputNames)

Helper function to validate the binning intervals from the configuration dict.

Returns

Boolean
True if binning intervals are consistent with the assessed metrics, False otherwise
Expand source code
def compare_config_assesssed_metrics_inputs(self, inputNames):
    """Helper function to validate the binning intervals from the configuration dict.

    Returns:
        Boolean: True if binning intervals are consistent with the assessed metrics, False otherwise
    """
    assessed_metrics_list = [metric.__class__.__name__ for metric in self.trust.metrics]

    if set(inputNames).issubset(set(assessed_metrics_list)):
        return True
    return False
def generate_trust_PDF(self, save_path)

Generates a PDF containing the graphical representation of the trustworthiness assessment with drill-down to the assessed metrics.

First traverses the JSON assessment to collect all the data to be plotted in the lists "states_names", "element_names" and "probabilities". Then it iterates through every element and generates a PDF page with a stacked bar chart.

Args

save_path : str
filepath to the PDF to generate
Expand source code
def generate_trust_PDF(self, save_path):
    """Generates a PDF containing the graphical representation of the trustworthiness assessment
    with drill-down to the assessed metrics.

    First traverses the JSON assessment to collect all the data to be plotted in the lists
    "states_names", "element_names" and "probabilities". Then it iterates through every element
    and generates a PDF page with a stacked bar chart.

    Args:
        save_path (str): filepath to the PDF to generate
    """
    import matplotlib.pyplot as plt
    import numpy as np
    from matplotlib.backends.backend_pdf import PdfPages

    state_names = []
    element_names = []
    probabilities = []
    
    def traverse_hierarchy(element):
        # Extract metric name
        element_name = element['siname']
        element_names.append(element_name)

        # Extract states and probabilities
        states = []
        probs = []
        for state_prob in element['probsSICategories']:
            state = state_prob['idSICategory']
            probability = state_prob['probSICategory']
            states.append(state)
            probs.append(probability)

        state_names.append(states)
        probabilities.append(probs)
        
        # Traverse the "parentNodes" list recursively
        if 'parentNodes' in element:
            for parent in element['parentNodes']:
                traverse_hierarchy(parent)

    # Start recursive traversal from the top-level element
    data = self.trust.trust_dict
    traverse_hierarchy(data)

    # Set up the plot
    # Plot each element in a separate plot
    with PdfPages(save_path) as pdf:
        for i, element_name in enumerate(element_names):
            fig, ax = plt.subplots(figsize=(2, 5))

            # Set up the plot
            num_states = len(state_names[i])
            ind = np.arange(1)
            width = 0.2

            # Plot the stacked bar
            bottom = 0
            for j in range(num_states):
                prob = probabilities[i][j]
                ax.bar(ind, prob, width, bottom=bottom, label=state_names[i][j])
                bottom += prob

            # Customize the plot
            fig.suptitle('Trustworthiness assessment - Bayesian Network', fontsize=16)

            ax.set_ylabel('Probability')
            ax.set_title("Element: " + element_name)
            ax.set_xticks([])
            ax.legend(title='States', bbox_to_anchor=(1.05, 1))

            # to switch off the horizontal axis
            frame1 = fig.gca()
            frame1.axes.get_xaxis().set_visible(False)

            pdf.savefig(fig, bbox_inches='tight')