def test_get_config(self) -> None:
        self.assertEqual(MemoryDescriptorSet().get_config(),
                         MemoryDescriptorSet.get_default_config())

        self.assertEqual(
            MemoryDescriptorSet(None).get_config(),
            MemoryDescriptorSet.get_default_config())

        empty_elem = DataMemoryElement()
        dme_key = 'smqtk_dataprovider.impls.data_element.memory.DataMemoryElement'
        self.assertEqual(
            MemoryDescriptorSet(empty_elem).get_config(),
            merge_dict(MemoryDescriptorSet.get_default_config(),
                       {'cache_element': {
                           'type': dme_key
                       }}))

        dict_pickle_bytes = pickle.dumps({1: 1, 2: 2, 3: 3}, -1)
        dict_pickle_bytes_str = dict_pickle_bytes.decode(BYTES_CONFIG_ENCODING)
        cache_elem = DataMemoryElement(bytes=dict_pickle_bytes)
        self.assertEqual(
            MemoryDescriptorSet(cache_elem).get_config(),
            merge_dict(
                MemoryDescriptorSet.get_default_config(), {
                    'cache_element': {
                        dme_key: {
                            'bytes': dict_pickle_bytes_str
                        },
                        'type': dme_key
                    }
                }))
    def from_config(  # type: ignore
            cls: Type[T],
            config_dict: Dict,
            type_str: str,
            uuid: Hashable,
            merge_default: bool = True) -> T:
        """
        Instantiate a new instance of this class given the desired type, uuid,
        and JSON-compliant configuration dictionary.

        :param type_str: Type of descriptor. This is usually the name of the
            content descriptor that generated this vector.
        :param uuid: Unique ID reference of the descriptor.
        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.

        :return: Constructed instance from the provided config.
        """
        c: Dict[str, Any] = {}
        merge_dict(c, config_dict)
        c['type_str'] = type_str
        c['uuid'] = uuid
        return super(DescriptorElement, cls).from_config(c, merge_default)
Exemple #3
0
 def get_config(self) -> Dict[str, Any]:
     c = merge_dict(self.get_default_config(), {
         "pickle_protocol": self.pickle_protocol,
     })
     if self.cache_element:
         merge_dict(c['cache_element'],
                    to_config_dict(self.cache_element))
     return c
 def get_config(self) -> Dict[str, Any]:
     c = merge_dict(self.get_default_config(), {
         'leaf_size': self.leaf_size,
         'random_seed': self.random_seed,
     })
     if self.cache_element:
         c['cache_element'] = merge_dict(c['cache_element'],
                                         to_config_dict(self.cache_element))
     return c
Exemple #5
0
    def from_config(
        cls: Type[T_LSH],
        config_dict: Dict,
        merge_default: bool = True
    ) -> T_LSH:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless and instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :type config_dict: dict

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.
        :type merge_default: bool

        :return: Constructed instance from the provided config.
        :rtype: LSHNearestNeighborIndex

        """
        # Controlling merge here so we can control known comment stripping from
        # default config.
        if merge_default:
            merged = cls.get_default_config()
            merge_dict(merged, config_dict)
        else:
            merged = config_dict

        merged['lsh_functor'] = \
            from_config_dict(merged['lsh_functor'], LshFunctor.get_impls())
        merged['descriptor_set'] = \
            from_config_dict(merged['descriptor_set'],
                             DescriptorSet.get_impls())

        # Hash index may be None for a default at-query-time linear indexing
        if merged['hash_index'] and merged['hash_index']['type']:
            merged['hash_index'] = \
                from_config_dict(merged['hash_index'],
                                 HashIndex.get_impls())
        else:
            LOG.debug("No HashIndex impl given. Passing ``None``.")
            merged['hash_index'] = None

        # remove possible comment added by default generator
        if 'hash_index_comment' in merged:
            del merged['hash_index_comment']

        merged['hash2uuids_kvstore'] = \
            from_config_dict(merged['hash2uuids_kvstore'],
                             KeyValueStore.get_impls())

        return super(LSHNearestNeighborIndex, cls).from_config(merged, False)
Exemple #6
0
 def test_subset_merge(self) -> None:
     """ Test that `b` updates key `a` in dict `a`. """
     a = {
         'a': 1,
         'b': 2,
     }
     b = {'a': 3}
     expected = {
         'a': 3,
         'b': 2,
     }
     merge_dict(a, b)
     self.assertEqual(a, expected)
Exemple #7
0
    def test_merge_dict_shallow(self) -> None:
        # basic dict merger
        merge_dict(self.a, self.b)
        self.assertEqual(self.a, self.expected)

        # set values that are mutable structures should be the same instances as
        # what's in ``b``.
        self.assertEqual(self.a['nested']['l'], self.b['nested']['l'])
        self.assertIs(self.a['nested']['l'], self.b['nested']['l'])

        self.assertEqual(self.a['nested']['even_deeper']['j'],
                         self.b['nested']['even_deeper']['j'])
        self.assertIs(self.a['nested']['even_deeper']['j'],
                      self.b['nested']['even_deeper']['j'])
Exemple #8
0
    def test_merge_dict_deepcopy(self) -> None:
        # dict merger with deepcopy
        merge_dict(self.a, self.b, deep_copy=True)
        self.assertEqual(self.a, self.expected)

        # set values that are mutable structures should be the same instances as
        # what's in ``b``.
        self.assertEqual(self.a['nested']['l'], self.b['nested']['l'])
        self.assertIsNot(self.a['nested']['l'], self.b['nested']['l'])

        self.assertEqual(self.a['nested']['even_deeper']['j'],
                         self.b['nested']['even_deeper']['j'])
        self.assertIsNot(self.a['nested']['even_deeper']['j'],
                         self.b['nested']['even_deeper']['j'])
Exemple #9
0
 def test_disjoint_update(self) -> None:
     """ Test that ``'c': 3`` gets added to `a`. """
     a = {
         'a': 1,
         'b': 2,
     }
     b = {'c': 3}
     expected = {
         'a': 1,
         'b': 2,
         'c': 3,
     }
     merge_dict(a, b)
     self.assertEqual(a, expected)
Exemple #10
0
    def from_config(cls: Type[T],
                    config_dict: Dict,
                    merge_default: bool = True) -> T:
        if merge_default:
            cfg = cls.get_default_config()
            merge_dict(cfg, config_dict)
        else:
            cfg = config_dict

        cfg['descriptor_set'] = \
            from_config_dict(cfg['descriptor_set'],
                             DescriptorSet.get_impls())

        return super(MRPTNearestNeighborsIndex, cls).from_config(cfg, False)
Exemple #11
0
    def get_config(self) -> Dict[str, Any]:
        """
        This implementation has no configuration properties.

        :return: JSON type compliant configuration dictionary.
        :rtype: dict

        """
        c = merge_dict(self.get_default_config(), {
            "pickle_protocol": self.pickle_protocol,
        })
        if self.cache_element:
            c['cache_element'] = merge_dict(c['cache_element'],
                                            to_config_dict(self.cache_element))
        return c
Exemple #12
0
    def from_config(cls: Type[T],
                    config_dict: Dict,
                    merge_default: bool = True) -> T:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :type config_dict: dict

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.
        :type merge_default: bool

        :return: Constructed instance from the provided config.
        :rtype: KVSDataSet
        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        # Convert KVStore config to instance for constructor.
        kvs_inst = from_config_dict(config_dict['kvstore'],
                                    KeyValueStore.get_impls())
        config_dict['kvstore'] = kvs_inst

        return super(KVSDataSet, cls).from_config(config_dict, False)
Exemple #13
0
    def from_config(cls: Type[T_IF],
                    config_dict: Dict,
                    merge_default: bool = True) -> T_IF:
        """
        Instantiate a new instance of this class given the JSON-compliant
        configuration dictionary encapsulating initialization arguments.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.

        :return: Constructed instance from the provided config.

        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        data_element_impls = DataElement.get_impls()
        # Mean vector cache element.
        mean_vec_cache = None
        if config_dict['mean_vec_cache'] and \
                config_dict['mean_vec_cache']['type']:
            mean_vec_cache = from_config_dict(config_dict['mean_vec_cache'],
                                              data_element_impls)
        config_dict['mean_vec_cache'] = mean_vec_cache
        # Rotation matrix cache element.
        rotation_cache = None
        if config_dict['rotation_cache'] and \
                config_dict['rotation_cache']['type']:
            rotation_cache = from_config_dict(config_dict['rotation_cache'],
                                              data_element_impls)
        config_dict['rotation_cache'] = rotation_cache

        return super(ItqFunctor, cls).from_config(config_dict, False)
Exemple #14
0
    def from_config(
        cls: Type[MDS],
        config_dict: Dict,
        merge_default: bool = True
    ) -> MDS:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.

        :return: Constructed instance from the provided config.

        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        # Optionally construct cache element from sub-config.
        if config_dict['cache_element'] \
                and config_dict['cache_element']['type']:
            e = from_config_dict(config_dict['cache_element'],
                                 DataElement.get_impls())
            config_dict['cache_element'] = e
        else:
            config_dict['cache_element'] = None

        return super(MemoryDescriptorSet, cls).from_config(config_dict, False)
Exemple #15
0
    def from_config(cls, config_dict, merge_default=True):
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless and instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :type config_dict: dict

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.
        :type merge_default: bool

        :return: Constructed instance from the provided config.
        :rtype: ClassificationElementFactory

        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        ce_type, ce_conf = cls_conf_from_config_dict(
            config_dict, ClassificationElement.get_impls())
        return ClassificationElementFactory(ce_type, ce_conf)
Exemple #16
0
    def from_config(
        cls: Type[T],
        config_dict: Dict,
        merge_default: bool = True
    ) -> T:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        Overrides base because this implementation's "bytes" argument wants to
        be given a ``bytes`` type object. When not None, in python 2 this is a
        normal string (not unicode), while in python 3 bytes is a distinct
        type.
        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(),
                                     config_dict)
        try:
            # In python 3, encode input ``str`` into ``bytes``.
            # In python 2, even though ``str`` and ``bytes`` are the same
            # underlying type, we could be given ``unicode``, which needs to be
            # encoded down to ``bytes`` (``str``).
            config_dict["bytes"] = \
                config_dict['bytes'].encode(BYTES_CONFIG_ENCODING)
        except AttributeError:
            # If this is a None value, which has no attributes at all, leave it
            # alone. If in python 2 and given a unicode string, as is the norm
            # return from ``json.load`` and ``json.loads``,
            pass
        return super(DataMemoryElement, cls).from_config(config_dict,
                                                         merge_default=False)
    def from_config(
        cls: Type[T],
        config_dict: Dict,
        merge_default: bool = True
    ) -> T:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless and instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.

        :return: Constructed instance from the provided config.
        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        de_type, de_conf = cls_conf_from_config_dict(
            config_dict, DescriptorElement.get_impls()
        )
        return cls(de_type, de_conf)
Exemple #18
0
    def from_config(cls: Type[T],
                    config_dict: Dict,
                    merge_default: bool = True) -> T:
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        data_elem_impl_set = DataElement.get_impls()

        # Translate prototext and model sub-configs into DataElement instances.
        config_dict['network_prototxt'] = \
            from_config_dict(config_dict['network_prototxt'],
                             data_elem_impl_set)
        config_dict['network_model'] = \
            from_config_dict(config_dict['network_model'],
                             data_elem_impl_set)

        # Translate optionally provided image mean sub-config into a
        # DataElement instance. May have been provided as ``None`` or a
        # configuration dictionary with type ``None`.
        # None, dict[type=None], dict[type=str]
        if config_dict['image_mean'] is None \
                or config_dict['image_mean'].get('type', None) is None:
            config_dict['image_mean'] = None
        else:
            config_dict['image_mean'] = \
                from_config_dict(config_dict['image_mean'], data_elem_impl_set)

        return super(CaffeDescriptorGenerator,
                     cls).from_config(config_dict, merge_default=False)
Exemple #19
0
    def from_config(cls: Type[T_FNNI],
                    config_dict: Dict,
                    merge_default: bool = True) -> T_FNNI:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless and instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.

        :return: Constructed instance from the provided config.

        """
        if merge_default:
            cfg = cls.get_default_config()
            merge_dict(cfg, config_dict)
        else:
            cfg = config_dict

        cfg['descriptor_set'] = from_config_dict(cfg['descriptor_set'],
                                                 DescriptorSet.get_impls())
        cfg['uid2idx_kvs'] = from_config_dict(cfg['uid2idx_kvs'],
                                              KeyValueStore.get_impls())
        cfg['idx2uid_kvs'] = from_config_dict(cfg['idx2uid_kvs'],
                                              KeyValueStore.get_impls())

        if (cfg['index_element'] and cfg['index_element']['type']):
            index_element = from_config_dict(cfg['index_element'],
                                             DataElement.get_impls())
            cfg['index_element'] = index_element
        else:
            cfg['index_element'] = None

        if (cfg['index_param_element'] and cfg['index_param_element']['type']):
            index_param_element = from_config_dict(cfg['index_param_element'],
                                                   DataElement.get_impls())
            cfg['index_param_element'] = index_param_element
        else:
            cfg['index_param_element'] = None

        return super(FaissNearestNeighborsIndex, cls).from_config(cfg, False)
Exemple #20
0
 def get_config(self) -> Dict[str, Any]:
     return merge_dict(
         self.get_default_config(),
         dict(
             rank_relevancy=to_config_dict(self._rank_relevancy),
             n=self._n,
             seed=self._seed,
         ))
Exemple #21
0
 def test_overrides(self) -> None:
     """ Test that dict `b` overrides key `b` with a nested dict. """
     a = {
         'a': 1,
         'b': 2,
     }
     b = {
         'b': {
             'c': 3
         },
     }
     expected = {
         'a': 1,
         'b': {
             'c': 3,
         }
     }
     merge_dict(a, b)
     self.assertEqual(a, expected)
Exemple #22
0
 def test_partial_update(self) -> None:
     """
     Test that dict `b` updates and adds keys appropriately to dict `a` (adds
     key `c`, updates key `a`).
     """
     a = {
         'a': 1,
         'b': 2,
     }
     b = {
         'a': 3,
         'c': 4,
     }
     expected = {
         'a': 3,
         'b': 2,
         'c': 4,
     }
     merge_dict(a, b)
     self.assertEqual(a, expected)
Exemple #23
0
    def test_configuration_with_caches(self) -> None:
        # This should run without error in both python
        # 2 and 3, as str/unicode are JSON compliant in both.
        expected_mean_vec = numpy.array([1, 2, 3])
        expected_rotation = numpy.eye(3)

        expected_mean_vec_bytes = BytesIO()
        # noinspection PyTypeChecker
        numpy.save(expected_mean_vec_bytes, expected_mean_vec)
        expected_mean_vec_str = \
            expected_mean_vec_bytes.getvalue().decode(BYTES_CONFIG_ENCODING)

        expected_rotation_bytes = BytesIO()
        # noinspection PyTypeChecker
        numpy.save(expected_rotation_bytes, expected_rotation)
        expected_rotation_str = \
            expected_rotation_bytes.getvalue().decode(BYTES_CONFIG_ENCODING)

        new_parts = {
            'mean_vec_cache': {
                'smqtk_dataprovider.impls.data_element.memory.DataMemoryElement':
                {
                    'bytes': expected_mean_vec_str
                },
                'type':
                'smqtk_dataprovider.impls.data_element.memory.DataMemoryElement'
            },
            'rotation_cache': {
                'smqtk_dataprovider.impls.data_element.memory.DataMemoryElement':
                {
                    'bytes': expected_rotation_str
                },
                'type':
                'smqtk_dataprovider.impls.data_element.memory.DataMemoryElement'
            },
            'bit_length': 153,
            'itq_iterations': 7,
            'normalize': 2,
            'random_seed': 58,
        }
        c = merge_dict(ItqFunctor.get_default_config(), new_parts)

        itq = ItqFunctor.from_config(c)

        # Checking that loaded parameters were correctly set and cache elements
        # correctly return intended vector/matrix.
        numpy.testing.assert_equal(itq.mean_vec, [1, 2, 3])
        numpy.testing.assert_equal(itq.rotation,
                                   [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        self.assertEqual(itq.bit_length, 153)
        self.assertEqual(itq.itq_iterations, 7)
        self.assertEqual(itq.normalize, 2)
        self.assertEqual(itq.random_seed, 58)
Exemple #24
0
 def test_nested(self) -> None:
     """
     Test that nested dictionary updates occur correctly without losing
     values in sibling or nephew dictionaries.
     """
     a = {
         'a': 1,
         'b': {
             'c': 2,
             'd': {
                 'e': 3
             },
         },
         'f': {
             'g': 4,
             'h': {
                 'i': 5
             }
         },
     }
     b = {'b': {'c': 6}, 'f': {'h': {'i': 7}}, 'j': 8}
     expected = {
         'a': 1,
         'b': {
             'c': 6,
             'd': {
                 'e': 3
             },
         },
         'f': {
             'g': 4,
             'h': {
                 'i': 7
             }
         },
         'j': 8,
     }
     merge_dict(a, b)
     self.assertEqual(a, expected)
Exemple #25
0
    def from_config(cls: Type[T],
                    config_dict: Dict,
                    merge_default: bool = True) -> T:
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        cache_element = None
        if config_dict['cache_element'] and config_dict['cache_element'][
                'type']:
            cache_element = from_config_dict(config_dict['cache_element'],
                                             DataElement.get_impls())
        config_dict['cache_element'] = cache_element

        return super(DataMemorySet, cls).from_config(config_dict, False)
Exemple #26
0
    def get_default_config(cls) -> Dict:
        """
        Generate and return a default configuration dictionary for this class.

        It is not be guaranteed that the configuration dictionary returned
        from this method is valid for construction of an instance of this class.

        :return: Default configuration dictionary for the class.
        :rtype: dict
        """
        c = super(KVSDataSet, cls).get_default_config()
        c['kvstore'] = merge_dict(
            make_default_config(KeyValueStore.get_impls()),
            to_config_dict(c['kvstore']))
        return c
Exemple #27
0
 def get_config(self) -> Dict[str, Any]:
     # If no cache elements (set to None), return default plugin configs.
     c = merge_dict(
         self.get_default_config(), {
             "bit_length": self.bit_length,
             "itq_iterations": self.itq_iterations,
             "normalize": self.normalize,
             "random_seed": self.random_seed,
         })
     if self.mean_vec_cache_elem:
         c['mean_vec_cache'] = \
             to_config_dict(self.mean_vec_cache_elem)
     if self.rotation_cache_elem:
         c['rotation_cache'] = \
             to_config_dict(self.rotation_cache_elem)
     return c
    def from_config(
            cls,
            config_dict: Dict,
            merge_default: bool = True) -> "ClassifyDescriptorCollection":
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        classifier_map = {}

        # Copying list of keys so we can update the dictionary as we loop.
        for label in list(config_dict.keys()):
            # Skip the example section.
            if label == cls.EXAMPLE_KEY:
                continue

            classifier_config = config_dict[label]
            classifier = from_config_dict(classifier_config,
                                          ClassifyDescriptor.get_impls())
            classifier_map[label] = classifier

        return cls(classifiers=classifier_map)
    def from_config(cls, config_dict, merge_default=True):
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless an instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :type config_dict: dict

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.
        :type merge_default: bool

        :return: Constructed instance from the provided config.
        :rtype: ClassifierCollection

        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        classifier_map = {}

        # Copying list of keys so we can update the dictionary as we loop.
        for label in list(config_dict.keys()):
            # Skip the example section.
            if label == cls.EXAMPLE_KEY:
                continue

            classifier_config = config_dict[label]
            classifier = from_config_dict(classifier_config,
                                          Classifier.get_impls())
            classifier_map[label] = classifier

        # Don't merge back in "example" default
        return super(ClassifierCollection,
                     cls).from_config({'classifiers': classifier_map},
                                      merge_default=False)
    def from_config(
        cls: Type[T],
        config_dict: Dict,
        merge_default: bool = True
    ) -> T:
        """
        Instantiate a new instance of this class given the configuration
        JSON-compliant dictionary encapsulating initialization arguments.

        This method should not be called via super unless an instance of the
        class is desired.

        :param config_dict: JSON compliant dictionary encapsulating
            a configuration.
        :type config_dict: dict

        :param merge_default: Merge the given configuration on top of the
            default provided by ``get_default_config``.
        :type merge_default: bool

        :return: Constructed instance from the provided config.
        :rtype: SkLearnBallTreeHashIndex

        """
        if merge_default:
            config_dict = merge_dict(cls.get_default_config(), config_dict)

        # Parse ``cache_element`` configuration if set.
        cache_element = None
        if config_dict['cache_element'] and \
                config_dict['cache_element']['type']:
            cache_element = \
                from_config_dict(config_dict['cache_element'],
                                 DataElement.get_impls())
        config_dict['cache_element'] = cache_element

        return super(SkLearnBallTreeHashIndex, cls).from_config(config_dict,
                                                                False)