Deconvolution/2D+: Difference between revisions
Content added Content deleted
(→{{header|C}}: whew) |
(Formatted D entry, not improved) |
||
Line 320: | Line 320: | ||
=={{header|D}}== |
=={{header|D}}== |
||
<lang d>import std.stdio, std.conv |
<lang d>import std.stdio, std.conv, std.array, std.algorithm, std.numeric, |
||
std.range; |
|||
class M(T) { |
class M(T) { |
||
private size_t[] dim |
private size_t[] dim; |
||
private size_t[] subsize |
private size_t[] subsize; |
||
private T[] d |
private T[] d; |
||
this(size_t[] dimension ...) { |
this(size_t[] dimension ...) { |
||
setDimension(dimension) |
setDimension(dimension); |
||
d[] = 0 |
d[] = 0; // init each entry to zero; |
||
} |
} |
||
M!T dup() { |
M!T dup() { |
||
M!T m = new M!T(dim) |
M!T m = new M!T(dim); |
||
return m.set1DArray(d) |
return m.set1DArray(d); |
||
} |
} |
||
M!T setDimension(size_t[] dimension ...) { |
M!T setDimension(size_t[] dimension ...) { |
||
foreach(e |
foreach (e; dimension) |
||
assert(e > 0, "no zero dimension") |
assert(e > 0, "no zero dimension"); |
||
dim = dimension.dup |
dim = dimension.dup; |
||
subsize = dim.dup |
subsize = dim.dup; |
||
foreach(i;0..dim.length) |
foreach (i; 0 .. dim.length) |
||
subsize[i] = reduce!"a*b"(1,dim[i+1..$]) |
subsize[i] = reduce!"a*b"(1, dim[i + 1 .. $]); |
||
auto dlength = dim[0] * subsize[0] |
auto dlength = dim[0] * subsize[0]; |
||
if(d.length != dlength) |
if (d.length != dlength) |
||
d = new T[ |
d = new T[dlength]; |
||
return this |
return this; |
||
} |
} |
||
M!T set1DArray(T[] t ...) { |
M!T set1DArray(T[] t ...) { |
||
auto minLen = min(t.length, d.length) |
auto minLen = min(t.length, d.length); |
||
d[] = 0 |
d[] = 0; |
||
d[0..minLen] = t[0..minLen] |
d[0 .. minLen] = t[0 .. minLen]; |
||
return this |
return this; |
||
} |
} |
||
size_t[] seq2idx(size_t seq) { |
size_t[] seq2idx(size_t seq) { |
||
size_t acc = seq, tmp |
size_t acc = seq, tmp; |
||
size_t[] idx |
size_t[] idx; |
||
foreach(e |
foreach (e; subsize) { |
||
idx ~= tmp = acc / e |
idx ~= tmp = acc / e; |
||
acc = acc - tmp* |
acc = acc - tmp * e; // same as % (mod) e; |
||
} |
} |
||
return idx |
return idx; |
||
} |
} |
||
size_t size() const @property { return d.length |
size_t size() const @property { return d.length; } |
||
⚫ | |||
size_t |
size_t rank() const @property { return dim.length; } |
||
⚫ | |||
⚫ | |||
⚫ | |||
bool checkBound(size_t[] idx ...) const { |
bool checkBound(size_t[] idx ...) const { |
||
if(idx.length > dim.length) |
if (idx.length > dim.length) |
||
return false; |
|||
foreach (i, dm; idx) |
|||
if (dm >= dim[i]) |
|||
return false; |
|||
return true; |
|||
} |
} |
||
T opIndex(size_t[] idx ...) { |
T opIndex(size_t[] idx ...) { |
||
assert(checkBound(idx), "OOPS") |
assert(checkBound(idx), "OOPS"); |
||
return d[dotProduct(idx,subsize)] |
return d[dotProduct(idx, subsize)]; |
||
} |
} |
||
T opIndexAssign(T v, size_t[] idx ...) { |
T opIndexAssign(T v, size_t[] idx ...) { |
||
assert(checkBound(idx), "OOPS") |
assert(checkBound(idx), "OOPS"); |
||
d[dotProduct(idx,subsize)] = v |
d[dotProduct(idx, subsize)] = v; |
||
return v |
return v; |
||
} |
} |
||
bool opEquals(Object o) { |
override bool opEquals(Object o) { |
||
auto rhs = to!(M!T)(o) ; |
|||
auto rhs = to!(M!T)(o); |
|||
⚫ | |||
} |
} |
||
int opApply(int delegate(ref size_t[]) dg) { |
int opApply(int delegate(ref size_t[]) dg) { |
||
size_t[] yieldIdx |
size_t[] yieldIdx; |
||
foreach(i;0..d.length) { |
foreach (i; 0 .. d.length) { |
||
yieldIdx = seq2idx(i) |
yieldIdx = seq2idx(i); |
||
if(dg(yieldIdx)) |
if (dg(yieldIdx)) |
||
break |
break; |
||
} |
} |
||
return 0 |
return 0; |
||
} |
} |
||
int opApply(int delegate(ref size_t[], ref T) dg) { |
int opApply(int delegate(ref size_t[], ref T) dg) { |
||
size_t idx1d = 0 |
size_t idx1d = 0; |
||
foreach(size_t[] idx |
foreach (size_t[] idx; this) { |
||
if(dg(idx, d[idx1d++])) |
if (dg(idx, d[idx1d++])) |
||
break |
break; |
||
} |
} |
||
return 0 |
return 0; |
||
} |
} |
||
M!T convolute(M!T rhs) { // _this_ is h, rhs is f, output g |
M!T convolute(M!T rhs) { // _this_ is h, rhs is f, output g |
||
auto dm = dim.dup |
auto dm = dim.dup; |
||
dm[] += |
dm[] += rhs.dim[] - 1; |
||
M!T m = new M!T(dm) |
M!T m = new M!T(dm); // dm will be reused as m's idx |
||
auto bound = m.size |
auto bound = m.size; |
||
foreach(i;0..d.length) { |
foreach (i; 0 .. d.length) { |
||
auto thisIdx = seq2idx(i) |
auto thisIdx = seq2idx(i); |
||
foreach(j;0..rhs.d.length) { |
foreach (j; 0 .. rhs.d.length) { |
||
dm[] = thisIdx[] + rhs.seq2idx(j)[] |
dm[] = thisIdx[] + rhs.seq2idx(j)[]; |
||
auto midx1d = dotProduct(dm, m.subsize) |
auto midx1d = dotProduct(dm, m.subsize); |
||
if( midx1d < bound) |
if ( midx1d < bound) |
||
m.d[midx1d] += d[i]*rhs.d[j] |
m.d[midx1d] += d[i] * rhs.d[j]; |
||
else |
else |
||
break |
break; // bound reach, ok to break |
||
} |
} |
||
} |
} |
||
return m |
return m; |
||
} |
} |
||
M!T deconvolute(M!T rhs) { // _this_ is g, rhs is f, output is h |
M!T deconvolute(M!T rhs) { // _this_ is g, rhs is f, output is h |
||
auto dm = dim.dup |
auto dm = dim.dup; |
||
foreach(i, e |
foreach (i, e; dm) |
||
assert(e + 1 > rhs.dim[i], |
assert(e + 1 > rhs.dim[i], |
||
"deconv : dimensions is zero or negative"); |
|||
⚫ | |||
dm[] -= (rhs.dim[] - 1); |
|||
M!T m = new M!T(dm) |
M!T m = new M!T(dm); // dm will be reused as rhs' idx |
||
foreach(i;0..m.size) { |
foreach (i; 0 .. m.size) { |
||
auto idx = m.seq2idx(i) |
auto idx = m.seq2idx(i); |
||
m.d[i] = this[idx] |
m.d[i] = this[idx]; |
||
foreach(j;0..i) { |
foreach (j; 0 .. i) { |
||
auto jdx = m.seq2idx(j) |
auto jdx = m.seq2idx(j); |
||
dm[] = idx[] - jdx[]; |
dm[] = idx[] - jdx[]; |
||
if(rhs.checkBound(dm)) |
if (rhs.checkBound(dm)) |
||
m.d[i] -= m.d[j]*rhs[dm] |
m.d[i] -= m.d[j] * rhs[dm]; |
||
} |
} |
||
m.d[i] /= rhs.d[0] |
m.d[i] /= rhs.d[0]; |
||
} |
} |
||
return m |
return m; |
||
} |
} |
||
string toString() { return to!string(d) |
override string toString() { return to!string(d); } |
||
} |
} |
||
auto fold(T)(T[] arr, ref size_t[] d) { |
auto fold(T)(T[] arr, ref size_t[] d) { |
||
if(d.length == 0) |
if (d.length == 0) |
||
d ~= arr.length; |
|||
static if (is(T U : U[])) { // is arr an array of arrays? |
|||
assert(arr.length > 0, "no empty dimension") ; |
|||
assert(arr.length > 0, "no empty dimension"); |
|||
d ~= arr[0].length; |
|||
foreach (e; arr) |
|||
assert(e.length == arr[0].length, "not rectangular"); |
|||
return fold(reduce!q{a ~ b}(arr), d); |
|||
} else { |
} else { |
||
assert(arr.length == reduce! |
assert(arr.length == reduce!q{a * b}(d), "not same size"); |
||
return arr |
return arr; |
||
} |
} |
||
} |
} |
||
auto arr2M(T)(T a) { |
auto arr2M(T)(T a) { |
||
size_t[] dm |
size_t[] dm; |
||
auto d = fold(a, dm) |
auto d = fold(a, dm); |
||
alias ElementType!(typeof(d)) E |
alias ElementType!(typeof(d)) E; |
||
auto m = new M!E(dm) |
auto m = new M!E(dm); |
||
m.set1DArray(d) |
m.set1DArray(d); |
||
return m |
return m; |
||
} |
} |
||
void main() { |
void main() { |
||
alias M!int Mi |
alias M!int Mi; |
||
auto hh = [[[-6, -8, -5, 9], [-7, 9, -6, -8], [2, -7, 9, 8]], |
auto hh = [[[-6, -8, -5, 9], [-7, 9, -6, -8], [2, -7, 9, 8]], |
||
[[7, 4, 4, -6], [9, 9, 4, -4], [-3, 7, -2, -3]]] |
[[7, 4, 4, -6], [9, 9, 4, -4], [-3, 7, -2, -3]]]; |
||
auto ff = [[[-9, 5, -8], [3, 5, 1]],[[-1, -7, 2], [-5, -6, 6]], |
auto ff = [[[-9, 5, -8], [3, 5, 1]],[[-1, -7, 2], [-5, -6, 6]], |
||
[[8, 5, 8],[-2, -6, -4]]] |
[[8, 5, 8],[-2, -6, -4]]]; |
||
auto h = arr2M(hh) |
auto h = arr2M(hh); |
||
auto f = arr2M(ff) |
auto f = arr2M(ff); |
||
auto g = h.convolute(f) |
auto g = h.convolute(f); |
||
writeln("g == f convolute h ? ", g == f.convolute(h)) |
writeln("g == f convolute h ? ", g == f.convolute(h)); |
||
writeln("h == g deconv f ? ", h == g.deconvolute(f)) |
writeln("h == g deconv f ? ", h == g.deconvolute(f)); |
||
writeln("f == g deconv h ? ", f == g.deconvolute(h)) |
writeln("f == g deconv h ? ", f == g.deconvolute(h)); |
||
writeln(" f = ", f) |
writeln(" f = ", f); |
||
writeln("g deconv h = ", g.deconvolute(h)) |
writeln("g deconv h = ", g.deconvolute(h)); |
||
}</lang> |
}</lang> |
||
''todo(may be not :): pretty print & convert to normal D array'' |
''todo(may be not :): pretty print & convert to normal D array'' |