def perform_experiment(self, engine_list):
        """
        Performs nearest neighbour experiments with custom vector data
        for all engines in the specified list.

        Returns self.result contains list of (distance_ratio, search_time)
        tuple. All are the averaged values over all request vectors.
        search_time is the average retrieval/search time compared to the
        average exact search time.
        """
        # We will fill this array with measures for all the engines.
        result = []

        # For each engine, first index vectors and then retrieve neighbours
        for engine in engine_list:
            print('Engine %d / %d' % (engine_list.index(engine),
                                      len(engine_list)))

            # Clean storage
            engine.clean_all_buckets()
            # Use this to compute average distance_ratio
            avg_distance_ratio = 0.0
            # Use this to compute average result set size
            avg_result_size = 0.0
            # Use this to compute average search time
            avg_search_time = 0.0

            # Index all vectors and store them
            for index in range(self.vectors.shape[1]):
                engine.store_vector(self.vectors[:, index],
                                    'data_%d' % index)

            # Look for N nearest neighbours for query vectors
            for index in self.query_indices:
                # We have to time the search
                search_time_start = time.time()

                # Get nearest N according to engine
                nearest = engine.neighbours(self.vectors[:, index])

                # Get search time
                search_time = time.time() - search_time_start

                # Get average distance ratio (with respect to radius
                # of real N closest neighbours)
                distance_ratio = 0.0
                for n in nearest:
                    # If the vector is outside the real neighbour radius
                    if n[2] > self.nearest_radius[index]:
                        # Compute distance to real neighbour radius
                        d = (n[2] - self.nearest_radius[index])
                        # And normalize it. 1.0 means: distance to
                        # real neighbour radius is identical to radius
                        d /= self.nearest_radius[index]
                        # If all neighbours are in the radius, the
                        # distance ratio is 0.0
                        distance_ratio += d
                # Normalize distance ratio over all neighbours
                distance_ratio /= len(nearest)

                # Add to accumulator
                avg_distance_ratio += distance_ratio

                # Add to accumulator
                avg_result_size += len(nearest)

                # Add to accumulator
                avg_search_time += search_time

            # Normalize distance ratio over query set
            avg_distance_ratio /= float(len(self.query_indices))

            # Normalize avg result size
            avg_result_size /= float(len(self.query_indices))

            # Normalize search time over query set
            avg_search_time = avg_search_time / float(len(self.query_indices))

            # Normalize search time with respect to exact search
            avg_search_time /= self.exact_search_time_per_vector

            print('  distance_ratio=%f, result_size=%f, time=%f' % (avg_distance_ratio,
                                                                    avg_result_size,
                                                                    avg_search_time))

            result.append((avg_distance_ratio, avg_result_size, avg_search_time))

        return result
Performs nearest neighbour experiments with custom vector data
        for all engines in the specified list.

        Returns self.result contains list of (distance_ratio, search_time)
        tuple. All are the averaged values over all request vectors.
        search_time is the average retrieval/search time compared to the
        average exact search time.