#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
using namespace std;

typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef pair<ll, ll> LP;
typedef vector<int> vec;
typedef vector<string> svec;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;

struct uf {
private:
	vector<int> par, ran;
public:
	uf(int n) {
		par.resize(n, 0);
		ran.resize(n, 0);
		rep(i, n) {
			par[i] = i;
		}
	}
	int find(int x) {
		if (par[x] == x)return x;
		else return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (ran[x] < ran[y]) {
			par[x] = y;
		}
		else {
			par[y] = x;
			if (ran[x] == ran[y])ran[x]++;
		}
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
};

struct graph {
private:
	int n;
	vector<vector<int>> G;
public:
	graph(int sz) {
		n = sz; G.resize(n);
	}
	void add_edge(int a, int b) {
		G[a].push_back(b);
	}
	vector<int> center() {
		vector<int> d(n, 0);
		vector<int> ret;
		auto dfs = [&](int id, int fr) {
			int ma = 0;
			d[id] = 1;
			rep(j, G[id].size()) {
				int to = G[id][j];
				if (to == fr)continue;
				ma = max(ma, d[to]);
				d[id] += d[to];
			}
			if (ma <= n / 2 && n - d[id] <= n / 2)ret.push_back(id);
		};
		return ret;
	}
	vector<string> iso_check() {
		vector<int> g = center();
		vector<string> ret;
		function<string(int,int)> dfs = [&](int id, int fr)->string {
			string ret = "(";
			vector<string> s;
			rep(j, G[id].size()) {
				int to = G[id][j];
				if (to == fr)continue;
				s.push_back(dfs(to, id));
			}
			sort(s.begin(), s.end());
			rep(i, s.size())ret += s[i];
			ret.push_back(')');
			return ret;
		};
		rep(i, g.size()) {
			int root = g[i];
			ret.push_back(dfs(root, -1));
		}
		return ret;
	}
	string iso_check(int root) {
		function<string(int, int)> dfs = [&](int id, int fr)->string {
			string ret = "(";
			vector<string> s;
			rep(j, G[id].size()) {
				int to = G[id][j];
				if (to == fr)continue;
				s.push_back(dfs(to, id));
			}
			sort(s.begin(), s.end());
			rep(i, s.size())ret += s[i];
			ret.push_back(')');
			return ret;
		};
		return dfs(root, -1);
	}
	void compress() {
		rep(i, n) {
			sort(G[i].begin(), G[i].end());
			G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
		}
	}
};
int dx[8] = { 1,0,-1,0,1,1,-1,-1 };
int dy[8] = { 0,1,0,-1,1,-1,1,-1 };
int h, w;
string calc() {
	vector<vector<char>> mp(h + 2);
	rep(i, h + 2) {
		mp[i].resize(w + 2, '.');
	}
	rep1(i, h) {
		rep1(j, w) {
			cin >> mp[i][j];
		}
	}
	int sz = (h + 2)*(w + 2);
	uf u(sz);
	rep(i, h+2) {
		rep(j, w+2) {
			int cur = i * (w + 2) + j;
			if (mp[i][j] == '.') {
				rep(k, 4) {
					int nx = i + dx[k];
					int ny = j + dy[k];
					if (nx < 0 || nx >= h + 2 || ny < 0 || ny >= w + 2)continue;
					if (mp[nx][ny] == mp[i][j]) {
						int to = nx * (w + 2) + ny;
						u.unite(cur, to);
					}
				}
			}
			else {
				rep(k, 8) {
					int nx = i + dx[k];
					int ny = j + dy[k];
					if (nx < 0 || nx >= h + 2 || ny < 0 || ny >= w + 2)continue;
					if (mp[nx][ny] == mp[i][j]) {
						int to = nx * (w + 2) + ny;
						u.unite(cur, to);
					}
				}
			}
		}
	}
	vector<bool> exi(sz);
	rep(i, (h + 2)) {
		rep(j, w + 2) {
			int p = u.find(i*(w + 2) + j);
			exi[p] = true;
		}
	}
	vector<int> trans(sz);
	int tmp = 0;
	rep(i, sz) {
		if (exi[i]) {
			trans[i] = tmp; tmp++;
		}
	}
	/*rep(i, h + 2) {
		rep(j, w + 2) {
			int p = u.find(i*(w + 2) + j);
			cout << trans[p];
		}
		cout << endl;
	}*/
	graph g(tmp);
	int root = trans[u.find(0)];
	//cout << root << endl;
	rep(i, h + 2) {
		rep(j, w + 2) {
			int cur = i * (w + 2) + j;
			cur = trans[u.find(cur)];
			if (mp[i][j] == '.') {
				rep(k, 4) {
					int nx = i + dx[k];
					int ny = j + dy[k];
					if (nx < 0 || nx >= h + 2 || ny < 0 || ny >= w + 2)continue;
					if (mp[nx][ny] != mp[i][j]) {
						int to = nx * (w + 2) + ny;
						to = trans[u.find(to)];
						if (cur == to)continue;
						g.add_edge(cur, to);
						//cout << i << " " << j << " " << nx << " " << ny << endl;
						//cout << cur << " " << to << endl;
					}
				}
			}
			else {
				rep(k, 8) {
					int nx = i + dx[k];
					int ny = j + dy[k];
					if (nx < 0 || nx >= h + 2 || ny < 0 || ny >= w + 2)continue;
					if (mp[nx][ny] != mp[i][j]) {
						int to = nx * (w + 2) + ny;
						to = trans[u.find(to)];
						if (cur == to)continue;
						g.add_edge(cur, to);
						//cout << i << " " << j << " " << nx << " " << ny << endl;
						//cout << cur << " " << to << endl;
					}
				}
			}
		}
	}
	g.compress();
	return g.iso_check(root);
}
bool solve() {
	cin >> h >> w;
	if (h == 0)return false;
	string le = calc();
	cin >> h >> w;
	string ri = calc();
	bool f = (le==ri);

	if (f) {
		cout << "yes" << endl;
	}
	else {
		cout << "no" << endl;
	}
	

	return true;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	//cout << fixed << setprecision(10);
	//init();
	while (solve());
	//stop
		return 0;
}


Measured memory_bytes: 3344