You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: locally_linear_embedding.rb
    path of file: ./repos/rumale/rumale-manifold/lib/rumale/manifold
    
    the code of the file until where you have to start completion: # frozen_string_literal: true

require 'rumale/base/estimator'
require 'rumale/base/transformer'
require 'rumale/pairwise_metric'
require 'rumale/validation'

module Rumale
  module Manifold
    # LocallyLinearEmbedding is a class that implements Locally Linear Embedding.
    #
    # @example
    #   require 'numo/linalg/autoloader'
    #   require 'rumale/manifold/locally_linear_embedding'
    #
    #   lem = Rumale::Manifold::LocallyLinearEmbedding.new(n_components: 2, n_neighbors: 15)
    #   z = lem.fit_transform(x)
    #
    # *Reference*
    # - Roweis, S., and Saul, L., "Nonlinear Dimensionality Reduction by Locally Linear Embedding," J. of Science, vol. 290, pp. 2323-2326, 2000.
    class LocallyLinearEmbedding < Rumale::Base::Estimator
      include Rumale::Base::Transformer

      # Return the data in representation space.
      # @return [Numo::DFloat] (shape: [n_samples, n_components])
      attr_reader :embeddin
    
      def fit(x, _y = nil)
        raise 'LocallyLinearEmbedding#fit requires Numo::Linalg but that is not loaded' unless enable_linalg?(warning: false)

        x = Rumale::Validation.check_convert_sample_array(x)

        n_samples = x.shape[0]
        tol = @params[:reg_param].fdiv(@params[:n_neighbors])
        distance_mat = Rumale::PairwiseMetric.squared_error(x)
        neighbor_ids = neighbor_ids(distance_mat, @params[:n_neighbors], true)

        affinity_mat = Numo::DFloat.eye(n_samples)
        n_samples.times do |n|
          x_local = x[neighbor_ids[n, true], true] - x[n, true]
          gram_mat = x_local.dot(x_local.transpose)
          gram_mat += tol * gram_mat.trace * Numo::DFloat.eye(@params[:n_neighbors])
          weights = Numo::Linalg.solve(gram_mat, Numo::DFloat.ones(@params[:n_neighbors]))
          weights /= weights.sum + 1e-8
          affinity_mat[n, neighbor_ids[n, true]] -= weights
        end

        kernel_mat = affinity_mat.transpose.dot(affinity_mat)
        _, eig_vecs = Numo::Linalg.eigh(kernel_mat, vals_range: 1...(1 + @params[:n_components]))

        @embedding = @params[:n_components] == 1 ? eig_vecs[true, 0].dup : eig_vecs.dup
        @x_train = x.dup

        self
      end