You are here

abstract class AbstractUnitsMathematicalOperator in Units of Measurement 7.2

Abstract implementation of "mathematical operator" interface.

Hierarchy

Expanded class hierarchy of AbstractUnitsMathematicalOperator

File

./units.module, line 1289
Provide API for managing and converting units of measurement.

View source
abstract class AbstractUnitsMathematicalOperator implements UnitsMathematicalOperatorInterface {

  /**
   * Definition of the underlying cTools 'operator' plugin.
   *
   * @var array
   */
  protected $operator;

  /**
   * Operand #1 of this mathematical expression.
   *
   * @var UnitsMathematicalExpression
   */
  protected $operand1;

  /**
   * Operand #2 of this mathematical expression.
   *
   * @var UnitsMathematicalExpression
   */
  protected $operand2;

  /**
   * UnitsOperatorMathematicalExpression constructor.
   *
   * @param array $operator
   *   Definition of a cTools 'operator' plugin that represents the specific
   *   operator
   * @param \UnitsMathematicalExpression $operand1
   *   Operand #1 for this mathematical expression
   * @param \UnitsMathematicalExpression $operand2
   *   Operand #2 for this mathematical expression
   */
  public function __construct($operator, UnitsMathematicalExpression $operand1, UnitsMathematicalExpression $operand2) {
    $this->operator = $operator;
    $this->operand1 = $operand1;
    $this->operand2 = $operand2;
  }

  /**
   * Determine physical dimension of this mathematical expression.
   *
   * @return array
   *   Dimension array of this mathematical expression
   */
  public function dimension() {
    $dimension_callback = ctools_plugin_get_function($this->operator, 'dimension callback');
    list($evaluate1, $evaluate2) = $this
      ->evaluateOperands();
    return $dimension_callback($this->operand1
      ->dimension(), $this->operand2
      ->dimension(), $evaluate1, $evaluate2);
  }

  /**
   * Test whether this mathematical expression includes a dimensionless member.
   *
   * Whether this mathematical expression contains at least 1 dimensionless
   * member.
   *
   * @return bool
   *   Whether this mathematical expression contains at least 1 dimensionless
   *   member
   */
  public function containsDimensionlessMember() {
    return $this->operand1
      ->containsDimensionlessMember() || $this->operand2
      ->containsDimensionlessMember();
  }

  /**
   * Format a certain amount of quantity within this mathematical expression.
   *
   * @param float $quantity
   *   Quantity to be formatted
   *
   * @return UnitsMathematicalExpression
   *   Formatted quantity into this mathematical expression. Sometimes the
   *   mathematical expression itself must mutate in order to format the
   *   quantity. So the returned mathematical expression may not necessarily be
   *   the mathematical expression on which this method was invoked. For
   *   example, the expression "unit" would mutate into "1 * unit" in order to
   *   have a dimensionless member and therefore be able to format the $quantity
   */
  public function formatQuantity($quantity) {
    $contains_dimensionless1 = $this->operand1
      ->containsDimensionlessMember();
    $contains_dimensionless2 = $this->operand2
      ->containsDimensionlessMember();
    list($quantity1, $quantity2) = $this
      ->evaluateOperands();
    if ($contains_dimensionless1 xor $contains_dimensionless2) {
      if ($contains_dimensionless1) {
        $this->operand1
          ->formatQuantity($quantity / $quantity2);
      }
      else {
        $this->operand2
          ->formatQuantity($quantity / $quantity1);
      }
    }
    else {
      $split_quantity = ctools_plugin_get_function($this->operator, 'split quantity callback');
      list($quantity1, $quantity2) = $split_quantity($quantity, $quantity1, $quantity2, $this->operator);
      $this->operand1
        ->formatQuantity($quantity1);
      $this->operand2
        ->formatQuantity($quantity2);
    }
    return $this;
  }

  /**
   * Numerically evaluate this mathematical expression.
   *
   * @return float
   *   Numerical value of this mathematical expression
   *
   * @throws UnitsMathematicalExpressionDimensionException
   *   Exception is thrown if this mathematical expression has inconsistency in
   *   physical dimensions
   */
  public function evaluate() {
    if ($this->operator['dimension check'] && !units_dimension_equal($this->operand1
      ->dimension(), $this->operand2
      ->dimension())) {
      throw new UnitsMathematicalExpressionDimensionException();
    }
    list($evaluate1, $evaluate2) = $this
      ->evaluateOperands();
    $evaluate_callback = ctools_plugin_get_function($this->operator, 'evaluate callback');
    return $evaluate_callback($evaluate1, $evaluate2);
  }

  /**
   * Decompose (simplify) this mathematical expression.
   *
   * @return UnitsMathematicalExpression
   *   Decomposed (simplified) version of this mathematical expression
   */
  public function decompose() {
    return units_mathematical_expression_operator_construct($this->operator, $this
      ->operand1()
      ->decompose(), $this
      ->operand2()
      ->decompose());
  }

  /**
   * Represent this mathematical expression in postfix notation.
   *
   * Represent this mathematical expression in postfix (reverse polish)
   * notation.
   *
   * @param array $options
   *   Options regarding how to format this mathematical expression
   *
   * @return string
   *   Postfix (reverse polish) notation representation of this mathematical
   *   expression
   */
  public function toPostfix($options = array()) {
    return implode(' ', array(
      $this->operand1
        ->toPostfix(),
      $this->operand2
        ->toPostfix(),
      $this->operator['sign'],
    ));
  }

  /**
   * Represent this mathematical expression in human-friendly infix notation.
   *
   * @param array $options
   *   Options regarding how to format this mathematical expression
   *
   * @return string
   *   Human-friendly formatted version of this mathematical expression taking
   *   into account provided $options
   */
  public function toInfix($options = array()) {
    $child_options = array(
      'parent precedence' => $this->operator['precedence'],
    ) + $options;
    $output = implode(' ', array(
      $this->operand1
        ->toInfix(array(
        'operand' => 1,
      ) + $child_options),
      $this->operator['sign'],
      $this->operand2
        ->toInfix(array(
        'operand' => 2,
      ) + $child_options),
    ));
    if (isset($options['parent precedence']) && ($options['parent precedence'] > $this->operator['precedence'] || $options['operand'] == 2 && $options['parent precedence'] == $this->operator['precedence'])) {
      $output = '( ' . $output . ' )';
    }
    return $output;
  }

  /**
   * Whether this expression is linearly decomposable.
   *
   * @return bool
   *   Whether this expression is linearly decomposable, i.e. its decomposition
   *   can be plugged in into another mathematical expression via multiplication
   *   without losing sense
   */
  public function isLinear() {
    return TRUE;
  }

  /**
   * Save the mathematical expression into database.
   *
   * @param int $mathematical_expression_id
   *   If the ID of the mathematical expression is known, under which it should
   *   be saved, provide it here. Otherwise it will be generated automatically
   * @param int $order
   *   Order of this member when the mathematical expression is written down in
   *   postfix notation. Primarily this argument is used for internal purposes
   *
   * @return int
   *   Mathematical expression ID under which this expression has been saved in
   *   the database
   */
  public function unitsMathematicalExpressionSave($mathematical_expression_id, &$order) {
    $mathematical_expression_id = $this
      ->operand1()
      ->unitsMathematicalExpressionSave($mathematical_expression_id, $order);
    $this
      ->operand2()
      ->unitsMathematicalExpressionSave($mathematical_expression_id, $order);
    db_insert('units_mathematical_expression_postfix')
      ->fields(array(
      'mathematical_expression_id' => $mathematical_expression_id,
      'type' => UNITS_TOKEN_TYPE_OPERATOR,
      'value_string' => $this->operator['name'],
      'postfix_order' => ++$order,
    ))
      ->execute();
    return $mathematical_expression_id;
  }

  /**
   * Retrieve operand #1 from this mathematical operator.
   *
   * @return UnitsMathematicalExpression
   *   Operand #1 from this mathematical expression
   */
  public function operand1() {
    return $this->operand1;
  }

  /**
   * Retrieve operand #2 from this mathematical operator.
   *
   * @return UnitsConstantMathematicalExpression
   *   Operand #2 from this mathematical expression
   */
  public function operand2() {
    return $this->operand2;
  }

  /**
   * Numerically isolate a certain operand of this mathematical expression.
   *
   * Given result of this mathematical expression, numerically, i.e.
   * dimensionlessly isolate a certain operand of this mathematical expression.
   *
   * @param \UnitsMathematicalExpression $equal_expression
   *   Result of this mathematical expression
   * @param int $operand_to_isolate
   *   What operand of this mathematical expression to isolate. Allowed values
   *   are:
   *   - 1: to isolate operand #1
   *   - 2: to isolate operand #2
   *
   * @return UnitsConstantMathematicalExpression
   *   Mathematical expression to which the isolated member numerically equals
   */
  public function isolateOperand(UnitsMathematicalExpression $equal_expression, $operand_to_isolate) {
    $isolate_callback = ctools_plugin_get_function($this->operator, 'isolate operand callback');
    if ($isolate_callback) {
      list($operand1, $operand2) = $this
        ->evaluateOperands();
      if ($operand_to_isolate == 1) {
        $operand1 = $this
          ->operand1();
        $operand2 = new UnitsConstantMathematicalExpression($operand2);
      }
      else {
        $operand1 = new UnitsConstantMathematicalExpression($operand1);
        $operand2 = $this
          ->operand2();
      }
      return $isolate_callback($operand1, $operand2, $equal_expression, $operand_to_isolate);
    }
  }

  /**
   * Numerically evaluate both operands and return them as an array.
   *
   * @return array
   *   Array of length 2: the 2 operands numerically evaluated
   */
  protected function evaluateOperands() {
    $evaluate1 = $this->operand1
      ->evaluate();
    $evaluate2 = $this->operand2
      ->evaluate();
    if (is_null($evaluate1)) {
      $evaluate1 = $this->operator['transparent operand1'];
    }
    if (is_null($evaluate2)) {
      $evaluate2 = $this->operator['transparent operand2'];
    }
    return array(
      $evaluate1,
      $evaluate2,
    );
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AbstractUnitsMathematicalOperator::$operand1 protected property Operand #1 of this mathematical expression.
AbstractUnitsMathematicalOperator::$operand2 protected property Operand #2 of this mathematical expression.
AbstractUnitsMathematicalOperator::$operator protected property Definition of the underlying cTools 'operator' plugin.
AbstractUnitsMathematicalOperator::containsDimensionlessMember public function Test whether this mathematical expression includes a dimensionless member. Overrides UnitsMathematicalExpression::containsDimensionlessMember
AbstractUnitsMathematicalOperator::decompose public function Decompose (simplify) this mathematical expression. Overrides UnitsMathematicalExpression::decompose 1
AbstractUnitsMathematicalOperator::dimension public function Determine physical dimension of this mathematical expression. Overrides UnitsMathematicalExpression::dimension 1
AbstractUnitsMathematicalOperator::evaluate public function Numerically evaluate this mathematical expression. Overrides UnitsMathematicalExpression::evaluate 1
AbstractUnitsMathematicalOperator::evaluateOperands protected function Numerically evaluate both operands and return them as an array.
AbstractUnitsMathematicalOperator::formatQuantity public function Format a certain amount of quantity within this mathematical expression. Overrides UnitsMathematicalExpression::formatQuantity 1
AbstractUnitsMathematicalOperator::isLinear public function Whether this expression is linearly decomposable. Overrides UnitsMathematicalExpression::isLinear 1
AbstractUnitsMathematicalOperator::isolateOperand public function Numerically isolate a certain operand of this mathematical expression. Overrides UnitsMathematicalOperatorInterface::isolateOperand
AbstractUnitsMathematicalOperator::operand1 public function Retrieve operand #1 from this mathematical operator. Overrides UnitsMathematicalOperatorInterface::operand1
AbstractUnitsMathematicalOperator::operand2 public function Retrieve operand #2 from this mathematical operator. Overrides UnitsMathematicalOperatorInterface::operand2
AbstractUnitsMathematicalOperator::toInfix public function Represent this mathematical expression in human-friendly infix notation. Overrides UnitsMathematicalExpression::toInfix
AbstractUnitsMathematicalOperator::toPostfix public function Represent this mathematical expression in postfix notation. Overrides UnitsMathematicalExpression::toPostfix
AbstractUnitsMathematicalOperator::unitsMathematicalExpressionSave public function Save the mathematical expression into database. Overrides UnitsMathematicalExpression::unitsMathematicalExpressionSave
AbstractUnitsMathematicalOperator::__construct public function UnitsOperatorMathematicalExpression constructor. 1