/*
* Copyright (C) 2016 RankSys http://ranksys.org
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.ranksys.diversity.intentaware;
import cern.colt.matrix.DoubleMatrix1D;
import cern.colt.matrix.DoubleMatrix2D;
import cern.jet.math.Functions;
import es.uam.eps.ir.ranksys.diversity.intentaware.AspectModel;
import es.uam.eps.ir.ranksys.diversity.intentaware.IntentModel;
import es.uam.eps.ir.ranksys.fast.feature.FastFeatureData;
import es.uam.eps.ir.ranksys.fast.preference.FastPreferenceData;
import org.ranksys.core.util.tuples.Tuple2od;
import org.ranksys.mf.plsa.CPLSAFactorizer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* CPLSA aspect and intent models factory. It learns CPLSA model which then is used to create aspect and intent model.
*
* J. Wasilewski, N. Hurley. Intent-Aware Diversification Using a Constrained PLSA. RecSys 2016.
*
* @author Jacek Wasilewski (jacek.wasilewski@insight-centre.org)
*
* @param <U> user type
* @param <I> item type
* @param <F> aspect type
*/
public class CPLSAIAFactorizationModelFactory<U, I, F> extends IAFactorizationModelFactory<U, I, F> {
private final CPLSAIntentModel intentModel;
private final CPLSAAspectModel aspectModel;
private final FastFeatureData<I, F, ?> featureData;
/**
* Creates the CPLSA models factory. When called, factorizes data using CPLSA.
*
* @param numIter number of expectation-maximization steps
* @param data training data
* @param featureData aspects data
*/
public CPLSAIAFactorizationModelFactory(int numIter, FastPreferenceData<U, I> data, FastFeatureData<I, F, ?> featureData) {
super(new NormalizedCPLSAFactorizer<U, I, F>(numIter, featureData).factorize(data));
this.featureData = featureData;
this.intentModel = new CPLSAIntentModel();
this.aspectModel = new CPLSAAspectModel(intentModel);
}
@Override
public IntentModel<U, I, F> getIntentModel() {
return intentModel;
}
@Override
public AspectModel<U, I, F> getAspectModel() {
return aspectModel;
}
private static class NormalizedCPLSAFactorizer<U, I, F> extends CPLSAFactorizer<U, I, F> {
public NormalizedCPLSAFactorizer(int numIter, FastFeatureData<I, F, ?> featureData) {
super(numIter, featureData);
}
/**
* Normalizes matrix of p(z|u) such that \forall_u: \sum_z p(z|u) = 1.
*
* @param pu_z normalized matrix of p(z|u)
*/
@Override
protected void normalizePuz(DoubleMatrix2D pu_z) {
for (int u = 0; u < pu_z.rows(); u++) {
DoubleMatrix1D tmp = pu_z.viewRow(u);
double norm = tmp.aggregate(Functions.plus, Functions.identity);
if (norm != 0.0) {
tmp.assign(Functions.mult(1 / norm));
}
}
}
/**
* Normalizes matrix of p(i|z) such that \forall_z: \sum_i p(i|z) = 1.
*
* @param piz normalized matrix of p(i|z)
*/
@Override
protected void normalizePiz(DoubleMatrix2D piz) {
for (int i = 0; i < piz.columns(); i++) {
DoubleMatrix1D tmp = piz.viewColumn(i);
double norm = tmp.aggregate(Functions.plus, Functions.identity);
if (norm != 0.0) {
tmp.assign(Functions.mult(1 / norm));
}
}
}
}
private class CPLSAIntentModel extends IntentModel<U, I, F> {
@Override
protected UserIntentModel<U, I, F> get(U user) {
DoubleMatrix1D userVector = getFactorization().getUserVector(user);
return new FactorizationUserIntentModel(userVector);
}
private class FactorizationUserIntentModel implements UserIntentModel<U, I, F> {
private final DoubleMatrix1D userVector;
private final Set<F> nonZeroFactors;
public FactorizationUserIntentModel(DoubleMatrix1D userVector) {
Set<Integer> nonZeroFidx = new HashSet<>();
for (int i = 0; i < userVector.size(); i++) {
if (userVector.getQuick(i) > 0) {
nonZeroFidx.add(i);
}
}
this.userVector = userVector;
this.nonZeroFactors = nonZeroFidx.stream()
.map(featureData::fidx2feature)
.collect(Collectors.toSet());
}
@Override
public Set<F> getIntents() {
return nonZeroFactors;
}
@Override
public Stream<F> getItemIntents(I i) {
DoubleMatrix1D itemVector = getFactorization().getItemVector(i);
return getIntents().stream().filter(f -> itemVector.getQuick(featureData.feature2fidx(f)) > 0.0);
}
@Override
public double pf_u(F f) {
return userVector.getQuick(featureData.feature2fidx(f));
}
}
}
private class CPLSAAspectModel extends AspectModel<U, I, F> {
public CPLSAAspectModel(CPLSAIntentModel intentModel) {
super(intentModel);
}
@Override
protected LatentUserAspectModel get(U user) {
return new LatentUserAspectModel(user);
}
private class LatentUserAspectModel extends UserAspectModel {
public LatentUserAspectModel(U user) {
super(user);
}
@Override
public ItemAspectModel<I, F> getItemAspectModel(List<Tuple2od<I>> items) {
return (iv, f) -> getFactorization().getItemVector(iv.v1).getQuick(featureData.feature2fidx(f));
}
}
}
}