12
\$\begingroup\$

Background

Math SE's HNQ How to straighten a parabola? has 4,000+ views, ~60 up votes, 16 bookmarks and six answers so far and has a related companion HNQ in Mathematica SE How to straighten a curve? which includes a second part asking to move a point cloud along with the curve that we can ignore here.

From the Math SE question:

Consider the function \$f(x)=a_0x^2\$ for some \$a_0\in \mathbb{R}^+\$. Take \$x_0\in\mathbb{R}^+\$ so that the arc length \$L\$ between \$(0,0)\$ and \$(x_0,f(x_0))\$ is fixed. Given a different arbitrary \$a_1\$, how does one find the point \$(x_1,y_1)\$ so that the arc length is the same?

Schematically,

flattening a parabola

In other words, I'm looking for a function \$g:\mathbb{R}^3\to\mathbb{R}\$, \$g(a_0,a_1,x_0)\$, that takes an initial fixed quadratic coefficient \$a_0\$ and point and returns the corresponding point after "straightening" via the new coefficient \$a_1\$, keeping the arc length with respect to \$(0,0)\$. Note that the \$y\$ coordinates are simply given by \$y_0=f(x_0)\$ and \$y_1=a_1x_1^2\$.

flattening a parabola

Problem

Given a positive integer n and values a0 and a1 defining the original and new parabolas:

  1. Generate \$n\$ equally spaced values for \$x_0\$ from 0 to 1 and corresponding \$y_0\$ values.
  2. Calculate the new \$x_1\$ and \$y_1\$ such that their path distances along the new parabola are equal to their old distances.
  3. Output the \$x_0\$, \$x_1\$ and \$y_1\$ lists so that a user could plot the two parabolas.

note: The basis of the calculation can come from any of the answers to either linked question or something totally different. If you choose to use a numerical rather than analytical solution an error of \$1 \times 10^{-3}\$ would be sufficient for the user to make their plot.

Regular Code Golf; goal is shortest answer.

Example

This is quite a bit late but here is an example calculation and results. I chose the same numbers as in Eta's answer in order to check my math.

flattening the parabola code golf

s0: [0.00000, 0.13589, 0.32491, 0.59085, 0.94211, 1.38218, 1.91278, 2.53486, 3.24903]
x0: [0.00000, 0.12500, 0.25000, 0.37500, 0.50000, 0.62500, 0.75000, 0.87500, 1.00000]
x1: [0.00000, 0.13248, 0.29124, 0.46652, 0.64682, 0.82802, 1.00900, 1.18950, 1.36954]

script:

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import root

def get_lengths(x, a): # https://www.wolframalpha.com/input?i=integrate+sqrt%281%2B4+a%5E2x%5E2%29+x%3D0+to+1
    return 0.5 * x * np.sqrt(4 * a**2 * x**2 + 1) + (np.arcsinh(2 * a * x)) / (4 * a)

def mini_me(x, a, targets):
    return get_lengths(x, a) - targets

a0, a1 = 3, 1.5

x0 = np.arange(9)/8

lengths_0 = get_lengths(x0, a0)

wow = root(mini_me, x0.copy(), args=(a1, lengths_0))

x1 = wow.x

fig, ax = plt.subplots(1, 1)

y0, y1 = a0 * x0**2, a1 * x1**2

ax.plot(x0, y0, '-')
ax.plot(x0, y0, 'ok')

ax.plot(x1, y1, '-')
ax.plot(x1, y1, 'ok')

np.set_printoptions(precision=5, floatmode='fixed')

things = [str(q).replace(' ', ', ') for q in (lengths_0, x0, x1)]
names = [q + ': ' for q in ('s0', 'x0', 'x1')]

for name, thing in zip(names, things):
    print('    ' + name + thing)
    
_, ymax = ax.get_ylim()
xmin, _ = ax.get_xlim()

ax.text(x0[-1:]+0.03, y0[-1:]-0.1, str(a0) + 'x²')
ax.text(x1[-1:]-0.04, y1[-1:]-0.1, str(a1) + 'x²', horizontalalignment='right')

title = '\n'.join([name + thing for (name, thing) in zip(names, things)])

ax.set_title(title, fontsize=9)

plt.show()
\$\endgroup\$
4

1 Answer 1

7
\$\begingroup\$

Mathematica, 108 107 bytes

{n,a,b}=Input[];L=ArcLength;Subdivide@--n
x/.FindRoot[{t,t^2a}~L~{t,0,#}-{t,t^2b}~L~{t,0,x},{x,0}]&/@%
%^2b

(Assuming an interactive environment). Input is entered in the form {n, a0, a1}. Below is the output of a sample run with input {9, 3, 1.5}:

{0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1}
{0., 0.13247799662957596, 0.2912428843578418, 0.4665152489073556, 0.6468180849532895, 0.8280191118364263, 1.0089961907516996, 1.189503180997409, 1.369535545562379}
{0., 0.026325629386478908, 0.1272336265336128, 0.3264547161946379, 0.6275604525339613, 1.0284234743495764, 1.5271099694271602, 2.122376726404432, 2.8134414158382643}

Explanation

This uses FindRoot to find xs where the ArcLength of the original equation to each point in x0 matches the ArcLength of the flattened equation up to each x.

Here is a visualization of the points in the example: enter image description here

With the (identical) corresponding arc lengths at each point:

{0., 0.1358872650466621, 0.32491055615709175, 0.5908450391982809, 0.9421066199781004, 1.3821781999397988, 1.9127768947936938, 2.534864156640448, 3.249029586202852}
\$\endgroup\$
2
  • 5
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! If you haven't already, make sure to check out the Tips for Golfing in Mathematica to see if there's any way to shorten your answer. \$\endgroup\$ Aug 6, 2021 at 22:00
  • 1
    \$\begingroup\$ 91 bytes function taking [a1, a0, n] returning a list of {x0, x1, y1}s \$\endgroup\$
    – att
    Aug 8, 2021 at 5:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.