diff --git a/include/math/argmax.hpp b/include/math/argmax.hpp new file mode 100644 index 0000000..57555ad --- /dev/null +++ b/include/math/argmax.hpp @@ -0,0 +1,176 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: argmax.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to find the index of the maximum value; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once + +#include +#include // for panic::vector +#include // for panic::matrix + +namespace panic{ +namespace math{ + + + + +/** + * @brief Returns the index of maximum value of a vector + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a Input vector. + * + * @return A new vector containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::types::uint_t argmax(const panic::tensor::vector& a); + + +/** + * @brief Calculates the index of the maximum value of a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param b Output vector for index + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + */ +template +bool argmax(const panic::tensor::matrix& A, panic::tensor::uint_vector& b); + + +/** + * @brief Returns the index of the maximum value of a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + */ +template +panic::types::uint_t argmax(const panic::tensor::matrix& A); + + + +/** + * @brief Find the index of the maximum values row-wise of a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param C Output vector with indexes. Resized to match @p A.cols(). + * + * @return true if @p c was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool argmax_rowwise(const panic::tensor::matrix& A, panic::tensor::uint_vector& c); + +/** + * @brief Returns a new matrix containing the index of the maiximum row-wise elementwise. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::uint_vector argmax_rowwise(const panic::tensor::matrix& A); + + +/** + * @brief Find the index of the maximum values column-wise of a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param C Output matrix. Resized to match @p A.rows(). + * + * @return true if @p c was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool argmax_colwise(const panic::tensor::matrix& A, panic::tensor::uint_vector& c); + +/** + * @brief Returns a new matrix containing the index of the maiximum column-wise elementwise. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::uint_vector argmax_colwise(const panic::tensor::matrix& A); + +} // namespace math +} // namespace panic \ No newline at end of file diff --git a/include/math/dot.hpp b/include/math/dot.hpp new file mode 100644 index 0000000..72b9bd1 --- /dev/null +++ b/include/math/dot.hpp @@ -0,0 +1,102 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: dot.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to calculate dot product of tensors; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- + +#include +#include // for panic::real_matrix + +namespace panic{ +namespace math{ + +/** + * @brief Returns dor product of vector and vector. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a First vector. + * @param b Second vector for dot product. Need to be @p a.size() + * + */ +template +T dot(const panic::tensor::vector& a, const panic::tensor::vector& b); + +/** + * @brief Returns a new vector of dot product of a matrix and vector. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param b Input vector. @ p b.size needs to be the size of @p A.cols. + * @param c Output vector with result. + * + * @return true if success + * @return false if resizeing fails or dimention mismatch + * + */ +template +bool dot(const panic::tensor::matrix& A, const panic::tensor::matrix& b, panic::tensor::vector& c); + + +/** + * @brief Returns a new vector of dot product of a matrix and vector. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param b Input vector. @ p b.size needs to be the size of @p A.cols. + * + * @return A new matrix containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new matrix. + */ +template +panic::tensor::vector dot(const panic::tensor::matrix& A, const panic::tensor::matrix& b); + + + +} // namespace math +} // namespace panic \ No newline at end of file diff --git a/include/math/equal.hpp b/include/math/equal.hpp new file mode 100644 index 0000000..7acbc3a --- /dev/null +++ b/include/math/equal.hpp @@ -0,0 +1,294 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: equal.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to find the equal in panic::tensor + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * @file mul.hpp + * @brief Public API for multiplying operations on PANIC vectors and matrices. + * + * This header contains the declarations that users of the math module should call. + * The comments here describe how each function is used, what dimensions are required, + * and what is returned on failure. + * + * Implementation details, OpenMP thresholds, and explicit template instantiations are + * kept in mul.cpp. + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once + +#include // for panic::vector +#include // for panic::matrix + +namespace panic{ +namespace math{ + + +/** + * @brief Find the equal for a scalar to every element of a vector. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a Input vector. + * @param k Scalar value compared to each element of @p a. + * @param c Output vector. Resized to match @p a. + * + * @return true if @p c was resized and filled successfully. + * @return false if resizing @p c failed. + * + * @note This overload writes the result into an existing vector to avoid + * unnecessary temporary allocations. + */ +template +bool equal(const panic::tensor::vector& a, const T k, panic::tensor::vector& c); + + +/** + * @brief Returns a new vector containing a scalar equaled to every element. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a Input vector. + * @param k Scalar value compared to each element of @p a. + * + * @return A new vector containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::vector equal(const panic::tensor::vector& a, const T k); + + +/** + * @brief Equal a vector elementwise too a vector. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a First vector. + * @param b Second vector. Must have size of @p a + * @param c Output vector. Resized to match @p a. + * + * @return true if @p c was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool equal(const panic::tensor::vector& a, const panic::tensor::vector& b, panic::tensor::vector& c); + +/** + * @brief Returns a new vector containing a vector with equals elementwise. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param a First vector. + * @param b Second vector. Must have size of @p a + * @param k Scalar value compared to each element of @p a. + * + * @return A new vector containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::vector equal(const panic::tensor::vector& a, const panic::tensor::vector& b); + + + +/** + * @brief Equal compared a scalar to every element of a matix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param k Scalar value multiplied to each element of @p A. + * @param C Output Matrix. Resized to match @p A. + * + * @return true if @p C was resized and filled successfully. + * @return false if resizing @p C failed. + * + * @note This overload writes the result into an existing vector to avoid + * unnecessary temporary allocations. + */ +template +bool equal(const panic::tensor::matrix& A, const T k, panic::tensor::matrix& C); + +/** + * @brief Returns a new matrix containing a scalar equal compared to every element. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param k Scalar value multiplied to each element of @p A. + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::matrix equal(const panic::tensor::matrix& A, const T k); + +/** + * @brief Equal compared a matrix elementwise too a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A First matrix. + * @param B Second matrix. Must have size of @p A. + * @param C Output matrix. Resized to match @p A. + * + * @return true if @p C was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool equal(const panic::tensor::matrix& A, const panic::tensor::matrix& B, panic::tensor::matrix& C); + +/** + * @brief Returns a new matrix containing a matrix equal compaed elementwise. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param B Second matrix. Must have size of @p A. + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::matrix equal(const panic::tensor::matrix& A, const panic::tensor::matrix& B); + + +/** + * @brief Equal compared a vector rowwise too a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Matrix. + * @param b Vector. Must have size of @p A.cols(). + * @param C Output matrix. Resized to match @p A. + * + * @return true if @p C was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool equal_rowwise(const panic::tensor::matrix& A, const panic::tensor::vector& b, panic::tensor::matrix& C); + +/** + * @brief Equal compared a vector rowwise too a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Matrix. + * @param b Vector. Must have size of @p A.cols(). + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::matrix equal_rowwise(const panic::tensor::matrix& A, const panic::tensor::vector& b); + +/** + * @brief Equal compared a vector colwise too a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Matrix. + * @param b Vector. Must have size of @p A.rows(). + * @param C Output matrix. Resized to match @p A. + * + * @return true if @p C was resized and filled successfully. + * @return false if vector sizes do not match or resizing @p c failed. + */ +template +bool equal_colwise(const panic::tensor::matrix& A, const panic::tensor::vector& b, panic::tensor::matrix& C); + +/** + * @brief Equal compared a vector colwise too a matrix. + * + * Computes: + * @code + * @endcode + * + * @tparam T Numeric element type. + * @param A Matrix. + * @param b Vector. Must have size of @p A.rows(). + * + * @return A new matrix containing the result. + * @return An empty matrix if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +template +panic::tensor::matrix equal_colwise(const panic::tensor::matrix& A, const panic::tensor::vector& b); + + + + +} // namespace math +} // namespace panic \ No newline at end of file diff --git a/include/math/exp.hpp b/include/math/exp.hpp index 75269c6..d6c59bf 100644 --- a/include/math/exp.hpp +++ b/include/math/exp.hpp @@ -99,7 +99,7 @@ bool exp(const panic::tensor::vector& a, panic::tensor::vector& c); * @note This overload is convenient, but may allocate a new vector. */ template -panic::tensor::vector add(const panic::tensor::vector& a); +panic::tensor::vector exp(const panic::tensor::vector& a); /** * @brief Calculates the expnential elementwise of a matrix diff --git a/include/math/log.hpp b/include/math/log.hpp index bf2e939..8b7a096 100644 --- a/include/math/log.hpp +++ b/include/math/log.hpp @@ -24,11 +24,11 @@ * Module Name: math * File Name: log.cpp * Revision: 0.1.0 - * Date: 29-07-2026 + * Date: 31-07-2026 * Author: Michelle Bausager * * Description: - * Functions to calculate the logorithem of numbers + * Functions to calculate the natural logorithem of numbers * *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #pragma once @@ -42,30 +42,30 @@ namespace math{ /** - * @brief calculates the exponential of a value. + * @brief calculates the log of a value. * * Computes: * @code - * result = exp(k) + * result = log(k) * @endcode * * @tparam T Numeric element type. - * @param k Value to take the exp of. + * @param x Value to take the log of. * * @return The calculated value * * @note This function is omp-friendly. */ template -T exp(const T x); +T log(const T x); /** - * @brief Calculates the exponential elementwise in a vector + * @brief Calculates the natrual logorithmic elementwise in a vector * * Computes: * @code - * c[i] = exp(a[i]) + * c[i] = log(a[i]) * @endcode * * @tparam T Numeric element type. @@ -79,14 +79,14 @@ T exp(const T x); * unnecessary temporary allocations. */ template -bool exp(const panic::tensor::vector& a, panic::tensor::vector& c); +bool log(const panic::tensor::vector& a, panic::tensor::vector& c); /** - * @brief Calculates the exponential elementwise in a vector + * @brief Calculates the natrual log elementwise in a vector * * Computes: * @code - * result[i] = exp(a[i]) + * result[i] = log(a[i]) * @endcode * * @tparam T Numeric element type. @@ -98,14 +98,14 @@ bool exp(const panic::tensor::vector& a, panic::tensor::vector& c); * @note This overload is convenient, but may allocate a new vector. */ template -panic::tensor::vector add(const panic::tensor::vector& a); +panic::tensor::vector log(const panic::tensor::vector& a); /** - * @brief Calculates the expnential elementwise of a matrix + * @brief Calculates the natrual log elementwise of a matrix * * Computes: * @code - * C(i,j) = exp(A(i,j)) + * C(i,j) = log(A(i,j)) * @endcode * * @tparam T Numeric element type. @@ -119,14 +119,14 @@ panic::tensor::vector add(const panic::tensor::vector& a); * unnecessary temporary allocations. */ template -bool exp(const panic::tensor::matrix& A, panic::tensor::matrix& C); +bool log(const panic::tensor::matrix& A, panic::tensor::matrix& C); /** - * @brief Returns the calculated ecponential elementwise of the matrix + * @brief Returns the calculated natrual log elementwise of the matrix * * Computes: * @code - * result(i,j) = exp(A(i,j)) + * result(i,j) = log(A(i,j)) * @endcode * * @tparam T Numeric element type. @@ -138,7 +138,7 @@ bool exp(const panic::tensor::matrix& A, panic::tensor::matrix& C); * @note This overload is convenient, but may allocate a new vector. */ template -panic::tensor::matrix exp(const panic::tensor::matrix& A); +panic::tensor::matrix log(const panic::tensor::matrix& A); } // namespace math } // namespace panic \ No newline at end of file diff --git a/include/math/mean.hpp b/include/math/mean.hpp index 626b630..87d6524 100644 --- a/include/math/mean.hpp +++ b/include/math/mean.hpp @@ -33,6 +33,7 @@ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #pragma once +#include #include // for panic::vector #include // for panic::matrix @@ -60,7 +61,7 @@ namespace math{ * @note This overload is convenient, but may allocate a new vector. */ template -T mean(const panic::tensor::vector& a); +panic::types::real_t mean(const panic::tensor::vector& a); /** * @brief Returns the mean value of a matrix. @@ -78,7 +79,7 @@ T mean(const panic::tensor::vector& a); * */ template -T mean(const panic::tensor::matrix& A); +panic::types::real_t mean(const panic::tensor::matrix& A); /** * @brief Find the mean values row-wise of a matrix. @@ -96,7 +97,7 @@ T mean(const panic::tensor::matrix& A); * @return false if vector sizes do not match or resizing @p c failed. */ template -bool mean_rowwise(const panic::tensor::matrix& A, panic::tensor::vector& c); +bool mean_rowwise(const panic::tensor::real_matrix& A, panic::tensor::real_vector& c); /** * @brief Returns a new matrix containing the mean row-wise elementwise. @@ -115,7 +116,7 @@ bool mean_rowwise(const panic::tensor::matrix& A, panic::tensor::vector& c * @note This overload is convenient, but may allocate a new vector. */ template -panic::tensor::vector mean_rowwise(const panic::tensor::matrix& A); +panic::tensor::real_vector mean_rowwise(const panic::tensor::real_matrix& A); /** @@ -134,7 +135,7 @@ panic::tensor::vector mean_rowwise(const panic::tensor::matrix& A); * @return false if vector sizes do not match or resizing @p c failed. */ template -bool mean_colwise(const panic::tensor::matrix& A, panic::tensor::vector& c); +bool mean_colwise(const panic::tensor::real_matrix& A, panic::tensor::real_vector& c); /** * @brief Returns a new matrix containing the mean column-wise elementwise. @@ -153,7 +154,7 @@ bool mean_colwise(const panic::tensor::matrix& A, panic::tensor::vector& c * @note This overload is convenient, but may allocate a new vector. */ template -panic::tensor::vector mean_colwise(const panic::tensor::matrix& A); +panic::tensor::real_vector mean_colwise(const panic::tensor::real_matrix& A); } // namespace math } // namespace panic \ No newline at end of file diff --git a/include/math/transpose.hpp b/include/math/transpose.hpp new file mode 100644 index 0000000..cad08b5 --- /dev/null +++ b/include/math/transpose.hpp @@ -0,0 +1,86 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: transpose.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to transpose a matrix; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- + +#include // for panic::real_matrix + +namespace panic{ +namespace math{ + + +/** + * @brief Transposes a matrix. + * + * Computes: + * @code + * B = transpose(A) + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * @param B Output matrix with result. + * + * @return true if success + * @return false if resizeing fails or dimention mismatch + * + */ +template +bool transpose(const panic::tensor::matrix& A, panic::tensor::matrix& B); + +/** + * @brief Returns a new matrix of the transposed A. + * + * Computes: + * @code + * result = transpose(A) + * @endcode + * + * @tparam T Numeric element type. + * @param A Input matrix. + * + * @return A new matrix containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new matrix. + */ +template +panic::tensor::matrix transpose(const panic::tensor::matrix& A); + + + +} // namespace math +} // namespace panic \ No newline at end of file diff --git a/include/neural_network/activation/activation_relu.hpp b/include/neural_network/activation/activation_relu.hpp index 2063d3c..15330d6 100644 --- a/include/neural_network/activation/activation_relu.hpp +++ b/include/neural_network/activation/activation_relu.hpp @@ -77,7 +77,7 @@ struct activation_relu : public layer{ * * @Note Calculates -> outputs = inputs * weights + biases */ - bool forward(const panic::tensor::real_matrix& inputs); + bool forward(const panic::tensor::real_matrix& input_data); /** * @brief Backward function for layer @@ -86,7 +86,7 @@ struct activation_relu : public layer{ * * @Note Calculates derivative of forward function. */ - bool backward(const panic::tensor::real_matrix& dinpus); + bool backward(const panic::tensor::real_matrix& dvalues); }; } // namespace tensor diff --git a/include/neural_network/activation/activation_softmax.hpp b/include/neural_network/activation/activation_softmax.hpp index 3e97f7c..491df45 100644 --- a/include/neural_network/activation/activation_softmax.hpp +++ b/include/neural_network/activation/activation_softmax.hpp @@ -77,7 +77,7 @@ struct activation_softmax : public layer{ * * @Note Calculates -> outputs = inputs * weights + biases */ - bool forward(const panic::tensor::real_matrix& inputs); + bool forward(const panic::tensor::real_matrix& input_data); /** * @brief Backward function for layer @@ -86,7 +86,7 @@ struct activation_softmax : public layer{ * * @Note Calculates derivative of forward function. */ - bool backward(const panic::tensor::real_matrix& dinpus); + bool backward(const panic::tensor::real_matrix& dvalues); }; } // namespace tensor diff --git a/include/neural_network/layer/layer.hpp b/include/neural_network/layer/layer.hpp index 284e5c0..a8520df 100644 --- a/include/neural_network/layer/layer.hpp +++ b/include/neural_network/layer/layer.hpp @@ -56,6 +56,14 @@ namespace panic{ */ struct layer{ + /** + * @brief Emphty output matrix to store layer input + * + * Output shape: + * samples x neuron_count + */ + panic::tensor::real_matrix inputs; + /** * @brief Emphty output matrix to store layer output * @@ -64,6 +72,12 @@ struct layer{ */ panic::tensor::real_matrix outputs; + /** + * @brief Emphty matrix to store output for backward pass + * + */ + panic::tensor::real_matrix dinputs; + /** * @brief Default de-constructor * diff --git a/include/neural_network/layer/layer_dense.hpp b/include/neural_network/layer/layer_dense.hpp index ff4600a..0f39612 100644 --- a/include/neural_network/layer/layer_dense.hpp +++ b/include/neural_network/layer/layer_dense.hpp @@ -58,6 +58,12 @@ namespace panic{ */ struct layer_dense : public layer{ + /** + * @brief Emphty matrix to store input data + * + */ + panic::tensor::real_matrix ipnuts; + /** * @brief Emphty weight matrix to store layer weights * @@ -65,6 +71,7 @@ struct layer_dense : public layer{ * input_size x neuron_count */ panic::tensor::real_matrix weights; + panic::tensor::real_matrix dweights; /** * @brief Emphty bias vector to store layer bias @@ -73,6 +80,7 @@ struct layer_dense : public layer{ * 1 x neuron_count */ panic::tensor::real_vector biases; + panic::tensor::real_vector dbiases; /** * @brief Empthy constructor @@ -102,7 +110,7 @@ struct layer_dense : public layer{ * * @Note Calculates -> outputs = inputs * weights + biases */ - bool forward(const panic::tensor::real_matrix& inputs); + bool forward(const panic::tensor::real_matrix& input_data); /** * @brief Backward function for layer @@ -111,7 +119,7 @@ struct layer_dense : public layer{ * * @Note Calculates derivative of forward function. */ - bool backward(const panic::tensor::real_matrix& dinpus); + bool backward(const panic::tensor::real_matrix& dvalues); }; } // namespace tensor diff --git a/include/neural_network/loss/loss.hpp b/include/neural_network/loss/loss.hpp index 0fc6a08..03f322a 100644 --- a/include/neural_network/loss/loss.hpp +++ b/include/neural_network/loss/loss.hpp @@ -68,6 +68,12 @@ struct loss{ */ panic::types::real_t data_loss; + /** + * @brief Matrix for backwards pass + */ + panic::tensor::real_matrix dinputs; + + /** * @brief Default de-constructor * diff --git a/include/neural_network/loss/loss_categorical_crossentropy.hpp b/include/neural_network/loss/loss_categorical_crossentropy.hpp index ffd04aa..ce9f9d7 100644 --- a/include/neural_network/loss/loss_categorical_crossentropy.hpp +++ b/include/neural_network/loss/loss_categorical_crossentropy.hpp @@ -82,9 +82,35 @@ struct loss_categorical_crossentropy: loss{ const panic::tensor::real_matrix& y_pred, const panic::tensor::real_matrix& y_true); -}; + /** + * @brief backward function to calculate from losses + * + * @param y_pred Matrix of model predection. + * @param y_true Vector of true label of data. + * + */ + bool backward( + const panic::tensor::real_matrix& dvalues, + const panic::tensor::uint_vector& y_true); + + /** + * @brief backward function to calculate from losses + * + * @param y_pred Matrix of model predection. + * @param y_true Vector of true label of data. + * + * @Note Overloaded if one-shot endcoded + * is used. + */ + bool backward( + const panic::tensor::real_matrix& dvalues, + const panic::tensor::real_matrix& y_true); + + +}; + } // namespace neural_network } // namespace panic diff --git a/include/tensor/generators/eye.hpp b/include/tensor/generators/eye.hpp new file mode 100644 index 0000000..3282bb5 --- /dev/null +++ b/include/tensor/generators/eye.hpp @@ -0,0 +1,93 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: tensor + * File Name: eye.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to generate eye matrices + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once + +#include // for panic::vector +#include + +namespace panic{ +namespace tensor{ + +/** + * @brief Outputs an eye matrix + * + * Computes: + * @code + + * @endcode + * + * @tparam T Numeric element type. + * @param size Number or rows and columns. + * @param A Output matrix + * + * @return true if @p A was resized and filled successfully. + * @return false if resizing @p A failed. + * + * @note This overload writes the result into an existing vector to avoid + * unnecessary temporary allocations. + */ +template +bool eye(const panic::types::uint_t size, panic::tensor::matrix A); + +/** + * @brief Returns a eye matrix + * + * Computes: + * @code + * @endcode + * + * @param T Numeric element type. + * @param size Number of rows and columns. + * + * @return A new vector containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +//template +//panic::tensor::matrix eye(const T size); + + + + + + + + + + + +} // namespace tensor +} // namespace panic \ No newline at end of file diff --git a/include/tensor/generators/one_hot.hpp b/include/tensor/generators/one_hot.hpp new file mode 100644 index 0000000..2b138c5 --- /dev/null +++ b/include/tensor/generators/one_hot.hpp @@ -0,0 +1,91 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: tensor + * File Name: one_hot.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to one_hot matrices + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#pragma once + +#include +#include // for panic::vector +#include + +namespace panic{ +namespace tensor{ + +/** + * @brief Outputs an one_hot matrix + * + * Computes: + * @code + + * @endcode + * + * @tparam T Numeric element type. + * @param size Number of columns. + * @param a Input vector that contains here 1 should be + * @param B Output matrix + * + * @return true if @p B was resized and filled successfully. + * @return false if resizing @p B failed. + * + * @note This overload writes the result into an existing vector to avoid + * unnecessary temporary allocations. + */ +template +bool one_hot(const panic::types::uint_t size, const panic::tensor::uint_vector& a, panic::tensor::matrix& B); + +/** + * @brief Returns a one_hot matrix + * + * Computes: + * @code + * @endcode + * + * @param T Numeric element type. + * @param size Number of columns. + * @param a Input vector that contains here 1 should be + * + * @return A new vector containing the result. + * @return An empty vector if the operation fails. + * + * @note This overload is convenient, but may allocate a new vector. + */ +//template +//panic::tensor::matrix one_hot(const panic::types::uint_t size, const panic::tensor::vector& a); + + + + + + +} // namespace tensor +} // namespace panic \ No newline at end of file diff --git a/main.cpp b/main.cpp index e31d6fd..068b058 100644 --- a/main.cpp +++ b/main.cpp @@ -59,6 +59,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -731,12 +735,35 @@ int main(void) { // Create activation softmax layer mymodel.add_activation_softmax(); - mymodel.forward(X); + // create loss function + panic::neural_network::loss_categorical_crossentropy loss_function; - panic::io::print_matrix(mymodel.outputs); + mymodel.forward(X); + + loss_function.calculate(mymodel.outputs, y); + + panic::tensor::uint_vector prediction; + prediction = panic::math::argmax_rowwise(mymodel.outputs); + + panic::types::real_t accuracy; + panic::tensor::uint_vector comparisons; + + comparisons = panic::math::equal(prediction, y); + + accuracy = panic::math::mean(comparisons); + + std::cout << "loss: " << loss_function.data_loss << std::endl; + + std::cout << "acc: " << accuracy << std::endl; + + + + + + return 0; } \ No newline at end of file diff --git a/src/math/argmax.cpp b/src/math/argmax.cpp new file mode 100644 index 0000000..27f3153 --- /dev/null +++ b/src/math/argmax.cpp @@ -0,0 +1,387 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: argmax.cpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to find the index of the maximum value; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- + +#include +#include +#include + +#include // for panic::vector +#include // for panic::matrix + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t argmax_omp_min_work = 500; +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace math { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax +// +// Description: +// Find the argmax index for a vector +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::types::uint_t argmax(const panic::tensor::vector& a){ + + panic::types::uint_t idx = 0; + + if (a.size() == 0){ + return idx; + } + + for (panic::types::uint_t i = 0; i < a.size(); ++i){ + if (a[idx] < a[i]){ + idx = i; + } + } + + return idx; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::types::uint_t argmax(const panic::tensor::vector& a +); +template panic::types::uint_t argmax(const panic::tensor::vector& a +); +template panic::types::uint_t argmax(const panic::tensor::vector& a +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax +// +// Description: +// Find the argmax value for a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool argmax(const panic::tensor::matrix& A, panic::tensor::uint_vector& b){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if (!b.resize(2)){ + return false; + } + + b.fill(0); + + for (panic::types::uint_t i = 0; i < A.rows(); ++i) { + for (panic::types::uint_t j = 0; j < A.cols(); ++j){ + if (A(b[0], b[1]) < A(i,j)) { + b[0] = i; + b[1] = j; + } + } + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool argmax(const panic::tensor::matrix& a, + panic::tensor::uint_vector& b +); +template bool argmax(const panic::tensor::matrix& a, + panic::tensor::uint_vector& b +); +template bool argmax(const panic::tensor::matrix& a, + panic::tensor::uint_vector& b +); + + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax +// +// Description: +// Find the argmax value for a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::uint_vector argmax(const panic::tensor::matrix& A){ + + panic::tensor::uint_vector b; + + if (! argmax(A, b)){ + return panic::tensor::uint_vector(); + } + + return b; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::uint_vector argmax(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector argmax(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector argmax(const panic::tensor::matrix& A +); + + + + + + + + + + + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax_rowwise +// +// Description: +// Find the index value of maximum row-wise of a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool argmax_rowwise(const panic::tensor::matrix& A, panic::tensor::uint_vector& b){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( !b.resize(rows) ){ + return false; + } + + b.fill(0); + + PANIC_OMP_PARALLEL_FOR_IF(work > argmax_omp_min_work) + for (panic::types::uint_t i = 0; i < rows; ++i){ + for (panic::types::uint_t j = 0; j < cols; ++j){ + + if (A(i, b[i]) < A(i,j)){ + b[i] = j; + } + } + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool argmax_rowwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); +template bool argmax_rowwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); +template bool argmax_rowwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax_rowwise +// +// Description: +// Returns index row-wise max values +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::uint_vector argmax_rowwise(const panic::tensor::matrix& A){ + panic::tensor::uint_vector b; + + if (!argmax_rowwise(A, b)){ + return panic::tensor::uint_vector(); + } + + return b; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::uint_vector + argmax_rowwise(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector + argmax_rowwise(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector + argmax_rowwise(const panic::tensor::matrix& A +); + + + + + + + + + + + + + + + + + + + + + + + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax_colwise +// +// Description: +// Find the index of the maximum column-wise of a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool argmax_colwise(const panic::tensor::matrix& A, panic::tensor::uint_vector& b){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( !b.resize(cols) ){ + return false; + } + + b.fill(0); + PANIC_OMP_PARALLEL_FOR_IF(work > argmax_omp_min_work) + for (panic::types::uint_t i = 0; i < cols; ++i){ + for (panic::types::uint_t j = 0; j < rows; ++j){ + + if(A(j, b[i]) < A(j,i)){ + b[i] = j; + } + + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool argmax_colwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); +template bool argmax_colwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); +template bool argmax_colwise(const panic::tensor::matrix& A, + panic::tensor::uint_vector& b +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::argmax_colwise +// +// Description: +// Returns column-wise max index values +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::uint_vector argmax_colwise(const panic::tensor::matrix& A){ + panic::tensor::uint_vector b; + + if (!argmax_colwise(A, b)){ + return panic::tensor::uint_vector(); + } + + return b; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::uint_vector + argmax_colwise(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector + argmax_colwise(const panic::tensor::matrix& A +); +template panic::tensor::uint_vector + argmax_colwise(const panic::tensor::matrix& A +); + + + } // namespace math +} // namespace panic diff --git a/src/math/dot.cpp b/src/math/dot.cpp new file mode 100644 index 0000000..9711a53 --- /dev/null +++ b/src/math/dot.cpp @@ -0,0 +1,199 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: dot.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to calculate dot product of tensors; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- +#include +#include + +#include +#include // for panic::tensor::matrix + + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t dot_omp_min_work = 500; + +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace math { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::dot +// +// Description: +// Multiply sum two vector. +//-------------------------------------------------------------------------------------------------------------------------- +template +T dot(const panic::tensor::vector& a, const panic::tensor::vector& b){ + + T result = T{0}; + + if (a.size() != b.size()){ + return result; + } + + // Find the maximum in parallel for large vectors. + // Each thread computes a partial sum, then OpenMP combines them into result. + PANIC_OMP_PARALLEL_FOR_REDUCTION_IF(a.size() > dot_omp_min_work, +, result) + for (panic::types::uint_t i = 0; i < a.size(); ++i){ + result += a[i]*b[i]; + } + + return result; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::types::uint_t dot(const panic::tensor::vector& a, + const panic::tensor::vector& b +); +template panic::types::int_t dot(const panic::tensor::vector& a, + const panic::tensor::vector& b +); +template panic::types::real_t dot(const panic::tensor::vector& a, + const panic::tensor::vector& b +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::dot +// +// Description: +// Multiply sum a matrix and vector +//-------------------------------------------------------------------------------------------------------------------------- +template +bool dot(const panic::tensor::matrix& A, const panic::tensor::vector& b, panic::tensor::vector& c){ + + if (b.size() != A.rows()){ + return false; + } + + c.fill(0); + + PANIC_OMP_PARALLEL_FOR_IF(A.rows()*A.cols() > dot_omp_min_work) + for (panic::types::uint_t i = 0; i < A.rows(); ++i){ + for (panic::types::uint_t j = 0; j < A.cols(); ++j){ + c[i] += A(i,j) * b[j]; + } + } + + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::vector& c +); + +template bool dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::vector& c +); + +template bool dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::vector& c +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::dot +// +// Description: +// Multiply sum a matrix and vector +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::vector dot(const panic::tensor::matrix& A, const panic::tensor::vector& b){ + + panic::tensor::vector c; + + if (! dot(A,b,c)){ + return panic::tensor::vector(); + } + + + + return c; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::vector dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b +); + +template panic::tensor::vector dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b +); +template panic::tensor::vector dot( + const panic::tensor::matrix& A, + const panic::tensor::vector& b +); + + + } // namespace math +} // namespace panic diff --git a/src/math/equal.cpp b/src/math/equal.cpp new file mode 100644 index 0000000..248b7cb --- /dev/null +++ b/src/math/equal.cpp @@ -0,0 +1,614 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: equal.cpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to find the equal in panic::tensor + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- + +#include +#include + +#include // for panic::vector +#include // for panic::matrix + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t equal_omp_min_work = 500; +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace math { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// Equal compares a constant to a vector +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal(const panic::tensor::vector& a, const T k, panic::tensor::vector& c){ + + if (!c.resize(a.size())){ + return false; + } + + PANIC_OMP_PARALLEL_FOR_IF(a.size() > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < a.size(); ++i){ + if (a[i] == k){ + c[i] = T{1}; + } + else{ + c[i] = T{0}; + } + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal(const panic::tensor::vector& a, + const panic::types::uint_t k, + panic::tensor::vector& c +); +template bool equal(const panic::tensor::vector& a, + const panic::types::int_t k, + panic::tensor::vector& c +); +template bool equal(const panic::tensor::vector& a, + const panic::types::real_t k, + panic::tensor::vector& c +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// Equal compared a constant to a vector +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::vector equal(const panic::tensor::vector& a, const T k){ + panic::tensor::vector c(a.size()); + + if (!equal(a, k, c)){ + return panic::tensor::vector(); + } + + return c; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::types::uint_t k +); +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::types::int_t k +); +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::types::real_t k +); + + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// Equal compared a vector to a vector +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal(const panic::tensor::vector& a, const panic::tensor::vector& b, panic::tensor::vector& c){ + + if (a.size() != b.size()){ + return false; + } + + if (!c.resize(a.size())){ + return false; + } + + PANIC_OMP_PARALLEL_FOR_IF(a.size() > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < a.size(); ++i){ + if (a[i] == b[i]){ + c[i] = T{1}; + } + else{ + c[i] = T{0}; + } + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal(const panic::tensor::vector& a, + const panic::tensor::vector& b, + panic::tensor::vector& c +); +template bool equal(const panic::tensor::vector& a, + const panic::tensor::vector& b, + panic::tensor::vector& c +); +template bool equal(const panic::tensor::vector& a, + const panic::tensor::vector& b, + panic::tensor::vector& c +); + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// equal compared a vector to a vector +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::vector equal(const panic::tensor::vector& a, const panic::tensor::vector& b){ + panic::tensor::vector c(a.size()); + + if (!equal(a, b, c)){ + return panic::tensor::vector(); + } + + return c; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::tensor::vector& b +); +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::tensor::vector& b +); +template panic::tensor::vector + equal(const panic::tensor::vector& a, + const panic::tensor::vector& b +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// equal compared a constant to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal(const panic::tensor::matrix& A, const T k, panic::tensor::matrix& C){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( !C.resize(rows, cols) ){ + return false; + } + + + PANIC_OMP_PARALLEL_FOR_IF(work > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < rows; ++i){ + for (panic::types::uint_t j = 0; j < cols; ++j){ + if (A(i,j) == k){ + C(i,j) = T{1}; + } + else{ + C(i,j) = T{0}; + } + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal(const panic::tensor::matrix& A, + const panic::types::uint_t k, + panic::tensor::matrix& C +); +template bool equal(const panic::tensor::matrix& A, + const panic::types::int_t k, + panic::tensor::matrix& C +); +template bool equal(const panic::tensor::matrix& A, + const panic::types::real_t k, + panic::tensor::matrix& C +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// equal compared a constant to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix equal(const panic::tensor::matrix& A, const T k){ + panic::tensor::matrix C; + + if (!equal(A, k, C)){ + return panic::tensor::matrix(); + } + + return C; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::types::uint_t k +); +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::types::int_t k +); +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::types::real_t k +); + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// equal compared a matrix to a matrix elementwise +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal(const panic::tensor::matrix& A, const panic::tensor::matrix& B, panic::tensor::matrix& C){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( (rows != B.rows()) || (cols != B.cols())){ + return false; + } + + if ( !C.resize(rows, cols) ){ + return false; + } + + + PANIC_OMP_PARALLEL_FOR_IF(work > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < rows; ++i){ + for (panic::types::uint_t j = 0; j < cols; ++j){ + if ( A(i,j) == B(i,j)){ + C(i,j) = T{1}; + } + else{ + C(i,j) = T{0}; + } + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B, + panic::tensor::matrix& C +); +template bool equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B, + panic::tensor::matrix& C +); +template bool equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B, + panic::tensor::matrix& C +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal +// +// Description: +// equal compared a matrix to a matrix elementwise +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix equal(const panic::tensor::matrix& A, const panic::tensor::matrix& B){ + panic::tensor::matrix C; + + if (!equal(A, B, C)){ + return panic::tensor::matrix(); + } + + return C; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B +); +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B +); +template panic::tensor::matrix + equal(const panic::tensor::matrix& A, + const panic::tensor::matrix& B +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal_rowwise +// +// Description: +// equal compared a vector row-wise to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal_rowwise(const panic::tensor::matrix& A, const panic::tensor::vector& b, panic::tensor::matrix& C){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( cols != b.size() ){ + return false; + } + + if ( !C.resize(rows, cols) ){ + return false; + } + + + PANIC_OMP_PARALLEL_FOR_IF(work > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < rows; ++i){ + for (panic::types::uint_t j = 0; j < cols; ++j){ + if (A(i,j) == b[j]){ + C(i,j) = T{1}; + } + else{ + C(i,j) = T{0}; + } + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); +template bool equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); +template bool equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal_rowwise +// +// Description: +// equal_rowwise a vector row-wise to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix equal_rowwise(const panic::tensor::matrix& A, const panic::tensor::vector& b){ + panic::tensor::matrix C; + + if (!equal_rowwise(A, b, C)){ + return panic::tensor::matrix(); + } + + return C; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix + equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); +template panic::tensor::matrix + equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); +template panic::tensor::matrix + equal_rowwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal_colwise +// +// Description: +// equal_colwise a vector coloumn-wise to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool equal_colwise(const panic::tensor::matrix& A, const panic::tensor::vector& b, panic::tensor::matrix& C){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( rows != b.size() ){ + return false; + } + + if ( !C.resize(rows, cols) ){ + return false; + } + + + PANIC_OMP_PARALLEL_FOR_IF(work > equal_omp_min_work) + for (panic::types::uint_t i = 0; i < cols; ++i){ + for (panic::types::uint_t j = 0; j < rows; ++j){ + if (A(j,i) == b[i]){ + C(j,i) == T{1}; + } + else{ + C(j,i) = T{0}; + } + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); +template bool equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); +template bool equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b, + panic::tensor::matrix& C +); + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::equal_colwise +// +// Description: +// equal_colwise a vector coloumn-wise to a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix equal_colwise(const panic::tensor::matrix& A, const panic::tensor::vector& b){ + panic::tensor::matrix C; + + + if (!equal_colwise(A, b, C)){ + return panic::tensor::matrix(); + } + + return C; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix + equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); +template panic::tensor::matrix + equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); +template panic::tensor::matrix + equal_colwise(const panic::tensor::matrix& A, + const panic::tensor::vector& b +); + + + + } // namespace math +} // namespace panic diff --git a/src/math/log.cpp b/src/math/log.cpp index fc004d4..2c137b6 100644 --- a/src/math/log.cpp +++ b/src/math/log.cpp @@ -24,11 +24,11 @@ * Module Name: math * File Name: log.cpp * Revision: 0.1.0 - * Date: 29-07-2026 + * Date: 31-07-2026 * Author: Michelle Bausager * * Description: - * Functions to calculate the logorithem of numbers + * Functions to calculate the natrual logorithem of numbers * *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ @@ -52,7 +52,7 @@ * Small vectors and matrices are kept serial because the overhead of starting * worker threads can be larger than the work itself. */ -static const panic::types::uint_t exp_omp_min_work = 500; +static const panic::types::uint_t log_omp_min_work = 250; //--------------------------------------------------------------------------------------------------------------------------- // INPLEMENTATION //--------------------------------------------------------------------------------------------------------------------------- @@ -64,94 +64,184 @@ namespace panic { //-------------------------------------------------------------------------------------------------------------------------- -// Function Name : panic::math::exp +// Function Name : panic::math::log // // Description: -// Calculates the exponential +// Calculates the natural log //-------------------------------------------------------------------------------------------------------------------------- template -T exp(const T x){ +T log(const T x){ - // The identity: - // - // e^(-x) = 1 / e^x - // - // lets the rest of the function work only with positive values. - if (x < static_cast(0)) { - return static_cast(1) / exp(-x); + T result = T{0}; + + const T zero = T{0}; + const T one = T{1}; + const T two = T{2}; + + /* + * The real natural logarithm is only defined for + * positive numbers. + * + * log(0) approaches negative infinity, while negative + * x would require complex numbers. + */ + if (x <= zero){ + return result; } - // Natural logarithm of 2. - // - // This is useful because: - // - // e^(ln(2)) = 2 - // - const T ln2 = static_cast(0.69314718055994530942); - - // Split x into: - // - // x = k * ln(2) + r - // - // For example, when x = 2: - // - // k = floor(2 / ln(2)) = 2 - // r = 2 - 2 * ln(2) ≈ 0.6137 - // - // This makes r small, which makes the Taylor series - // converge much faster. - const panic::types::uint_t k = static_cast(x / ln2); - - const T r = x - static_cast(k) * ln2; - - // Taylor series: - // - // r² r³ r⁴ - // e^r = 1 + r + ---- + ---- + ---- + ... - // 2! 3! 4! - // - // result starts with the first term: 1. - T result = static_cast(1); - - // term also starts at 1, representing: - // - // r^0 / 0! = 1 - T term = static_cast(1); - - - for (panic::types::uint_t n = 1; n <= 15; ++n){ - - // Produce the next Taylor term from the previous one. - // - // For example: - // - // n = 1: term = 1 * r / 1 = r - // n = 2: term = r * r / 2 = r² / 2! - // n = 3: term = r²/2 * r/3 = r³ / 3! - // - // This avoids separately calculating powers and factorials. - term *= r / static_cast(n); - - // Add the new term to the approximation. - result += term; + /* + * NaN is the only floating-point value that is not + * equal to itself. + */ + if (x != x){ + return result; } - // We currently have e^r. - // - // From: - // - // x = k * ln(2) + r - // - // we get: - // - // e^x = e^(k * ln(2)) * e^r - // = 2^k * e^r - // - // Therefore, multiply the result by 2 exactly k times. - for (panic::types::uint_t i = 0; i < k; ++i) { - result *= static_cast(2); + /* + * This is ln(2). + * + * We need it later because we rewrite the input as: + * + * input = value * 2^exponent + * + * Therefore: + * + * ln(input) = ln(value) + exponent * ln(2) + */ + static const T ln_2 = static_cast(0.69314718055994530942); + + /* + * value will be reduced to the interval [1, 2). + * + * exponent records how many powers of two were removed + * or added. + */ + T value = x; + panic::types::int_t exponent = 0; + + + /* + * Example: + * + * x = 20 + * + * 20 / 2 = 10 + * 10 / 2 = 5 + * 5 / 2 = 2.5 + * 2.5 / 2 = 1.25 + * + * Therefore: + * + * 20 = 1.25 * 2^4 + * + * So value becomes 1.25 and exponent becomes 4. + */ + while (value >= two){ + value *= T{0.5}; + ++exponent; } + /* + * For an input smaller than 1, multiply by two until it + * reaches [1, 2). + * + * Example: + * + * 0.25 * 2 = 0.5 + * 0.5 * 2 = 1 + * + * Therefore: + * + * 0.25 = 1 * 2^-2 + */ + while (value < one){ + value *= two; + --exponent; + } + + + /* + * Transform value into a smaller number near zero: + * + * y = (value - 1) / (value + 1) + * + * Since value is in [1, 2), y is in [0, 1/3). + * + * Small y values are useful because powers such as + * y^3, y^5 and y^7 become small very quickly. + */ + const T y = (value - one) / (value + one); + + + /* + * The series uses only odd powers: + * + * y, y^3, y^5, y^7, ... + * + * Multiplying by y^2 moves from one odd power to the next: + * + * y * y^2 = y^3 + * y^3 * y^2 = y^5 + */ + const T y_squared = y * y; + + /* + * term begins as y^1. + */ + T term = y; + + /* + * Accumulates: + * + * y + y^3/3 + y^5/5 + ... + */ + T sum = zero; + + + /* + * Twenty terms are more than enough for float + * after the range reduction above. + * + * A fixed number of iterations also makes the runtime + * predictable. + */ + for (panic::types::uint_t i = 0; i < 20; ++i){ + + /* + * The denominators are: + * + * 1, 3, 5, 7, ... + * + * which are generated by 2*i + 1. + */ + const panic::types::uint_t denominator = + 2 * i + 1; + + sum += term / static_cast(denominator); + + /* + * Advance: + * + * y -> y^3 -> y^5 -> y^7 + */ + term *= y_squared; + } + + /* + * The series calculates: + * + * ln(value) = + * 2 * (y + y^3/3 + y^5/5 + ...) + * + * Then restore the power of two removed during range + * reduction: + * + * ln(input) = + * ln(value) + exponent * ln(2) + */ + result = two * sum + static_cast(exponent) * ln_2; + + return result; } //-------------------------------------------------------------------------------------------------------------------------- @@ -160,28 +250,28 @@ T exp(const T x){ // The implementation is in this .cpp file. // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- -template panic::types::real_t exp(const panic::types::real_t x +template panic::types::real_t log(const panic::types::real_t x ); //-------------------------------------------------------------------------------------------------------------------------- -// Function Name : panic::math::exp +// Function Name : panic::math::log // // Description: -// Calculates the exponential elementwise of a vector +// Calculates the natrual log elementwise of a vector //-------------------------------------------------------------------------------------------------------------------------- template -bool exp(const panic::tensor::vector& a, panic::tensor::vector& c){ +bool log(const panic::tensor::vector& a, panic::tensor::vector& c){ if (!c.resize(a.size())){ return false; } - PANIC_OMP_PARALLEL_FOR_IF(a.size() > exp_omp_min_work) + PANIC_OMP_PARALLEL_FOR_IF(a.size() > log_omp_min_work) for (panic::types::uint_t i = 0; i < a.size(); ++i){ - c[i] = exp(a[i]); + c[i] = log(a[i]); } return true; @@ -193,23 +283,23 @@ bool exp(const panic::tensor::vector& a, panic::tensor::vector& c){ // The implementation is in this .cpp file. // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- -template bool exp(const panic::tensor::vector& a, +template bool log(const panic::tensor::vector& a, panic::tensor::vector& c ); //-------------------------------------------------------------------------------------------------------------------------- -// Function Name : panic::math::exp +// Function Name : panic::math::log // // Description: -// Calculates the exponential elementwise for a vector +// Calculates the natrual log elementwise for a vector //-------------------------------------------------------------------------------------------------------------------------- template -panic::tensor::vector exp(const panic::tensor::vector& a){ +panic::tensor::vector log(const panic::tensor::vector& a){ panic::tensor::vector c(a.size()); - if (!exp(a, c)){ + if (!log(a, c)){ return panic::tensor::vector(); } @@ -222,18 +312,18 @@ panic::tensor::vector exp(const panic::tensor::vector& a){ // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- template panic::tensor::vector - exp(const panic::tensor::vector& a + log(const panic::tensor::vector& a ); //-------------------------------------------------------------------------------------------------------------------------- -// Function Name : panic::math::exp +// Function Name : panic::math::log // // Description: -// calculates the exponential elementwise of a matrix +// calculates the natrual log elementwise of a matrix //-------------------------------------------------------------------------------------------------------------------------- template -bool exp(const panic::tensor::matrix& A, panic::tensor::matrix& C){ +bool log(const panic::tensor::matrix& A, panic::tensor::matrix& C){ panic::types::uint_t rows = A.rows(); panic::types::uint_t cols = A.cols(); @@ -244,10 +334,10 @@ bool exp(const panic::tensor::matrix& A, panic::tensor::matrix& C){ } - PANIC_OMP_PARALLEL_FOR_IF(work > exp_omp_min_work) + PANIC_OMP_PARALLEL_FOR_IF(work > log_omp_min_work) for (panic::types::uint_t i = 0; i < rows; ++i){ for (panic::types::uint_t j = 0; j < cols; ++j){ - C(i,j) = exp(A(i,j)); + C(i,j) = log(A(i,j)); } } @@ -260,7 +350,7 @@ bool exp(const panic::tensor::matrix& A, panic::tensor::matrix& C){ // The implementation is in this .cpp file. // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- -template bool exp(const panic::tensor::matrix& A, +template bool log(const panic::tensor::matrix& A, panic::tensor::matrix& C ); @@ -268,16 +358,16 @@ template bool exp(const panic::tensor::matrix& A, //-------------------------------------------------------------------------------------------------------------------------- -// Function Name : panic::math::exp +// Function Name : panic::math::log // // Description: -// Calculates the exponential element-wise of a matrix +// Calculates the natrual log element-wise of a matrix //-------------------------------------------------------------------------------------------------------------------------- template -panic::tensor::matrix exp(const panic::tensor::matrix& A){ +panic::tensor::matrix log(const panic::tensor::matrix& A){ panic::tensor::matrix C; - if (!exp(A, C)){ + if (!log(A, C)){ return panic::tensor::matrix(); } @@ -290,7 +380,7 @@ panic::tensor::matrix exp(const panic::tensor::matrix& A){ // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- template panic::tensor::matrix - exp(const panic::tensor::matrix& A + log(const panic::tensor::matrix& A ); diff --git a/src/math/max.cpp b/src/math/max.cpp index 2317b87..833cd72 100644 --- a/src/math/max.cpp +++ b/src/math/max.cpp @@ -36,7 +36,7 @@ // INCLUDE DESCRIPTION //----------------------------------------------------------------------------------------------------- -#include +#include #include #include // for panic::vector diff --git a/src/math/mean.cpp b/src/math/mean.cpp index 3103990..3aa0ed8 100644 --- a/src/math/mean.cpp +++ b/src/math/mean.cpp @@ -38,6 +38,7 @@ #include #include +#include #include // for panic::vector #include // for panic::matrix @@ -69,11 +70,11 @@ namespace panic { // Find the mean value for a vector //-------------------------------------------------------------------------------------------------------------------------- template -T mean(const panic::tensor::vector& a){ +panic::types::real_t mean(const panic::tensor::vector& a){ - T sum = panic::math::sum(a); + const panic::types::real_t sum = static_cast(panic::math::sum(a)); - return sum / static_cast(a.size()); + return sum / static_cast(a.size()); } //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION @@ -81,9 +82,9 @@ T mean(const panic::tensor::vector& a){ // The implementation is in this .cpp file. // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- -template panic::types::uint_t mean(const panic::tensor::vector& a +template panic::types::real_t mean(const panic::tensor::vector& a ); -template panic::types::int_t mean(const panic::tensor::vector& a +template panic::types::real_t mean(const panic::tensor::vector& a ); template panic::types::real_t mean(const panic::tensor::vector& a ); @@ -97,15 +98,15 @@ template panic::types::real_t mean(const panic::tensor::ve // Find the mean value for a matrix //-------------------------------------------------------------------------------------------------------------------------- template -T mean(const panic::tensor::matrix& A){ +panic::types::real_t mean(const panic::tensor::matrix& A){ panic::types::uint_t rows = A.rows(); panic::types::uint_t cols = A.cols(); panic::types::uint_t work = rows*cols; - T sum = panic::math::sum(A); + panic::types::real_t sum = static_cast (panic::math::sum(A)); - return sum / static_cast(work); + return sum / static_cast(work); } //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION @@ -113,9 +114,9 @@ T mean(const panic::tensor::matrix& A){ // The implementation is in this .cpp file. // Build the overload for the official PANIC numeric types. //-------------------------------------------------------------------------------------------------------------------------- -template panic::types::uint_t mean(const panic::tensor::matrix& a +template panic::types::real_t mean(const panic::tensor::matrix& a ); -template panic::types::int_t mean(const panic::tensor::matrix& a +template panic::types::real_t mean(const panic::tensor::matrix& a ); template panic::types::real_t mean(const panic::tensor::matrix& a ); @@ -130,8 +131,8 @@ template panic::types::real_t mean(const panic::tensor::ma // Description: // Find the mean row-wise of a matrix //-------------------------------------------------------------------------------------------------------------------------- -template -bool mean_rowwise(const panic::tensor::matrix& A, panic::tensor::vector& b){ +//template +bool mean_rowwise(const panic::tensor::real_matrix& A, panic::tensor::real_vector& b){ panic::types::uint_t rows = A.rows(); panic::types::uint_t cols = A.cols(); @@ -154,7 +155,7 @@ bool mean_rowwise(const panic::tensor::matrix& A, panic::tensor::vector& b } return true; -} +}/* //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION // @@ -170,7 +171,7 @@ template bool mean_rowwise(const panic::tensor::matrix(const panic::tensor::matrix& A, panic::tensor::vector& b ); - +*/ @@ -180,16 +181,16 @@ template bool mean_rowwise(const panic::tensor::matrix -panic::tensor::vector mean_rowwise(const panic::tensor::matrix& A){ - panic::tensor::vector b; +//template +panic::tensor::real_vector mean_rowwise(const panic::tensor::real_matrix& A){ + panic::tensor::real_vector b; if (!mean_rowwise(A, b)){ - return panic::tensor::vector(); + return panic::tensor::real_vector(); } return b; -} +}/* //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION // @@ -204,7 +205,7 @@ template panic::tensor::vector ); template panic::tensor::vector mean_rowwise(const panic::tensor::matrix& A -); +);*/ @@ -237,8 +238,8 @@ template panic::tensor::vector // Description: // Find the mean column-wise of a matrix //-------------------------------------------------------------------------------------------------------------------------- -template -bool mean_colwise(const panic::tensor::matrix& A, panic::tensor::vector& b){ +//template +bool mean_colwise(const panic::tensor::real_matrix& A, panic::tensor::real_vector& b){ panic::types::uint_t rows = A.rows(); panic::types::uint_t cols = A.cols(); @@ -259,7 +260,7 @@ bool mean_colwise(const panic::tensor::matrix& A, panic::tensor::vector& b } return true; -} +}/* //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION // @@ -274,7 +275,7 @@ template bool mean_colwise(const panic::tensor::matrix(const panic::tensor::matrix& A, panic::tensor::vector& b -); +);*/ @@ -285,16 +286,16 @@ template bool mean_colwise(const panic::tensor::matrix -panic::tensor::vector mean_colwise(const panic::tensor::matrix& A){ - panic::tensor::vector b; +//template +panic::tensor::real_vector mean_colwise(const panic::tensor::real_matrix& A){ + panic::tensor::real_vector b; if (!mean_colwise(A, b)){ - return panic::tensor::vector(); + return panic::tensor::real_vector(); } return b; -} +}/* //-------------------------------------------------------------------------------------------------------------------------- // EXPLICIT TEMPLATE INSTANTIATION // @@ -309,7 +310,7 @@ template panic::tensor::vector ); template panic::tensor::vector mean_colwise(const panic::tensor::matrix& A -); +);*/ } // namespace math diff --git a/src/math/transpose.cpp b/src/math/transpose.cpp new file mode 100644 index 0000000..574eb84 --- /dev/null +++ b/src/math/transpose.cpp @@ -0,0 +1,146 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: math + * File Name: transpose.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to transpose a matrix; + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +//--------------------------------------------------------------------------------------------------------------------------- +// INCLUDE DESCRIPTION +//----------------------------------------------------------------------------------------------------- +#include +#include + +#include // for panic::tensor::matrix + + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t transpose_omp_min_work = 500; + +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace math { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::transpose +// +// Description: +// Transposes a matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool transpose(const panic::tensor::matrix& A, panic::tensor::matrix& B){ + + panic::types::uint_t rows = A.rows(); + panic::types::uint_t cols = A.cols(); + panic::types::uint_t work = rows*cols; + + if ( !B.resize(cols, rows) ){ + return false; + } + + + PANIC_OMP_PARALLEL_FOR_IF(work > transpose_omp_min_work) + for (panic::types::uint_t i = 0; i < rows; ++i){ + for (panic::types::uint_t j = 0; j < cols; ++j){ + B(j,i) = A(i,j); + } + + } + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool transpose(const panic::tensor::matrix& A, + panic::tensor::matrix& B +); +template bool transpose(const panic::tensor::matrix& A, + panic::tensor::matrix& B +); +template bool transpose(const panic::tensor::matrix& A, + panic::tensor::matrix& B +); + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::dot +// +// Description: +// Multiply sum a matrix and vector +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix transpose(const panic::tensor::matrix& A){ + + panic::tensor::matrix B; + + if (! transpose(A,B)){ + return panic::tensor::matrix(); + } + + + + return B; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix transpose( + const panic::tensor::matrix& A +); + +template panic::tensor::matrix transpose( + const panic::tensor::matrix& A +); +template panic::tensor::matrix transpose( + const panic::tensor::matrix& A +); + + + } // namespace math +} // namespace panic diff --git a/src/neural_network/activation/activation_relu.cpp b/src/neural_network/activation/activation_relu.cpp index 6a9f093..c2a849e 100644 --- a/src/neural_network/activation/activation_relu.cpp +++ b/src/neural_network/activation/activation_relu.cpp @@ -76,7 +76,9 @@ activation_relu::activation_relu() { // Calculated the forward pass: // outputs = max(inputs, 0) //-------------------------------------------------------------------------------------------------------------------------- -bool activation_relu::forward(const panic::tensor::real_matrix& inputs){ +bool activation_relu::forward(const panic::tensor::real_matrix& input_data){ + + inputs = input_data; panic::math::clip_lower(inputs, 0.0f, outputs); @@ -92,7 +94,11 @@ bool activation_relu::forward(const panic::tensor::real_matrix& inputs){ // Calculated the backward pass: // ?? //-------------------------------------------------------------------------------------------------------------------------- -bool activation_relu::backward(const panic::tensor::real_matrix& dinputs){ +bool activation_relu::backward(const panic::tensor::real_matrix& dvalues){ + + // Zero gradients where input values were negative + panic::types::real_t zero = 0; + dinputs = panic::math::clip_lower(dvalues, zero); return true; diff --git a/src/neural_network/activation/activation_softmax.cpp b/src/neural_network/activation/activation_softmax.cpp index 7c47916..220ea1b 100644 --- a/src/neural_network/activation/activation_softmax.cpp +++ b/src/neural_network/activation/activation_softmax.cpp @@ -80,7 +80,9 @@ activation_softmax::activation_softmax() { // Calculated the forward pass: // outputs = max(inputs, 0) //-------------------------------------------------------------------------------------------------------------------------- -bool activation_softmax::forward(const panic::tensor::real_matrix& inputs){ +bool activation_softmax::forward(const panic::tensor::real_matrix& input_data){ + + inputs = input_data; panic::tensor::real_vector row_maximums; panic::tensor::real_vector row_sums; @@ -133,9 +135,30 @@ bool activation_softmax::forward(const panic::tensor::real_matrix& inputs){ // Calculated the backward pass: // ?? //-------------------------------------------------------------------------------------------------------------------------- -bool activation_softmax::backward(const panic::tensor::real_matrix& dinputs){ +bool activation_softmax::backward(const panic::tensor::real_matrix& dvalues){ + const panic::types::uint_t rows = dvalues.rows(); + const panic::types::uint_t cols = dvalues.cols(); + const panic::types::uint_t work = rows*cols; + if (outputs.rows() != rows || outputs.cols() != cols ){ + return false; + } + + if (!dinputs.resize(rows, cols)){ + return false; + } + + PANIC_OMP_PARALLEL_FOR_IF(work > activation_softmax_omp_min_size) + for (panic::types::uint_t i = 0; i < rows; ++i){ + panic::types::real_t dot = 0; + for (panic::types::uint_t j = 0; j < cols; ++j){ + dot += outputs(i,j) * dvalues(i,j); + } + for (panic::types::uint_t j = 0; j < cols; ++j){ + dinputs(i,j) = outputs(i,j) * (dvalues(i,j) -dot); + } + } return true; } diff --git a/src/neural_network/layer/layer_dense.cpp b/src/neural_network/layer/layer_dense.cpp index d8c7210..6e88d76 100644 --- a/src/neural_network/layer/layer_dense.cpp +++ b/src/neural_network/layer/layer_dense.cpp @@ -43,6 +43,9 @@ #include #include +#include +#include + //--------------------------------------------------------------------------------------------------------------------------- // PRIVATE CONSTANTS //--------------------------------------------------------------------------------------------------------------------------- @@ -70,7 +73,8 @@ namespace panic{ layer_dense::layer_dense() { weights.resize(0,0); biases.resize(0); - outputs.resize(0,0); + dweights.resize(0,0); + dbiases.resize(0); } //-------------------------------------------------------------------------------------------------------------------------- @@ -86,9 +90,7 @@ layer_dense::layer_dense(panic::types::uint_t input_size, panic::types::uint_t n biases.resize(neurons); biases.fill(0); - //panic::random::uniform(biases); - - outputs.resize(0,0); + } @@ -99,7 +101,9 @@ layer_dense::layer_dense(panic::types::uint_t input_size, panic::types::uint_t n // Calculated the forward pass: // outputs = inputs * weights + biases //-------------------------------------------------------------------------------------------------------------------------- -bool layer_dense::forward(const panic::tensor::real_matrix& inputs){ +bool layer_dense::forward(const panic::tensor::real_matrix& input_data){ + + inputs = input_data; if (inputs.cols() != weights.rows()){ return false; @@ -128,9 +132,16 @@ bool layer_dense::forward(const panic::tensor::real_matrix& inputs){ // Calculated the backward pass: // ?? //-------------------------------------------------------------------------------------------------------------------------- -bool layer_dense::backward(const panic::tensor::real_matrix& dinputs){ +bool layer_dense::backward(const panic::tensor::real_matrix& dvalues){ + // Gradients on parameters + dweights = panic::math::matmul(panic::math::transpose(inputs), dvalues); + dbiases = panic::math::sum_colwise(dvalues); + + // Gradients on values + dinputs = panic::math::matmul(dvalues, panic::math::transpose(weights)); + return true; } diff --git a/src/neural_network/loss/loss.cpp b/src/neural_network/loss/loss.cpp index 33ac345..7e89592 100644 --- a/src/neural_network/loss/loss.cpp +++ b/src/neural_network/loss/loss.cpp @@ -95,7 +95,8 @@ bool loss::calculate( return false; } - //return calculate_mean(); + data_loss = panic::math::mean(sample_losses); + return true; } diff --git a/src/neural_network/loss/loss_categorical_crossentropy.cpp b/src/neural_network/loss/loss_categorical_crossentropy.cpp index ff4229a..c57443a 100644 --- a/src/neural_network/loss/loss_categorical_crossentropy.cpp +++ b/src/neural_network/loss/loss_categorical_crossentropy.cpp @@ -40,8 +40,13 @@ #include // panic::tensor::real_matrix (uint_matrix, int_matrix) #include -#include +#include +#include +#include +#include +#include +#include //--------------------------------------------------------------------------------------------------------------------------- // PRIVATE CONSTANTS @@ -53,6 +58,11 @@ * worker threads can be larger than the work itself. */ static const panic::types::uint_t loss_categorical_crossentropy_omp_min_size = 500; + +static const panic::types::real_t clip_min = 1e-7; +static const panic::types::real_t clip_max = 1 - 1e-7; +static const panic::types::real_t neg = -1; + //--------------------------------------------------------------------------------------------------------------------------- @@ -63,13 +73,47 @@ namespace panic{ // Function Name : panic::neural_network::loss_categorical_crossentropy::forward // // Description: -// Default implementation. Derived classes can override it. +// Default implementation for catecorical labels. Derived classes can override it. //-------------------------------------------------------------------------------------------------------------------------- bool loss_categorical_crossentropy::forward( const panic::tensor::real_matrix& y_pred, const panic::tensor::uint_vector& y_true){ - return false; + // Number of samples in a batch + const panic::types::uint_t samples = y_pred.rows(); + + if (samples != y_true.size()){ + return false; + } + + + // clip data to prevent log by 0 + // Clip both sides to not drag the mean towards any value + panic::tensor::real_matrix y_pred_cliped = panic::math::clip(y_pred, clip_min, clip_max); + + // Vector to hold the correct confidences + panic::tensor::real_vector correct_confidences(samples); + + PANIC_OMP_PARALLEL_FOR_IF(samples > loss_categorical_crossentropy_omp_min_size) + for (panic::types::uint_t i = 0; i < samples; ++i){ + const panic::types::uint_t idx = y_true[i]; + + //if (idx >= y_pred.cols()){ + // return false; + //} + + correct_confidences[i] = y_pred_cliped(i, idx); + } + + // Calculate losses + panic::tensor::real_vector negative_log_likelihoos(samples); + + negative_log_likelihoos = panic::math::mul(panic::math::log(correct_confidences), neg); + + sample_losses = negative_log_likelihoos; + + + return true; } @@ -77,16 +121,120 @@ bool loss_categorical_crossentropy::forward( // Function Name : panic::neural_network::loss_categorical_crossentropy::forward // // Description: -// Default matrix-target implementation. Derived classes can override it. +// Default one-hot encoded labels implementation. Derived classes can override it. //-------------------------------------------------------------------------------------------------------------------------- bool loss_categorical_crossentropy::forward( const panic::tensor::real_matrix& y_pred, const panic::tensor::real_matrix& y_true){ - return false; + + if (y_pred.rows() != y_true.rows() || y_pred.cols() != y_true.cols()){ + return false; + } + + // Number of samples in a batch + const panic::types::uint_t samples = y_pred.rows(); + + + // clip data to prevent log by 0 + // Clip both sides to not drag the mean towards any value + panic::tensor::real_matrix y_pred_cliped = panic::math::clip(y_pred, clip_min, clip_max); + + // Vector to hold the correct confidences + panic::tensor::real_vector correct_confidences(samples); + + + correct_confidences = panic::math::sum_rowwise(panic::math::mul(y_pred_cliped, y_true)); + + + // Calculate losses + panic::tensor::real_vector negative_log_likelihoos(samples); + + negative_log_likelihoos = panic::math::mul(panic::math::log(correct_confidences), neg); + + sample_losses = negative_log_likelihoos; + + return true; } + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::neural_network::loss_categorical_crossentropy::backward +// +// Description: +// Default implementation for catecorical labels. Derived classes can override it. +//-------------------------------------------------------------------------------------------------------------------------- +bool loss_categorical_crossentropy::backward( + const panic::tensor::real_matrix& dvalues, + const panic::tensor::uint_vector& y_true){ + + if (dvalues.rows() == 0 || dvalues.cols() == 0 || y_true.size() != dvalues.rows()){ + return false; + } + + panic::tensor::real_matrix y_true_one_hot; + + // Transforms it to one_hot + if (! panic::tensor::one_hot(dvalues.cols(), y_true, y_true_one_hot)){ + return false; + } + + // Uses other backward overloaded function to handle the rest. + return backward(dvalues, y_true_one_hot); +} + + + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::neural_network::loss_categorical_crossentropy::backward +// +// Description: +// Default one-hot encoded labels implementation. Derived classes can override it. +//-------------------------------------------------------------------------------------------------------------------------- +bool loss_categorical_crossentropy::backward( + const panic::tensor::real_matrix& dvalues, + const panic::tensor::real_matrix& y_true){ + + // Number of samples + const panic::types::uint_t samples = dvalues.rows(); + + if (samples == 0 || dvalues.cols() == 0 || y_true.rows() != dvalues.rows() || y_true.cols() != dvalues.cols()){ + return false; + } + + // dinputs = y_true / dvalues + if (!panic::math::div(y_true, dvalues, dinputs)){ + return false; + } + + // scale = -1 / samples + const panic::types::real_t scale = -static_cast(1) / static_cast(samples); + + + // dinputs *= scale + if (!panic::math::mul(dinputs, scale, dinputs)){ + return false; + } + + return true; +} + + + + + + + + + + + + + } // namespace tensor } // namespace panic diff --git a/src/tensor/generators/eye.cpp b/src/tensor/generators/eye.cpp new file mode 100644 index 0000000..6f7f912 --- /dev/null +++ b/src/tensor/generators/eye.cpp @@ -0,0 +1,141 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: tensor + * File Name: eye.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to generate eye matrices + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#include +#include + +#include // for panic::vector +#include // for panic::matrix + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t eye_omp_min_work = 500; +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace tensor { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::tensor::eye +// +// Description: +// Creates a eye matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool eye(const panic::types::uint_t size, panic::tensor::matrix& A){ + + if (!A.resize(size,size)){ + return false; + } + + PANIC_OMP_PARALLEL_FOR_IF(size*size > eye_omp_min_work) + for (panic::types::uint_t i = 0; i < size; ++i){ + for (panic::types::uint_t j = 0; j < size; ++j){ + if (i == j){ + A(i,j) = T{1}; + } + else{ + A(i,j) = T{0}; + } + } + } + + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool eye(const panic::types::uint_t size, + panic::tensor::matrix& A +); +template bool eye(const panic::types::uint_t size, + panic::tensor::matrix& A +); +template bool eye(const panic::types::uint_t size, + panic::tensor::matrix& A +); + +/* + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::eye +// +// Description: +// Retuens a eye matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix eye(const T size){ + + panic::tensor::matrix A(static_cast(size), static_cast(size)); + + if (!eye(A.rows(), A)){ + return panic::tensor::matrix(); + } + + return A; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix eye(const panic::types::uint_t size +); +template panic::tensor::matrix eye(const panic::types::int_t size +); +template panic::tensor::matrix eye(const panic::types::real_t size +); + +*/ + + + + +} // namespace tensor +} // namespace panic \ No newline at end of file diff --git a/src/tensor/generators/one_hot.cpp b/src/tensor/generators/one_hot.cpp new file mode 100644 index 0000000..839dc93 --- /dev/null +++ b/src/tensor/generators/one_hot.cpp @@ -0,0 +1,154 @@ +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * + * PANIC + * Portable Algorithms and Numerics In C++ + * + * Scientific computing from scratch, with feeling. + * + * Copyright (c) 2026 Michelle Bausager + * + * This file is part of PANIC. + * + * PANIC is free software licensed under the GNU General Public License v3.0 or later. + * You may redistribute and/or modify it under the terms of the GPL. + * + * PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the LICENSE file for the full license text. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Project Name: PANIC + * Module Name: tensor + * File Name: one_hot.hpp + * Revision: 0.1.0 + * Date: 31-07-2026 + * Author: Michelle Bausager + * + * Description: + * Functions to generate one_hot matrices + * + *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#include +#include +#include + +#include // for panic::vector +#include // for panic::matrix + +//--------------------------------------------------------------------------------------------------------------------------- +// PRIVATE CONSTANTS +//--------------------------------------------------------------------------------------------------------------------------- +/** + * @brief Minimum number of element operations before using the OpenMP-enabled loop. + * + * Small vectors and matrices are kept serial because the overhead of starting + * worker threads can be larger than the work itself. + */ +static const panic::types::uint_t one_hot_omp_min_work = 500; +//--------------------------------------------------------------------------------------------------------------------------- +// INPLEMENTATION +//--------------------------------------------------------------------------------------------------------------------------- + +namespace panic { + namespace tensor { + + +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::tensor::one_hot +// +// Description: +// Creates a one_hot matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +bool one_hot(const panic::types::uint_t size, const panic::tensor::uint_vector & a, panic::tensor::matrix& B){ + + if (!B.resize(size,size)){ + return false; + } + + if (size != a.size()){ + return false; + } + + PANIC_OMP_PARALLEL_FOR_IF(size*size > one_hot_omp_min_work) + for (panic::types::uint_t i = 0; i < size; ++i){ + for (panic::types::uint_t j = 0; j < size; ++j){ + if (a[i] == j){ + B(i,j) = T{1}; + } + else{ + B(i,j) = T{0}; + } + } + } + + + return true; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template bool one_hot(const panic::types::uint_t size, + const panic::tensor::uint_vector& a, + panic::tensor::matrix& B +); +template bool one_hot(const panic::types::uint_t size, + const panic::tensor::uint_vector& a, + panic::tensor::matrix& B +); +template bool one_hot(const panic::types::uint_t size, + const panic::tensor::uint_vector& a, + panic::tensor::matrix& B +); + + +/* +//-------------------------------------------------------------------------------------------------------------------------- +// Function Name : panic::math::one_hot +// +// Description: +// Retuens a one_hot matrix +//-------------------------------------------------------------------------------------------------------------------------- +template +panic::tensor::matrix one_hot(const panic::types::uint_t size, const panic::tensor::uint_vector& a){ + + panic::tensor::matrix B(size, size); + + if (!one_hot(size, a, B)){ + return panic::tensor::matrix(); + } + + return B; +} +//-------------------------------------------------------------------------------------------------------------------------- +// EXPLICIT TEMPLATE INSTANTIATION +// +// The implementation is in this .cpp file. +// Build the overload for the official PANIC numeric types. +//-------------------------------------------------------------------------------------------------------------------------- +template panic::tensor::matrix one_hot(const panic::types::uint_t size, + const panic::tensor::vector& a + +); +template panic::tensor::matrix one_hot(const panic::types::uint_t size, + const panic::tensor::vector& a + +); +template panic::tensor::matrix one_hot(const panic::types::uint_t size, + const panic::tensor::vector& a +); + +*/ + + + + +} // namespace tensor +} // namespace panic \ No newline at end of file