```lua
local LSTM = {}
LSTM.__index = LSTM
function LSTM:new(input_size, hidden_size)
    local instance = setmetatable({}, LSTM)
    instance.input_size = input_size
    instance.hidden_size = hidden_size
    instance.Wf = instance:randomMatrix(hidden_size, input_size + hidden_size)
    instance.Wi = instance:randomMatrix(hidden_size, input_size + hidden_size)
    instance.WC = instance:randomMatrix(hidden_size, input_size + hidden_size)
    instance.Wo = instance:randomMatrix(hidden_size, input_size + hidden_size)
    instance.bf = instance:zeroVector(hidden_size)
    instance.bi = instance:zeroVector(hidden_size)
    instance.bC = instance:zeroVector(hidden_size)
    instance.bo = instance:zeroVector(hidden_size)
    return instance
end

function LSTM:randomMatrix(rows, cols)
    local matrix = {}
    for i = 1, rows do
        matrix[i] = {}
        for j = 1, cols do
            matrix[i][j] = math.random() * 0.01
        end
    end
    return matrix
end

function LSTM:zeroVector(size)
    local vector = {}
    for i = 1, size do
        vector[i] = 0
    end
    return vector
end

function LSTM:sigmoid(x)
    return 1 / (1 + math.exp(-x))
end

function LSTM:tanh(x)
    return math.tanh(x)
end

function LSTM:dot(a, b)
    assert(type(a) == "table" and type(b) == "table", "Both arguments must be tables.")
    assert(#a == #b, "Vectors must be of the same length.")
    local sum = 0
    for i = 1, #a do
        assert(a[i] ~= nil, "a" .. i .. " is nil") -- Проверка на nil
        assert(b[i] ~= nil, "b" .. i .. " is nil")
        sum = sum + a[i] * b[i]
    end
    return sum
end

function LSTM:forward(x_t, h_prev, C_prev)
    local combined = {}
    for i = 1, #h_prev do
        combined[i] = h_prev[i]
    end

    for i = 1, #x_t do
        combined[#h_prev + i] = x_t[i]
    end

    local f_t, i_t, C_tilde = {}, {}, {}
    for i = 1, self.hidden_size do
        f_t[i] = self:sigmoid(self:dot(self.Wf[i], combined) + self.bf[i])
        i_t[i] = self:sigmoid(self:dot(self.Wi[i], combined) + self.bi[i])
        C_tilde[i] = self:tanh(self:dot(self.WC[i], combined) + self.bC[i])
    end

    local C_t = {}
    for i = 1, self.hidden_size do
        C_t[i] = f_t[i] * C_prev[i] + i_t[i] * C_tilde[i]
    end

    local o_t, h_t = {}, {}
    for i = 1, self.hidden_size do
        o_t[i] = self:sigmoid(self:dot(self.Wo[i], combined) + self.bo[i])
        h_t[i] = o_t[i] * self:tanh(C_t[i])
    end
    return h_t, C_t
end

function LSTM:backward(dh_next, dc_next, x_t, h_prev, C_prev)
    local combined = {}
    for i = 1, #h_prev do
        combined[i] = h_prev[i]
    end

    for i = 1, #x_t do
        combined[#h_prev + i] = x_t[i]
    end

    local dWf = self:zeroMatrix(self.hidden_size, self.input_size + self.hidden_size)
    local dWi = self:zeroMatrix(self.hidden_size, self.input_size + self.hidden_size)
    local dWC = self:zeroMatrix(self.hidden_size, self.input_size + self.hidden_size)
    local dWo = self:zeroMatrix(self.hidden_size, self.input_size + self.hidden_size)
    local dbf, dbi, dBC, dbo = self:zeroVector(self.hidden_size), self:zeroVector(self.hidden_size), self:zeroVector(self.hidden_size), self:zeroVector(self.hidden_size)
    for i = 1, self.hidden_size do
        local do_t = dh_next[i] * self:tanh(C_prev[i]) * self:sigmoid(self:dot(self.Wo[i], combined) + self.bo[i]) * (1 - self:sigmoid(self:dot(self.Wo[i], combined) + self.bo[i]))
        assert(type(do_t) == "number", "do_t must be a number") -- Проверка типов
        local dC_t = dh_next[i] * self:dot(self.Wo[i], combined) * (1 - self:tanh(C_prev[i]) ^ 2) + dc_next
        assert(type(dC_t) == "number", "dC_t must be a number") -- Проверка типов
        local di_t = dC_t * C_tilde[i] * self:sigmoid(self:dot(self.Wi[i], combined) + self.bi[i]) * (1 - self:sigmoid(self:dot(self.Wi[i], combined) + self.bi[i]))
        local df_t = dC_t * C_prev[i] * self:sigmoid(self:dot(self.Wf[i], combined) + self.bf[i]) * (1 - self:sigmoid(self:dot(self.Wf[i], combined) + self.bf[i]))
        local dC_tilde = dC_t * i_t[i] * (1 - self:tanh(self:dot(self.WC[i], combined) + self.bC[i]) ^ 2)
        assert(type(di_t) == "number", "di_t must be a number") -- Проверка типов
        assert(type(df_t) == "number", "df_t must be a number")
        assert(type(dC_tilde) == "number", "dC_tilde must be a number")
        dWf[i] = df_t
        dWi[i] = di_t
        dWC[i] = dC_tilde
        dWo[i] = do_t
        dbf[i] = df_t
        dbi[i] = di_t
        dBC[i] = dC_tilde
        dbo[i] = do_t
    end

    self.Wf = self:matrixAdd(self.Wf, dWf)
    self.Wi = self:matrixAdd(self.Wi, dWi)
    self.WC = self:matrixAdd(self.WC, dWC)
    self.Wo = self:matrixAdd(self.Wo, dWo)
    self.bf = self:vectorAdd(self.bf, dbf)
    self.bi = self:vectorAdd(self.bi, dbi)
    self.bC = self:vectorAdd(self.bC, dBC)
    self.bo = self:vectorAdd(self.bo, dbo)
end

function LSTM:zeroMatrix(rows, cols)
    local matrix = {}
    for i = 1, rows do
        matrix[i] = self:zeroVector(cols)
    end
    return matrix
end

function LSTM:matrixAdd(A, B)
    local result = {}
    for i = 1, #A do
        result[i] = {}
        for j = 1, #A[i] do
            result[i][j] = A[i][j] + B[i][j]
        end
    end
    return result
end

function LSTM:vectorAdd(A, B)
    local result = {}
    for i = 1, #A do
        result[i] = A[i] + B[i]
    end
    return result
end

local E_LSTM = {}
E_LSTM.__index = E_LSTM
setmetatable(E_LSTM, {
    __index = LSTM
})

function E_LSTM:new(input_size, hidden_size, output_size)
    local self = setmetatable({}, E_LSTM)
    self.lstm = LSTM:new(input_size, hidden_size)
    self.fc_weights = self:randomMatrix(output_size, hidden_size)
    self.fc_bias = self:zeroVector(output_size)
    return self
end

function E_LSTM:forward(input_sequence)
    local h_prev = self.lstm:zeroVector(self.lstm.hidden_size)
    local C_prev = self.lstm:zeroVector(self.lstm.hidden_size)
    local outputs = {}
    for t = 1, #input_sequence do
        local x_t = input_sequence[t]
        h_prev, C_prev = self.lstm:forward(x_t, h_prev, C_prev)
        table.insert(outputs, h_prev)
    end

    local final_output = {}
    for i = 1, #self.fc_weights do
        final_output[i] = self:dot(self.fc_weights[i], outputs[#outputs]) + self.fc_bias[i]
    end
    return final_output
end

function E_LSTM:train(inputs, targets, learning_rate)
    for i = 1, #inputs do
        local output = self:forward(inputs[i])
        local loss = self:calculateLoss(output, targets[i])
        local dh_next = self:calculateGradient(output, targets[i]) -- Передаем как градиент
        print("Size of dh_next: ", #dh_next) -- Отладочная информация
        print("Expected size values: ") -- Вывод значений fc_weights
        for j = 1, #self.fc_weights do
            if type(self.fc_weights[j]) == "table" then -- Проверяем, что fc_weights[j] - это таблица
                for k = 1, #self.fc_weights[j] do
                    print(string.format("fc_weights[%d][%d]: %f", j, k, self.fc_weights[j][k]))
                end
            else
                print(string.format("fc_weights[%d]: %f", j, self.fc_weights[j]))
            end
        end

        assert(#dh_next == #self.fc_weights, "Gradient size mismatch") -- Проверка на соответствие размеров
        self.lstm:backward(dh_next, 0, inputs[i], self.lstm:zeroVector(self.lstm.hidden_size), self.lstm:zeroVector(self.lstm.hidden_size))
    end
end

function E_LSTM:calculateLoss(output, target)
    local loss = 0
    for i = 1, #output do
        loss = loss + (output[i] - target[i]) ^ 2
    end
    return loss / #output
end

function E_LSTM:calculateGradient(output, target)
    local gradient = {}
    for i = 1, #output do
        gradient[i] = 2 * (output[i] - target[i]) / #output -- Производная MSE
    end
    return gradient
end
return E_LSTM
```
Найди баги, ошибки, несоответствия в стиле кода, несоответствия в структуре, оптимизируй методы, алгоритмы, формулы, способы, методы.