IMathLib-ソースコード-

  • pocket
  • はてなブックマーク

#ifndef IMATHLIB_H_MATH_LINER_ALGEBRA_MATRIX_HPP
#define IMATHLIB_H_MATH_LINER_ALGEBRA_MATRIX_HPP

#include "IMathLib/math/liner_algebra/vector.hpp"


namespace iml {

	template <class, size_t, size_t>
	class matrix;


	//行列型のパラメータ
	template <class T, size_t M, size_t N, class... Types>
	using matrix_parameter = type_parameter<matrix<T, M, N>, type_tuple<Types...>>;
	template <class T, size_t M, size_t N, class... Params>
	struct type_parameter<matrix<T, M, N>, type_tuple<type_parameter<T, Params>...>> {
		static_assert(M * N == type_tuple<type_parameter<T, Params>...>::value, "There must be M*N parameters.");

		using type = matrix<T, M, N>;
		static constexpr type value = type(type_parameter<T, Params>::value...);

		template <class = std::enable_if_t<is_exist_additive_inverse_v<T>>>
		auto operator-() const { return matrix_parameter<T, M, N, decltype(-type_parameter<T, Params>())...>(); }
		auto operator+() const { return *this; }

		template <class T, T Val, class = std::enable_if_t<(Val >= 0) && (Val < M)>>
		auto operator[](int_parameter<T, Val>) const {
			using array_type = array_parameter<T, index_tuple<size_t, M, N>, type_parameter<T, Params>...>;
			return array_type()[int_parameter<T, Val>];
		}
	};


	// 行列におけるスカラー演算と標準演算の十分条件の定義
	// 乗算
	template <class T1, class T2, size_t M, size_t N>
	struct is_lscalar_operation_impl2<is_multipliable, T1, matrix<T2, M, N>> : std::bool_constant<is_multipliable_v<T1, T2>> {};
	template <class T1, size_t M, size_t N, class T2>
	struct is_rscalar_operation_impl2<is_multipliable, matrix<T1, M, N>, T2> : std::bool_constant<is_multipliable_v<T1, T2>> {};
	template <class T1, class T2, size_t M, size_t N, size_t L>
	struct is_standard_operation_impl2<is_multipliable, matrix<T1, M, L>, matrix<T2, L, N>> : std::bool_constant<is_magma<mul_result_t<T1, T2>>::add_value> {};
	template <class T1, class T2, size_t M, size_t N>
	struct is_standard_operation_impl2<is_multipliable, matrix<T1, M, N>, vector<T2, N>> : std::bool_constant<is_magma<mul_result_t<T1, T2>>::add_value> {};
	// 乗算代入
	template <class T1, size_t M, size_t N, class T2>
	struct is_rscalar_operation_impl2<is_mul_assignable, matrix<T1, M, N>, T2> : std::bool_constant<is_high_rank_math_type_v<mul_result_t<T1, T2>, T1>> {};
	template <class T1, size_t M, size_t N, class T2>
	struct is_standard_operation_impl2<is_mul_assignable, matrix<T1, M, N>, matrix<T2, M, N>> : std::bool_constant<(M == N) && is_high_rank_math_type_v<mul_result_t<T1, T2>, T1> && is_magma<mul_result_t<T1, T2>>::add_value> {};


	template <class, size_t M, size_t N, class = index_range_t<size_t, 0, (M * N)>>
	class matrix_base;
	template <class T, size_t M, size_t N, size_t... Indices>
	class matrix_base<T, M, N, index_tuple<size_t, Indices...>> {
		template <class, size_t, size_t> friend class matrix;
		template <class, size_t, size_t, class> friend class matrix_base;
	protected:
		T x_m[M][N];
	public:
		constexpr matrix_base() : x_m{} {}
		template <class... UTypes, class = std::enable_if_t<(sizeof...(UTypes) == M * N) && is_high_rank_math_type_v<common_math_type_t<UTypes...>, T>>>
		constexpr matrix_base(const UTypes&... args) : x_m{ T(args)... } {}
		template <class U, class = std::enable_if_t<is_high_rank_math_type_v<U, T>>>
		constexpr matrix_base(const matrix<U, M, N>& ma) : x_m{ ma.x_m[0][Indices]... } {}
		template <class U, class = std::enable_if_t<is_high_rank_math_type_v<U, T>>>
		constexpr matrix_base(matrix<U, M, N>&& ma) : x_m{ ma.x_m[0][Indices]... } {}

		//単項演算
		template <class = std::enable_if_t<is_exist_additive_inverse_v<T>>>
		constexpr matrix<T, M, N> operator-() const { return matrix<T, M, N>(-this->x_m[0][Indices]...); }
		constexpr matrix<T, M, N> operator+() const { return matrix<T, M, N>(*this); }

		//2項演算(多重定義防止にスカラー型でない方をTとして扱い,そうでないならT1 = Tとして扱う)
		template <class T2, class = std::enable_if_t<is_addable_v<T, T2>>>
		friend constexpr auto operator+(const matrix<T, M, N>& lhs, const matrix<T2, M, N>& rhs) {
			return matrix<add_result_t<T, T2>, M, N>((lhs[0][Indices] + rhs[0][Indices])...);
		}
		template <class T2, class... Types1, class... Types2, class = std::enable_if_t<is_addable_v<T, T2>>>
		friend auto operator+(matrix_parameter<T, M, N, Types1...>, matrix_parameter<T2, M, N, Types2...>) {
			return matrix_parameter<add_result_t<T, T2>, M, N, decltype(Types1() + Types2())...>();
		}
		template <class T2, class = std::enable_if_t<is_subtractable_v<T, T2>>>
		friend constexpr auto operator-(const matrix<T, M, N>& lhs, const matrix<T2, M, N>& rhs) {
			return matrix<sub_result_t<T, T2>, M, N>((lhs[0][Indices] - rhs[0][Indices])...);
		}
		template <class T2, class... Types1, class... Types2, class = std::enable_if_t<is_subtractable_v<T, T2>>>
		friend auto operator-(matrix_parameter<T, M, N, Types1...>, matrix_parameter<T2, M, N, Types2...>) {
			return matrix_parameter<sub_result_t<T, T2>, M, N, decltype(Types1() - Types2())...>();
		}
		template <class T2, class = std::enable_if_t<is_rscalar_operation_v<is_multipliable, matrix<T, M, N>, T2>>>
		friend constexpr auto operator*(const matrix<T, M, N>& lhs, const T2& rhs) {
			return matrix<mul_result_t<T, T2>, M, N>((lhs[0][Indices] * rhs)...);
		}
		template <class T2, class... Types, class Param, class = std::enable_if_t<is_rscalar_operation_v<is_multipliable, matrix<T, M, N>, T2>>>
		friend auto operator*(matrix_parameter<T, M, N, Types...>, type_parameter<T2, Param> rhs) {
			return matrix_parameter<mul_result_t<T, T2>, M, N, decltype(Types() * rhs)...>();
		}
		template <class T1, class = std::enable_if_t<is_lscalar_operation_v<is_multipliable, T1, matrix<T, M, N>>>>
		friend constexpr auto operator*(const T1& lhs, const matrix<T, M, N>& rhs) {
			return matrix<mul_result_t<T1, T>, M, N>((lhs * rhs[0][Indices])...);
		}
		template <class T1, class Param, class... Types, class = std::enable_if_t<is_lscalar_operation_v<is_multipliable, T1, matrix<T, M, N>>>>
		friend auto operator*(type_parameter<T1, Param> lhs, matrix_parameter<T, M, N, Types...>) {
			return matrix_parameter<mul_result_t<T1, T>, M, N, decltype(lhs * Types())...>();
		}
		template <class T2, class = std::enable_if_t<is_divisible_v<T, T2>>>
		friend constexpr auto operator/(const matrix<T, M, N>& lhs, const T2& rhs) {
			return matrix<div_result_t<T, T2>, M, N>((lhs[0][Indices] / rhs)...);
		}
		template <class T2, class... Types, class Param, class = std::enable_if_t<is_divisible_v<T, T2>>>
		friend auto operator/(matrix_parameter<T, M, N, Types...>, type_parameter<T2, Param> rhs) {
			return matrix_parameter<div_result_t<T, T2>, M, N, decltype(Types() / rhs)...>();
		}
	};

	//行列型
	template <class T, size_t M, size_t N>
	class matrix : public matrix_base<T, M, N> {
		//MとNは0より大きくなければならない
		static_assert(M > 0 && N > 0, "M and N must be greater than 0.");

		template <class, size_t, size_t> friend class matrix;
		template <class, size_t, size_t, class> friend class matrix_base;
	public:
		using matrix_base<T, M, N>::matrix_base;

		using basis_type = T;
		using iterator = linear_iterator<T>;
		using const_iterator = linear_iterator<const T>;

		template<class Other>
		struct rebind {
			using other = matrix<Other, M, N>;
		};

		constexpr iterator begin() noexcept { return iterator(x_m[0]); }
		constexpr const_iterator begin() const noexcept { return const_iterator(x_m[0]); }
		constexpr iterator end() noexcept { return iterator(x_m[0] + M * N); }
		constexpr const_iterator end() const noexcept { return const_iterator(x_m[0] + M * N); }

		//単項演算
		using matrix_base<T, M, N>::operator-;
		using matrix_base<T, M, N>::operator+;
		//代入演算
		matrix& operator=(const matrix& ma) {
			if (this != std::addressof(ma)) for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] = ma.x_m[0][i];
			return *this;
		}
		template <class U, class = std::enable_if_t<is_high_rank_math_type_v<U, T>>>
		matrix& operator=(const matrix<U, M, N>& ma) {
			for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] = ma.x_m[0][i];
			return *this;
		}
		template <class U, class = std::enable_if_t<is_operation<T, U, T>::add_value>>
		matrix& operator+=(const matrix<U, M, N>& ma) {
			for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] += ma.x_m[0][i];
			return *this;
		}
		template <class U, class = std::enable_if_t<is_operation<T, U, T>::sub_value>>
		matrix& operator-=(const matrix<U, M, N>& ma) {
			for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] -= ma.x_m[0][i];
			return *this;
		}
		//内積
		template <class U, class = std::enable_if_t<is_standard_operation_v<is_mul_assignable, matrix, matrix<U, M, N>>>>
		matrix& operator*=(const matrix<U, M, N>& ma) {
			matrix<T, M, M> temp{};
			for (size_t i = 0; i < M; ++i)
				for (size_t j = 0; j < M; ++j)
					for (size_t k = 0; k < M; ++k)
						temp[i][j] += this->x_m[i][k] * ma.x_m[k][j];
			return *this = temp;
		}
		template <class U, class = std::enable_if_t<is_rscalar_operation_v<is_mul_assignable, matrix, U>>>
		matrix& operator*=(const U& k) {
			for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] *= k;
			return *this;
		}
		template <class U, class = std::enable_if_t<is_operation<T, U, T>::div_value>>
		matrix& operator/=(const U& k) {
			for (size_t i = 0; i < M * N; ++i) this->x_m[0][i] /= k;
			return *this;
		}

		//添え字演算
		const constexpr auto& operator[](size_t index) const { return this->x_m[index]; }
		constexpr auto& operator[](size_t index) { return this->x_m[index]; }

		//ストリーム出力
		friend std::ostream& operator<<(std::ostream& os, const matrix& ma) {
			//-1は改行対策
			for (size_t i = 0; i < M - 1; ++i) {
				for (size_t j = 0; j < N; ++j)
					os << ma.x_m[i][j] << ' ';
				os << std::endl;
			}
			for (size_t j = 0; j < N; ++j)
				os << ma.x_m[M - 1][j] << ' ';
			return os;
		}
		friend std::wostream& operator<<(std::wostream& os, const matrix& ma) {
			//-1は改行対策
			for (size_t i = 0; i < M - 1; ++i) {
				for (size_t j = 0; j < N; ++j)
					os << ma.x_m[i][j] << L' ';
				os << std::endl;
			}
			for (size_t j = 0; j < N; ++j)
				os << ma.x_m[M - 1][j] << L' ';
			return os;
		}

		template <class T>
		constexpr linear_input<iterator> operator<<(const T& value) {
			iterator itr = this->begin();
			*itr = value; ++itr;
			return linear_input<iterator>(itr, this->end());
		}
	};


	//内積
	template <class T1, class T2, size_t M, size_t N, size_t L, class = std::enable_if_t<is_standard_operation_v<is_multipliable, matrix<T1, M, L>, matrix<T2, L, N>>>>
	inline constexpr auto operator*(const matrix<T1, M, L>& lhs, const matrix<T2, L, N>& rhs) {
		matrix<mul_result_t<T1, T2>, M, N> temp{};
		for (size_t i = 0; i < M; ++i)
			for (size_t j = 0; j < N; ++j)
				for (size_t k = 0; k < L; ++k)
					temp[i][j] += lhs[i][k] * rhs[k][j];
		return temp;
	}
	namespace tp {
		//行列型のパラメータの乗算の計算
		template <size_t, class, class, class>
		struct matrix_parameter_mul_impl2;
		template <size_t RC, class T1, class T2, size_t M, size_t L, size_t N, class... Types1, class... Types2, size_t... Indices>
		struct matrix_parameter_mul_impl2<RC, matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>, index_tuple<size_t, Indices...>> {
			//メモリの配置が temp[0][0], temp[0][1], ・・・, temp[1][0], temp[1][1], ・・・となることから算出
			static constexpr size_t row = RC % M;		//行
			static constexpr size_t col = RC / M;		//列
			//内積をとる
			using type = decltype(tp::sum((matrix_parameter<T1, M, L, Types1...>()[int_parameter<size_t, row>()][int_parameter<size_t, Indices>()]
				* matrix_parameter<T2, L, N, Types2...>()[int_parameter<size_t, Indices>()][int_parameter<size_t, col>()])...));
		};
		template <class, class, class>
		struct matrix_parameter_mul_impl;
		template <class T1, class T2, size_t M, size_t L, size_t N, class... Types1, class... Types2, size_t... Indices>
		struct matrix_parameter_mul_impl<matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>, index_tuple<size_t, Indices...>> {
			//各成分づつ計算
			using type = matrix_parameter<mul_result_t<T1, T2>, M, N
				, typename matrix_parameter_mul_impl2<Indices, matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>, index_range_t<size_t, 0, L>>::type...>;
		};
		template <class, class>
		struct matrix_parameter_mul;
		template <class T1, class T2, size_t M, size_t L, size_t N, class... Types1, class... Types2>
		struct matrix_parameter_mul<matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>>
			//M*N行列の全要素を走査するためのインデックスの生成
			: matrix_parameter_mul_impl<matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>, index_range_t<size_t, 0, M * N>> {};
	}
	template <class T1, class T2, size_t M, size_t N, size_t L, class... Types1, class... Types2, class = std::enable_if_t<is_standard_operation_v<is_multipliable, matrix<T1, M, L>, matrix<T2, L, N>>>>
	inline auto operator*(matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>) {
		return typename tp::matrix_parameter_mul<matrix_parameter<T1, M, L, Types1...>, matrix_parameter<T2, L, N, Types2...>>::type()\
	}
	template <class T1, class T2, size_t M, size_t N, class = std::enable_if_t<is_standard_operation_v<is_multipliable, matrix<T1, M, N>, vector<T2, N>>>>
	inline constexpr auto operator*(const matrix<T1, M, N>& lhs, const vector<T2, N>& rhs) {
		vector<mul_result_t<T1, T2>, M> temp{};
		for (size_t i = 0; i < M; ++i) for (size_t j = 0; j < N; ++j) temp[i] += lhs[i][j] * rhs[j];
		return temp;
	}
	namespace tp {
		//内積の補助(Indices1 : ベクトルの各要素に対応するシーケンス, Indices2 : 内積をとるためのシーケンス)
		template <class, class, class, class>
		struct matrix_vector_parameter_mul_impl;
		template <class T1, class... Types1, class T2, class... Types2, size_t M, size_t N, size_t... Indices1, size_t... Indices2>
		struct matrix_vector_parameter_mul_impl<matrix_parameter<T1, M, N, Types1...>, vector_parameter<T2, N, Types2...>, index_tuple<size_t, Indices1...>, index_tuple<size_t, Indices2...>> {
			using type = vector_parameter<mul_result_t<T1, T2>, M
				, decltype(tp::sum(matrix_parameter<T1, M, N, Types1...>()[int_parameter<size_t, Indices1>()][int_parameter<size_t, Indices2>()]
					* vector_parameter<T2, N, Types2...>()[int_parameter<size_t, Indices2>()]...))...>;
		};
	}
	template <class T1, class... Types1, class T2, class... Types2, size_t M, size_t N, class = std::enable_if_t<is_standard_operation_v<is_multipliable, matrix<T1, M, N>, vector<T2, N>>>>
	inline auto operator*(matrix_parameter<T1, M, N, Types1...> lhs, vector_parameter<T2, N, Types2...> rhs) {
		return typename tp::matrix_vector_parameter_mul_impl<matrix_parameter<T1, M, N, Types1...>, vector_parameter<T2, N, Types2...>
			, index_range_t<size_t, 0, M>, index_range_t<size_t, 0, N>>::type();
	}


	//比較演算
	template <class T1, class T2, size_t M, size_t N, class = std::enable_if_t<is_comparable_v<T1, T2>>>
	inline constexpr bool operator==(const matrix<T1, M, N>& lhs, const matrix<T2, M, N>& rhs) {
		for (size_t i = 0; i < M * N; ++i) if (lhs[0][i] != rhs[0][i]) return false;
		return true;
	}
	template <class T1, class T2, size_t M, size_t N, class... Types1, class... Types2, class = std::enable_if_t<is_comparable_v<T1, T2>>>
	inline auto operator==(matrix_parameter<T1, M, N, Types1...>, matrix_parameter<T2, M, N, Types2...>) {
		constexpr bool temp = tp::sum((Types1() == Types2())...)::value == M * N;
		return int_parameter<bool, temp>();
	}
	template <class T1, class T2, size_t M, size_t N, class = std::enable_if_t<is_comparable_v<T1, T2>>>
	inline constexpr bool operator!=(const matrix<T1, M, N>& lhs, const matrix<T2, M, N>& rhs) { return !(lhs == rhs); }
	template <class T1, class T2, size_t M, size_t N, class... Types1, class... Types2, class = std::enable_if_t<is_comparable_v<T1, T2>>>
	inline auto operator!=(matrix_parameter<T1, M, N, Types1...> rhs, matrix_parameter<T2, M, N, Types2...> lhs) { return !(lhs == rhs); }


	//行列の判定
	template <class T>
	struct is_matrix_impl : std::false_type {};
	template <class T, size_t M, size_t N>
	struct is_matrix_impl<matrix<T, M, N>> : std::true_type {};
	template <class T>
	struct is_matrix : is_matrix_impl<std::remove_cv_t<T>> {};
	template <class T>
	inline constexpr bool is_matrix_v = is_matrix<T>::value;


	//行列の除去
	template <class T>
	struct remove_matrix {
		using type = T;
	};
	template <class T, size_t M, size_t N>
	struct remove_matrix<matrix<T, M, N>> {
		using type = T;
	};
	template <class T>
	using remove_matrix_t = typename remove_matrix<T>::type;


	//各種行列の定義
	template <class T>
	using matrix2 = matrix<T, 2, 2>;
	template <class T>
	using matrix3 = matrix<T, 3, 3>;
	template <class T>
	using matrix4 = matrix<T, 4, 4>;


	template <class From, class To, size_t M, size_t N>
	struct is_high_rank_math_type<matrix<From, M, N>, matrix<To, M, N>> : is_high_rank_math_type<From, To> {};
	template <class From, class To, size_t N>
	struct is_high_rank_math_type<matrix<From, N, 1>, vector<To, N>> : is_high_rank_math_type<From, To> {};
	template <class From, class To, size_t N>
	struct is_high_rank_math_type<vector<From, N>, matrix<To, N, 1>> : is_high_rank_math_type<From, To> {};


	//加法の特性
	template <class T, size_t M, size_t N>
	struct addition_traits<matrix<T, M, N>> {
		//単位元(零行列)
		template <class = std::enable_if_t<is_exist_additive_identity_v<T>>>
		static constexpr matrix<T, M, N> identity_element() { return matrix<T, M, N>(); }
		//結合律
		static constexpr bool associative_value = addition_traits<T>::associative_value;
		//消約律
		static constexpr bool cancellative_value = addition_traits<T>::cancellative_value;
		//可換律
		static constexpr bool commutative_value = addition_traits<T>::commutative_value;
	};
	//乗法の特性
	template <class T, size_t M, size_t N>
	struct multiplication_traits<matrix<T, M, N>> {
		//単位元(単位行列)
		template <class = std::enable_if_t<is_exist_multiplicative_identity_v<T> && (M == N)>>
		static constexpr matrix<T, M, M> identity_element() {
			matrix<T, M, M> temp{};
			for (size_t i = 0; i < M; ++i) temp[i][i] = multiplication_traits<T>::identity_element();
			return temp;
		}
		//吸収元(零行列)
		template <class = std::enable_if_t<is_exist_absorbing_element_v<T> && (M == N)>>
		static constexpr matrix<T, M, M> absorbing_element() { return matrix<T, M, M>(); }
		//結合律
		static constexpr bool associative_value = multiplication_traits<T>::associative_value;
		//消約律
		static constexpr bool cancellative_value = false;
		//可換律
		static constexpr bool commutative_value = false;
		//分配律
		static constexpr bool distributive_value = multiplication_traits<T>::distributive_value;
	};


	//逆元が存在するならば逆元の取得(存在しない場合は例外を出す)
	template <class T, size_t M, size_t N>
	struct Inverse_element<matrix<T, M, N>> {
		template <size_t... Indices>
		static constexpr matrix<T, M, N> _additive_inverse_impl_(const matrix<T, M, N>& x, index_tuple<size_t, Indices...>) {
			return matrix<T, M, N>(additive_inverse(x[Indices])...);
		}
		static constexpr matrix<T, M, N> _additive_inverse_(const matrix<T, M, N>& x) {
			return _additive_inverse_impl_(x, index_range_t<size_t, 0, M * N>());
		}

		//Tに乗法逆元が存在する場合の乗法逆元
		static constexpr matrix<T, M, M> _multiplicative_inverse_impl_(matrix<T, M, M> x, std::true_type) {
			matrix<T, M, M> result(multiplication_traits<matrix<T, M, M>>::identity_element());

			//xを単位行列になるように操作する(ガウスの消去法)
			for (size_t i = 0; i < M; ++i) {
				//対角成分が0であれば現在走査中の行より下段の0でない行と交換する
				if (x[i][i] == 0) {
					size_t j = i + 1;
					for (; j < M; ++j) {
						//0でない項が存在するとき行を交換
						if (x[j][i] != 0) {
							//for (size_t k = i; k < M; ++k) swap(x[i][k], x[j][k]);
							//for (size_t k = 0; k < M; ++k) swap(result[i][k], result[j][k]);
							size_t k = 0;
							for (; k < i; ++k) swap(result[i][k], result[j][k]);
							for (; k < M; ++k) { swap(x[i][k], x[j][k]); swap(result[i][k], result[j][k]); }
							break;
						}
					}
					//交換できなかった時は正則ではない
					if (j == M) return matrix<T, M, M>();
				}
				//i行を対角成で正規化(無駄を省くために対角成分は正規化しない)
				//for (size_t j = i + 1; j < M; ++j) x[i][j] /= x[i][i];
				//for (size_t j = 0; j < M; ++j) result[i][j] /= x[i][i];
				size_t l = 0;
				for (; l < i + 1; ++l) result[i][l] /= x[i][i];
				for (; l < M; ++l) { x[i][l] /= x[i][i]; result[i][l] /= x[i][i]; }
				//第i列の対角成分より上を0にする
				for (size_t j = 0; j < i; ++j) {
					if (x[j][i] != 0) {
						//i列目から順に引いていく(i列より左は全て0であるため計算しない)
						//実際、i列の成分は以後0となるため計算する必要がない
						//for (size_t k = i + 1; k < M; ++k) x[j][k] -= x[i][k] * x[j][i];
						//for (size_t k = 0; k < M; ++k) result[j][k] -= result[i][k] * x[j][i];
						size_t k = 0;
						for (; k < i + 1; ++k) result[j][k] -= result[i][k] * x[j][i];
						for (; k < M; ++k) { x[j][k] -= x[i][k] * x[j][i]; result[j][k] -= result[i][k] * x[j][i]; }
					}
				}
				//第i列の対角成分より下を0にする
				for (size_t j = i + 1; j < M; ++j) {
					if (x[j][i] != 0) {
						//i列目から順に引いていく(i列より左は全て0であるため計算しない)
						//実際、i列の成分は以後0となるため計算する必要がない
						//for (size_t k = i + 1; k < M; ++k) x[j][k] -= x[i][k] * x[j][i];
						//for (size_t k = 0; k < M; ++k) result[j][k] -= result[i][k] * x[j][i];
						size_t k = 0;
						for (; k < i + 1; ++k) result[j][k] -= result[i][k] * x[j][i];
						for (; k < M; ++k) { x[j][k] -= x[i][k] * x[j][i]; result[j][k] -= result[i][k] * x[j][i]; }
					}
				}
			}
			return result;
		}
		//Tの乗法逆元が存在しない場合の乗法逆元
		static constexpr matrix<T, M, M> _multiplicative_inverse_impl_(matrix<T, M, M> x, std::false_type) {
			matrix<T, M, M> result(multiplication_traits<matrix<T, M, M>>::identity_element());

			//xを単位行列になるように操作する(ガウスの消去法)
			for (size_t i = 0; i < M; ++i) {
				//対角成分が0であれば現在走査中の行より下段の0でない行と交換する
				if (x[i][i] == 0) {
					size_t j = i + 1;
					for (; j < M; ++j) {
						//0でない項が存在するとき行を交換
						if (x[j][i] != 0) {
							//for (size_t k = i; k < M; ++k) swap(x[i][k], x[j][k]);
							//for (size_t k = 0; k < M; ++k) swap(result[i][k], result[j][k]);
							size_t k = 0;
							for (; k < i; ++k) swap(result[i][k], result[j][k]);
							for (; k < M; ++k) { swap(x[i][k], x[j][k]); swap(result[i][k], result[j][k]); }
							break;
						}
					}
					//交換できなかった時は正則ではない
					if (j == M) return matrix<T, M, M>();
				}
				//i行を対角成で正規化(無駄を省くために対角成分は正規化しない)
				T temp = multiplicative_inverse(x[i][i]);
				//for (size_t j = i + 1; j < M; ++j) x[i][j] *= temp;
				//for (size_t j = 0; j < M; ++j) result[i][j] *= temp;
				size_t l = 0;
				for (; l < i + 1; ++l) result[i][l] *= temp;
				for (; l < M; ++l) { x[i][l] *= temp; result[i][l] *= temp; }
				//第i列の対角成分より上を0にする
				for (size_t j = 0; j < i; ++j) {
					if (x[j][i] != 0) {
						//i列目から順に引いていく(i列より左は全て0であるため計算しない)
						//実際、i列の成分は以後0となるため計算する必要がない
						//for (size_t k = i + 1; k < M; ++k) x[j][k] -= x[i][k] * x[j][i];
						//for (size_t k = 0; k < M; ++k) result[j][k] -= result[i][k] * x[j][i];
						size_t k = 0;
						for (; k < i + 1; ++k) result[j][k] -= result[i][k] * x[j][i];
						for (; k < M; ++k) { x[j][k] -= x[i][k] * x[j][i]; result[j][k] -= result[i][k] * x[j][i]; }
					}
				}
				//第i列の対角成分より下を0にする
				for (size_t j = i + 1; j < M; ++j) {
					if (x[j][i] != 0) {
						//i列目から順に引いていく(i列より左は全て0であるため計算しない)
						//実際、i列の成分は以後0となるため計算する必要がない
						//for (size_t k = i + 1; k < M; ++k) x[j][k] -= x[i][k] * x[j][i];
						//for (size_t k = 0; k < M; ++k) result[j][k] -= result[i][k] * x[j][i];
						size_t k = 0;
						for (; k < i + 1; ++k) result[j][k] -= result[i][k] * x[j][i];
						for (; k < M; ++k) { x[j][k] -= x[i][k] * x[j][i]; result[j][k] -= result[i][k] * x[j][i]; }
					}
				}
			}
			return result;
		}
		template <class = std::enable_if_t<M == N>>
		static constexpr matrix<T, M, M> _multiplicative_inverse_(const matrix<T, M, M>& x) {
			return _multiplicative_inverse_impl_(x, std::bool_constant<is_exist_multiplicative_inverse_v<T>>());
		}
	};


	//誤差評価
	template <class T, size_t M, size_t N>
	struct Error_evaluation<matrix<T, M, N>> {
		static constexpr matrix<T, M, N> epsilon() {
			matrix<T, M, N> temp{};
			for (size_t i = 0; i < M * N; ++i) temp[0][i] = Error_evaluation<T>::epsilon();
			return temp;
		}
		static constexpr bool _error_evaluation_(const matrix<T, M, N>& x1, const matrix<T, M, N>& x2) {
			for (size_t i = 0; i < M * N; ++i) if (!error_evaluation(x1[0][i], x2[0][i])) return false;
			return true;
		}
	};
}

#endif