TransWikia.com

How can I find a functional square root in Mathematica?

Mathematica Asked on July 25, 2021

A functional square root of a function $g$ is another function $f$ such that $g=fcirc f$. According to that article, there is a systematic approach to finding a functional square root that involves solving Schröder’s equation though I don’t know what procedure to apply.

For example, the functional square root of $x/(2 – x)$ is $x/(sqrt{2} + x – xsqrt{2})$ and we can verify:

f[x_] := x/(Sqrt[2] + x - x*Sqrt[2])
FullSimplify[f[f[x]]]
(* returns: x/(2 - x) *)

I’d like to know how to go about finding exact or approximate functional square roots in Mathematica.
Suppose I want to find an $f$ for $g(x)=cos(4 pi x)$. I try to frame it as a differential equation but this is unsuccessful. I am not even sure what the initial conditions should be either:

D[f[f[x]], x]
(* Derivative[1][f][x] Derivative[1][f][f[x]] *)

D[Cos[4 Pi x], x]
(* -4 Pi Sin[4 Pi x] *)

NDSolve[{-4 Pi Sin[4 Pi x] == Derivative[1][f][x] Derivative[1][f][f[x]], f[0] == 1}, f, {x, 0, 1}]
(* Power::infy: Infinite expression 1/0 encountered. *)

Apparently there are power series methods that can solve problems like this, and these things called Carleman Matrices. I looked around in the docs and found CarlemanLinearize but I can’t tell if this is related to this problem.

@J.M. has a function to construct a Carleman matrix here so I will take a look at that.


I’ve tried to follow along with this answer here but my coefficients end up as complex numbers and the plot doesn’t really look like iterating twice will remotely resemble a cosine:

x0 = 0; n = 30;(*expansion point and order*)
cosCM = N[CarlemanMatrix[Cos[4 Pi x], {x, x0, n}], 30];
shalfCoeffs = MatrixPower[Transpose[cosCM], 1/2, UnitVector[n + 1, 2]];
shalf[x_] = Fold[(#1 x + #2) &, 0, Reverse[shalfCoeffs]];
ReImPlot[shalf[x], {x, 0, 1}]

One Answer

I was not able to get a half iterate for $cos(...)$ anything, and from reading around a bit it appears that half iterates of $cos$ might be impossible either due to convergence or the evenness of $cos$'s series expansion terms. However, I was able to get a half-iterate for a small part of the domain of $sin(4 pi x)$ through fixed point iteration on the series, though it becomes inaccurate quite quickly:

(* Try to find a half iterate of Sin[4 [Pi] x] *)
halfit[x_] = Nest[(Sin[4 [Pi]*Normal[InverseSeries[Series[#, {x, 0, 6}]]]] + #)/2 &, x, 8];

Plot[{halfit[halfit[x]], Sin[4 [Pi] x]}, {x, -[Pi]/2, [Pi]/2}, 
 PlotRange -> {-1, 1}, 
 PlotStyle -> {Directive[Thick, Red], Directive[Blue]}]

half iterate approx

I was able to get an approximation of the half-sine by a different method using a Newton series, though this does not work for a higher frequency sine like $sin(4 pi x)$ and produces a very noisy function. The resulting $mathrm{hsin}(mathrm{hsin}(x))approxsin(x)$ is not too bad an approximation judging by the plot:

newtonfhalf[f_, x_, mmax_] := 
 Sum[Binomial[1/2, m] Sum[
    Binomial[m, k] (-1)^(m - k) Nest[f, x, k], {k, 0, m}], {m, 0, mmax}]

nth = Function[{x}, newtonfhalf[Sin[#] &, x, 40]];
nthh2 = nth[nth[x]];
Plot[{Sin[x], nthh2}, {x, -4, 4}, 
 PlotStyle -> {Directive[Thick, Blue], Directive[Red]}]

half sine newton


I've had some luck with a neural network approach to the problem. I've found it's possible to train a network in a non-standard way to find an approximate half-iterate. Assume a network $N$ of 1 input and 1 output node with arbitrary layers in between and that we're trying to find a half-iterate for the function $mathrm{target}(x)$:

  1. Run $N$ forward on a random input $x_i$ and generate output $y_i$
  2. Run $N$ forward again using $y_i$ as input, generating output $y_i'$
  3. The loss is $(mathrm{target}(x_i) - y_i')^2$. Back-propagate and update $N$ and return to step 1.

The resulting network is hopefully trained such that $N(N(x)) approx mathrm{target}(x)$.

I wasn't sure how to approach this in Mathematica but this is my first time using PyTorch ever, so what follows may be a bit basic:

import torch
import torch.nn as nn
import torch.optim as optim

from math import pi, sin, cos
import random
import csv


def targetfn(x):
    return sin(x)


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.lin = nn.Linear(1, 20)
        self.lmid1 = nn.Tanh()
        self.lmid2 = nn.Linear(20, 20)
        self.lmid3 = nn.Tanh()
        self.lout = nn.Linear(20, 1)

    def forward(self, w):
        w = self.lin(w)
        w = self.lmid1(w)
        w = self.lmid2(w)
        w = self.lmid3(w)
        return self.lout(w)


def train():
    net = Net()
    print(net)

    optimizer = optim.SGD(net.parameters(), lr=0.01)
    criterion = nn.MSELoss()

    # init random
    net.zero_grad()
    outinit = net(torch.randn(1))
    outinit.backward(torch.randn(1))

    for i in range(100000):
        x = random.uniform(-2 * pi, 2 * pi)
        target = torch.tensor([targetfn(x)])
        y1 = net(torch.tensor([x]))
        net.zero_grad()
        optimizer.zero_grad()
        y2 = net(y1)
        loss = criterion(y2, target)
        loss.backward()
        optimizer.step()

    return net


def main():
    net = train()

    with open("hfn.csv", 'w', newline='') as csvfile:
        csvwriter = csv.writer(csvfile, delimiter=',')
        n = 2000
        xmin = -2 * pi
        xmax = 2 * pi
        step = (xmax - xmin) / n
        x = xmin
        for i in range(n):
            csvwriter.writerow([x, net(torch.tensor([x])).item()])
            x += step


if __name__ == '__main__':
    main()

... and plotting in Mathematica:

data = Import["hfn.csv"];
intp = Interpolation[data];
Plot[{Sin[t], intp[intp[t]]}, {t, -2 [Pi], 2 [Pi]}, 
 PlotRange -> {-1.3, 1.3}, 
 PlotStyle -> {Directive[Thick, Blue], Directive[Thin, Red]}, 
 PlotTheme -> "Scientific"]

pytorch half sin

This is looking good for $sin(x)$. What about $cos(x)$? I changed targetfn in the python code above and at least I got something that looked close to a cosine wave:

half cosine approximation

Answered by flinty on July 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP