Fonksiyonel Programlama Kavramları

Fonksiyonel programlamaya giriş

Earth Engine, çok sayıda makinede hesaplama yapmak için paralel işleme sistemi kullanır. Earth Engine, bu tür bir işlemeyi etkinleştirmek için önemli optimizasyon ve verimlilik kazanımları sağlamak amacıyla işlevsel diller tarafından yaygın olarak kullanılan standart tekniklerden (ör. referans şeffaflığı ve geç değerlendirme) yararlanır.

Fonksiyonel programlamayı prosedürel programlamadan ayıran temel kavram, yan etkilerin olmamasıdır. Yani yazdığınız işlevler, işlevin dışındaki verilere bağlı değildir veya bu verileri güncellemez. Aşağıdaki örneklerde göreceğiniz gibi, sorununuzu yan etkileri olmayan işlevler kullanarak çözülebilecek şekilde yeniden yapılandırmak mümkündür. Bu işlevler, paralel olarak yürütülmeye çok daha uygundur.

"For" döngüleri

Earth Engine'de for döngülerinin kullanılması önerilmez. Aynı sonuçlar, her öğeye bağımsız olarak uygulanabilen bir işlev belirttiğiniz map() işlemi kullanılarak da elde edilebilir. Bu sayede sistem, işleme görevini farklı makinelere dağıtabilir.

Aşağıdaki örnekte, bir sayı listesini alıp map() kullanarak her sayının karesini içeren başka bir liste oluşturma işlemi gösterilmektedir:

Kod Düzenleyici (JavaScript)

// This generates a list of numbers from 1 to 10.
var myList = ee.List.sequence(1, 10);

// The map() operation takes a function that works on each element independently
// and returns a value. You define a function that can be applied to the input.
var computeSquares = function(number) {
  // We define the operation using the EE API.
  return ee.Number(number).pow(2);
};

// Apply your function to each item in the list by using the map() function.
var squares = myList.map(computeSquares);
print(squares);  // [1, 4, 9, 16, 25, 36, 49, 64, 81]

Eğer/Değilse Koşulları

Yordamsal programlama paradigmasına alışkın olan yeni kullanıcıların karşılaştığı bir diğer yaygın sorun, Earth Engine'de if/else koşullu operatörlerinin doğru kullanımıdır. API, ee.Algorithms.If() algoritması sağlasa da map() ve filtreleri kullanan daha işlevsel bir yaklaşım tercih edildiğinden bu algoritmanın kullanılması kesinlikle önerilmez. Earth Engine, ertelenmiş yürütme kullanır. Bu, bir ifadenin değerlendirilmesinin, gerçekleşen değerine gerçekten ihtiyaç duyulana kadar ertelendiği anlamına gelir. Bazı durumlarda bu tür bir yürütme modeli, bir ee.Algorithms.If() ifadesinin hem doğru hem de yanlış alternatiflerini değerlendirir. Bu durum, ifadelere ve bunları yürütmek için gereken kaynaklara bağlı olarak ek hesaplama ve bellek kullanımına neden olabilir.

Yukarıdaki örneğin, yalnızca tek sayıların karelerini hesaplama görevinin yer aldığı bir varyantını çözmek istediğinizi varsayalım. Bu sorunu if/else koşulları olmadan çözmeye yönelik işlevsel bir yaklaşım aşağıda gösterilmiştir:

Kod Düzenleyici (JavaScript)

// The following function determines if a number is even or odd.  The mod(2)
// function returns 0 if the number is even and 1 if it is odd (the remainder
// after dividing by 2).  The input is multiplied by this remainder so even
// numbers get set to 0 and odd numbers are left unchanged.
var getOddNumbers = function(number) {
  number = ee.Number(number);   // Cast the input to a Number so we can use mod.
  var remainder = number.mod(2);
  return number.multiply(remainder);
};

var newList = myList.map(getOddNumbers);

// Remove the 0 values.
var oddNumbers = newList.removeAll([0]);

var squares = oddNumbers.map(computeSquares);
print(squares);  // [1, 9, 25, 49, 81]

Bu paradigma, özellikle koleksiyonlarla çalışırken geçerlidir. Koleksiyona belirli koşullara göre farklı bir algoritma uygulamak istiyorsanız tercih edilen yöntem, önce koleksiyonu koşula göre filtrelemek ve ardından alt kümelerin her birine farklı bir işlev map(). Bu sayede sistem, işlemi paralel hale getirebilir. Örneğin:

Kod Düzenleyici (JavaScript)

// Import Landsat 8 TOA collection and filter to 2018 images.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterDate('2018-01-01', '2019-01-01');

// Divide the collection into 2 subsets and apply a different algorithm on them.
var subset1 = collection.filter(ee.Filter.lt('SUN_ELEVATION', 40));
var subset2 = collection.filter(ee.Filter.gte('SUN_ELEVATION', 40));

// Multiply all images in subset1 collection by 2;
// do nothing to subset2 collection.
var processed1 = subset1.map(function(image) {
  return image.multiply(2);
});
var processed2 = subset2;

// Merge the collections to get a single collection.
var final = processed1.merge(processed2);
print('Original collection size', collection.size());
print('Processed collection size', final.size());

Kümülatif İterasyon

Her iterasyonun sonucunun bir sonraki iterasyon tarafından kullanıldığı sıralı işlem yapmanız gerekebilir. Earth Engine, bu tür görevler için iterate() yöntemini sunar. iterate() işlevinin sıralı bir şekilde yürütüldüğünü ve bu nedenle büyük işlemler için yavaş olacağını unutmayın. Bu işlevi yalnızca istediğiniz çıkışı elde etmek için map() ve filtreleri kullanamadığınızda kullanın.

iterate() için iyi bir örnek, Fibonacci sayısı dizisinin oluşturulmasıdır. Burada, dizideki her sayı, önceki iki sayının toplamıdır. iterate() işlevi, bir işlev (algoritma) ve bir başlangıç değeri olmak üzere 2 bağımsız değişken alır. İşlevin kendisine 2 değer iletilir: Yinelemedeki mevcut değer ve önceki yinelemenin sonucu. Aşağıdaki örnekte, Earth Engine'de Fibonacci dizisinin nasıl uygulanacağı gösterilmektedir.

Kod Düzenleyici (JavaScript)

var algorithm = function(current, previous) {
  previous = ee.List(previous);
  var n1 = ee.Number(previous.get(-1));
  var n2 = ee.Number(previous.get(-2));
  return previous.add(n1.add(n2));
};

// Compute 10 iterations.
var numIteration = ee.List.repeat(1, 10);
var start = [0, 1];
var sequence = numIteration.iterate(algorithm, start);
print(sequence);  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

JavaScript kavramlarını iyi anladığınıza göre Earth Engine API'nin coğrafi işlevlerine giriş için API Eğitimi'ne göz atabilirsiniz.