import std.algorithm;
import std.array;
import std.ascii;
import std.container;
import std.conv;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
void log(A...)(A arg) { stderr.writeln(arg); }
int size(T)(in T s) { return cast(int)s.length; }

class Image {
    int H, W;
    string[] F;

    int[][] X;
    int[][] tree;
    this(int H, int W, string[] F0) {
        this.H = H + 2;
        this.W = W + 2;
        auto F = new char[][](H + 2, W + 2);
        for (int h = 0; h <= H + 1; h++) {
            for (int w = 0; w <= W + 1; w++) {
                if (h == 0 || w == 0 || h == H + 1 || w == W + 1) {
                    F[h][w] = '.';
                } else {
                    F[h][w] = F0[h - 1][w - 1];
                }
            }
        }
        this.F = cast(string[])F;
        this.X = new int[][](this.H, this.W);
        foreach (i; 0 .. this.H) {
            foreach (j; 0 .. this.W) {
                this.X[i][j] = -1;
            }
        }
        scan();
        make_tree();
    }
    const DY = [
        [-1, 0, 1, 0], // white
        [-1, -1, 0, 1, 1, 1, 0, -1] // black
    ];
    const DX = [ 
        [0, 1, 0, -1], // white
        [0, 1, 1, 1, 0, -1, -1, -1] // black
    ];
    int id;
    void scan() {
        void dfs(int y, int x, int i) {
            int wb = F[y][x] == '.' ? 0 : 1;
            X[y][x] = i;
            for (int k = 0; k < DX[wb].length; k++) {
                int dx = DX[wb][k];
                int dy = DY[wb][k];
                int nx = x + dx;
                int ny = y + dy;
                if (nx < 0 || nx >= W) continue;
                if (ny < 0 || ny >= H) continue;
                if (F[ny][nx] != F[y][x]) continue;
                if (X[ny][nx] >= 0) continue;
                dfs(ny, nx, i);
            }
        }
        bool updated = true;
        int wb = 0;
        id = 0;
        while (updated) {
            updated = false;
            foreach (y; 0 .. H) {
                foreach (x; 0 .. W) {
                    if (X[y][x] < 0) {
                        updated = true;
                        dfs(y, x, id);
                        id++;
                    }
                }
            }
        }
    }
    void make_tree() {
        auto checked = new bool[][](H, W);
        void find_neighbor(int y, int x) {
            checked[y][x] = true;
            int id = X[y][x];
            int wb = F[y][x] == '.' ? 0 : 1;
            for (int k = 0; k < DX[wb].length; k++) {
                int dx = DX[wb][k];
                int dy = DY[wb][k];
                int ny = y + dy;
                int nx = x + dx;
                if (ny < 0 || ny >= H) continue;
                if (nx < 0 || nx >= W) continue;
                int nid = X[ny][nx];
                if (nid > id) {
                    tree[id] ~= nid;
                }
            }
        }
        tree = new int[][id];
        foreach (i; 0 .. id) {
            foreach (y; 0 .. H) {
                foreach (x; 0 .. W) {
                    if (checked[y][x]) continue;
                    find_neighbor(y, x);
                }
            }
        }
        foreach (ref children; tree) {
            children = sort(children).uniq.array;
        }
    }
}

class TreeHasher {
    const int N = 3000;
    const int L = 2000;
    const ulong MOD = cast(ulong)(1e9 + 7);
    ulong[] primes;
    bool isPrime(ulong n) {
        foreach (p; primes) {
            if (n % p == 0) return false;
            if (p * p > n) return true;
        }
        return true;
    }
    this() {
        primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31];
        for (ulong i = 33; primes.length < N; i += 2) {
            if (isPrime(i)) {
                primes ~= i;
            }
        }
    }
    int height(int n, in int[][] tree) {
        auto f = delegate(int acc, int c) {
            return max(acc, height(c, tree) + 1);
        };
        return reduce!f(0, tree[n]);
    }
    ulong hash(in int[][] tree, int n) {
        if (height(n, tree) == 0) return 1;
        int h = height(n, tree);
        ulong P = primes[L + h];
        ulong ret = 1;
        foreach (c; tree[n]) {
            ret = (ret * (hash(tree, c) + P)) % MOD;
        }
        return ret;
    }
}

void main() {
    Image[2] I;
    bool input() {
        int H, W;
        string[] F;
        readf("%d %d\n", &H, &W);
        if (H == 0 && W == 0) return false;
        F = iota(0, H, 1).map!((i) => readln.chomp).array;
        I[0] = new Image(H, W, F);
        readf("%d %d\n", &H, &W);
        F = iota(0, H, 1).map!((i) => readln.chomp).array;
        I[1] = new Image(H, W, F);
        return true;
    }
    void solve() {
        //writeln(I[0].F.join("\n"));
        //writeln;
        //writeln(I[1].F.join("\n"));
        //writeln(I[0].X.map!"a.to!string".join("\n"));
        //writeln(I[1].X.map!"a.to!string".join("\n"));
        //writeln;
        //writeln(I[0].tree);
        //writeln(I[1].tree);
        auto hasher = new TreeHasher;

        writeln(hasher.hash(I[0].tree, 0) == hasher.hash(I[1].tree, 0) ? "yes" : "no");
    }
    while (input()) solve();
}