#define _CRT_SECURE_NO_WARNINGS
#pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#define rep(i, n) for(int i=0;i<(int)(n);i++)
#define REP(i, n) for(int i=1;i<=(int)(n);i++)
#define all(V) V.begin(),V.end()
typedef long long lint;
typedef std::pair<lint, lint> P;
constexpr int INF = INT_MAX / 10;
constexpr lint LINF = LLONG_MAX / 2;
constexpr double eps = 1e-9;
template<class T>
class prique :public std::priority_queue<T, std::vector<T>, std::greater<T>> {};

template<class T, class Alloc = std::allocator<T>>
class Vector {

	using traits = std::allocator_traits<Alloc>;

public:

	using value_type = T;
	using allocator_type = Alloc;
	using size_type = unsigned int;
	using difference_type = int;
	using reference = T&;
	using const_reference = const T&;
	using pointer = typename traits::pointer;
	using const_pointer = typename traits::const_pointer;

	class iterator {

	public:

		using difference_type = int;
		using value_type = Vector::value_type;
		using pointer = Vector::pointer;
		using reference = Vector::reference;
		using iterator_category = std::random_access_iterator_tag;

	private:

		pointer p;

	public:

		iterator()noexcept :p() {}
		iterator(const Vector& base, difference_type index) noexcept :p(base.e + index) {}
		iterator(const iterator& i) :p(i.p) {}

		iterator& operator=(const iterator& i) = default;
		iterator& operator=(iterator&& i)noexcept = default;

		iterator& operator++() {
			p++;
			return *this;
		}

		iterator operator++(int) {
			iterator res = *this;
			p++;
			return res;
		}

		iterator operator+(const difference_type& x)const {
			iterator res = *this;
			return res += x;
		}

		iterator& operator+=(const difference_type& x) {
			p += x;
			return *this;
		}

		iterator& operator--() {
			p--;
			return *this;
		}

		iterator operator--(int) {
			iterator res = *this;
			p--;
			return res;
		}

		iterator operator-(const difference_type x)const {
			iterator res = *this;
			return res -= x;
		}

		difference_type operator-(const iterator& i)const {
			return p - i.p;
		}

		iterator& operator-=(const difference_type x) {
			p -= x;
			return *this;
		}

		reference operator*()const {
			return *p;
		}

		reference operator[](const difference_type x)const {
			return *(p + x);
		}

		bool operator<(const iterator& i)const {
			return p < i.p;
		}

		bool operator<=(const iterator& i)const {
			return p <= i.p;
		}

		bool operator==(const iterator& i)const {
			return p == i.p;
		}

		bool operator>(const iterator& i)const {
			return p > i.p;
		}

		bool operator>=(const iterator& i)const {
			return p >= i.p;
		}

		bool operator!=(const iterator& i)const {
			return p != i.p;
		}

	};

	class const_iterator {

	public:

		using difference_type = int;
		using value_type = Vector::value_type;
		using pointer = const Vector::pointer;
		using reference = const Vector::reference;
		using iterator_category = std::random_access_iterator_tag;

	private:

		pointer p;

	public:

		const_iterator()noexcept :p() {}
		const_iterator(const Vector& base, difference_type index) noexcept :p(base.e + index) {}
		const_iterator(const const_iterator& i) :p(i.p) {}

		const_iterator& operator=(const const_iterator& i)noexcept = default;
		const_iterator& operator=(const_iterator&& i)noexcept = default;

		const_iterator& operator++() {
			p++;
			return *this;
		}

		const_iterator operator++(int) {
			const_iterator res = *this;
			p++;
			return res;
		}

		const_iterator operator+(const difference_type x)const {
			const_iterator res = *this;
			return res += x;
		}

		const_iterator& operator+=(const difference_type x) {
			p += x;
			return *this;
		}

		const_iterator& operator--() {
			p--;
			return *this;
		}

		const_iterator operator--(int) {
			const_iterator res = *this;
			p--;
			return res;
		}

		const_iterator operator-(const difference_type x)const {
			const_iterator res = *this;
			return res -= x;
		}

		difference_type operator-(const const_iterator& i)const {
			return p - i.p;
		}

		const_iterator& operator-=(const difference_type x) {
			p -= x;
			return *this;
		}

		reference operator*()const {
			return *p;
		}

		reference operator[](const difference_type x)const {
			return *(p + x);
		}

		bool operator<(const const_iterator& i)const {
			return p < i.p;
		}

		bool operator<=(const const_iterator& i)const {
			return p <= i.p;
		}

		bool operator==(const const_iterator& i)const {
			return p == i.p;
		}

		bool operator>(const const_iterator& i)const {
			return p > i.p;
		}

		bool operator>=(const const_iterator& i)const {
			return p >= i.p;
		}

		bool operator!=(const const_iterator& i)const {
			return p != i.p;
		}

	};

	using reverse_iterator = std::reverse_iterator<iterator>;
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;

private:

	pointer e;
	size_type length = 0, cap = 1;
	Alloc alloc;

	static_assert(std::is_same<T, typename Alloc::value_type>::value, "The allocator value type is not matched the Vector value type.");
	static_assert(!std::is_const<T>::value, "This library forbids containers of const elements");

public:

	Vector() :Vector(Alloc()) {}

	explicit Vector(const Alloc& a)noexcept :alloc(a) {
		e = alloc.allocate(cap);
	}

	explicit Vector(size_type n, const Alloc& a = Alloc()) :alloc(a) {
		while (cap < n)cap *= 2;
		e = alloc.allocate(cap);
		rep(i, n)emplace_back();
	}

	explicit Vector(size_type n, const_reference value, const Alloc& a = Alloc()) :alloc(a) {
		while (cap < n)cap *= 2;
		e = alloc.allocate(cap);
		rep(i, n)emplace_back(value);
	}

	template<class InputIter>
	Vector(InputIter first, InputIter last, const Alloc& a = Alloc()) :alloc(a) {
		e = alloc.allocate(cap);
		for (InputIter i = first; i != last; i++) {
			emplace_back(*i);
		}
	}

	Vector(const Vector& x, const Alloc& a = Alloc()) :alloc(a) {
		while (cap < x.length)cap *= 2;
		length = x.length;
		e = alloc.allocate(cap);
		rep(i, x.length)traits::construct(alloc, e + i, *(x.e + i));
	}

	Vector(Vector&& x, const Alloc& a = Alloc()) :alloc(a) {
		cap = x.cap;
		length = x.length;
		e = x.e;
		x.e = nullptr;
	}

	~Vector() {
		if (e != nullptr) {
			rep(i, length)traits::destroy(alloc, e + i);
			alloc.deallocate(e, cap);
		}
	}

	Vector& operator=(const Vector& x) {
		rep(i, length)traits::destroy(alloc, e + i);
		alloc.deallocate(e, cap);
		length = x.length;
		cap = 1;
		while (cap < length)cap *= 2;
		e = alloc.allocate(cap);
		rep(i, length)traits::construct(alloc, e + i, *(x.e + i));
		return *this;
	}

	Vector& operator=(Vector&& x) {
		rep(i, length)traits::destroy(alloc, e + i);
		alloc.deallocate(e, cap);
		cap = x.cap;
		length = x.length;
		e = x.e;
		x.e = nullptr;
		return *this;
	}

private:

	void extension() {
		pointer e_ = alloc.allocate(cap * 2);
		rep(i, length)traits::construct(alloc, e_ + i, *(e + i));
		rep(i, length)traits::destroy(alloc, e + i);
		alloc.deallocate(e, cap);
		e = e_;
		cap *= 2;
	}

	void extension(size_type n) {
		unsigned int r = 1;
		while (cap * r < n)r *= 2;
		if (r == 1)return;
		pointer e_ = alloc.allocate(cap * r);
		rep(i, length)traits::construct(alloc, e_ + i, *(e + i));
		rep(i, length)traits::destroy(alloc, e + i);
		alloc.deallocate(e, cap);
		e = e_;
		cap *= r;
	}

public:

	template<class InputIter>
	void assign(InputIter first, InputIter last) {
		size_type cnt = 0;
		for (InputIter i = first; i != last; i++) {
			if (cnt == cap) {
				length = std::max(length, cnt);
				extension();
			}
			traits::construct(alloc, e + cnt, *i);
			cnt++;
		}
	}

	void assign(size_type n, const_reference value) {
		extension(n);
		std::fill(e, e + n, value);
	}

	template<class... Args>
	void emplace_back(Args&&... args) {
		if (length == cap)extension();
		traits::construct(alloc, e + length, std::forward<Args>(args)...);
		length++;
	}

	void push_back(const_reference value) {
		emplace_back(value);
	}

	void push_back(T&& value) {
		emplace_back(std::move(value));
	}

	void pop_back() {
		traits::destroy(alloc, e + length);
		length--;
	}

	void reserve(size_type n) {
		extension(n);
	}

	iterator erase(iterator pos) {
		const iterator res = pos;
		iterator t = pos; t++;
		for (iterator i = pos; t != end(); i++, t++) {
			*i = std::move(*t);
		}
		pop_back();
		return res;
	}

	iterator erase(iterator first, iterator last) {
		const iterator res = first;
		typename iterator::difference_type d = last - first;
		for (iterator i = first; i + d != end(); i++) {
			*i = std::move(*(i + d));
		}
		rep(i, d)pop_back();
		return res;
	}

	void swap(Vector& x) {
		std::swap(length, x.length);
		std::swap(cap, x.cap);
		std::swap(e, x.e);
	}

	void clear() {
		while (length)pop_back();
	}

	size_type size()const {
		return length;
	}

	void resize(size_type  n, const_reference value = T()) {
		extension(n);
		while (n < length)pop_back();
		length = n;
		std::fill(e, e + n, value);
	}

	size_type capacity()const {
		return cap;
	}

	bool empty()const {
		return !length;
	}

	reference operator[](const size_type pos)const {
		return e[pos];
	}

	pointer data() {
		return e;
	}

	reference front() {
		return *e;
	}

	reference back() {
		return *(e + length - 1);
	}

	iterator begin() noexcept {
		return iterator(*this, 0);
	}

	const_iterator begin()const noexcept {
		return const_iterator(*this, 0);
	}

	const_iterator cbegin()const noexcept {
		return const_iterator(*this, 0);
	}

	iterator rbegin()noexcept {
		return reverse_iterator(*this, 0);
	}

	const_iterator rbegin()const noexcept {
		return const_reverse_iterator(*this, 0);
	}

	const_iterator crbegin()const noexcept {
		return const_reverse_iterator(*this, 0);
	}

	iterator end() noexcept {
		return iterator(*this, length);
	}

	const_iterator end()const noexcept {
		return const_iterator(*this, length);
	}

	const_iterator cend()const noexcept {
		return const_iterator(*this, length);
	}

	iterator rend()noexcept {
		return reverse_iterator(*this, length);
	}

	const_iterator rend()const noexcept {
		return const_reverse_iterator(*this, length);
	}

	const_iterator crend()const noexcept {
		return const_reverse_iterator(*this, length);
	}

};
template <class T, class U>
inline bool chmax(T& lhs, const U& rhs) {
	if (lhs < rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
template <class T, class U>
inline bool chmin(T& lhs, const U& rhs) {
	if (lhs > rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
inline lint gcd(lint a, lint b) {
	while (b) {
		lint c = a;
		a = b; b = c % b;
	}
	return a;
}
inline lint lcm(lint a, lint b) {
	return a / gcd(a, b) * b;
}
bool isprime(lint n) {
	if (n == 1)return false;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0)return false;
	}
	return true;
}
lint mypow(lint a, lint b) {
	if (!b)return 1;
	if (b & 1)return mypow(a, b - 1) * a;
	lint memo = mypow(a, b >> 1);
	return memo * memo;
}
lint modpow(lint a, lint b, lint m) {
	if (!b)return 1;
	if (b & 1)return modpow(a, b - 1, m) * a % m;
	lint memo = modpow(a, b >> 1, m);
	return memo * memo % m;
}
template<typename T>
void printArray(std::vector<T>& vec) {
	rep(i, vec.size() - 1)std::cout << vec[i] << " ";
	std::cout << vec.back() << std::endl;
}
template<typename T>
void printArray(Vector<T>& vec) {
	rep(i, vec.size() - 1)std::cout << vec[i] << " ";
	std::cout << vec.back() << std::endl;
}
template<typename T>
void printArray(T l, T r) {
	T rprev = r;
	rprev--;
	for (T i = l; i != rprev; i++) {
		std::cout << *i << " ";
	}
	std::cout << *rprev << std::endl;
}
std::string to_string(Vector<int>& vec) {
	std::string res = "[";
	rep(i, vec.size() - 1)res += std::to_string(vec[i]) + ", ";
	res += std::to_string(vec.back()) + "]";
	return res;
}
template<unsigned int modulo = 1000000007>
class ModInt {
	lint value;
public:
	ModInt() : value(0) {}
	template<typename T>
	ModInt(T value = 0) : value(value) {
		if (value < 0)value = -(lint)(-value % modulo) + modulo;
		this->value = value % modulo;
	}
	inline operator int()const { return value; }
	inline ModInt& operator+=(const ModInt& x) {
		value += x.value;
		if (value >= modulo)value -= modulo;
		return *this;
	}
	inline ModInt& operator++() {
		if (value == modulo - 1)value = 0;
		else value++;
		return *this;
	}
	inline ModInt operator-()const {
		return ModInt(0) -= *this;
	}
	inline ModInt& operator-=(const ModInt& x) {
		value -= x.value;
		if (value < 0)value += modulo;
		return *this;
	}
	inline ModInt& operator--() {
		if (value == 0)value = modulo - 1;
		else value--;
		return *this;
	}
	inline ModInt& operator*=(const ModInt& x) {
		value = value * x.value % modulo;
		return *this;
	}
	inline ModInt& operator/=(ModInt rhs) {
		int exp = modulo - 2;
		while (exp) {
			if (exp & 1)*this *= rhs;
			rhs *= rhs;
			exp >>= 1;
		}
		return *this;
	}
	template<typename T> ModInt operator+(const T& rhs)const { return ModInt(*this) += rhs; }
	template<typename T> ModInt& operator+=(const T& rhs) { return operator+=(ModInt(rhs)); }
	template<typename T> ModInt operator-(const T& rhs)const { return ModInt(*this) -= rhs; }
	template<typename T> ModInt& operator-=(const T& rhs) { return operator-=(ModInt(rhs)); }
	template<typename T> ModInt operator*(const T& rhs)const { return ModInt(*this) *= rhs; }
	template<typename T> ModInt& operator*=(const T& rhs) { return operator*=(ModInt(rhs)); }
	template<typename T> ModInt operator/(const T& rhs)const { return ModInt(*this) /= rhs; }
	template<typename T> ModInt& operator/=(const T& rhs) { return operator/=(ModInt(rhs)); }
};
template<unsigned int T>
std::istream& operator>>(std::istream& ist, ModInt<T>& x) {
	lint a;
	ist >> a;
	x = a;
	return ist;
}
int n, m, a, b;
char ans[1010][1010];
int main() {
	std::cin >> n >> m >> a >> b;
	rep(i, n) {
		rep(j, m)ans[i][j] = 'x';
	}
	if ((a + b) * 2 > n * m) {
		puts("NO");
		return 0;
	}
	if (n % 2 == 0 && m % 2 == 0) {
		if (a % 2 && b % 2 && (a + b) * 2 == n * m) {
			puts("NO");
			return 0;
		}
		rep(i, n) {
			for (int j = 0; j < m; j += 2) {
				ans[i][j] = '<'; ans[i][j + 1] = '>';
			}
		}
		int cnt = 0;
		for (int i = 0; i < n; i += 2) {
			bool f = false;
			for (int j = 0; j < m; j += 2) {
				if (b <= cnt) {
					f = true;
					break;
				}
				ans[i][j] = ans[i][j + 1] = '^';
				ans[i + 1][j] = ans[i + 1][j + 1] = 'v';
				cnt += 2;
				if (b < cnt) {
					ans[i][j + 1] = ans[i + 1][j + 1] = '.';
				}
			}
			if (f)break;
		}
		cnt = n * m / 2 - (b + 1) / 2 * 2;
		rep(i, n) {
			bool f = false;
			for (int j = 0; j < m; j += 2) {
				if (a == cnt) {
					f = true;
					break;
				}
				if (ans[i][j] == '<') {
					ans[i][j] = ans[i][j + 1] = '.';
					cnt--;
				}
			}
			if (f)break;
		}
		puts("YES");
		rep(i, n) {
			rep(j, m)std::cout << ans[i][j];
			std::cout << std::endl;
		}
	}
	else if (n % 2 && m % 2 == 0) {
		if (a < m / 2) {
			if ((a + b) * 2 > n * m - (m - 2 * a)) {
				puts("NO");
				return 0;
			}
			rep(i, a) {
				ans[0][2 * i] = '<';
				ans[0][2 * i + 1] = '>';
			}
		}
		else {
			if ((a - (m / 2)) % 2 && (a + b) * 2 >= n * m) {
				puts("NO");
				return 0;
			}
			for (int i = 0; i < m; i += 2) {
				ans[0][i] = '<'; ans[0][i + 1] = '>';
				a--;
			}
			for (int i = 1; i < n; i += 2) {
				bool f = false;
				for (int j = 0; j < m; j += 2) {
					if (a == 0) {
						f = true;
						break;
					}
					ans[i][j] = ans[i + 1][j] = '<';
					ans[i][j + 1] = ans[i + 1][j + 1] = '>';
					a -= 2;
					if (a == -1) {
						ans[i + 1][j] = ans[i + 1][j + 1] = 'x';
						f = true;
						break;
					}
				}
				if (f)break;
			}
		}
		int cnt = 0;
		rep(i, n - 1) {
			bool f = false;
			rep(j, m) {
				if (cnt == b) {
					f = true;
					break;
				}
				if (ans[i][j] == 'x' && ans[i + 1][j] == 'x') {
					ans[i][j] = '^'; ans[i + 1][j] = 'v';
					cnt++;
				}
			}
			if (f)break;
		}
		rep(i, n) {
			rep(j, m) {
				if (ans[i][j] == 'x')ans[i][j] = '.';
			}
		}
		puts("YES");
		rep(i, n) {
			rep(j, m)std::cout << ans[i][j];
			std::cout << std::endl;
		}
	}
	else if (n % 2 == 0 && m % 2) {
		if (b < n / 2) {
			if ((a + b) * 2 > n * m - (n - 2 * b)) {
				puts("NO");
				return 0;
			}
			rep(i, b) {
				ans[2 * i][0] = '^';
				ans[2 * i + 1][0] = 'v';
			}
		}
		else {
			if ((b - n / 2) % 2 && (a + b) * 2 >= n * m) {
				puts("NO");
				return 0;
			}
			for (int i = 0; i < n; i += 2) {
				ans[i][0] = '^'; ans[i + 1][0] = 'v';
				b--;
			}
			for (int i = 1; i < m; i += 2) {
				bool f = false;
				for (int j = 0; j < n; j += 2) {
					if (b == 0) {
						f = true;
						break;
					}
					ans[j][i] = ans[j][i + 1] = '^';
					ans[j + 1][i] = ans[j + 1][i + 1] = 'v';
					b -= 2;
					if (b == -1) {
						ans[j][i + 1] = ans[j + 1][i + 1] = 'x';
						f = true;
						break;
					}
				}
				if (f)break;
			}
		}
		int cnt = 0;
		rep(i, n) {
			bool f = false;
			rep(j, m - 1) {
				if (cnt == a) {
					f = true;
					break;
				}
				if (ans[i][j] == 'x' && ans[i][j + 1] == 'x') {
					ans[i][j] = '<'; ans[i][j + 1] = '>';
					cnt++;
				}
			}
			if (f)break;
		}
		rep(i, n) {
			rep(j, m) {
				if (ans[i][j] == 'x')ans[i][j] = '.';
			}
		}
		puts("YES");
		rep(i, n) {
			rep(j, m)std::cout << ans[i][j];
			std::cout << std::endl;
		}
	}
	else {
		if (a < m / 2) {
			if ((a + b) * 2 > n * m - (m - 2 * a)) {
				puts("NO");
				return 0;
			}
			rep(i, a) {
				ans[0][2 * i] = '<'; ans[0][2 * i + 1] = '>';
			}
		}
		else {
			if (a * 2 > n * m - n || (a + b) * 2 > n * m - 1) {
				puts("NO");
				return 0;
			}
			for (int i = 0; i < m - 1; i += 2) {
				ans[0][i] = '<'; ans[0][i + 1] = '>';
				a--;
			}
			if (a % 2) {
				ans[n - 1][m - 2] = '<'; ans[n - 1][m - 1] = '>';
				a--;
			}
			for (int i = 1; i < n; i += 2) {
				bool f = false;
				for (int j = 0; j < m - 1; j += 2) {
					if (a == 0) {
						f = true;
						break;
					}
					ans[i][j] = ans[i + 1][j] = '<';
					ans[i][j + 1] = ans[i + 1][j + 1] = '>';
					a -= 2;
					if (a == -1) {
						ans[i + 1][j] = ans[i + 1][j + 1] = 'x';
						f = true;
						break;
					}
				}
				if (f)break;
			}
		}
		int cnt = 0;
		rep(i, n - 1) {
			bool f = false;
			rep(j, m) {
				if (cnt == b) {
					f = true;
					break;
				}
				if (ans[i][j] == 'x' && ans[i + 1][j] == 'x') {
					ans[i][j] = '^'; ans[i + 1][j] = 'v';
					cnt++;
				}
			}
			if (f)break;
		}
		rep(i, n) {
			rep(j, m) {
				if (ans[i][j] == 'x')ans[i][j] = '.';
			}
		}
		puts("YES");
		rep(i, n) {
			rep(j, m)std::cout << ans[i][j];
			std::cout << std::endl;
		}
	}
	return 0;
}

Measured memory_bytes: 2176