Published
Edited
Sep 12, 2021
Importers
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lossFunc = (x) =>
(12. - ( (x[0]+x[1]) * (5) + x[0]*sliders.r1 ) )**2 + (12 - ( (x[0]+x[1])*(5) + x[1]*sliders.r2 ) )**2
Insert cell
Insert cell
x0=[startPt.x, startPt.y]
Insert cell
Insert cell
descentPath = gradDescent(lossFunc, x0, 1000.,alph)
Insert cell
gradDescent=function(f,xStart,tStart,alpha) {
const path = [{x:xStart, f:f(xStart)}];
let xNow = xStart;
let t = tStart;
let conv = 1E9;
while (conv > 1E-5) { // convergence loop
let xNew = backtrack(f,xNow,t,alpha);
xNow = xNew.x;
t = xNew.t;
conv = xNew.f;
path.push({x:xNow, f:conv, t});
}
return path;
}
Insert cell
backtrack = function(f,xNow,t,alpha) {
let nDim = xNow.length;
let fNow = f(xNow);
let dt = t/1000.;
const dfdx = [];
let dfmag = 0;
for (let n=0; n<nDim; n++) {
let xPlusDt = [...xNow];
xPlusDt[n] += dt;
let xMinusDt = [...xNow];
xMinusDt[n] -= dt;
let dfdxn = ( f(xPlusDt)-f(xMinusDt) )/(2*dt);
dfdx.push(dfdxn);
dfmag += dfdxn**2;
}
dfmag = Math.sqrt(dfmag);
const dfdxNorm = dfdx.map( d => d/dfmag );
let xNew = xNow.map( (d,idx) => (d - t*dfdxNorm[idx]) );
let fNew = f(xNew);
let dotProd = 0.;
dfdx.forEach( (d,idx) => dotProd += d*dfdxNorm[idx] );
let dist = dotProd*alpha*t;
while (fNow - fNew - dist < 0) { // backtracking test
t *= 0.8;
xNew = xNow.map( (d,idx) => (d - t*dfdxNorm[idx]) );
fNew = f(xNew);
dist = dotProd*alpha*t;
}
return ({x:xNew,f:fNew,t});
}
Insert cell
Insert cell
Insert cell
import {chart} with {value as value, thresholds as thresholds, xScale as x, yScale as y, color as color,height as height} from "@d3/contours"
Insert cell
Insert cell
chgStart = {
svg.on("click", (event)=> {
const [x,y] = d3.pointer(event);
mutable startPt = {x:xScale.invert(x), y:yScale.invert(y)};
});
}
Insert cell
pts = descentPath.map(d => ({x:xScale(d.x[0]), y:yScale(d.x[1])}))
Insert cell
Insert cell
plotDescent = {
svg.select(".line").remove();
svg.append("path")
.datum(pts)
.attr("class","line")
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 3.)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", d3.line().x(d => d.x).y(d=>d.y) );
svg.selectAll("circle")
.data(pts)
.join("circle")
.attr("cx",d => d.x)
.attr("cy",d => d.y)
.attr("r",6)
.attr("fill","white")
.attr("stroke","red");

}
Insert cell
value = (x,y) => (lossFunc([x,y]))
Insert cell
svg = d3.select(chart)
Insert cell
mutable startPt=({x:0,y:0});
Insert cell
sample = { // sample the function to help determine thresholds for contouring
const sample = [];
const nSamp = 64;
for (let i=0; i<nSamp; i++) {
let x = xScale.invert(i/(nSamp-1) * width);
for (let j=0; j<nSamp; j++) {
let y = yScale.invert(j/(nSamp-1) * height);
sample.push( lossFunc([x,y]) );
}
}
return sample;
}
Insert cell
d1=Math.floor(Math.log10(d3.min(sample)))
Insert cell
d2=Math.floor(Math.log10(d3.max(sample)))+1
Insert cell
thresholds= d3.range(21).map(d => Math.pow(10, d1+d*(d2-d1)/20))
Insert cell
color=d3.scaleSequentialLog(d3.extent(thresholds), d3.interpolateSpectral)
Insert cell
xScale=d3.scaleLinear([-2., 4], [0, width+28])
Insert cell
yScale=d3.scaleLinear([-1., 3], [height, 0])
Insert cell
height=0.67*width
Insert cell
d3 = require("d3@7")
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
import {inputsGroup} from "@bumbeishvili/input-groups"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more