Can ChatGPT Self-Improve Self-Written Python Code for Cholesky Decomposition?

It is needless to say about next big thing in the field of artificial intelligence (AI) known as ChatGPT. ChatGPT is a large language model developed by OpenAI. It is based on the GPT (Generative Pre-training Transformer) architecture and is trained on a massive dataset of text data. This allows it to generate human-like text and perform a wide range of natural language processing tasks, such as language translation, text summarization, and question answering.

One of the main advantages of ChatGPT is its ability to generate human-like text, which makes it useful for tasks such as writing essays, articles, and even code. It can be fine-tuned on specific tasks and domains, such as financial domain, allowing it to generate financial reports, financial predictions, code snippets and more.

The model is trained on a large dataset of text, which allows it to understand and generate text in a variety of styles and formats. It can also generate text based on a given prompt, making it useful for tasks such as text completion, text generation, and text summarisation.

1. ChatGPT for Quantitative Finance?

There is a lot of hype around the use of ChatGPT because it is a powerful and versatile language model that can perform a wide range of natural language processing tasks. ChatGPT can be useful in quantitative finance for several reasons:

  • Time-saving: it can generate code snippets quickly, allowing financial engineers and quantitative analysts to focus on more complex and high-level tasks.
  • Consistency and accuracy: it can generate code that is consistent and accurate, reducing the risk of errors in financial computations.
  • Flexibility: it can be used to generate code for a wide range of financial computations, from simple calculations to complex financial modeling.
  • Scalability: it can be used to generate code for large-scale financial computations, such as portfolio optimization or risk management.
  • Multi-language support: it can generate code in multiple programming languages, which allows for efficient and memory-friendly solutions for big computations.
  • Efficient use of historical data: it can help generate code that makes the most of historical data, which is crucial in quantitative finance, where past performance is used to predict future outcomes.
  • Repetitive task automation: it can help automate repetitive tasks, allowing financial engineers and quantitative analysts to focus on higher-level tasks and improve productivity.
    Cost-effective: it can help reduce costs by automating repetitive tasks, reducing human error and increasing productivity.

Overall, ChatGPT can help financial engineers and quantitative analysts to work more efficiently, accurately and effectively, which can lead to better decision making and improved performance in financial markets.

2. So, Is It Reasonable to Use ChatGPT for Writing Python Code for Financial Applications?

ChatGPT can be used to write Python code for financial applications by providing concise, accurate and efficient code snippets for various financial computations. Some examples of financial computations that can be done using ChatGPT include:

  • Calculation of portfolio profit and loss
  • Calculation of VaR (Value at Risk) and Liquidity VaR
  • Calculation of expected shortfall for a portfolio
  • Arbitrage on two FX currency pairs
  • Cholesky decomposition for a given matrix
  • Calculation of portfolio value given different trading strategies
  • Filtering of noisy correlations in a correlation matrix
  • Calculation of average loss for a cryptocurrency based on past performance

ChatGPT can also be used to generate code in other languages like Rust, providing solutions that are efficient and memory-friendly. Rust, right after Solidity, it the language of choice for all recently-born blockchain developers, allowing Decentralised Finance (DeFi) application to blossom.

It is important to note that the ChatGPT model is only able to provide the code based on the knowledge it has been trained on, and the performance of the generated code depends on the quality of the input data and the specific use case. It is always recommended to test and verify the generated code before using it in production environments.

3. Speaking of, Cholesky Decomposition. What code it can generate?

Cholesky decomposition is a method for decomposing a Hermitian, positive-definite matrix into the product of a lower triangular matrix and its conjugate transpose, which is useful for efficient numerical solutions, such as Monte Carlo simulations.

Here is an example delivered by the model of a Python script that performs Cholesky decomposition on a matrix:

import numpy as np

def cholesky(matrix):
    """
    Perform Cholesky decomposition on a matrix
    :param matrix: Square matrix to decompose
    :return: Lower triangular matrix L
    """
    n = matrix.shape[0]
    L = np.zeros((n, n))
    for i in range(n):
        for j in range(i+1):
            temp = sum(L[i][k] * L[j][k] for k in range(j))
            if i == j:
                L[i][j] = np.sqrt(matrix[i][i] - temp)
            else:
                L[i][j] = (1.0 / L[j][j] * (matrix[i][j] - temp))
    return L

# Example usage
matrix = np.array([[4, 12, -16], [12, 37, -43], [-16, -43, 98]])
L = cholesky(matrix)
print(L)

In the above script the matrix is passed as an argument to the function cholesky() which decomposes the matrix and returns the lower triangular matrix.
Please note that the matrix passed to the function should be Hermitian, Positive-definite.

4. Code Self-Improved, Optimised for Speed?

It look like it can be done, too! In this can all we need is to ask politely ChatGPT “Can you rewrite the following function optimised for speed, please?” pasting the above script. Its response is quite optimistic, saying “There are multiple ways to optimize the function for speed, here is one possible way:”

import numpy as np

def cholesky(matrix):
    """
    Perform Cholesky decomposition on a matrix
    :param matrix: Square matrix to decompose
    :return: Lower triangular matrix L
    """
    n = matrix.shape[0]
    L = np.zeros((n, n))
    for i in range(n):
        L[i][i] = np.sqrt(matrix[i][i] - np.dot(L[i, :i], L[i, :i]))
        for j in range(i+1, n):
            L[j][i] = (matrix[j][i] - np.dot(L[i, :i], L[j, :i])) / L[i][i]
    return L

This implementation uses numpy’s dot product function which is implemented in C and is therefore faster than using a Python for loop. This way it reduces the time complexity of the function and makes it faster.

Additionally, the function uses only one for loop to calculate both the upper and lower triangular matrix. It also calculates the diagonal element of the matrix at the same time, which reduces the number of operations and improves performance.

5. Second Derivative, i.e. How to Self-Self-Improve Itself?

I have never thought I would be writing an article on such a bizarre topic. Never, ever, in my life. Until today! I asked again “Can you rewrite the above function in order to make it run faster, please?” And guess what? That soulless soul told me “Here is one possible way to optimize the function for speed:”

import numpy as np

def cholesky(matrix):
    """
    Perform Cholesky decomposition on a matrix
    :param matrix: Square matrix to decompose
    :return: Lower triangular matrix L
    """
    n = matrix.shape[0]
    L = np.zeros((n, n))
    for i in range(n):
        L[i, i:] = matrix[i, i:] - np.dot(L[:i, i:], L[:i, i:].T)
        L[i, i:] /= L[i, i]
    return L

This implementation uses array slicing to access specific parts of the matrix and perform operations on them, which reduces the number of operations and improves performance.

6. Back to the Class-room?

My desire for asking and learning more continues with my next question “Can you rewrite that function in Python as a class and add n as an input parameter provider by the user?” Again, two seconds of “thinking” and this guy start printing:

import numpy as np

class CholeskyDecomposition:
    def __init__(self, n):
        self.n = n
    def decompose(self, matrix):
        """
        Perform Cholesky decomposition on a matrix
        :param matrix: Square matrix to decompose
        :return: Lower triangular matrix L
        """
        L = np.zeros((self.n, self.n))
        for i in range(self.n):
            L[i, i:] = matrix[i, i:] - np.dot(L[:i, i:], L[:i, i:].T)
            L[i, i:] /= L[i, i]
        return L
        
# Example usage:
n = 3
matrix = np.array([[4, 12, -16], [12, 37, -43], [-16, -43, 98]])
cholesky_decomposition = CholeskyDecomposition(n)
L = cholesky_decomposition.decompose(matrix)
print(L)

In this example, the user provides the value of n to the class constructor and the class uses it to define the shape of the matrix. This way the user can control the size of the matrix, and the class will be able to operate with any square matrix.

7. Parlez Vous Français?

Now an icing on the cake. It is 2023 and programming in Python became boring and too popular. If you want to feel the thrill and some adrenaline, go to France, try communication with other people using different language! What I’m trying to say here is that taking Python code and translating it into, for example Rust language, now, is no longer an issue. Have a look. Just ask again “Rewrite the following Python function in Rust language, please.” I do like to add “, please” at the end to get that personal touch to human-model conversation. I hope you know what I mean…

Here is an example of the Cholesky decomposition function implemented in Rust – the response appears without hesitation, followed by the code:

use ndarray::{Array, Array2};
use ndarray_linalg::cholesky::cholesky_unpack;

fn cholesky(matrix: Array2<f64>) -> Array2<f64> {
    let (l, _) = cholesky_unpack(matrix);
    l
}

// Example usage:
let matrix = array![[4.0, 12.0, -16.0], [12.0, 37.0, -43.0], [-16.0, -43.0, 98.0]];
let L = cholesky(matrix);
println!("{}", L);

Note that this example uses the ndarray and ndarray_linalg crates, which provide functionality for working with arrays and performing linear algebra operations. In this example, the input matrix is passed to the cholesky_unpack function from ndarray_linalg crate, which returns a tuple of lower triangular matrix and its transpose. The lower triangular matrix is then returned. This implementation is more concise and efficient than the previous one because it uses the optimized linear algebra libraries and doesn’t require to iterate and perform the calculations manually.

They say, in Rust you cannot do quantitative matrix operations! Not true! I ask ChatGPT for the last time “Write code in Rust performing Cholesky decomposiiton for matrix of size 500 by 500” followed by repeated but reordered feedback “Here is an example of how to perform Cholesky decomposition on a matrix of size 500×500 in Rust:”

use ndarray::{Array, Array2};
use ndarray_linalg::cholesky::cholesky_unpack;

fn cholesky(matrix: Array2<f64>) -> Array2<f64> {
    let (l, _) = cholesky_unpack(matrix);
    l
}

fn main() {
    let mut matrix = Array::zeros((500, 500));
    // Fill the matrix with some values
    // ...
    let L = cholesky(matrix);
    println!("{}", L);
}

In this example, we first create a 2D array of size 500×500 using the Array::zeros function from the ndarray crate. Then we fill the matrix with some values, it could be from reading from a file or from some other calculation. Then we pass the matrix to the cholesky_unpack function from ndarray_linalg crate, which returns a tuple of lower triangular matrix and its transpose. The lower triangular matrix is then returned and printed. As we are working with a big matrix, it is recommended to use this implementation as it uses the optimized linear algebra libraries and doesn’t require to iterate and perform the calculations manually.

Amazing!?

Now I’ll go and check if all these code lines actually work?! ;-)

chatgpt quantatrisk

 

Explore Further

ChatGPT by Wiki
Czekanowski Index-Based Similarity as Alternative Correlation Measure in N-Asset Portfolio Analysis

1 comment
Leave a Reply

Your email address will not be published. Required fields are marked *