#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;

struct Node {
	vector<Node *> children;
};
using Hash = int;

constexpr int MAX = 20000;
Node pool[MAX];
int number_of_nodes;

inline Node *new_node() {
	assert(number_of_nodes < MAX);
	pool[number_of_nodes].children.clear();
	return pool + number_of_nodes++;
}

Node *make_tree() {
	int h, w;
	if(!(cin >> h >> w && h)) throw "finish";
	h += 2;
	w += 2;
	vector<string> image(h, string(w, '.'));
	for(int i = 1; i < h - 1; ++i) {
		string line;
		cin >> line;
		image[i] = '.' + move(line) + '.';
	}

	const auto out = [&h, &w](const int x, const int y) { return x < 0 || y < 0 || x >= w || y >= h; };
	static constexpr int dx[] = {0, 1, 0, -1, 1, 1, -1, -1};
	static constexpr int dy[] = {1, 0, -1, 0, 1, -1, -1, 1};
	int size = 0;
	vector<vector<int>> label(h, vector<int>(w, -1));
	const auto bfs = [&](const int sx, const int sy, const int dn) {
		const char color = image[sy][sx];
		label[sy][sx] = size++;
		queue<pair<int, int>> que{{{sx, sy}}};
		while(!que.empty()) {
			const int x = que.front().first;
			const int y = que.front().second;
			que.pop();
			for(int d = 0; d < dn; ++d) {
				const int nx = x + dx[d];
				const int ny = y + dy[d];
				if(out(nx, ny) || label[ny][nx] != -1 || image[ny][nx] != color) continue;
				que.emplace(nx, ny);
				label[ny][nx] = label[y][x];
			}
		}
	};
	for(int y = 0; y < h; ++y) {
		for(int x = 0; x < w; ++x) {
			if(label[y][x] == -1) bfs(x, y, image[y][x] == '.' ? 4 : 8);
		}
	}
	vector<set<int>> G(size);
	const auto add_edge = [&](const int x1, const int y1, const int x2, const int y2) {
		if(out(x1, y1) || out(x2, y2)) return;
		const int u = label[y1][x1];
		const int v = label[y2][x2];
		if(u != v) {
			G[u].emplace(v);
			G[v].emplace(u);
		}
	};
	for(int y = 0; y < h; ++y) {
		for(int x = 0; x < w; ++x) {
			add_edge(x, y, x + 1, y);
			add_edge(x, y, x, y + 1);
		}
	}

	queue<int> que{{0}};
	vector<bool> used(size, false);
	vector<Node *> nodes(size, nullptr);;
	for(int i = 0; i < size; ++i) {
		nodes[i] = new_node();
	}
	used[0] = true;
	while(!que.empty()) {
		const int v = que.front();
		que.pop();
		for(const auto &u : G[v]) {
			if(!used[u]) {
				que.emplace(u);
				nodes[v]->children.emplace_back(nodes[u]);
				used[u] = true;
			}
		}
	}
	return nodes[0];
}

Hash calc_hash(const Node *tree) {
	static map<vector<Hash>, Hash> table;
	static function<Hash(const Node*)> f = [](const Node *v) -> Hash {
		vector<Hash> children_hashes;
		children_hashes.reserve(v->children.size());
		for(const auto &c : v->children) {
			children_hashes.emplace_back(f(c));
		}
		sort(begin(children_hashes), end(children_hashes));
		const auto p = table.emplace(children_hashes, table.size());
		return p.first->second;
	};
	return f(tree);
}

int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	while(true) {
		number_of_nodes = 0;
		try {
			cout << (calc_hash(make_tree()) == calc_hash(make_tree()) ? "yes" : "no") << endl;
		} catch(const char *s) {
			return EXIT_SUCCESS;
		}
	}
}