[Question]
  [
# Bowl Pile Height
The goal of this puzzle is to compute the height of a stack of bowls.
[![A stack of bowls](https://i.stack.imgur.com/9dZsZm.jpg)](https://i.stack.imgur.com/9dZsZm.jpg)
A bowl is defined to be a radially symmetric device without thickness.
Its silhouette shape is an even polynomial. The stack is described by a list of radii, each associated with an even polynomial, given as input as a list of coefficients (e.g. the list `3.1 4.2` represents the polynomial \$3.1x^2+4.2x^4\$).
The polynomial may have arbitrary degree. For simplicity, the height of the pile is defined as the altitude of the center of the top-most bowl (see plot of Example 3 for an illustration).
Test cases are in the format `radius:coeff1 coeff2 ...`: each line starts with a float number representing the radius of the bowl, followed by a colon and a space-separated list containing the coefficients for the even powers, starting with power 2 (zero constant part is implied). For example, the line `2.3:3.1 4.2` describes a bowl of radius `2.3` and the shape-polynomial `3.1 * x^2 + 4.2 * x^4`.
## Example 1
```
42:3.141
```
describes a pile of zero height since a single bowl has no height.
## Example 2
```
1:1 2
1.2:5
1:3
```
describes a pile of height `2.0` (see plot).
[![Plot of a stack of three bowls](https://i.stack.imgur.com/eyrxF.png)](https://i.stack.imgur.com/eyrxF.png)
## Example 3
```
1:1.0
0.6:0.2
0.6:0.4
1.4:0.2
0.4:0 10
```
describes a pile of height 0.8 (see green arrow in the plot).
[![Plot of a stack of three bowls](https://i.stack.imgur.com/9wFYRm.png)](https://i.stack.imgur.com/9wFYRm.png)
This is code golf, so the shortest code wins.
I have [reference code](https://gist.github.com/pasbi/89f86df9fb1049bd3dfb6cffeac093b2).
# Edit:
The reference implementation relies on a library to compute the roots of polynomials.
You may do that as well but you don't need to.
Since the reference implementation is only a (quite good) numerical approximation, I will accept any code which produces correct results within common floating-point tolerances.
The idea counts. I don't care if there are small erros \$<\varepsilon\$.
Another variant of this puzzle is to minimize the height by reordering the bowls. I'm not sure if there's a fast solution (I guess it's NP-hard). If anyone has a better idea (or can prove NP-completeness), please tell me!
  
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~54~~ 53 bytes
```
J×$ÆrAƑƇ«⁹;⁹*€J{ḋ⁸ŻṀ
Œcz€0ḢṂç@I0;ⱮFƲƲ€ṚṁL’R€Ɗ;+Ṁ¥¥ƒ0Ṁ
```
[Try it online!](https://tio.run/##TY0/SwMxGMb3fIp36KQYkty1YAKii2BxchCcxUU6uVWXSwcPdPIc/IMuSnFQBIuUC4UOCZfvkXyR873QgkPyPO/z/p7k/Gw0Grft0D303PXFnr/zpf2M2ig8G3HyNbwK9W3UdbMIpiBNdXqJIQv1WzAT97F7wFT8@d73Mz/DPJjnYPRhLJ6OcPI3ahNLdmqnvmLo2qYK5lHF4gW2diAWr8qVKeqRqJcSxmHxG8w7VnEHx52mN11JmvtuoZd2bueuxPikbXMhM8pzTgiXHAThVMg@@iwFlBFGB5JRsdIcgXw1owJnyNFEwpoRkK9pyP7x24mHASGp2UfJGKDrvuqQ7uaA7g8 "Jelly – Try It Online")
A monadic link that takes as its argument the list of bowls from top to bottom in the format `[[b1_radius, b1_coef1, ...], [b2_radius, b2_coef1, ...]]` and returns the y position of the bottom of the top bowl.
Now correctly handles bowls which meet at places other than the minimal radius.
## Explanation
### Helper link: takes as left argument `l` the differences in coefficients of the polynomials representing the bowls from 1 upwards, and its right argument `r` the minimum radius; returns the maximum y value where the two bowls meet
```
  $                   | Following as a monad:
J                     | - Sequence from 1..<len(l)>
 ×                    | - Multiply (by l)
   Ær                 | Roots of polynomial
     AƑƇ              | Keep only those invariant when passed through absolute function (excludes negative, imaginary and complex numbers)
        «⁹            | Min of these filtered roots and r
          ;⁹          | Concatenate r to the list
            *€        | Each root/radius to the power of:
              J{      | - Sequence from 1..<len(l)>
                ḋ⁸    | Dot product with l
                  Ż   | Prepend zero
                   Ṁ  | Maximum
```
### Main link, takes a bowl pile as its argument and returns y value of base of top bowl
```
Œc                               | Combinations length 2
  z€0                            | Transpose each using 0 as a filler
               Ʋ€                | For each one, do the following as a monad:
     Ḣ                           | - Take the head (the radii)     
      Ṃ                          | - Minimum
       ç@     Ʋ                  | - Call the helper link with this (min radius) as right argument and the following as left argument:
         I                       |   - Increments (difference between second and first polynomial for each coefficient)
          0;Ɱ                    |   - Prepend each with a zero (odd coefficients are all zero)
             F                   |   - Flatten
                 Ṛ               | Reverse
                  ṁ    Ɗ         | Mould to the following as a monad:
                   L             | Length
                    ’            | Decrease by 1
                     R€          | Range of each (e.g. [1],[1,2],[1,2,3],[1,2,3,4]
                            ¥ƒ0  | Reduce using the following as a dyad and starting with 0
                        ;  ¥     | - Concatenate the following as a dyad
                         +       |   - Add
                          Ṁ      |   - Take the maximum
                               Ṁ | Finally take the overall maximum
```
### Python reference
[Finally, here’s a TIO version of the Python reference that @pasbi included for the main problem.](https://tio.run/##lVXbbqMwEH3nK0bpi91SBNmq0qJ2fwQhyw1OcJcYhEmb7M93Z3xJIG1XWl7AczkzczwzDKep7c2Pjw@9H/pxAnPYDyeQFsyQBJE92SS5gYEdOTyDPexZBQPcwvH2VsO2H0GneNYGFDqrUU6KDZbXPGnUFhq93apRmUkHeZkAPqOaDqMBD/QPFKiroqwTBzX2/WQ/QZghi4qqLO8LjOus1ZvsDh4lhePS5z9qCEXYSZqNYvjRCpmCe79EUNnogxV5CraVgxI5suQN5@oiqouofpmpUbbXhl2gohd3RsQicR/w7yOUVzYOcc4znbznIBw7aOFZahqsyXlhXdqKvTzqPdJB2lDPjKgziU2TOgAOvyDP8gWENmKUZqe@wUBzeHLO8PQc6lr4j0p23/jKF@s0md7LHSd/RPNPccEgC7HV3aTGb3CuCwVpms@pR@klIR/jBmkctZnYynFYwiqNvF6TXPlCqaPcB3ZUVOovEoU6XK/vL49wIR1vMdL@FeK1890X3sgXTz9BukuI0bHxxDwDZIqdz3w@NwvLMJRKNiRrWaeNWkwEkkRwJM/s0Gnkr1zxZdNvu15Ooe29Sr0pI5wjTrYcR3lilbfaeBY2jgIbIWFFY@puITj9UWNv2fq2U4YFNH5XRJtqXZbrGi2Dal7fJW9f3CAbtz5MqAvPjWrEMpDhS11VUmDaHmi1xD/bBPgO24G4U5b5V4gjrVW4eAknyGnsnMr1QUjTLQFiwxuVcG57g6GLPD@fjyFjvAs7SFxk9xEjvkMV9Jyu2tCFoR3qgh8p4DE2n6u8mzIqhR0R5xRHAoWd2inTMD9hs2L4xcS2/TvDMcPhEMLIvRICnp9hJXBesdnEqow93obpuGo4lxN9UVr4p8rs1GiTkRVJLeM0eAYHx/fhJMfJvuupZaubFQcsI4mEUd9XlKYrOIzcJ5Zrfp0RQyPqlMCT4d@5xmAn0W@3VoWFQfuxPt@tJnPPGP4x5qRdltpyXSx@TspWr3Ua4lW69qm8XkA1n93cOZFMDgNd1XL0@Tyix6uKuspr2jRnX5T6stBt81u0Su/aCeYG@FP2F@6W6NyMf3wUWVEWSME6ybPHMs/W8BC@HuBHUmQPJEPJzzLHlobHvw)  It reads from stdin. 
[Answer]
# [Python 3](https://docs.python.org/3/) + numpy + scipy, ~~248~~ 240 bytes
```
from scipy.optimize import*
from numpy import*
def f(b,i=0):
 for r,c in b:p=zeros(2*len(c)+1);p[-3::-2]=c;p[-1]=h=max([0,*(-fminbound(lambda x:polyval(polysub(p,d),x),0,min(s,r),full_output=1)[1]for s,d in b[:i])]);b[i][1]=p;i+=1
 return h
```
[Try it online!](https://tio.run/##bVLBjtsgEL37K0a@BLLEMk6y2jr1qad@g2NF2MYNEgYEeDfZn0/BjrLZqlxmmPfe8AYwV3/Wanu7DVaP4Dphrpk2Xozik4MYjbZ@ncyYmkZzfZR6PsCAWiKqHJcJDNqCJR0IBW1pqk9utUPFWnKFOvxC8cHUm21Zboqm6mJOm@pcjeyC6pys0WYYhWr1pHok2dj2DC6l0fL6ziSK0U0tMqTH5IJJTgIXOWIxGSYpT3ryZvIVxTVtogtH@tlFXYoGN/jQ1qIJUGUO4qWiCVjuJ6vgfPPc@VPHHHdQQZ2gdFeU24zuaEogxyQU0vSY0JJCkdCsKPch3x6TUCXFM5zlSZ69lnlW3OMu0Hf3fYhA80WVZ285fShnZB/CNoeQ3RvT14y@/djjpEmSOE3PPCPAL4Z3ns@DfdkO1x5Wqz/kPEEzb6NIRl5UZs5I4aVQ3CG80OOyrBeTI@DOzPBTN9l3HhrIhY1W5Qo/qN8p8R84b4X6g56A0IibagVPstlUxozh4UnrQWrm0XIq/nZss0jCG8buaJYtJTEAax2KyOYxP4afQPlm9xjFBC8epb@0tYEATLkPbtOlA5eO/0v8rbr/UR@E2QCJfr4u/T7eUa3w7S8 "Python 3 – Try It Online")
*-8 bytes thanks to @xnor*
The function takes a list of `[radius, polynomial]` pairs as input and returns the pile height.
This solution uses more or less the same algorithm as the reference code except that it does not compute the maximum using derivatives. Meanwhile, it is written using built-in `numpy` and `scipy` functions in Python. The ungolfed version is shown in the following. This serves as an alternative version of the reference code for those who wants a shorter version to capture the idea quickly.
```
from scipy.optimize import fminbound
import numpy as np
def compute_pile_height(bowl_data):
    for i, (r, curve) in enumerate(bowl_data):
        distances = [0]  # Initialize the distances array with 0 as the lower bound for max
        # Construct a complete polynominal coefficient array
        curve_poly = np.zeros(2 * len(curve) + 1)
        curve_poly[-3::-2] = curve
        
        # Iterate over all bowls under the current bowl
        for j in range(i):
            b_r, b_curve_poly = bowl_data[j]
            # Calculate the difference polynominal between the current bowl and bowl j
            diff = np.polysub(curve_poly, b_curve_poly)
            # Find the maximum height difference between bowl j and the current bowl in the range [0, min(b_r, r)]
            max_height_diff = -fminbound(lambda x:np.polyval(diff, x), 0, min(b_r, r), full_output=True)[1]
            distances.append(max_height_diff)
        # Compute the maximum distance as the height for the current bowl, 
        # update the polynominal using the height as the constant coefficient
        curve_poly[-1] = height = max(distances)
        # Update stored data for the current bowl
        bowl_data[i][1] = curve_poly
    return height
```
[Try it online!](https://tio.run/##dVXBcpswEL3zFTvuIdBiBmynkzLNKTOdyb09OR5GxkusjJA0kkji/ny6QpiAk3IBxO7bt09vhT65o5Lrt7fGqBZszfUpU9rxlv9F4K1WxkHTcrlXnTxEw4LsWn0CZkHqKDpgA7Vqdeew0lxgdUT@eHTxXr2I6sAcS8oI6GqUAZ5CbFKoO/OMCXAJSFBomMMP4f46cOuYrNHCLWzzHcAXuJfccSY8O3fESQQzhp3ghbsj5J6a/yrUCxroqfflW/Y6Yn@BOyWtM13tgPUNCHQIWomTVNQwE7SITcNrjtIF@DG5b6DyscRM6uwvGmXjFXwFgTIe2vsGRfJJxna5LsvlakeZ/eIYMqF273pRQD0TfyYEeHUsUB/07jujTONp@fUxz7f45FU1TD5izCdK@mtfkfT7asZ9VH37tItm0aQPE3UnPI2gdNMg1aznGu3RvSDKD6SAkeb9w9MM1sMEzTyK7fbxO585u@SSzy9OkL4ObSNvuxaC0abMzmxC4Z7DB2I8kO01IlelQI3EvTYm2c1KUp3BzNVAezmOQixYuz8weC2HVp6ZiH1UCq9JCnPYFJpOiEp1jqbk9rfpMNkWuwtdBiNnTGsk/IviEzW8c/txm4lxBjh7fxDHe@JSgnRqtU4fzls83dfOcvk4BRpgaz80jIAmw/GpyQtv8CH31rOMxxZnvfwJ9a1TBg/grfgp5zHj3bF8ty3GKeqr9kEGXWfkUPrNoXVVzWw4Q6J4sVmV66zYFAvapCSlhcXiISrKAlZRka3Ka3peP0S0mq6mn7M8yrPvZZ6thvuGwjfDO92hyENWnt3kxZjZf7mm2zqnY6kYgIvvWXHz4zqJaOZ8s76dFPBVY@1IBO/QkXaY4TD/1MFuPEt7J/vMzGrBneASbTwZecMOvLMp2CPTGOaKAESIjq/Kq/fDaR5ChvY/AzobyQLx5Bthob69gklmz@ts2W0jFHNxKJzMKu9CCk2A37D//C1sCOINsL2NfexyFCWBn1DgcjP2p4mdixd3ijzij3Bp6axfBAQUFi8D72X9WegY0BNIPcP3nRgafpBXyds/ "Python 3 – Try It Online")
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), ~~104~~ 93 bytes
```
FoldPair[{(R=#;F=#2)&@@#2;H=Max[0,{#2-F,0<x<#~Min~R}~MaxValue~x&@@@#],#~Join~{R|H+F}}&,{},#]&
```
[Try it online!](https://tio.run/##XY7NisJAEITvPkWgIazYzs5MRi8xklOQBUFy8BIMDK5hA/6ARBiY7Xn12Ansgh6rvuqqvtju53SxXXu0fZP1xe38vbPtvfIfZQZpkYGexnkOOt1kW@sqiR70vEC5cisI2/YaSgoM9vb8OAXH0RwOCOHrxsiXv5tZQRSjJ4RD3O/u7bWrYL5uOBV/5n7ivdERJkIZ5WpNhOyoKEIWM@1qw0bkldC4GPAomCbv2ZFIsUQp9Ks0/3fCvFKDSg4LY4/hHrX4GxxUIocfXL0kmlD/BA "Wolfram Language (Mathematica) – Try It Online")
Takes input as a List of `{radius, polynomial}` pairs representing bowls, with polynomials in terms of \$x\$.
For decimal instead of symbolic output, use `NMaxValue` instead (or just call `N` on the result). 
```
(* Step through a list of bowls: *)
(* At each step, calls a function taking {previous-bowls-list},current-bowl *)
(*  which returns {height,{bowls-list}} *)
(* and returns the final height *)
FoldPair[
  (R=#;F=#2)&@@#2;          (*  extract Radius and Function*)
  {
    H=Max[0,                (*  Height - at least zero; the greatest of *)
      MaxValue[{#2-F,       (*   the required heights *)
          0<x<#~Min~R},x]   (*     within the relevant domain *)
      &@@@#]                (*   given all previous bowls *)
  ,
    #~Join~{R|H+F}          (*   append to list of bowls *)
  }&,
  {},                       (* initial list of bowls (empty) *)
  #                         (* list of bowls *)
]&
```
[Answer]
# [R](https://www.r-project.org/), ~~451~~ 436 bytes
```
function(x){x=c(x[1],x);a=rev(pmax(0,c(combn(x,2,function(y,z=sapply(y,"length<-",max(lengths(y)))){z[is.na(z)]=0
b=rep(0,2*(n=nrow(z)-1))
b[2*1:n]=e=z[-1,2]-z[-1,1]
b=b*1:(2*n)
while(!c(b,1)[1])b=b[-1]
b=rev(b)
s=`if`(length(b)>1,eigen(rbind(-(b/b[1])[-1],cbind(diag(length(b)-2),0)))$va,0)
max(outer(c(pmin(abs(s[s==abs(s)]),r<-min(z[1,])),r),2*1:n,`^`)%*%e)}))))
o={}
for(i in seq(a=x[-1])){o=c(o,max(c(0,o)+a[1:i+F]));F=F+i}
max(o)}
```
[Try it online!](https://tio.run/##bVLbjpswEH33V7ioK40TQzFhVyob70ulfeofsFQxxCGWiKGYZEmifHs6kEsjtUjYczlnfDzj9ryS59XWFp2pLfTs2MsC@lRkvGevSrZ6B81G9RDyAop6kyOGR/xO2PODdKppqj2aXqVt2a3nvscHysVzsGf4HQ@pcYFVcGCZDEmOlRssGk3AStvWnxj3BWMkT6OJSGwmtTykvuBR5o@7yJCTYwqiiWXkc20qDV8KyLlgqJZhEmHZWHgHOSNOLsxqcRWBgTfBtSm1hTY3dgk@5N/ygTiweDHGlkaVfwl@xHiIyr/uFO5kuFG97XQLBXbEWFC5A5c6KUeDZYy3c39IHFLBM4Yu4@Nd@OLXgj1NnjQ7DZ0gtTyeyKpuwVBjqdO/Qcl@kIFdqrH79di9ArtTs6lKRWKm75h7fZfvU3O6CGGnc0nnPn2YHD2S4erVZRqua11TmQ5Kt83BSzxOPYpLq9Xyp7HaQaf77kdtrb4VQMkIYVzhnLYb3ZoCxZ7I@t9zelmiQQrVgVcZhyunjXKdhutb6B9eCBszIXjFHRbiY6FFXaFWp6kcdOG5@Huo4b8J6r8NzgqPRffDou10MyC8USN4cRJS8UziZBZStDA8BKNkFoj46olE0IiIIEqeiUhm92AQkjB4ScIguu4xguKrP9YNr9hgRNMbLqLxjUFnD5zvI4e@eOz8Bw "R – Try It Online")
[Try it online!](https://tio.run/##bVJdk5owFH3Pr0iZ7syNBkqQ3ZmyZl/62n9AaRcwahwMlKCLOv52e4lonWmZgdyPc24OJ2kvS3lZ7kzZ6dpAz069LKFPRcZ79prLVu2h2eY9hLyEst4WiOERvxMO/Cht3jTVAUOvUmbVree@xwfKNbNwYPicjqm2gcnhyDIZkgInNzg0moCRpq0/sO4LxkiRRhORmEwqeUx9waPMd6vIkFNgC6KJYeRjrSsFn0oouGColmETYZkbvIeCESv1cpSA6ZtgSq@UgbbQZgE@FF@KgTZweOlqC52v/hL8iPEQdX/e51RVVtGQDP9U7zrVQomeaAN5YcGmVkoXsIzxdu4PjWMqeMYwZdz9DX//@c6eJk@KnQcvSI0eM7JBH5Z1C5pqQ636/Qs3vwnonRunAVg7M0s0q2bTPBWJnm5w@OtGbqb6fFXFzpcVnfv04SDpiQxOVNfDsV1rm0p3sLK7ArzE49Sj@GlVvviujbLQqb77VhujbgNQP0IYz/HYdlvV6hKVn8n63316ucKAlHkHXqUtfjltctspGK9G/3BhmOuE4JV3WIh3h5Z1hVrRaDnown3x9VDDfxvUfxuSJW6L6Q@DsVXNgPCcRvDiJKTimcTJLKQYYXkoRsksEPGYiUTQiIggSp6JSGb3YhCSMHhJwiAa1xhB8Zi7ueGIDRya3nARjW8MOnvgfHUc@uKxyx8 "R – Try It Online")
Broadly speaking an R port of my Jelly answer, though since base R has no function to find the roots of polynomials this is implemented using the method found in `polynom::solve.polynomial`.
A function taking a list of numeric vectors from top to bottom of pile. 
Thanks to @RobinRyder for golfing off 15 bytes!
]