<commit_before>#!/usr/bin/env python

import numpy as np
from scipy import sparse
import pandas as pd
import os
import os.path
import matrix_io as mio
from glob import glob
import re
import csv

try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import SafeConfigParser as ConfigParser

from .result import Prediction

def read_config_file(file_name, dir_name = None):
    cp = ConfigParser()

    if dir_name:
        full_name = os.path.join(dir_name, file_name)
    else:
        full_name = file_name

    with open(full_name) as f:
        try:
            cp.read_file(f, full_name)
        except AttributeError:
            cp.readfp(f, full_name)

    return cp

class Sample:
    @classmethod
    def fromStepFile(cls, file_name, dir_name):
        cp = read_config_file(file_name, dir_name)
        nmodes = int(cp["global"]["num_modes"])
        iter = int(cp["global"]["number"])
        sample = cls(nmodes, iter)

        # latent matrices
        for i in range(sample.nmodes):
            file_name = os.path.join(dir_name, cp["latents"]["latents_" + str(i)])
            sample.add_latent(mio.read_matrix(file_name))

        # link matrices (beta)
        for i in range(sample.nmodes):
            file_name = cp["link_matrices"]["link_matrix_" + str(i)]
            if (file_name != 'none'):
                sample.add_beta(mio.read_matrix(os.path.join(dir_name, file_name)))
            else:
                sample.add_beta(np.ndarray((0, 0)))

        return sample

    def __init__(self, nmodes, iter):
        assert nmodes == 2
        self.nmodes = nmodes
        self.iter = iter
        self.latents = []
        self.latent_means = []
        self.betas = []

    def check(self):
        for l, b in zip(self.latents, self.betas):
            assert l.shape[0] == self.num_latent()
            assert b.shape[0] == 0 or b.shape[0] == self.num_latent()

    def add_beta(self, b):
        self.betas.append(b)
        self.check()

    def add_latent(self, U):
        self.latents.append(U)
        self.latent_means.append(np.mean(U, axis=1))
        self.check()

    def num_latent(self):
       return self.latents[0].shape[0]

    def data_shape(self):
       return [u.shape[1] for u in self.latents]

    def beta_shape(self):
       return [b.shape[1] for b in self.betas]

    def predict(self, coords_or_sideinfo=None):
        # for one prediction: einsum(U[:,coords[0]], [0], U[:,coords[1]], [0], ...)
        # for all predictions: einsum(U[0], [0, 0], U[1], [0, 1], U[2], [0, 2], ...)

        cs = coords_or_sideinfo if coords_or_sideinfo is not None else [
            None] * self.nmodes

        operands = []
        for U, Umean, c, m in zip(self.latents, self.latent_means, cs, range(self.nmodes)):
            # predict all in this dimension
            if c is None:
                operands += [U, [0, m+1]]
            else:
                # if side_info was specified for this dimension, we predict for this side_info
                try:  # try to compute sideinfo * beta using dot
                    # compute latent vector from side_info
                    uhat = c.dot(self.betas[m].transpose()) + Umean
                    uhat = np.squeeze(uhat)
                    operands += [uhat, [0]]
                except AttributeError:  # assume it is a coord
                    # if coords was specified for this dimension, we predict for this coord
                    operands += [U[:, c], [0]]

        return np.einsum(*operands)


class PredictSession:
    """Session for making predictions using a model generated using a :class:`TrainSession`.

    A :class:`PredictSession` can be made directly from a :class:`TrainSession`

    >>> predict_session  = train_session.makePredictSession()

    or from a root file

    >>> predict_session = PredictSession.fromRootFile("root.ini")
<commit_msg>FIX: Do we need Umean in predict???<commit_after>#!/usr/bin/env python

import numpy as np
from scipy import sparse
import pandas as pd
import os
import os.path
import matrix_io as mio
from glob import glob
import re
import csv

try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import SafeConfigParser as ConfigParser

from .result import Prediction

def read_config_file(file_name, dir_name = None):
    cp = ConfigParser()

    if dir_name:
        full_name = os.path.join(dir_name, file_name)
    else:
        full_name = file_name

    with open(full_name) as f:
        try:
            cp.read_file(f, full_name)
        except AttributeError:
            cp.readfp(f, full_name)

    return cp

class Sample:
    @classmethod
    def fromStepFile(cls, file_name, dir_name):
        cp = read_config_file(file_name, dir_name)
        nmodes = int(cp["global"]["num_modes"])
        iter = int(cp["global"]["number"])
        sample = cls(nmodes, iter)

        # latent matrices
        for i in range(sample.nmodes):
            file_name = os.path.join(dir_name, cp["latents"]["latents_" + str(i)])
            sample.add_latent(mio.read_matrix(file_name))

        # link matrices (beta)
        for i in range(sample.nmodes):
            file_name = cp["link_matrices"]["link_matrix_" + str(i)]
            if (file_name != 'none'):
                sample.add_beta(mio.read_matrix(os.path.join(dir_name, file_name)))
            else:
                sample.add_beta(np.ndarray((0, 0)))

        return sample

    def __init__(self, nmodes, iter):
        assert nmodes == 2
        self.nmodes = nmodes
        self.iter = iter
        self.latents = []
        self.latent_means = []
        self.betas = []

    def check(self):
        for l, b in zip(self.latents, self.betas):
            assert l.shape[0] == self.num_latent()
            assert b.shape[0] == 0 or b.shape[0] == self.num_latent()

    def add_beta(self, b):
        self.betas.append(b)
        self.check()

    def add_latent(self, U):
        self.latents.append(U)
        self.latent_means.append(np.mean(U, axis=1))
        self.check()

    def num_latent(self):
       return self.latents[0].shape[0]

    def data_shape(self):
       return [u.shape[1] for u in self.latents]

    def beta_shape(self):
       return [b.shape[1] for b in self.betas]

    def predict(self, coords_or_sideinfo=None):
        # for one prediction: einsum(U[:,coords[0]], [0], U[:,coords[1]], [0], ...)
        # for all predictions: einsum(U[0], [0, 0], U[1], [0, 1], U[2], [0, 2], ...)

        cs = coords_or_sideinfo if coords_or_sideinfo is not None else [
            None] * self.nmodes

        operands = []
        for U, Umean, c, m in zip(self.latents, self.latent_means, cs, range(self.nmodes)):
            # predict all in this dimension
            if c is None:
                operands += [U, [0, m+1]]
            else:
                # if side_info was specified for this dimension, we predict for this side_info
                try:  # try to compute sideinfo * beta using dot
                    # compute latent vector from side_info
                    uhat = c.dot(self.betas[m].transpose()) # ????? + Umean
                    uhat = np.squeeze(uhat)
                    operands += [uhat, [0]]
                except AttributeError:  # assume it is a coord
                    # if coords was specified for this dimension, we predict for this coord
                    operands += [U[:, c], [0]]

        return np.einsum(*operands)


class PredictSession:
    """Session for making predictions using a model generated using a :class:`TrainSession`.

    A :class:`PredictSession` can be made directly from a :class:`TrainSession`

    >>> predict_session  = train_session.makePredictSession()

    or from a root file

    >>> predict_session = PredictSession.fromRootFile("root.ini")

{'fraction_non_alphanumeric': 0.11392081736909324, 'fraction_numerical': 0.007407407407407408, 'mean_word_length': 2.2213081036610447, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '340132', 'n_tokens_mistral': 2541, 'n_tokens_neox': 2426, 'n_words': 668}