Могу ли я обобщить решение системы уравнений (с помощью np.linalg.solve) на трехмерные массивы (все еще с двумя неизвестными)?

#python #arrays #numpy #slice #solver

#python #массивы #numpy #срез #решатель

Вопрос:

Я хочу знать, может ли следующая проблема быть обобщена на трехмерный массив и может быть выполнена с помощью нарезки и т. Д.:

Допустим, у меня есть массив x, который имеет размер (n, 2). Я настраиваю систему линейных уравнений, используя значения в массиве, и решаю следующим образом:

 import numpy as np
def solve(x):
        a_array = np.array([[16, -1], [-2, 1]])
        b = np.array([x[-3, 0] - 16*x[-2, 0]   30*x[-1, 0], 1*x[-3, 0] - 2*x[-2, 0] - 0*x[-1, 0]])
        u = np.linalg.solve(a_array, b)

        c = np.array([x[-3, 1] - 16*x[-2, 1]   30*x[-1, 1], 1*x[-3, 1] - 2*x[-2, 1] - 0*x[-1, 1]])
        v = np.linalg.solve(a_array, c)

        total_uv = np.column_stack((u, v))
        
        final_x = np.concatenate((x, total_uv))
    return final_x

 

По сути, я решаю систему линейных уравнений (с двумя переменными) на основе значений в моем массиве x, чтобы получить (1,2) массивы u и v. Затем я складываю их вместе, чтобы получить общий массив (2,2) и объединить этот массив с моим исходным x. Теперь я получаю размер массива final_x (n 2, 2) по сравнению с исходным x.

Мой вопрос: допустим, что x, с которого я начинаю, теперь имеет размер (m, n, 2). Для каждого (n,2) массива (которых m) я хочу решить эту систему уравнений, чтобы получить мой массив total_uv. Затем я объединяю каждый массив total_uv с каждым (n,2) массивом (так что теперь вдоль оси = 1), поэтому мой конечный результат имеет размер (m, n 2,2).

Есть ли способ сделать это без использования циклов for (т. Е. перебора всех (n, 2) массивов и выполнения вычислений, их сохранения и последующего объединения)? Например, просто с помощью нотации среза или более элегантным способом в целом?

Похоже, что нарезка массива x (для получения переменных b и c) через x[:, -3, 0] ... на самом деле не работает, потому что a_array имеет другой размер.

Уточнение решения для (m, n, 2):

 def solve(x):
        m = x.shape[0]
        a_array = np.array([[16, -1], [-2, 1]])
        b = np.stack((x[:, -3, 0] - 16*x[:, -2, 0]   30*x[:, -1, 0],
              1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
        u = np.linalg.solve(a_array[None, :, :], b)

        c = np.stack((x[:, -3, 0] - 16*x[:, -2, 0]   30*x[:, -1, 0],
              1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
        v = np.linalg.solve(a_array[None, :, :], c)

        # Concatenation here:
        total_uv = np.column_stack((u, v))

        uv_reshaped = total_uv.reshape((m, 2, 2))

        final_x = np.concatenate((x, uv_reshaped), axis=1)
    return final_x
 

Ответ №1:

Вы можете использовать нотацию среза для создания b c векторов и в виде двумерных массивов:

 b = np.stack((x[:, -3, 0] - 16*x[:, -2, 0]   30*x[:, -1, 0],
              1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
 

Затем вы можете добавить дополнительное (пакетное) измерение a_array , чтобы использовать его с np.linalg.solve :

 u = np.linalg.solve(a_array[None, ...], b)
 

Кстати, поскольку ваши коэффициенты кажутся одинаковыми для b и c вы могли бы сделать то же самое здесь, устраняя необходимость в двух вызовах np.linalg.solve :

 bc = np.stack((x[:, -3] - 16*x[:, -2]   30*x[:, -1],
               1*x[:, -3] - 2*x[:, -2] - 0*x[:, -1]), axis=2)
uv = np.linalg.solve(a_array[None, None, ...], bc)
 

Тогда у вас есть два пакетных измерения (n, 2) , где второе представляет u / v.

Комментарии:

1. Просто чтобы уточнить: отражает ли напечатанное решение в моем отредактированном сообщении то, что вы пытались сказать? То есть, u=np.linalg.solve(a_array[None, :, :], b) это то, что вы имели в виду? Кроме того, здесь размер u и v будет (m, 2), где m — исходное измерение m во входном массиве (m, n, 2). Можете ли вы, не выполняя цикл for, получить массив u и v (2,2) для каждого m (например, как в моем исходном решении), а затем объединить его с каждым (n, 2) массивом, как в моем отредактированном решении?

2. @user6496380 Я хотел сказать, что вам даже не нужны два отдельных вектора b , c и поэтому вы можете сделать все это за один раз. Смотрите Конец моего ответа, используя bc и uv ; uv тогда это ваше решение.