‘matlab’ etiketi için arşiv.
Zaman ölçer
Büyük büyük verilerde uzun uzun işlemler yapıyoruz. Kodu yazdık, bastık 'run'a. Bekle Allah bekle...
Bir sayaç olaydı da bize geçen süreyi göstereydi, hatta kalan süreyi tahmin edeydi ne de güzel olurdu diye iç geçiriyoruz. Biliyoruz tic/toc var ama daha modüler bir şeyler olsun istiyoruz. Gelin, bugün böyle bir şey yazalım.
Bunun için persistent anahtar sözcüğünü kullanacağız. Hatırlarsanız kalıcı değişkenler yaratmamıza yarıyordu kendisi. Kalıcı olmasını istediğimiz şey ölçümün ilk yapıldığı an.
Yazacağımız zaman ölçme fonksiyonu bir döngünün içinden çağıracağımızı düşünelim. Toplamda n tane iterasyon olsun ve fonksiyonu i. iterasyonda çağıracağımızı varsayalım ve başlayalım:
function [gecenSure, kalanTahminiSure, mesaj] = zaman_olcer(i, n)
persistent zaman
Fonksiyon ilk kez çağrıldığında zaman değişkeni boş olacak, bunu hesaba katarak ilklendirmeyi yapalım:
if(isempty(zaman)) % İlk çağrıldığında t'yi şu anki zamana eşitle
zaman = clock;
end
Geçen süreyi etime fonksiyonu ile ölçmek çok kolay:
gecenSure = etime(clock, zaman); % Geçen süre = şu anki zaman - bir önceki ölçüm
Buraya kadar hava hoştu. Eğer kalan süreyi tahmin etmemiz bekleniyorsa, döngünün neresinde olunduğu bilgisi (i ve n parametreleri) verilmeli:
if nargout > 1 % Birden fazla sonuç isteniyorsa
assert(nargin == 2) % Şu anki döngü numarası ve toplam döngü sayısı verilmeli
kalanTahminiSure = gecenSure / i * (n-i);
if nargout > 2 % mesaj olarak basılacaksa
mesaj = sprintf('Geçen süre: %.1f sn. Tahmini kalan süre: %.1f sec\n', ...
gecenSure, kalanTahminiSure);
end
end
end
Şimdi de test için, her döngüde (aynı dağılımdan gelen rastgele) bir süre harcayan şöyle basit bir betik yazalım:
zaman_olcer(); % ilklendirme
K = 200;
for k = 1:K
pause(rand/10) % Döngüde bir takım işlemler yapılsın ve biraz zaman alsın
[gecenSure, kalanTahminiSure, mesaj] = zaman_olcer(k, K);
fprintf(mesaj)
end
İşimiz bittiğinde fonksiyonu silmeyi aman unutmayalım:
clear zaman_olcer;
Sonuçların her döngüde yeni bir satıra yazılması sizi rahatsız ediyor mu? Beni çok rahatsız ediyor. Gelin tek satırda bu işi çözelim! Sonucu eskisini güncelleyerek göstermeye yarayacak bir 'akıllı çıktı' fonksiyonu yazalım:
function cikti = akilli_cikti(girdi)
persistent silgi
if(isempty(silgi))
silgi = '';
end
cikti = sprintf([silgi, girdi]);
silgi = repmat(sprintf('\b'), 1, length(girdi));
end
Burada silgi dediğimiz değişken girdi'deki karakter sayısı kadar '\b' karakterinin yan yana dizilmesinden oluşuyor. '\b', backslash yerine geçiyor; yani önceki yazılan karakterleri siliyor. repmat ise belli bir girdiyi yatay veya dikey döşeyerek daha büyük değişkenler elde etmeye yarıyor. Bu durumda '\b'leri yan yana döşüyor.
Artık test betiğimizdeki ekrana basma satırını güncelleyebiliriz:
fprintf(akilli_cikti(mesaj))
Harika! Artık yüzlerce satır görmek yerine her döngüde güncellenen tek bir satırda ne olup bittiğinden haberdar olabiliyoruz.
Bu arada unutmayalım: Akıllı çıktıyı sadece zaman ölçmede değil, kaçıncı turu attığımızı görmek gibi binbir türlü küçük ekran raporlamalarında kullanabiliriz.
MATLAB'de neden döngülerden kaçınmalıyız ve ilklendirme yapmalıyız?
Bildiğimiz üzere, MATLAB, yorumlayıcı (interpreter) diller sınıfına ait. Yavaşlığa neden olan bu altyapı yüzünden MATLAB kullanırken döngülerden kaçınmamız tembihlenir. Peki biz bu tembihlere denemeden inanır mıyız? Cevabı aldım, evet, inanmayız!
Bir e-deney (bunu yeni uydurdum, bilgisayarcının deneyi böyle olur) tasarlayalım. Döngü kullanmanın ve ilklendirme yapmanın, yani MATLAB diliyle konuşursak, for kullanmanın ve zeros ile değişken için yer açmanın etkisini merak ediyoruz. Bunun için şu üç farklı yöntemi test edeceğiz:
- Döngülü ve ilklendirmesiz
- Döngülü ve ilklendirmeli
- Vektörleştirme (vectorization)
Deneyleri bir kere yapmaktansa çok kere tekrarlayıp ortalamasını almak bizim gibi titiz e-deneyciye daha çok yakışır. Bunları gözönünde tutarak elemanlar üstünde $y = x^2-4x+3$ polinomunu hesaplayan şöyle bir kod yazalım:
clc, clear
n = 1000000;
x = 1:n;
deneySayisi = 100;
%% Döngülü ve ilklendirmesiz
tic;
t = 0;
for d = 1:deneySayisi
clear y
for i = 1:n
y(i) = x(i)^2 - 4*x(i) + 3;
end
t = t + toc;
end
display(sprintf('Geçen ortalama süre: %.6f sn', t/deneySayisi))
%% Döngülü fakat ilklendirmeli
tic;
t = 0;
for d = 1:deneySayisi
clear y
y = zeros(size(x));
for i = 1:n
y(i) = x(i)^2 - 4*x(i) + 3;
end
t = t + toc;
end
display(sprintf('Geçen ortalama süre: %.6f sn', t/deneySayisi))
%% Vektörleştirme kullanımı
tic;
t = 0;
for d = 1:deneySayisi
clear y
y = x.^2 - 4*x + 3;
t = t + toc;
end
display(sprintf('Geçen ortalama süre: %.6f sn', t/deneySayisi))
Şimdi de sonuçlara bakalım:
Geçen ortalama süre: 13.945716 sn Geçen ortalama süre: 1.209971 sn Geçen ortalama süre: 0.304579 sn
Görüldüğü üzere ilklendirme yapmak, yani döngü kaçınılmazsa zeros ile yer açmak işleri 10 kat kadar hızlandırıyor. Döngüden kaçınmak ise daha iyi bir yol ve ilk yönteme göre 40 kat kadar daha iyi! Örnekteki süre zaten kısa olduğu için fark size önemsiz gelebilir, fakat daha uzun çalışan kodlarda bu gelişme ciddi bir avantaj sağlayacaktır. Koda işlev kazandırdıktan sonra bir es verip kodu toparlamak iyi bir alışkanlıktır.
Not: Son sürümlerde bu konunun geliştirildiğini söylüyorlar, fakat görüldüğü üzere buna dikkat etmekte hâlâ çok fayda var.
Not 2: Polinom hesaplamak yerine sin fonksiyonu ile de denedim, onda da benzer sonuçlar elde ediliyor.
Eleman eleman işlem yapma - 2
Önceki yazıya takviye olan bu yazıda bsxfun fonksiyonuna bakacağız. İlk yazıda bahsi geçen fonksiyonlar tek bir dizilimdeki elemanlar üstünde işlem yapmaya yarıyordu. bsxfun ise iki farklı dizilimde eleman eleman ikili işlem (binary operation) yapıp sonuçları yine bir dizilimde saklamaya yarıyor. Örneğin iki vektörde toplama yapmanın türlü türlü yolu var:
a = [1 2 3];
b = [5 10 15];
a + b
ans =
6 12 18
plus(a,b)
ans =
6 12 18
bsxfun(@plus, a, b)
ans =
6 12 18
Son ifadede kullandığımız bsxfun'a parametre olarak bir fonksiyon tutucu ve iki adet dizilim verdik. Dizilimler şu türlerden birine ait olabilir: numeric, logical, char, struct, cell. Örnekte numeric değerler kullandık. Bu örnek işlevsel bir örnek değildi, sadece konuyu anlamak için verdim.
Şimdi işe yarar bir kullanıma bakalım. Problemimiz özgün veriden ortalanmış veri (centralized data) elde etmek olsun. Daha net ifade edersek, elimizdeki veri matrisinin her sütunundan (her örneklemden) ortalama sütunu çıkaralım. Mesela eldeki veri şöyle olsun:
A = [2.1 3.2 4.8 2.1 4.8 2.7 5.3 3.4 5.8 -1.1 5.8 3.3
1.8 3.7 0.7 -2.7 1.8 3.2 1.8 5.2 3.8 0.6 0.1 4.8];
plot(A(1,:), A(2,:),'.')
grid on
axis([-10 10 -10 10])

Özgün veri ortalanmamış görünüyor. Şimdi bsxfun kullanarak her sütundan ortalamayı çıkaralım ve tekrar çizelim:
A2 = bsxfun(@minus, A, mean(A,2)); plot(A2(1,:), A2(2,:),'.') grid on axis([-10 10 -10 10])

İlk satırda veriyi ortaladık. mean(A,2) ile sütun ortalamasını bulduk. 2xn'lik bir matris ile 2x1'lik bir vektörü ikili işleme koyduğumuzda matrisin her vektörünü eleman eleman bu vektörle işleme koymuş olduk. Görüldüğü üzere veri ortalandı.
Bir adım daha öteye gidelim ve boyutları normalize edelim. Yani standart sapmaya bölelim:
A3 = bsxfun(@rdivide, A2, std(A2, 0, 2)) plot(A3(1,:), A3(2,:),'.') grid on axis([-10 10 -10 10])

İlk satırdaki std(A2, 0, 2) kodu ile her satırdaki standart sapmayı hesapladık. İki satır olduğu için sonuç yine 2x1'lik bir sütun vektörü oldu. Bunu std(A2')' ile de yapmak mümkündü. Ortalanmış veri matrisinin her sütununu standart sapma sütun vektörüne rdivide ile böldük. Bu fonksiyon "./" ile ifade de edilebilen eleman eleman bölmü yapma fonksiyonu. Sonuç itibariyle iki boyut için de ortalama sıfır, standart sapma 1 oldu. Aradaki çizim fonksiyonlarını atarsak, veriyi iki satırda normalize ettik:
A = bsxfun(@minus, A, mean(A,2)); A = bsxfun(@rdivide, A, std(A, 0 ,2));
Not: Eleman eleman işlem yapmayı anlatırken ikili işlemlerden bahsetmeyi unutmuşum, bu yazı M. Gönen'in tavsiyesiyle ortaya çıktı.
Fonksiyon tutucular ve anonim fonksiyonlar
Bu yazıda MATLAB kullanıcılarının çok bilmediği fonksiyon tutucular (function handle) ve anonim fonksiyonlara bakalım. İlk örneğimiz integral almak olsun ve şöyle basit bir fonksiyonumuz olsun:
$$h(x) = 10x$$
Bu fonksiyonun [1,10] aralığında integralini analitik olarak alalım:
\begin{align}\int_1^{10} h(x) \, dx &= 10 \frac{x^2}{2}\bigg|_{1}^{10}\\&= 500 - 5 \\&= 495\end{align}
Şimdi bunu MATLAB ile nasıl yapacağımıza bakalım. İlk olarak $h(x)$ fonksiyonunu anonim bir fonksiyon olarak yazalım:
h = @(x) 10*x;
Üstte girdi olarak x alan ve çıktı olarak 10*x döndüren bir anonim fonksiyon var. Bu anonim fonksiyonu h değişkenine atayarak h'yi bu fonksiyonu çağırmak için kullanabileceğiz. Çağırmayı deneyelim:
h(3)
ans =
30
Bunu yeni bir "h.m" dosyası yaratarak şöyle de yapabilirdik:
function y = h(x)
y = 10*x;
end
Bunun yerine tek satırda yaptık ve de yeni bir dosya yaratmaya gerek kalmadı. Diyebilirsiniz ki "neden doğrudan h = 10*x yazmadık?" Öyle yapsaydık, h fonksiyon tipinde değil de sayı tipinde olacaktı ve içinde nümerik değerler saklayacaktı. Biz ise ilerde bu fonksiyonu başka fonksiyonlara girdi olarak vereceğiz ve fonksiyona erişildiği an x'in değerleri ne ise ona bağımlı bir sonuç dönecek. Çalışma ortamına bakarsak değişkenin sınıfının function_handle olduğunu görebiliriz:

Şimdi bir fonksiyon daha düşünelim:
$$f(x) = \sin(\alpha x)$$
Bunu MATLAB'de tanımlayalım:
alpha = 0.9; f = @(x) sin(alpha*x);
ve $[0,\pi]$ aralığında alan olarak çizdirelim:
x = linspace(0,pi,100); area(x,f(x))

Çizdiğimiz alan ne kadar acaba? Sayısal olarak integral hesaplamaya yarayan quad
fonksiyonuna tanımladığımız fonksiyonu ve sınırları vererek bunu hesaplayabiliriz.
quad(f,0,pi)
ans =
2.1678
Yani $\int_0^\pi sin(0.9 x) \approx 2.1678$ imiş. İlk örnekteki h fonksiyonunu kullanarak quad(h,1,10) yazarsanız 495 değerini göreceksiniz. Elle hesapladığımız değerle aynı.
Şimdi de integral dışında bir örneğe bakalım. Yeni problemimiz bir eniyileme problemi: Belli bir aralıktaki en küçük değeri istiyoruz. Fonksiyonumuz şöyle olsun:
$$f(x) = x^2 - 2x + 1$$
Yani MATLAB diliyle konuşursak:
f = @(x) (x.^2 * 2*x + 1); ezplot(f)

Şimdi fminbnd fonksiyonu ile belli bir aralıktaki en küçük değeri veren x'i bulalım ve grafikte yıldız işaretiyle onu da gösterelim:
hold on minimum = fminbnd(f, -2, 2); plot(minimum, f(minimum), '*') hold off
Bir eğrinin üstündeki minimum nokta nasıl bulunur sorusunu fonksiyon tutucu kullanarak cevaplamış olduk. Kendi yazdığımız bir fonksiyon yerine doğrudan MATLAB'ın fonksiyonları için de buna bakabilirdik. Örneğin fminbnd(@sin,0,2*pi) ile sin fonksiyonunun en düşük değerini veren açıyı radyan cinsinden bulabiliriz. Dikkat etmeniz gereken şey fminbnd'ye ilk parametre olarak bir fonksiyon tutucu yollamak. Doğrudan sin yazarsanız hata verecektir.
Şimdi iki boyutta nasıl kullanabileceğimize bakalım. İki değişkenli bir fonksiyon tanımlayalım ve çizelim:
a = 1.4; b = 0.9; f = @(x,y) (a*sin(x) + b*cos(y)); ezsurf(f)

Görüldüğü üzere anonim fonksiyonları tek bir girdi parametresi ile değil, birden çok girdi ile kullanabiliyoruz.
Yazıyı uzatmak mümkün ama temel bilgiyi içerdiğini düşünüyorum ve burada bırakıyorum. Konu ile ilgili daha ayrıntılı görsel bilgiye Açık Ders'ten ulaşabilirsiniz.
Log hilesi ve Stirling yaklaşımı ile büyük sayıların faktöryelini hesaplama
Faktöryel fonksiyonu çok hızlı büyüyen bir fonksiyon: $n$ çok büyük olmamasına rağmen $n!$ kısa sürede pratik olarak hesaplanamaz duruma gelebiliyor. Örneğin MATLAB'deki factorial fonksiyonu $n\leq 21$ için doğru hesaplanabilirken daha büyük $n$ değerleri için yalnızca ilk 15 basamağa kadar doğru sonuç alınabiliyor.
Bu durumda Stirling yaklaşımı olarak bilinen alttaki formülden yararlanmak düşünülebilir.
$$n! \approx \sqrt{2\pi n} \ n^n e^{-n}$$
Fakat burda da $n^n$ ile üs alımı var ve bu da çok hızlı büyüyen bir fonksiyon. Nümerik işlem yapıyorsak üs almaktan ve çarpma yapmaktan mümkün olduğunca sakınmalıyız. Bu durumda log hilesini kullanmak iyi olacak. Yani işlemleri doğrudan yapmak yerine loglarını alarak yapmak. Bu durumda çarpmalar toplamaya dönüşecek, üsler de çarpmaya dönüşecek ve son durumda elimizde $n$ üslü bir terim olmayacak. Kulağa harika geliyor. Stirling'in log alınmış haline bakalım:
$$log(n!) \approx \frac{1}{2} \log(2\pi n) + n^2 - n$$
Şimdi bunu pratikte sınayalım. Önce fonksiyonu yazalım:
log_factorial_by_stirling_approximation = @(n)(log(2*pi*n)/2 + n.*log(n) - n);
Fonksiyonu anonim bir fonksiyon tutucusu olarak yazdım, isterseniz ayrı bir fonksiyon olarak yazabilirsiniz. $n \log(n)$ çarpımında vektörizasyon kullanıldığına dikkat edin.
Şimdi bu fonksiyonu MATLAB'ın faktöryel fonksiyonu ile karşılaştıralım ve farklarına bakalım:
n = 1:250;
y1 = log(factorial(n));
y2 = log_factorial_by_stirling_approximation(n);
subplot(3,1,1),
plot(n,y1, 'k-'), axis([0 max(n) 0 max(y2)]), title('MATLAB faktöryelinin logu')
subplot(3,1,2),
plot(n,y2, 'b-'), axis([0 max(n) 0 max(y2)]), title('Stirling yaklaşımının logu')
subplot(3,1,3),
plot(n,abs(y1-y2), 'r-'), title('Fark')

Görüldüğü üzere $n$ büyüdükçe yaklaşımdaki fark küçülüyor, yani Stirling yaklaşımı gerçekten de başarılı!
Figürde MATLAB'daki faktöryelin 170lerde çuvalladığı (bu değerler için sonuç Inf çıktığı için çizilmiyor) görülüyor, ama log hilesi ile bunu aşmak mümkün. Dahası yaptığımız log hilesi ile çok çok büyük $n$ değerleri için dahi faktöryel hesaplayabiliyoruz.
Unutmamak gerekir ki bu faktöryel değil, faktöryelin logu. Eğer bu değerleri üstel fonksiyona sokarsak pratikte yine patlar. Ama buna genelde ihtiyacımız olmuyor. Düşünün ki elimizde içinde faktöryel hesaplamamız gereken birkısım yöntem var ve biz en iyisinin hangisi olduğunu arıyoruz. Yani karşılaştırma yapıyoruz. Bizim için önemli olan birinin özel olarak değeri değil, diğerlerinden büyük veya küçük oluşu. log fonksiyonu karşılaştırmayı etkilemiyor, yani $\log(x) > \log(y)$ ise $x > y$ sonucuna varabiliyoruz.
log hilesi sadece faktöryel hesabında değil üs almanın bulunduğu tüm pratik işlemlerde işe yarayabilecek güzel bir araç.
Konuyla ilgili olaraktan şunlar da dikkate değer:
Kalıcı değişkenler
MATLAB'de kalıcı değişken tanımlarken kullanabileceğiniz bir anahtar sözcük var: persistent. Yaratılan değişkenin siz fonksiyondan çıksanız bile hafızada korunmasını sağlıyor. C'deki static anahtar sözcüğü gibi düşünebilirsiniz. Örneğin bir koşan ortalama (running averager) fonksiyonu yazalım:
function ortalama = kosanOrtalama(x)
persistent n;
persistent toplam;
if x == 'sifirla' % Kalıcı değişkenleri ilklendir
n = 0;
toplam = 0;
ortalama = 0;
else % Yeni veri geldi
n = n + 1;
toplam = toplam + x;
ortalama = toplam / n; % Ortalamayı güncelle.
end
Üstteki fonksiyonda n ve toplam değişkenlerini kalıcı olarak yarattık. Fonksiyonu 'sifirla' parametresi ile çağırdığımızda değerleri ilklendirecek. Eğer sayı verirsek ise o sayıyı kullanarak ortalamayı güncelleyecek.
kosanOrtalama('sifirla')
ans =
0
>> kosanOrtalama(10)
ans =
10
>> kosanOrtalama(5)
ans =
7.5000
Şu sıralar yazdığım kodda veri üstünde bir model için olabilirlik değeri hesaplıyorum ve bunu yeni veriler geldikçe veya döngüde ilerlerken güncelleyerek yapıyorum. Bu durumda güncellediğim değerleri fonksiyondan alıp sonra yine vermek yerine persistent ile kalıcı yaratmak işimi bir hayli hızlandırdı.
Bilgisayarla görüde popüler olan aktif görü (active vision) alanı da bu biçimde değişkenler için biçilmiş kaftan. Çünkü orada da yeni veri geldikçe güncellenen sonuçlar mevcut.
Kaynak: CITS1005 dersi
Güncelleme: Barış'ın katkılarıyla kodun daha anlaşılır ve hızlı çalışan sürümü şöyle:
function ortalama = kosanOrtalama(x)
persistent n;
persistent toplam;
if isempty(n)
n = 0;
toplam = 0;
end
n = n + 1;
toplam = toplam + x;
ortalama = toplam / n; % Ortalamayi güncelle.
end
Sıfırlamak için de clear kosanOrtalama; yazmak gerekiyor.
Eleman eleman işlem yapma
MATLAB kullanıyorsanız arrayfun, cellfun, spfun ve structfun fonksiyonlarından haberdar olmak işinizi rahatlatabilir. Bu fonksiyonlar en genel anlamda konuşacak olursak, kullandığınız verideki elemanlar üstünde hızlıca işlem yapıp sonuçları yine bir listede oluşturmanızı sağlar. Hemen taze kullandığım bir örnek vereyim:
klasor= '../veri/yuzler/'; dosyaAdlari= arrayfun(@(x) x.name, dir([klasor '*.jpg']), 'UniformOutput', false);
Üstteki örnekte, ilgili klasördeki 'jpg' uzantılı dosya adlarını dosyaAdlari değişkeninde topluyorum. Bu değişken cell yapısında. dir fonksiyonu her elemanı struct yapısında olan bir dizi döndürüyor. Her eleman, name isimli alanında dosya adını taşıyor. @ ile başlayan kısım bir fonksiyon tutucu. @(x) x.name anonim fonksiyonu, içine aldığı elemanın name alanını döndürüyor.
Bu işi yapmanın birçok yolu olabilir, hatta daha kısası ve sadesi mümkündür ama bu yöntem hoşuma gitti.
Bir örneği de dokümantasyondakinden esinlenerek vereyim:
s.a1 = 'Ocak'; s.a2 = 'Şubat'; s.a3 = 'Mart'; s.a4 = 'Nisan'; s.a5 = 'Mayıs'; s.a6 = 'Haziran'; s.a7 = 'Temmuz'; s.a8 = 'Ağustos'; s.a9 = 'Eylül'; s.a10 = 'Ekim'; s.a11 = 'Kasım'; s.a12 = 'Aralık'; aylarinHarfSayisi = structfun(@numel, s) kisaAyAdlari = structfun(@(x) ( x(1:3) ), s, 'UniformOutput', false)
UniformOutput parametresi önemli. Eğer doğru olarak verirseniz, sonuçların skaler olacağını varsayıyor ve dönecek verinin bir skaler dizilimi oluyor. Örneğin aylarinHarfSayisi değişkeni skaler değerlerden oluşan bir dizilim. Fakat kisaAyAdlari bir cell dizilimi.
Dizilerin üstünde gezinecek for döngüleri yazmaktansa bu birebir mapping yöntemi çok daha güzel bir yöntem.
Erguvan
Bu yazıda benim çok şık bulduğum bir kod yazalım. Amacımız, verilen bir resmi siyah beyaz yapmak fakat belli bir rengi aynen bırakmak. Schindler'in Listesi'ndeki kırmızı montlu kız sahnesinde olduğu gibi veya bir meşk klişesi olan siyah beyaz arkaplana renkli gül efekti gibi bir şey yapalım. Ve bunu Boğaziçi'nin simgesi erguvan rengi için yapalım. Yani uzun lafın kısası, erguvan ağacının olduğu bir resme bir maske uygulayıp erguvan renginde olmayan yerlerini siyah beyaza çevirelim.
Resmimiz şu olsun

Akla ilk gelen yöntem, resmi okuduğumuz özgün uzay olan RGB renk uzayında bir filtreleme yapmak olacaktır. Fakat bu hem kımızı, hem yeşil, hem de mavi renk kanallarındaki erguvana denk gelen aralıkları bilmemiz demek olacaktır.
MATLAB'da rastsallığı kontrol etme
Rastsal (random) bir algoritma yazmaya çalışıyorum. Veriyi de belli parametrelere göre yine rastsal hazırlıyorum. Sonra bilinmeyenleri kestirmeye çalışıyorum. Yazdığım kodu her çalıştırdığımda farklı bir veri ile karşılaştığım için "algoritma iyi mi, kötü mü", "hangi durumlarda zayıf kalıyor" gibi sorulara cevap bulmak zor oluyor. Rastsallığın başlangıcını kontrol etmeyi zaten biliyordum ama her nedense başka şeylere kafa yormaktan bu aklıma gelmemiş. Bunun için rastsal sayı üreticisine ilk tohumu (seed) elle verebiliyorsunuz. Böylelikle tohumu değiştirmediğiniz sürece aynı veri üretiliyor. Siz de kodun değişik yerlerini güncelleyip sonucu gözlemleyebiliyorsunuz. Uzun lafın kısası MATLAB ile bunu yapmanın yolu rng fonksiyonunu bilmekten geçiyor. Önceden state gibi parametrelerle rand ve randn fonksiyonları ayrı ayrı ayarlanabiliyordu, fakat son sürümlerdeki üreteçler için önerilen fonksiyon rng. Basitçe:
% Ayarları öğrenelim s = rng; % [0,1] arası birörnek dağılımdan bir örnek çekelim a = rand % Birim normal dağılımdan örnek çekelim b = randn % İlk tohumu tekrar verelim % Buradaki tohumları elle rng(5) gibisinden de verebilirdik rng(s); % Dağılımlardan birer örnek daha çekelim ve öncekilerle aynı olduklarını görelim x = rand y = randn
İlk tohumu verdikten sonraki süreç her çalışmada aynı olacak. Veriyi üretirken bu mantıklı olacaktır, fakat sonrasında çalışan algoritmanın da hep aynı çalışacağını unutmamak lazım. Örneğin üretilen veri için yerel bir optimuma her seferinde aynı biçimde takılabilir. Böyle durumlarda aynı veride farklı çalışmasını isteyebiliriz. Bunun için veriyi ürettikten sonra rng('shuffle') ile tohumu şu anki saniyeden alabilir ve algoritmanın ilklendirilmesindeki rastsallığı tekrar sağlayabiliriz.
Ah spy vah spy!
Bizim laba özgü spy çekmek, spylanmak, spy'ı gömmek gibi tabirler var. Bir yere giderken bilgisayarınızı açık unutursanız MATLAB spy'ını anında yersiniz. Hatta başka başka yerlerde de çıktı alınmış spylarla karşılaşabilirsiniz. Bu yer, farenizin optik gözünden Facebook duvarınıza kadar değişebilir. spy normalde seyrek matrisleri çizdirmek için kullanılıyor. Fakat girdi olarak hiçbir şey vermezseniz bir sürpriz yaparak size Spy vs. Spy oyunundaki altta çizdiğim kargayı gösteriyor.

Yani şimdiye kadar öyleydi. R2011a'da tutup bunu değiştirmişler ve alttaki kurdu koymuşlar!

Ne gerek vardı şimdi buna? Bugün şahane bir fırsat yakaladım, bir spy çakayım dedim. Bana sürpriz oldu.
Üzdü bu olay beni. spy'ın da tadı kaçtı. Bunu bassan neee, basmasan ne!
Not: spy dosyasının içine girince defaultspy değişkenini üreten bir fonksiyon görülüyor. Eskisi ile yer değiştirilebilir elbette ama ne gerek vardı böyle bir aksiyona.

