import qualified Data.IntMap.Strict as IM

type Brd = IM.IntMap (IM.IntMap Char)

iminit :: Int -> Int -> Brd
iminit m n = foldr op IM.empty [0..n-1]
  where
    op y im = IM.insert y isub im
    isub = foldr op2 IM.empty [0..m-1]
      where op2 x im = IM.insert x '.' im
  
imset :: Int -> Int -> Char -> Brd -> Brd
imset i j c im = IM.update upd j im
  where upd imsub = Just (IM.update (const (Just c)) i imsub)

imsetA :: Int -> Int -> Brd -> Brd
imsetA i j = imset i j '<' . imset (i+1) j '>'

imsetB :: Int -> Int -> Brd -> Brd
imsetB i j = imset i j '^' . imset i (j+1) 'v'

imBlock :: Char -> Int -> Int -> Int -> Brd -> Brd
imBlock 'a' i j 1 = imsetA i j
imBlock 'a' i j 2 = imsetA i j . imsetA i (j+1)
imBlock 'b' i j 1 = imsetB i j
imBlock 'b' i j 2 = imsetB i j . imsetB (i+1) j

solve :: Int -> Int -> Int -> Int -> String
solve n m a b
  | possible = "YES\n" ++ disp
  | otherwise = "NO\n"
  where
    (n_block, n_odd) = divMod n 2
    (m_block, m_odd) = divMod m 2
    aT = n_odd * min a m_block
    bL = m_odd * min b n_block
    (aC, aCm) = divMod (a - aT + 1) 2
    (bC, bCm) = divMod (b - bL + 1) 2
    possible = aC + bC <= n_block * m_block

    imFin = setC (setL (setT (iminit m n)))

    setT im = foldr op im [0 .. aT-1]
      where op i = imsetA (m_odd + 2*i) 0

    setL im = foldr op im [0 .. bL-1]
      where op j = imsetB 0 (n_odd + 2*j)

    setC = setC1 'a' 0 aC aCm . setC1 'b' aC bC bCm

    setC1 ch shift size flag im =
      foldr (op ch) im (zip ns [shift .. shift+size-1])
      where
        ns = if flag == 0 then 1 : (repeat 2) else repeat 2
        op ch (n,s) = imBlock ch i j n
          where (y,x) = divMod s m_block
                i = m_odd + 2 * x
                j = n_odd + 2 * y

    disp = unlines $ map (map snd . IM.toAscList . snd) (IM.toAscList imFin)

main :: IO ()
main = do
  conts <- getContents
  let [n,m,a,b] = map read (words conts)
      answer = solve n m a b
  putStr answer
