#Maximum Likelihood Ranking

import numpy as np

def maximum_likelihood_ranking(data):
    num_items = len(data)
    num_features = len(data[0])

    # Initialize the weight vector
    weights = np.ones(num_features)

    # Run the maximum likelihood estimation
    max_iterations = 1000  # Maximum number of iterations (adjust as needed)
    epsilon = 1e-6  # Convergence threshold (adjust as needed)
    for _ in range(max_iterations):
        old_weights = np.copy(weights)
        gradients = np.zeros(num_features)
        for i in range(num_items):
            xi = data[i]
            exp_sum = sum(np.exp(np.dot(weights, xj)) for j, xj in enumerate(data))
            for k in range(num_features):
                gradients[k] += xi[k] * np.exp(np.dot(weights, xi)) / exp_sum
        weights += gradients
        if np.linalg.norm(weights - old_weights) < epsilon:
            break

    # Normalize the weight vector
    weights /= np.linalg.norm(weights)

    # Sort the items based on the weight vector
    rankings = sorted(range(num_items), key=lambda i: np.dot(weights, data[i]), reverse=True)

    return rankings, weights

# Example usage
if __name__ == '__main__':
    # Define your data matrix where each row represents an item and each column represents a feature
    data = np.array([
        [1, 2, 3],
        [2, 1, 3],
        [3, 2, 1],
        [1, 3, 2]
    ])

    # Run the maximum likelihood ranking
    rankings, weights = maximum_likelihood_ranking(data)

    # Print the results
    print("Rankings:", rankings)
    print("Weights:", weights)
