使用 JavaScript 編寫優化演算法 (1)

獨木發表於2014-07-28

之前一直用Python來寫優化演算法,為了增強 JS 的熟練程度,開始將原有的程式碼改寫成 JS。採用的工具包括 node.js + Grunt + nodeunit + github + npm + travis-ci。

 

最初的版本採用過程式的方式實現,沒有采用物件導向或事件驅動的模式。

 

#!/usr/bin/env node --harmony

// Random Search

"use strict";

var util = require("util");

function objective_function(v) {
    return v.map(function(x) {
        return x*x;
    }).reduce(function(a, b) {
        return a+b;
    });
}

function random_vector(min_max) {
    return min_max.map(function(x) {
        return x[0] + (x[1] - x[0]) * Math.random();
    });
}

function search(search_space, max_iteration) {
    var best = {};
    for (var iteration = 0; iteration < max_iteration; iteration++) {
        var candidate = {
            'vector': random_vector(search_space)
        };
        candidate['cost'] = objective_function(candidate['vector']);
        //console.log(candidate);
        if (iteration === 0 || candidate['cost'] < best['cost']) {
            best = candidate;
        }
        console.log(' > iteration=' + (iteration+1) + ', best=' + best['cost']);
    }
    return best;
}

function generate_array(element, repeat) {
    return new Array(repeat+1).join(1).split('').map(function(){return element;});
}

function run () {
    var problem_size = 2;
    var search_space = generate_array([-5, 5], problem_size);
    var max_iteration = 100;
    var best = search(search_space, max_iteration);
    console.log("Done. Best Solution: " + util.inspect(best));
}

exports.objective_function = objective_function;
exports.random_vector = random_vector;
exports.generate_array = generate_array;
exports.search = search;
exports.run = run;

  

呼叫方式很簡單。

 

var rs = require('clever_algorithms_js').random_search;

rs.run();

 

單元測試:

var random_search = require('../../lib/stochastic/random_search');

exports['objective'] = function (test) {
    test.equal(random_search.objective_function([1, 2]), 5);
    test.done();
};

exports['random_vector'] = function (test) {
    var rv = random_search.random_vector([[1, 2], [2, 3]]);
    test.equal(rv.length, 2);
    test.ok(1 <= rv[0] && rv[0] <= 2);
    test.ok(2 <= rv[1] && rv[1] <= 3);
    test.done();
};

exports['generate_array'] = function (test) {
    var a = random_search.generate_array([-5, 5], 2);
    test.equal(a.length, 2);
    test.deepEqual(a, [[-5,5], [-5,5]]);
    test.done();
};

exports['search'] = function (test) {
    var problem_size = 2,
        search_space = random_search.generate_array([-5, 5], problem_size),
        max_iter = 100;
    var best = random_search.search(search_space, max_iter);
    test.notEqual(best, {});
    test.ok(-5 <= best['cost'] && best['cost'] <= 5);
    test.done();
};

 

 如果採用CoffeeScript進行改寫的話,程式碼會更簡潔一些:

# Random Search

util = require("util");

objective_function = (v) ->
  v.reduce (x,y) -> x*x + y*y

random_vector = (min_max) ->
  min_max.map (rx) -> rx[0] + (rx[1] - rx[0]) * Math.random()

generate_array = (element, repeat) ->
  (element for [1..repeat])

search = (search_space, max_iteration) ->
  best = {}
  for iteration in [0..max_iteration-1]
    candidate = {
      'vector': random_vector(search_space)
    }
    candidate['cost'] = objective_function(candidate['vector'])
    best = candidate if iteration == 0 || candidate['cost'] < best['cost']
    console.log ' > iteration=' + (iteration+1) + ' best=' + best['cost'];
  best

run = () ->
  problem_size = 2
  search_space = generate_array([-5, 5], problem_size)
  max_iteration = 100
  best = search(search_space, max_iteration)
  console.log "Done. Best Solution: " + util.inspect(best);
  return

exports.objective_function = objective_function;
exports.random_vector = random_vector;
exports.generate_array = generate_array;
exports.search = search;
exports.run = run;

  

編譯出的JavaScript程式碼,看起來是這個樣子:

 

(function() {
  var generate_array, objective_function, random_vector, run, search, util;

  util = require("util");

  objective_function = function(v) {
    return v.reduce(function(x, y) {
      return x * x + y * y;
    });
  };

  random_vector = function(min_max) {
    return min_max.map(function(rx) {
      return rx[0] + (rx[1] - rx[0]) * Math.random();
    });
  };

  generate_array = function(element, repeat) {
    var _i, _results;
    _results = [];
    for (_i = 1; 1 <= repeat ? _i <= repeat : _i >= repeat; 1 <= repeat ? _i++ : _i--) {
      _results.push(element);
    }
    return _results;
  };

  search = function(search_space, max_iteration) {
    var best, candidate, iteration, _i, _ref;
    best = {};
    for (iteration = _i = 0, _ref = max_iteration - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; iteration = 0 <= _ref ? ++_i : --_i) {
      candidate = {
        'vector': random_vector(search_space)
      };
      candidate['cost'] = objective_function(candidate['vector']);
      if (iteration === 0 || candidate['cost'] < best['cost']) {
        best = candidate;
      }
      console.log(' > iteration=' + (iteration + 1) + ' best=' + best['cost']);
    }
    return best;
  };

  run = function() {
    var best, max_iteration, problem_size, search_space;
    problem_size = 2;
    search_space = generate_array([-5, 5], problem_size);
    max_iteration = 100;
    best = search(search_space, max_iteration);
    console.log("Done. Best Solution: " + util.inspect(best));
  };

  exports.objective_function = objective_function;

  exports.random_vector = random_vector;

  exports.generate_array = generate_array;

  exports.search = search;

  exports.run = run;

}).call(this);

  

  

 

[1] https://www.npmjs.org/package/clever_algorithms_js

[2] https://github.com/fox000002/clever_algorithms_js

相關文章