<?php
# Modelo scenario
define("DEFAULT_COU", "default");
define("UTILITY", "minimum_utility");
define("TRAFFIC", "traffic_percent");
define("MODEL_SCENARIO_GROUP_CPM", "cpm_sum");
define("MODEL_SCENARIO_CPM", "cpm");
define("MODEL_SCENARIO_UTILITY", "utility");
define("MODEL_SCENARIO_MEMBERS", "members");
echo 'DATA 1';
echo '<br/>';
$prints = 54700;
$data = [
1 => 26.14,
2 => 5.64,
3 => 5.14,
4 => 7.17,
5 => 8.11,
6 => 7.69,
7 => 7.16,
];
$distribucion = Test::getAdsDistributionV2($data, DEFAULT_COU);
$printResult = Test::printDistribution($prints, $distribucion);
echo '<br/>';
echo 'Distribución de ' . $prints . ' prints';
print("<pre>" . print_r($printResult, true) . "</pre>");
$spendResult = Test::spendDistribution($data, $printResult);
echo 'Spend por anuncio';
print("<pre>" . print_r($spendResult, true) . "</pre>");
$spendTotal1 = Test::spendTotal($spendResult);
echo 'SPEND TOTAL DATA 1 = ' . $spendTotal1 . '$';
echo '<br/>';
echo '<br/>';
echo 'DATA 2';
echo '<br/>';
$prints = 54700;
$data = [
1 => 26.14,
2 => 5.64,
3 => 5.14,
4 => 7.17,
5 => 8.11,
6 => 7.69,
7 => 7.16,
];
$distribucion = Test::getAdsDistributionV2($data, 'BR');
$printResult = Test::printDistribution($prints, $distribucion);
echo '<br/>';
echo 'Distribución de ' . $prints . ' prints';
print("<pre>" . print_r($printResult, true) . "</pre>");
$spendResult = Test::spendDistribution($data, $printResult);
echo 'Spend por anuncio';
print("<pre>" . print_r($spendResult, true) . "</pre>");
$spendTotal2 = Test::spendTotal($spendResult);
echo 'SPEND TOTAL 2 = ' . $spendTotal2. '$';
echo '<br/>';
echo '<br/>';
echo 'DIFERENCIA = ' . ($spendTotal2 - $spendTotal1).'$';
echo '<br/>';
echo 'PORCENTAJE DE MEJORA= ' . (($spendTotal2*100/$spendTotal1)-100) . '%';
class Test
{
public static function spendTotal($spendResult)
{
$total = 0;
foreach ($spendResult as $adId => $spend) {
$total += $spend;
}
return $total;
}
public static function spendDistribution($data, $printResult)
{
$result = [];
foreach ($printResult as $adId => $dist) {
$result[$adId] = $printResult[$adId] * $data[$adId] / 1000;
}
return $result;
}
public static function printDistribution($prints, $distribution)
{
$total = 0;
foreach ($distribution as $adId => $dist) {
$total += $dist;
}
$result = [];
foreach ($distribution as $adId => $dist) {
$result[$adId] = $dist / $total * $prints;
}
return $result;
}
public static function getAdsDistributionV2(array $ads, $country)
{
if ($ads) {
$dist = Test::getDist($country);
$distGroupsCount = count($dist);
arsort($ads);
// obtener el CPM mayor de los anuncios a distribuir
$firstCpm = reset($ads);
// si el primer CPM es válido
if ($firstCpm > 0) {
// inicialmente tenemos una distribución con todos los anuncios a 0
$adDistribution = array_fill_keys(array_keys($ads), 0);
$adsNormalization = array();
for ($i = 1; $i <= $distGroupsCount; $i++) {
$dist[$i][MODEL_SCENARIO_GROUP_CPM] = 0;
}
// para cada anuncio vamos a situarlo en el grupo de CPM que le corresponda
foreach ($ads as $adId => $cpm) {
// normalizamos entre 0 y 1 la utilidad del anuncio, relativas al máximo CPM
$adsNormalization[$adId] = array(
MODEL_SCENARIO_CPM => $cpm,
MODEL_SCENARIO_UTILITY => $cpm / $firstCpm,
);
// IMPORTANTE: si algún anuncio tiene CPM = 0, su utilidad será 0 y tiene que caer obligatoriamente
// en el último grupo, a menos que se haya indicado en la uración
// una utilidad de 0 para el último grupo,
// para cada grupo de CPM de la uración del primero al penúltimo
for ($i = 1; $i < $distGroupsCount; $i++) {
// si la utilidad del anuncio actual es mayor que la del grupo actual
if ($adsNormalization[$adId][MODEL_SCENARIO_UTILITY] >= $dist[$i][UTILITY]) {
// ubicamos el anuncio en el grupo de CPM
$dist[$i][MODEL_SCENARIO_MEMBERS][$adId] = $cpm;
// incrementamos el CPM total de anuncios del grupo con el CPM del anuncio actual
$dist[$i][MODEL_SCENARIO_GROUP_CPM] += $cpm;
}
}
// si la utilidad del anuncio actual es menor que la del penúltimo grupo, entonces pertenece al último grupo
if ($adsNormalization[$adId][MODEL_SCENARIO_UTILITY] < $dist[$distGroupsCount - 1][UTILITY]) {
// ubicamos el anuncio en el último grupo de CPM
// no es necesario agregar CPMs pporque se distribuirán uniformemente independientemente del CPM que tengan
$dist[$distGroupsCount][MODEL_SCENARIO_MEMBERS][$adId] = 1;
}
}
// calculamos todas las frecuencias de anuncios por grupo, del primero al penúltimo
// los anuncios que aparezcan en varios grupos, tendrán más peso pues se llevarán tráfico de cada uno de los grupos
for ($i = 1; $i < $distGroupsCount; $i++) {
// para cada anuncio dentro del grupo
if (isset($dist[$i][MODEL_SCENARIO_MEMBERS])) {
foreach ($dist[$i][MODEL_SCENARIO_MEMBERS] as $adId => $cpm) {
// aumentamos la frecuencia del anuncio actual según su CPM relativo dentro del grupo actual
$adDistribution[$adId] +=
($dist[$i][TRAFFIC] * $cpm) /
$dist[$i][MODEL_SCENARIO_GROUP_CPM];
}
}
}
// tenemos dentro de $adDistribution todos los anuncios de todos los grupos (menos el último) con sus frecuencias relativas
// si hay anuncios en el último grupo
if (isset($dist[$distGroupsCount][MODEL_SCENARIO_MEMBERS])) {
// todos los anuncios del último grupo tienen la misma frecuencia relativa, distribuyendo el tráfico correspondiente
$distribution = $dist[$distGroupsCount][TRAFFIC]
/ count($dist[$distGroupsCount][MODEL_SCENARIO_MEMBERS]);
// actualizamos las frecuencias relativas de los anuncios del último grupo
foreach ($dist[$distGroupsCount][MODEL_SCENARIO_MEMBERS] as $adId => $cpm) {
$adDistribution[$adId] = $distribution;
}
}
// eliminamos todos los elementos que puedan quedar con frecuencia 0
$adDistribution = Test::array_diff($adDistribution, array(0));
// normalizamos la distribución de cada anuncio ganador tomando como base la menor frecuencia
$divide = false;
foreach ($adDistribution as $adId => $frequency) {
if (intval($frequency) == 0) {
$divide = true;
break;
}
}
if ($divide) {
// obtenemos el valor de la menor frecuencia
arsort($adDistribution);
$lastProbability = end($adDistribution);
foreach ($adDistribution as $adId => &$frequency) {
$frequency = intval($frequency / $lastProbability);
}
} else {
foreach ($adDistribution as $adId => &$frequency) {
$frequency = intval($frequency);
}
}
} else {
// @codeCoverageIgnoreStart
// todos los anuncios se distribuyen uniformemente
$adDistribution = array_fill_keys(array_keys($ads), 1);
// @codeCoverageIgnoreEnd
}
} else {
// @codeCoverageIgnoreStart
$adDistribution = array();
// @codeCoverageIgnoreEnd
}
return $adDistribution;
}
public static function array_diff(array $b, array $a)
{
$at = array();
foreach ($a as $i) {
$at[(string)$i] = 1;
}
$d = array();
foreach ($b as $k => $i) {
if (!isset($at[(string)$i])) {
$d[$k] = $i;
}
}
return $d;
}
public static function getDist($country)
{
$distributions = array(
"BR" => array(
1 => array(
UTILITY => 0.9,
TRAFFIC => 85,
),
2 => array(
UTILITY => 0.55,
TRAFFIC => 10,
),
3 => array(
UTILITY => 0.45,
TRAFFIC => 4,
),
4 => array(
UTILITY => 0,
TRAFFIC => 1,
),
),
DEFAULT_COU => array(
1 => array(
UTILITY => 0.70,
TRAFFIC => 70,
),
2 => array(
UTILITY => 0.55,
TRAFFIC => 20,
),
3 => array(
UTILITY => 0.45,
TRAFFIC => 8,
),
4 => array(
UTILITY => 0,
TRAFFIC => 2,
),
),
);
return $distributions[$country];
}
}
?>