Project: s41467-024-53883-1 | Function: discretise (r)

system: You are an expert R programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow R best practices and maintain consistent code style.
Return **only** the complete R function code.

user: Complete this R function:

**DESCRIPTION:** Converts continuous marked point patterns into discrete categories using Gaussian mixture models or specified splits. Core function for spatial data discretization in PLASMA analysis.

**KEY TERMS:** {
  "points": "marked point pattern data",
  "splits": "threshold values for categorization",
  "informdeviance": "Gaussian fitting function"
}

**CONTEXT CODE:** #All PLASMA Functions
require(mclust)
require(dplyr)

#Adjusted Rand Index Analysis.

#' Discretise
#'
#' Converts a continuous marked point pattern into a discrete marked point pattern.
#'
#' @param points A marked point pattern. Matrix or data frame with first three columns corresponding to x, y and mark.
#' @param splits Split values which define intervals to categorise points. If left as null, these intervals will be automatically estimated from Gaussian fitting.
#' @param names A vector of characters, where each entry corresponds to the name of a category.
#' @param k Number of Gaussians to fit in case splits is left null. Should be equal to number of suspected categories.
#' @param createplot Boolean dictating whether to create a plot of the new discretised marked point pattern.
#' @return A discretised marked point pattern.
#' @export
discretise <- function(points, splits = NULL, names = NULL, k = 2, createplot = TRUE){
  stop("Function implementation has been masked")
}

#' Inform Cluster Persistence
#'
#' Estimates the persistence threshold to use for ToMATo clustering.
#'
#' @param points A marked point pattern. Matrix or data frame with first two columns corresponding to x and y.
#' @param radius Suspected cluster radius. If left null, this will be estimated from the Ripley's function.
#' @return A persistence threshold.
#' @export
informclusterpersistence <- function(points, radius = NULL){
  #Calculate number of neighbours within radius.
  if(is.null(radius)){
    radius <- informradius(points)
  }
  #Calculate number of neighbours within radius for each point.
  numberneighbours <- as.numeric(colSums(Rfast::Dist(points[,1:2]) <= radius))
  if(max(numberneighbours) < 2){
    print("Parameter Estimation: No neighbours found. This suggests that the given search radius is too small.")
    return(NULL)
  }
  #Calculate persistence.
  persistence <- informdeviance(numberneighbours[numberneighbours > 0])
  if(is.null(persistence)){
    return(NULL)
  } else {
    return(ceiling(persistence))
  }
}

#' Get ARI (Proxy for ToMATo Clustering)
#'
#' Perform ToMATo clustering.
#'
#' @param points A marked point pattern. Matrix or data frame with first two columns corresponding to x and y.
#' @param search_radius Cluster radius.
#' @param persistence Persistence threshold.
#' @return Point cloud with cluster index.
#' @export
getari <- function(points, search_radius, persistence){
  #Define useful properties.
  number_of_points <- nrow(points)
  distance_matrix <- as.matrix(Rfast::Dist(points[,1:2]))
  distance_radius <- distance_matrix <= search_radius
  #Get densities.
  densities <- as.numeric(colSums(distance_radius))
  #Get filtration.
  filtration <- 1:number_of_points
  point_ids <- Rfast::sort_cor_vectors(filtration, densities, descending = TRUE)
  filtration_ids <- Rfast::sort_cor_vectors(filtration, point_ids)
  #Perform persistent homology.
  r <- rep(0, number_of_points)
  for(i in filtration){
    #Get original point id.
    point_id <- point_ids[i]
    #Extract filtrations of neighbours of i.
    neighbour_filtrations <- filtration_ids[distance_radius[, point_id]]
    #Extract neighbours with lower filtration values than i.
    N <- neighbour_filtrations[neighbour_filtrations < i]
    #Check length of N.
    if(length(N) == 0){
      #If N is empty, then i is a peak. Create a new root. Update r and e.
      r[point_id] <- point_id
    }else{
      #If N is non-empty, then there must be at least one neighbour of higher density. #Cycle through neighbours and check persistence holds.
      potentials <- N[densities[point_ids[N]] <= densities[point_id] + persistence]
      #Check length of potentials.
      if(length(potentials) == 0){
        #Node cannot connect to any neighbours (persistence too low). Create new set for node.
        r[point_id] <- point_id
      } else {
        #Node can connect to at least one neighbour and bridges gap between other neighbours.
        potentials <- point_ids[Rfast::Sort(potentials)]
        j <- potentials[1]
        r[point_id] <- j
        if(length(potentials) > 1){
          #Merge the sets of the potentials.
          for(k in potentials[-1]){
            r_k <- r == k
            r[r_k] <- j
          }
        }
      }
    }
  }
  #Determine cluster indices.
  found <- 0
  #Filter out clusters with too few points.
  cluster_index <- rep(0, number_of_points)
  for(i in unique(r)){
    #Get points corresponding to that root.
    cluster_points <- filtration[r == i]
    #Filter out clusters below persistence.
    if(densities[i] <= persistence){
      #Set to outliers.
      cluster_index[cluster_points] <- 0
    } else {
      #Initialise new cluster.


Complete the function implementation replacing "stop("Not implemented")".