PHP Classes

File: batchresize.php

Recommend this page to a friend!
  Classes of Chris Jeffries   Value Seek   batchresize.php   Download  
File: batchresize.php
Role: Example script
Content type: text/plain
Description: Example code using ValueSeek to resize image files. Command line utility, not web page script
Class: Value Seek
Seek for optimal values with binary search
Author: By
Last change:
Date: 11 years ago
Size: 7,339 bytes
 

Contents

Class file image Download
<?php
/**
 * Seek the input value that generates the required output value for a given function and context
 *
 * Given a supplied (callback) function, finds out what input value to the function is required to generate the specified
 * result value for a given set of conditions. For example, what value of the quality parameter is needed to
 * achieve a specified file size for a given image. The binary chop search method is used to minimise the
 * number of attempts. This method requires a comparison between the required value and the most recent achieved value.
 * This comparison is also carried out in a callback function so that the comparison is under user control.
 *
 * @property callback string The name of a function which maps the independent variable to the dependent variable
 * @property comparator string The name of a function which compares the result of callback to the sought value
 * @property maxattempts integer Max number of times to iterate. Default 30
 * @property boundLower integer the minimum value of the independent variable. Default 0
 * @property boundUpper integer the maximum value of the independent variable. Default 99
 * @property searchvalue mixed this value will be passed to comparator for comparison with the result of callback function
 * @property items mixed cargo for the callback function. Invariate value(s)
 * @property-read status integer how the search was completed. Values 1-4
 * @ property-read statusmsg string how the search was completed.
 * @ property-read outputvalue mixed contains the final result from callback
 * @method mixed search returns outputvalue, documented above
 *
*/
class ValueSeeker
{ private $callback; //The function which transforms the input value into the output value - default: pick element from array
   
private $comparator; //used for tests of $searchvalue against outputvalue of callback function - default: simple comparison a gt/lt/= b
   
private $maxattempts; //maximum number of times the search is iterated before giving up - default 30
   
private $boundLower; //lowest input value to the callback function - default 0
   
private $boundUpper; //highest input value to the callback function - default 99
   
private $searchvalue; //The output value to be aimed for
   
private $items; //parametric data for the callback function
   
private $status;
    private
$statusmsg;
    private
$inputvalue; //used to probe output values of callback. value range between $boundUpper and $boundLower
   
private $outputvalue; //hold the result of the callback function

/**
 * Function to compare two result values
 *
 * This is a simple comparison between two integers or strings. It is the default
 * callback function for comparator. It will normally be overridden by a more complex
 * comparison.
 *
 * @param mixed a the value of the searchvalue property
 * @param mixed b the return value after calling the callback function defined in the callback property
 * @return integer -1: a is less, +1: b is less; 0: they are the same
 *
*/
   
private function compare($a, $b)
    {
//default function for comparator
       
if ($a == $b) return 0;
        if (
$a > $b) return 1;
        return -
1;
    }

/**
 * Function to map an independent variable to a dependent variable
 *
 * This is a sample function. It assumes that the property 'items' contains a number
 * indexed array. This sample callback function transforms the index of the array to
 * the value of that indexed item.
 *
*/
   
private function arrayselect($array, $index)
    {
//default function for callback
       
return $array[$index];
    }

    function
__construct()
    {
       
$this->callback = 'arrayselect';
       
$this->comparator = 'compare';
       
$this->maxattempts = 30;
       
$this->boundLower = 0;
       
$this->boundUpper = 99;
    }

    public function
__set ($var, $value)
    {
        switch (
$var)
        {
        case
'searchvalue':
           
$this->searchvalue = $value;
            break;

        case
'items':
           
$this->items = $value;
            break;

        case
'callback':
            if(!
function_exists($value)) throw new Exception("$var function '$value()' does not exist",4);
           
$this->callback = $value;
            break;

        case
'comparator':
            if(!
function_exists($value)) throw new Exception("$var function '$value()' does not exist",5);
           
$this->comparator = $value;
            break;

        case
'maxAttempts':
            if(!
is_integer($value)) throw new Exception("maxattempts is not an integer",2);
            if(
$maxattempts < 1 ) throw new Exception("maxattempts must be at least 1", 3);
           
$this->maxattempts = $value;
            break;

        case
'boundLower':
            if(!
is_integer($value)) throw new Exception("lower bound of range is not an integer",2);
           
$this->boundLower = $value;
            break;

        case
'boundUpper':
            if(!
is_integer($value)) throw new Exception("upper bound of range is not an integer",2);
           
$this->boundUpper = $value;
            break;

        default:
            throw new
Exception("Attempt to set non-existent property:$var\n\r",10);
        }
    }
    public function
__get($var)
    {
        switch (
$var)
        {
            case
'searchvalue': return $this->searchvalue; break;
            case
'items': return $this->items; break;
            case
'maxattempts': return $this->maxattempts; break;
            case
'boundLower': return $this->boundLower; break;
            case
'boundUpper': return $this->boundUpper; break;
            case
'comparator': return $this->comparator; break;
            case
'callback': return $this->callback; break;
            case
'outputvalue': return $this->outputvalue; break;
            case
'status': return $this->status; break;
            case
'statusmsg': return $this->statusmsg; break;
            default: throw new
Exception("Attempt to get non-existent property:$var\n\r",11);
        }
    }

    function
search()
    {
        if(
$this->boundUpper < $this->boundLower) throw new Exception("range invalid:lower bound > upper bound",1);

       
$boundUpper = $this->boundUpper;
       
$boundLower = $this->boundLower;

       
$inputValue = round(($boundUpper + $boundLower) / 2, 0);
       
$attempts = 0;
       
$comparison = 0;

        while(
$attempts < $this->maxattempts )
        {
           
$this->outputvalue = call_user_func($this->callback, $this->items, $inputValue);
           
$comparison = call_user_func($this->comparator, $this->searchvalue, $this->outputvalue );

            if (
$comparison > 0 )
            {
               
$boundLower = $inputValue;
               
$inputValue = round(($boundUpper + $inputValue) / 2, 0);
                if(
$inputValue == $boundLower)
                {
                        if(
$boundLower == $this->boundLower)
                        {
                           
$this->statusmsg = "Hit lower bound";
                           
$this->status = 3;
                        }
                        else
                        {
                           
$this->statusmsg = "Found nearest input value(-)";
                           
$this->status = 2;
                        }
                    return
$inputValue;//gone as low as we can
               
}
            }
            else
            {
                if (
$comparison < 0 )
                {
                   
$boundUpper = $inputValue;
                   
$inputValue = round(($boundLower + $inputValue) / 2, 0);
                    if(
$inputValue == $boundUpper )
                    {
                        if(
$boundUpper == $this->boundUpper)
                        {
                           
$this->statusmsg = "Hit upper bound";
                           
$this->status = 4;
                        }
                        else
                        {
                           
$this->statusmsg = "Found nearest input value(-)";
                           
$this->status = 2;
                        }
                        return
$inputValue - 1;//gone as high as we can
                   
}
                }
                else
                {
                   
$this->statusmsg = "Reached target value";
                   
$this->status = 1;
                    return
$inputValue;
                }
            }
           
$attempts++;
        }
       
$this->statusmsg = "Performed maximum no of attempts";
       
$this->status = 4;
        return
$inputValue; //bombed out on attempts limit
   
}
}
?>