Question

C’est dans le contexte de la Différenciation automatique : que ferait un tel système avec une fonction comme map ou filtre - ou même l'un des Combinateurs SKI ?

Exemple: j'ai la fonction suivante:

def func(x):
    return sum(map(lambda a: a**x, range(20)))

Quel serait son dérivé? Quel sera le résultat d'un système AD? (Cette fonction est bien définie sur les entrées à nombres réels).

Était-ce utile?

La solution

Les fonctions d'ordre supérieur sont discrètes. Ils n'ont pas la qualité cartésienne d'avoir des arguments qui ont des correspondances bien définies sur des points dans un espace à n dimensions.

Cependant, avec vos éclaircissements sur la réponse, plusieurs choses peuvent être dites. Différencier symboliquement certaines fonctions d’ordre supérieur serait possible, mais uniquement pour certains modèles d’appel qui se résument à des fonctions bien connues.

Probablement, la différenciation numérique serait plus fructueuse, car elle permet d'estimer la dérivée de manière répétée évaluer la fonction donnée.

De même, les fonctions totalement générales - et votre exemple le suit, avec l'utilisation de fonctions relativement arbitraires - vous atteindrez éventuellement la complétude de Turing, ce qui signifiera qu'aucune habileté de la part d'un différenciateur symbolique ne être capable de différencier automatiquement la fonction.

Autres conseils

Un bon système AD y parviendra facilement. Si le code AD effectue la traduction source à source, il risque de rencontrer des problèmes avec la somme . Mais si c'est un système AD qui fonctionne en surchargeant les opérateurs arithmétiques, le code AD ne "verra" pas réellement la fonction sum , mais uniquement les opérations + que somme appels de fonction.

Je ne suis pas d'accord avec la réponse acceptée selon laquelle vous ne pouvez pas différencier utilement les fonctions de rang supérieur, ou que vous devez vous limiter à un sous-ensemble particulièrement réduit d'entre elles en le démontrant dans la pratique.

En utilisant mon package 'ad' Haskell, nous obtenons:

ghci> :m + Numeric.AD
ghci> diff (\x -> sum (map (**x) [1..20])) 10
7.073726805128313e13

Nous pouvons extraire ce qui a été fait en abusant d'un type numérique tracé pour répondre à votre question sur le dérivé est:

ghci> :m + Debug.Traced
ghci> putStrLn $ showAsExp $ diff (\x -> sum (map (**x) [1..20])) (unknown "x" :: Traced Double) 
1.0 * (1.0 ** x * log 1.0) + 
1.0 * (2.0 ** x * log 2.0) +
1.0 * (3.0 ** x * log 3.0) +
1.0 * (4.0 ** x * log 4.0) +
1.0 * (5.0 ** x * log 5.0) +
1.0 * (6.0 ** x * log 6.0) +
1.0 * (7.0 ** x * log 7.0) +
1.0 * (8.0 ** x * log 8.0) +
1.0 * (9.0 ** x * log 9.0) +
1.0 * (10.0 ** x * log 10.0) +
1.0 * (11.0 ** x * log 11.0) +
1.0 * (12.0 ** x * log 12.0) +
1.0 * (13.0 ** x * log 13.0) +
1.0 * (14.0 ** x * log 14.0) +
1.0 * (15.0 ** x * log 15.0) +
1.0 * (16.0 ** x * log 16.0) +
1.0 * (17.0 ** x * log 17.0) +
1.0 * (18.0 ** x * log 18.0) +
1.0 * (19.0 ** x * log 19.0) +
1.0 * (20.0 ** x * log 20.0)

Avec le partage complet, vous obtenez des résultats plutôt horribles, parfois plus efficaces de manière asymptotique.

ghci> putStrLn $ showAsExp $ reShare $ diff (\x -> sum (map (**x) [1..20])) 
      (unknown "x" :: Traced Double)
let _21 = 1.0 ** x;
    _23 = log 1.0;
    _20 = _21 * _23;
    _19 = 1.0 * _20;
    _26 = 2.0 ** x;
    _27 = log 2.0;
    _25 = _26 * _27;
    _24 = 1.0 * _25;
    _18 = _19 + _24;
    _30 = 3.0 ** x;
    _31 = log 3.0;
    _29 = _30 * _31;
    _28 = 1.0 * _29;
    _17 = _18 + _28;
    _34 = 4.0 ** x;
    _35 = log 4.0;
    _33 = _34 * _35;
    _32 = 1.0 * _33;
    _16 = _17 + _32;
    _38 = 5.0 ** x;
    _39 = log 5.0;
    _37 = _38 * _39;
    _36 = 1.0 * _37;
    _15 = _16 + _36;
    _42 = 6.0 ** x;
    _43 = log 6.0;
    _41 = _42 * _43;
    _40 = 1.0 * _41;
    _14 = _15 + _40;
    _46 = 7.0 ** x;
    _47 = log 7.0;
    _45 = _46 * _47;
    _44 = 1.0 * _45;
    _13 = _14 + _44;
    _50 = 8.0 ** x;
    _51 = log 8.0;
    _49 = _50 * _51;
    _48 = 1.0 * _49;
    _12 = _13 + _48;
    _54 = 9.0 ** x;
    _55 = log 9.0;
    _53 = _54 * _55;
    _52 = 1.0 * _53;
    _11 = _12 + _52;
    _58 = 10.0 ** x;
    _59 = log 10.0;
    _57 = _58 * _59;
    _56 = 1.0 * _57;
    _10 = _11 + _56;
    _62 = 11.0 ** x;
    _63 = log 11.0;
    _61 = _62 * _63;
    _60 = 1.0 * _61;
    _9 = _10 + _60;
    _66 = 12.0 ** x;
    _67 = log 12.0;
    _65 = _66 * _67;
    _64 = 1.0 * _65;
    _8 = _9 + _64;
    _70 = 13.0 ** x;
    _71 = log 13.0;
    _69 = _70 * _71;
    _68 = 1.0 * _69;
    _7 = _8 + _68;
    _74 = 14.0 ** x;
    _75 = log 14.0;
    _73 = _74 * _75;
    _72 = 1.0 * _73;
    _6 = _7 + _72;
    _78 = 15.0 ** x;
    _79 = log 15.0;
    _77 = _78 * _79;
    _76 = 1.0 * _77;
    _5 = _6 + _76;
    _82 = 16.0 ** x;
    _83 = log 16.0;
    _81 = _82 * _83;
    _80 = 1.0 * _81;
    _4 = _5 + _80;
    _86 = 17.0 ** x;
    _87 = log 17.0;
    _85 = _86 * _87;
    _84 = 1.0 * _85;
    _3 = _4 + _84;
    _90 = 18.0 ** x;
    _91 = log 18.0;
    _89 = _90 * _91;
    _88 = 1.0 * _89;
    _2 = _3 + _88;
    _94 = 19.0 ** x;
    _95 = log 19.0;
    _93 = _94 * _95;
    _92 = 1.0 * _93;
    _1 = _2 + _92;
    _98 = 20.0 ** x;
    _99 = log 20.0;
    _97 = _98 * _99;
    _96 = 1.0 * _97;
    _0 = _1 + _96;
in  _0

En général, la différenciation automatique ne pose aucun problème avec les fonctions de rang supérieur. Les traductions source à source peuvent toutefois rencontrer quelques pièges, en fonction des limites de l’outil concerné.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top