class_docstr: !
  @brief Class represents clustering algorithm OPTICS (Ordering Points To Identify Clustering Structure) with KD-tree optimization (ccore options is supported).
  @details OPTICS is a density-based algorithm. Purpose of the algorithm is to provide explicit clusters, but create clustering-ordering representation of the input data. 
           Clustering-ordering information contains information about internal structures of data set in terms of density and proper connectivity radius can be obtained
           for allocation required amount of clusters using this diagram. In case of usage additional input parameter 'amount of clusters' connectivity radius should be
           bigger than real - because it will be calculated by the algorithms if requested amount of clusters is not allocated.
  
  @image html optics_example_clustering.png "Scheme how does OPTICS works. At the beginning only one cluster is allocated, but two is requested. At the second step OPTICS calculates connectivity radius using cluster-ordering and performs final cluster allocation."
  
  Clustering example using sample 'Chainlink':
  @code
      from pyclustering.cluster import cluster_visualizer
      from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer
      from pyclustering.samples.definitions import FCPS_SAMPLES
      from pyclustering.utils import read_sample
  
      # Read sample for clustering from some file.
      sample = read_sample(FCPS_SAMPLES.SAMPLE_CHAINLINK)
  
      # Run cluster analysis where connectivity radius is bigger than real.
      radius = 0.5
      neighbors = 3
      optics_instance = optics(sample, radius, neighbors)
  
      # Performs cluster analysis.
      optics_instance.process()
  
      # Obtain results of clustering.
      clusters = optics_instance.get_clusters()
      noise = optics_instance.get_noise()
      ordering = optics_instance.get_ordering()
  
      # Visualize clustering results.
      visualizer = cluster_visualizer()
      visualizer.append_clusters(clusters, sample)
      visualizer.show()
  
      # Display ordering.
      analyser = ordering_analyser(ordering)
      ordering_visualizer.show_ordering_diagram(analyser, 2)
  @endcode
  
  Amount of clusters that should be allocated can be also specified. In this case connectivity radius should be greater than real, for example:
  @code
      from pyclustering.cluster import cluster_visualizer
      from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer
      from pyclustering.samples.definitions import FCPS_SAMPLES
      from pyclustering.utils import read_sample
  
      # Read sample for clustering from some file
      sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN)
  
      # Run cluster analysis where connectivity radius is bigger than real
      radius = 2.0
      neighbors = 3
      amount_of_clusters = 3
      optics_instance = optics(sample, radius, neighbors, amount_of_clusters)
  
      # Performs cluster analysis
      optics_instance.process()
  
      # Obtain results of clustering
      clusters = optics_instance.get_clusters()
      noise = optics_instance.get_noise()
      ordering = optics_instance.get_ordering()
  
      # Visualize ordering diagram
      analyser = ordering_analyser(ordering)
      ordering_visualizer.show_ordering_diagram(analyser, amount_of_clusters)
  
      # Visualize clustering results
      visualizer = cluster_visualizer()
      visualizer.append_clusters(clusters, sample)
      visualizer.show()
  @endcode
  
  Here is an example where OPTICS extracts outliers from sample 'Tetra':
  @code
      from pyclustering.cluster import cluster_visualizer
      from pyclustering.cluster.optics import optics
      from pyclustering.samples.definitions import FCPS_SAMPLES
      from pyclustering.utils import read_sample
  
      # Read sample for clustering from some file.
      sample = read_sample(FCPS_SAMPLES.SAMPLE_TETRA)
  
      # Run cluster analysis where connectivity radius is bigger than real.
      radius = 0.4
      neighbors = 3
      optics_instance = optics(sample, radius, neighbors)
  
      # Performs cluster analysis.
      optics_instance.process()
  
      # Obtain results of clustering.
      clusters = optics_instance.get_clusters()
      noise = optics_instance.get_noise()
  
      # Visualize clustering results (clusters and outliers).
      visualizer = cluster_visualizer()
      visualizer.append_clusters(clusters, sample)
      visualizer.append_cluster(noise, sample, marker='x')
      visualizer.show()
  @endcode
  
  Visualization result of allocated clusters and outliers is presented on the image below:
  @image html optics_noise_tetra.png "Clusters and outliers extracted by OPTICS algorithm from sample 'Tetra'."
docstr: !
  @brief Extract clusters and noise from order database.
code: def __extract_clusters(self):
      """!
      @brief Extract clusters and noise from order database.
  
      """
  
      self.__clusters = []
      self.__noise = []
  
      current_cluster = self.__noise
      for optics_object in self.__ordered_database:
          if (optics_object.reachability_distance is None) or (
              optics_object.reachability_distance > self.__eps
          ):
              if (optics_object.core_distance is not None) and (
                  optics_object.core_distance <= self.__eps
              ):
                  self.__clusters.append([optics_object.index_object])
                  current_cluster = self.__clusters[-1]
              else:
                  self.__noise.append(optics_object.index_object)
          else:
              current_cluster.append(optics_object.index_object)
  
imports: import math
  import matplotlib.pyplot
  from pyclustering.container.kdtree import kdtree_balanced
  from pyclustering.cluster.encoder import type_encoding
  from pyclustering.utils.color import color
  from pyclustering.core.wrapper import ccore_library
  import pyclustering.core.optics_wrapper
label_desc: Use image node_id 15 for calling the optics obj's underlying member method code with example usage: obj.__extract_clusters() without return types