Monotone kubisk interpolation

Inom det matematiska området för numerisk analys är monoton kubisk interpolation en variant av kubisk interpolation som bevarar monotoniteten hos datamängden som interpoleras .

Monotonicitet bevaras genom linjär interpolation men garanteras inte av kubisk interpolation .

Monotone kubisk Hermite interpolation

Exempel som visar icke-monoton kubisk interpolation (i rött) och monoton kubisk interpolation (i blått) av en monoton datamängd.

Monotone interpolation kan åstadkommas med kubisk Hermite spline med tangenterna modifierade för att säkerställa monotoniteten hos den resulterande Hermite spline.

En algoritm är också tillgänglig för monoton kvintisk Hermite-interpolation.

Interpolant val

Det finns flera sätt att välja interpolerande tangenter för varje datapunkt. Detta avsnitt kommer att beskriva användningen av Fritsch–Carlson-metoden. Observera att endast ett pass av algoritmen krävs.

Låt datapunkterna vara indexerade i sorterad ordning för .

  1. Beräkna lutningarna för sekantlinjerna mellan på varandra följande punkter:

    för .



  2. Dessa tilldelningar är provisoriska och kan ersättas i de återstående stegen. Initiera tangenterna vid varje inre datapunkt som medelvärdet av sekanterna,

    för . För endpoints, använd ensidiga skillnader:

    .

    Om och har motsatta tecken, sätt .



  3. För , där någonsin (där alltid två på varandra följande är lika), set eftersom spline som förbinder dessa punkter måste vara platt för att bevara monotoniteten. Ignorera steg 4 och 5 för de .

  4. Låt

    .

    Om antingen eller är negativ, är indatapunkterna inte strikt monotona, och är ett lokalt extremum. I sådana fall bitvisa monotona kurvor fortfarande genereras genom att välja om eller om , även om strikt monotoni inte är möjlig globalt.

  5. För att förhindra överskjutning och säkerställa monotonitet måste minst ett av följande tre villkor vara uppfyllt:
(a) funktionen

, eller

(b) eller (
c) .
Endast villkor (a) är tillräckligt för att säkerställa strikt monotoni: måste vara positivt.

Ett enkelt sätt att uppfylla denna begränsning är att begränsa vektorn till en cirkel med radie 3. Det vill säga, om ställ sedan in

,

och skala om tangenterna via

.

Alternativt är det tillräckligt att begränsa och . För att åstadkomma detta om in .

Kubisk interpolation

Efter förbearbetningen ovan är utvärdering av den interpolerade spline ekvivalent med cubic Hermite spline , med hjälp av data , och för .

För att utvärdera vid , hitta indexet i sekvensen där ligger mellan och , det vill säga: . Beräkna

då är det interpolerade värdet

där är basfunktionerna för den kubiska Hermite spline .

Exempel implementering

Följande JavaScript- implementering tar en datamängd och producerar en monoton kubisk spline-interpolantfunktion:








  
    
    

   0
     
        
    
    
           
       0      0  
        
        
        
           0
             
    
    
    
       
       0       
               
          
    
         
    
       0      
          
          
    

        
        
    
    
             
       0       
                      
          
          
          
    
    
       0
       0       
                
           0 
              0
          
                         
                    
        
    
      

        
        
      
        
    
    
          
       0       
           
           
           
                   
              
              
              
              
              
          
    
        
        

    
      
        
             
        
        
        
        
           0      
            
                
               
                      
                       
             
                
                
                    
                  
                
            
        
          0 

        
             
        
                        
        
                   
                              
        
        
            
    









   0    
   0    
   
   

    
    0       
        




        
   
   
    0       
       0  0
       
       0
       
                

 /*  * Monotone kubisk spline-interpolation  * Användningsexempel listat längst ner; detta är ett fullt fungerande paket.  Till   exempel * kan detta utföras antingen på webbplatser som  * https://www.programiz.com/javascript/online-compiler/  * eller med nodeJS.  */  function  DEBUG  (  s  )  {  /* Avkommentera följande för att möjliggöra utförlig utmatning av lösaren: */  //console.log(s);  }  var  outputCounter  =  ;  var  createInterpolant  =  funktion  (  xs  ,  ys  )  {  var  i  ,  length  =  xs  .  längd  ;  // Deal with length issues  if  (  length  !=  ys  .  length  )  {  throw  'Behöver ett lika stort antal xs och ys.'  ;  }  if  (  längd  ===  )  {  return  funktion  (  x  )  {  return  ;  };  }  if  (  längd  ===  1  )  {  // Impl: Förberäkning av resultatet förhindrar problem om ys muteras senare och tillåter sophämtning av ys //  Impl: Unary plus konverterar korrekt värden till tal  var  result  =  +  ys  [  ];  return  funktion  (  x  )  {  returnera  resultat  ;  };  }  // Ordna om xs och ys så att xs sorteras  var  indexes  =  [];  för  (  i  =  ;  i  <  längd  ;  i  ++  )  {  index  .  trycka  (  i  );  }  index  .  sort  (  funktion  (  a  ,  b  )  {  return  xs  [  a  ]  <  xs  [  b  ]  ?  -  1  :  1  ;  });  var  oldXs  =  xs  ,  oldYs  =  ys  ;  // Impl: Att skapa nya arrayer förhindrar också problem om inmatningsarrayerna muteras senare  xs  =  [];  ys  =  [];  // Impl: Unary plus konverterar korrekt värden till tal  för  (  i  =  ;  i  <  längd  ;  i  ++  )  {  xs  [  i  ]  =  +  oldXs  [  indexerar  [  i  ]];  ys  [  i  ]  =  +  oldYs  [  indexerar  [  i  ]];  }  DEBUG  (  "debug: xs = [ "  +  xs  +  " ]"  )  DEBUG  (  "debug: ys = [ "  +  ys  +  " ]"  )  // Få på varandra följande skillnader och lutningar  var  dys  =  [],  dxs  =  [] ,  ms  =  [];  för  (  i  =  ;  i  <  längd  -  1  ;  i  ++  )  {  var  dx  =  xs  [  i  +  1  ]  -  xs  [  i  ],  dy  =  ys  [  i  +  1  ]  -  ys  [  i  ];  dxs  [  i  ]  =  dx  ;  dys  [  i  ]  =  dy  ;  ms  [  i  ]  =  dy  /  dx  ;  }  // Få grad-1 koefficienter  var  c1s  =  [  ms  [  ]];  för  (  i  =  ;  i  <  dxs  .  längd  -  1  ;  i  ++  )  {  var  m  =  ms  [  i  ],  mNext  =  ms  [  i  +  1  ];  if  (  m  *  mNext  <=  )  {  c1s  [  i  ]  =  ;  }  else  {  var  dx_  =  dxs  [  i  ],  dxNext  =  dxs  [  i  +  1  ],  common  =  dx_  +  dxNext  ;  c1s  [  i  ]  =  3  *  common  /  ((  common  +  dxNext  )  /  m  +  (  common  +  dx_  )  /  mNext  );  }  }  c1s  .  push  (  ms  [  ms  .  längd  -  1  ]);  DEBUG  (  "debug: dxs = [ "  +  dxs  +  " ]"  )  DEBUG  (  "debug: ms = [ "  +  ms  +  " ]"  )  DEBUG  (  "debug: c1s.length = "  +  c1s  .  length  )  DEBUG  (  " debug: c1s = [ "  +  c1s  +  " ]"  )  // Få grad-2 och grad-3 koefficienter  var  c2s  =  [],  c3s  =  [];  för  (  i  =  ;  i  <  cls  .  längd  -  1  ;  i  ++  )  {  var  c1  =  c1s  [  i  ];  var  m_  =  ms  [  i  ];  var  invDx  =  1  /  dxs  [  i  ];  var  common_  =  c1  +  c1s  [  i  +  1  ]  -  m_  -  m_  ;  DEBUG  (  "debug: "  +  i  +  ". c1 = "  +  c1  );  DEBUG  (  "debug: "  +  i  +  ". m_ = "  +  m_  );  DEBUG  (  "debug: "  +  i  +  ". invDx = "  +  invDx  );  DEBUG  (  "debug: "  +  i  +  ". common_ = "  +  common_  );  c2s  [  i  ]  =  (  m_  -  c1  -  common_  )  *  invDx  ;  c3s  [  i  ]  =  common_  *  invDx  *  invDx  ;  }  DEBUG  (  "debug: c2s = [ "  +  c2s  +  " ]"  )  DEBUG  (  "debug: c3s = [ "  +  c3s  +  " ]"  )  // Returnera interpolant funktion  returfunktion  (  x  )  {  //  Punkten längst till höger i datasetet ska ge ett exakt resultat  var  i  =  xs  .  längd  -  1  ;  // Avkommentera följande för att endast returnera det interpolerade värdet.  //if (x == xs[i]) { returnera ys[i]; }   // Sök efter intervallet x är i, returnera motsvarande y om x är ett av de ursprungliga xs  var  low  =  ,  mid  ,  high  =  c3s  .  längd  -  1  ;  while  (  låg  <=  hög  )  {  mid  =  Math  .  golv  (  0,5  *  (  låg  +  hög  ));  var  xHere  =  xs  [  miden  ];  if  (  xHere  <  x  )  {  low  =  mid  +  1  ;  }  else  if  (  xHere  >  x  )  {  high  =  mid  -  1  ;  }  else  {  // Avkommentera följande för att endast returnera det interpolerade värdet.  //retur ys[miden];  låg  =  c3s  .  längd  -  1  ;  hög  =  medel  ;  bryta  ;  }  }  i  =  Matte  .  max  (  ,  hög  );  // Interpolera  var  diff  =  x  -  xs  [  i  ];  outputCounter  ++  ;  var  interpolatedValue  =  ys  [  i  ]  +  diff  *  (  c1s  [  i  ]  +  diff  *  (  c2s  [  i  ]  +  diff  *  c3s  [  i  ]));  // Värdet på interpolatorns derivata vid denna punkt.  var  derivativeValue  =  c1s  [  i  ]  +  diff  *  (  2  *  c2s  [  i  ]  +  diff  *  3  *  c3s  [  i  ]);  DEBUG  (  "debug: #"  +  outputCounter  +  ". x = "  +  x  +  ". i = "  +  i  +  ", diff = "  +  diff  +  ", interpolatedValue = "  +  interpolatedValue  +  ", derivativeValue = "  +  derivativeValue  ) ;  // Avkommentera följande för att endast returnera det interpolerade värdet.  // returnera interpolatedValue;  return  [  interpoleratVärde  ,  derivatVärde  ];  };  };  /*  Användningsexempel nedan kommer att uppskatta x^2 för 0 <= x <= 4.  Kommandoradsanvändningsexempel (kräver installation av nodejs):  node monotone-cubic-spline.js  */  var  X  =  [  ,  1  ,  2  ,  3  4  ]  ;  var  F  =  [  ,  1  ,  4  ,  9  ,  16  ];  var  f  =  skapa Interpolant  (  X  ,  F  );  var  N  =  X  .  längd  ;  konsol  .  log (  "  # BLOCK 0 :: Data för monotone-cubic-spline.js" )  ;  konsol  .  log  (  "X"  +  "\t"  +  "F"  );  for  (  var  i  =  ;  i  <  N  ;  i  +=  1  )  {  konsol  .  log  (  F  [  i  ]  +  '\t'  +  X  [  i  ]);  }  konsolen  .  log  (  ""  );  konsol  .  log  (  ""  );  konsol  .  log  (  "# BLOCK 1 :: Interpolerad data för monotone-cubic-spline.js" )  ;  konsol  .  log  (  " x "  +  "\t\t"  +  " P(x) "  +  "\t\t"  +  "dP(x)/dx "  );  var  meddelande  =  ''  ;  var  M  =  25  ;  för  (  vari  =  ;  i  <  =  M  ;  i  +  =  1  )  {  varx  =  X  [  ]  +  (  X  [  N  -  1  ]  -X  [  ]  )  *  i  /  M  ;  var  rvals  =  f  (  x  );  var  P  =  rvals  [  ];  var  D  =  rvals  [  1  ];  meddelande  +=  x  .  toPrecision  (  15  )  +  '\t'  +  P  .  toPrecision  (  15  )  +  '\t'  +  D  .  toPrecision  (  15  )  +  '\n'  ;  }  konsolen  .  log  (  meddelande  ); 
  • Fritsch, FN; Carlson, RE (1980). "Monotone bitvis kubisk interpolation". SIAM Journal on Numerical Analysis . SIAM. 17 (2): 238–246. doi : 10.1137/0717021 .
  • Dougherty, RL; Edelman, A.; Hyman, JM (april 1989). "Positivitets-, monotoni- eller konvexitetsbevarande kubisk och kvintisk Hermite-interpolation" . Beräkningsmatematik . 52 (186): 471–494. doi : 10.2307/2008477 .

externa länkar