2016年9月9日金曜日

開発環境

Pythonからはじめる数学入門 (Amit Saha (著)、黒川 利明 (翻訳)、オライリージャパン)の7章(初等解析問題を解く)、7.6(勾配上昇法を用いて最大値を求める)をJavaScriptで取り組んでみる。

7.6(勾配上昇法を用いて最大値を求める)

コード(Emacs)

HTML5

<div id="graph0"></div>
<div id="output0"></div>

<label for="initial0">
  初期値: 
</label>
<input id="initial0" type="number" min="0" value="0.05729577951308232">
<br>
<label for="step0">
  ステップサイズ: 
</label>
<input id="step0" type="number" min="0" value="0.005729577951308233">
<br>
<label for="epsilon0">
  ε = 
</label>
<input id="epsilon0" type="number" min="0">

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>

<script src="array.js"></script>
<script src="grad_ascent.js"></script>

JavaScript

(function () {
    'use strict';
    var g = 9.8,
        u = 25,
        degrees = range(0, 90, 1e-2),    
        width = 600,
        height = 600,
        padding  = 50,
        xscale,
        yscale,
        xaxis,
        yaxis,

        div_graph = document.querySelector('#graph0'),
        div_output = document.querySelector('#output0'),
        input_initial = document.querySelector('#initial0'),
        input_step = document.querySelector('#step0'),
        input_epsilon = document.querySelector('#epsilon0'),
        inputs = [input_initial, input_step, input_epsilon],
        toRadian,
        calcDistance,
        derivDistance,
        getPoints0,
        getPoints1,
        output;

    input_epsilon.value = Number.EPSILON;

    toRadian = function (degree) {
        return degree * Math.PI / 180;
    };
    xscale = d3.scaleLinear()
        .domain([0, 90])
        .range([padding, width - padding]);
    yscale = d3.scaleLinear()
        .domain([0, 70])
        .range([height - padding, padding]);
    xaxis = d3.axisBottom().scale(xscale);
    yaxis = d3.axisLeft().scale(yscale);

    calcDistance = function (theta) {
        return Math.pow(u, 2) * Math.sin(2 * theta) / g;
    };
    derivDistance = function (theta) {
        return Math.pow(u, 2) * 2 * Math.cos(2 * theta) / g;    
    };
    getPoints0 = function () {
        return degrees.map(function (degree) {
            return [degree, calcDistance(toRadian(degree)), 1, 'blue'];
        });
    };
    getPoints1 = function () {
        var points = [],
            step_size = toRadian(parseFloat(input_step.value)),
            x_old = toRadian(parseFloat(input_initial.value)),
            epsilon = toRadian(parseFloat(input_epsilon.value)),
            x_new = x_old + step_size * derivDistance(x_old);

        points.push([x_new * 180 / Math.PI, calcDistance(x_new), 5, 'green']);
        for (; Math.abs(x_old - x_new) > epsilon; ) {
            x_old = x_new;
            x_new = x_old + step_size * derivDistance(x_old);
            points.push(
                [x_new * 180 / Math.PI, calcDistance(x_new), 5,'green']);
        }
        return points;
    };
    output = function () {
        var svg,
            points0 = getPoints0(),
            points1 = getPoints1(),
            points = points0.concat(points1),
            degree = points1[points1.length - 1][0];

        div_graph.innerHTML = '';
        svg = d3.select('#graph0')
            .append('svg')
            .attr('width', width)
            .attr('height', height);

        svg.selectAll('circle')
            .data(points)
            .enter()
            .append('circle')
            .attr('cx', function (d) {
                return xscale(d[0]);
            })
            .attr('cy', function (d) {
                return yscale(d[1]);
            })
            .attr('r', function (d) {
                return d[2];
            })
            .attr('fill', function (d) {
                return d[3];
            });
        svg.append('g')
            .attr('transform', 'translate(0, ' + (height - padding) + ')')
            .call(xaxis);
        svg.append('g')
            .attr('transform', 'translate(' + padding + ', 0)')
            .call(yaxis);

        div_output.innerHTML =
            'Theta: ' + degree + '<br>' +
            'Maximum Range: ' + calcDistance(toRadian(degree)) + '<br>';
    };

    inputs.forEach(function (input) {
        input.onchange = output;
    });

    output();
}());


0 コメント:

コメントを投稿