pandorafms/pandora_console/include/functions_forecast.php

285 lines
7.3 KiB
PHP

<?php
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; version 2
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
/**
* @package Include
* @subpackage Forecast
*/
/**
* Create a prediction based on module data with least square method (linear regression)
*
* @param int Module id.
* @param int Period of the module data.
* @param int Period of the prediction or false to use it in prediction_date function (see below).
* @param int Maximun value using this function for prediction_date.
* @param int Minimun value using this function for prediction_date.
* @param bool Result data for CSV file exportation.
*
* @return array Void array or prediction of the module data.
*/
function forecast_projection_graph($module_id,
$period = SECONDS_2MONTHS, $prediction_period, $max_value = false,
$min_value = false, $csv = false) {
global $config;
$max_exec_time = ini_get('max_execution_time');
if ($max_exec_time !== false) {
$max_exec_time = (int)$max_exec_time;
}
$begin_time = time();
$module_data=grafico_modulo_sparse ($module_id, $period, 0,
300, 300 , '', null,
false, 0, false,
0, '', 0, 1, false,
true, '', 1, true);
if (empty($module_data)) {
return array();
}
// Prevents bad behaviour over image error
else if (!is_array($module_data) and preg_match('/^<img(.)*$/', $module_data)) {
return;
}
// Data initialization
$sum_obs = 0;
$sum_xi = 0;
$sum_yi = 0;
$sum_xi_yi = 0;
$sum_xi2 = 0;
$sum_yi2 = 0;
$sum_diff_dates = 0;
$last_timestamp = get_system_time();
$agent_interval = SECONDS_5MINUTES;
$cont = 1;
$data = array();
//$table->data = array();
// Creates data for calculation
if (is_array($module_data) || is_object($module_data)) {
foreach ($module_data as $utimestamp => $row) {
if ($utimestamp == '') {
continue;
}
$data[0] = '';
$data[1] = $cont;
$data[2] = date($config["date_format"], $utimestamp);
$data[3] = $utimestamp;
$data[4] = $row['sum'];
$data[5] = $utimestamp * $row['sum'];
$data[6] = $utimestamp * $utimestamp;
$data[7] = $row['sum'] * $row['sum'];
if ($cont == 1) {
$data[8] = 0;
}
else {
$data[8] = $utimestamp - $last_timestamp;
}
$sum_obs = $sum_obs + $cont;
$sum_xi = $sum_xi + $utimestamp;
$sum_yi = $sum_yi + $row['sum'];
$sum_xi_yi = $sum_xi_yi + $data[5];
$sum_xi2 = $sum_xi2 + $data[6];
$sum_yi2 = $sum_yi2 + $data[7];
$sum_diff_dates = $sum_diff_dates + $data[8];
$last_timestamp = $utimestamp;
$cont++;
}
}
$cont--;
// Calculation over data above:
// 1. Calculation of linear correlation coefficient...
// 1.1 Average for X: Sum(Xi)/Obs
// 1.2 Average for Y: Sum(Yi)/Obs
// 2. Covariance between vars
// 3.1 Standard deviation for X: sqrt((Sum(Xi²)/Obs) - (avg X)²)
// 3.2 Standard deviation for Y: sqrt((Sum(Yi²)/Obs) - (avg Y)²)
// Linear correlation coefficient:
if ($sum_xi != 0) {
$avg_x = $cont/$sum_xi;
} else {
$avg_x = 0;
}
if ($sum_yi != 0)
$avg_y = $cont/$sum_yi;
else
$avg_y = 0;
/*
if ($cont != 0) {
$covariance = $sum_xi_yi/$cont;
$dev_x = sqrt(($sum_xi2/$cont) - ($avg_x*$avg_x));
$dev_y = sqrt(($sum_yi2/$cont) - ($avg_y*$avg_y));
} else {
$covariance = 0;
$dev_x = 0;
$dev_y = 0;
}
// Prevents division by zero
if ($dev_x != 0 and $dev_y != 0) {
$linear_coef = $covariance / ($dev_x * $dev_y);
}
*/
// Agent interval could be zero, 300 is the predefined
if ($sum_obs == 0) {
$agent_interval = SECONDS_5MINUTES;
}
else {
$agent_interval = $sum_diff_dates / $sum_obs;
}
// Could be a inverse correlation coefficient
// if $linear_coef < 0.0
// if $linear_coef >= -1.0 and $linear_coef <= -0.8999
// Function variables have an inverse linear relathionship!
// else
// Function variables don't have an inverse linear relathionship!
// Could be a direct correlation coefficient
// else
// if ($linear_coef >= 0.8999 and $linear_coef <= 1.0) {
// Function variables have a direct linear relathionship!
// else
// Function variables don't have a direct linear relathionship!
// 2. Calculation of linear regresion...
$b_num = (($cont * $sum_xi_yi) - ($sum_xi * $sum_yi));
$b_den = (($cont * $sum_xi2) - ($sum_xi * $sum_xi));
if ($b_den == 0)
return;
$b = $b_num / $b_den;
$a_num = ($sum_yi) - ($b * $sum_xi);
if ($cont != 0) {
$a = $a_num / $cont;
} else {
$a = 0;
}
// Data inicialization
$output_data = array();
if ($prediction_period != false) {
$limit_timestamp = $last_timestamp + $prediction_period;
}
$current_ts = $last_timestamp;
$in_range = true;
$time_format_2 = '';
$temp_range = $period;
if ($period < $prediction_period)
$temp_range = $prediction_period;
if ($temp_range <= SECONDS_6HOURS) {
$time_format = 'H:i:s';
}
elseif ($temp_range < SECONDS_1DAY) {
$time_format = 'H:i';
}
elseif ($temp_range < SECONDS_15DAYS) {
$time_format = 'M d';
$time_format_2 = 'H\h';
}
elseif ($temp_range <= SECONDS_1MONTH) {
$time_format = 'M d';
$time_format_2 = 'H\h';
}
else {
$time_format = 'M d';
}
// Aplying linear regression to module data in order to do the prediction
$output_data = array();
$idx = 0;
// Create data in graph format like
while ($in_range) {
$now = time();
// Check that exec time is not greater than half max exec server time
if ($max_exec_time !== false) {
if (($begin_time + ($max_exec_time/2)) < $now) {
return false;
}
}
$timestamp_f = date($time_format, $current_ts);
//$timestamp_f = date($time_format, $current_ts);
$timestamp_f = graph_get_formatted_date($current_ts, $time_format, $time_format_2);
if ($csv) {
$output_data[$idx]['date'] = $current_ts;
$output_data[$idx]['data'] = ($a + ($b * $current_ts));
}
else {
$output_data[$timestamp_f] = ($a + ($b * $current_ts));
}
// Using this function for prediction_date
if ($prediction_period == false) {
// These statements stop the prediction when interval is greater than 2 years
if ($current_ts - $last_timestamp >= 94608000) {
return false;
}
// Found it
if ($max_value >= $output_data[$timestamp_f] and $min_value <= $output_data[$timestamp_f]) {
return $current_ts;
}
}
else if ($current_ts > $limit_timestamp) {
$in_range = false;
}
$current_ts = $current_ts + $agent_interval;
$idx++;
}
return $output_data;
}
/**
* Return a date when the date interval is reached
*
* @param int Module id.
* @param int Given data period to make the prediction
* @param int Max value in the interval.
* @param int Min value in the interval.
*
* @return mixed timestamp with the prediction date or false
*/
function forecast_prediction_date ($module_id,
$period = SECONDS_2MONTHS, $max_value = 0, $min_value = 0) {
// Checks interval
if ($min_value > $max_value) {
return false;
}
return forecast_projection_graph($module_id, $period, false, $max_value, $min_value);
}