Source code for medigan.select_model.model_match_candidate

# -*- coding: utf-8 -*-
# ! /usr/bin/env python
"""ModelMatchCandidate class that holds data to evaluate if a generative model matches against a search query. """

# Import python native libs
from __future__ import absolute_import

import json
import logging

# Import library internal modules
from .matched_entry import MatchedEntry


[docs]class ModelMatchCandidate: """`ModelMatchCandidate` class: A prospectively matching model given the target values as model search params. Parameters ---------- model_id: str The generative model's unique id target_values: list list of target values used to evaluate if a `ModelMatchCandidate` instance is a match target_values_operator: str the operator indicating the relationship between `values` in the evaluation of `ModelMatchCandidate` instances. Should be either "AND", "OR", or "XOR". is_case_sensitive: bool flag indicating whether the matching of `values` (and) keys should be case-sensitive are_keys_also_matched: bool flag indicating whether, apart from `values`, keys should also be matched is_match: bool flag indicating whether the `ModelMatchCandidate` instance is a match Attributes ---------- model_id: str The generative model's unique id target_values: list list of target values used to evaluate if a `ModelMatchCandidate` instance is a match target_values_operator: str the operator indicating the relationship between `values` in the evaluation of `ModelMatchCandidate` instances. Should be either "AND", "OR", or "XOR". is_case_sensitive: bool flag indicating whether the matching of `values` (and) keys should be case-sensitive are_keys_also_matched: bool flag indicating whether, apart from values, keys should also be matched matched_entries: list contains iteratively added `MatchedEntry` class instances. Each of the `MatchedEntry` instances indicates a match between one of the user specified values in `self.target_values` and the selection config keys or `values` of the model of this `ModelMatchCandidate`. is_match: bool flag indicating whether the `ModelMatchCandidate` instance is a match """ def __init__( self, model_id: str, target_values: list, target_values_operator: str = "AND", is_case_sensitive: bool = False, are_keys_also_matched: bool = False, is_match: bool = False, ): # Descriptive variables self.model_id = model_id self.target_values = target_values self.target_values_operator = target_values_operator self.is_case_sensitive = is_case_sensitive self.are_keys_also_matched = are_keys_also_matched # Dynamically filled/changed variables self.matched_entries = [] self.is_match = is_match
[docs] def add_matched_entry(self, matched_entry: MatchedEntry) -> None: """Add a `MatchedEntry` instance to the `matched_entries` list.""" self.matched_entries.append(matched_entry)
[docs] def get_all_matching_elements(self) -> list: """Get the matching element from each of the `MatchedEntry` instances in the `matched_entries` list. Returns ------- list list of all matching elements (i.e. string that matched a search value) from each `MatchedEntry` in `matched_entries` """ matching_elements = [] for matched_entry in self.matched_entries: matching_elements.append(matched_entry.matching_element) return matching_elements
[docs] def check_if_is_match(self) -> bool: """Evaluates whether the model represented by this instance is a match given search values and operator. The matching element from each `MatchEntry` of this instance ('self.matched_entries') are retrieved. To be a match, this instance ('self') needs to fulfill the requirement of the operator, which can be of value 'AND', or 'OR', or 'XOR'. For example, the default 'AND' requires that each search value ('self.target_values') has at least one corresponding `MatchEntry`, while in 'OR' only one of the search values needs to have been matched by a corresponding `MatchedEntry`. Returns ------- bool flag that, only if True, indicates that this instance is a match given the search values and operator. """ if self is not None and len(self) > 0: if self.target_values_operator == "OR": self.is_match = True elif self.target_values_operator == "AND": # removing duplicates via set conversion found_target_values = set(self.get_all_matching_elements()) if all(elem in found_target_values for elem in self.target_values): logging.debug( f"values: {self.target_values} AND found_target_values_list: {found_target_values}" ) self.is_match = True elif self.target_values_operator == "XOR": # removing duplicates via set conversion if ( len( list( set(self.get_all_matching_elements()).intersection( self.target_values ) ) ) == 1 ): self.is_match = True logging.debug(f"This ModelMatchCandidate was found to be a match: ({self}).") return self.is_match
def __str__(self): matched_entry_dicts = { f"{idx}": json.loads(str(match)) for idx, match in enumerate(self.matched_entries) } return json.dumps( { "model_id": self.model_id, "is_match": self.is_match, "target_values": self.target_values, "operator": self.target_values_operator, "are_keys_also_matched": self.are_keys_also_matched, "is_case_sensitive": self.is_case_sensitive, "matched_entries": matched_entry_dicts, } ) def __repr__(self): return f"ModelMatchCandidate(model_id={self.model_id}, is_match={self.is_match}, operator: {self.target_values_operator}, target_values={self.target_values})" def __len__(self): return len(self.matched_entries) def __getitem__(self, idx: int): return self.matched_entries[idx]