publish part2 preview!

This commit is contained in:
Joel Kaasinen
2021-02-05 09:42:17 +02:00
parent 5a8da034f3
commit 4ac9ff052b
28 changed files with 7874 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
module Examples.Bank where
import qualified Data.Map as Map
data Bank = Bank (Map.Map String Int)
deriving (Show,Eq)
deposit :: String -> Int -> Bank -> Bank
deposit accountName amount (Bank accounts) =
Bank (Map.adjust (\x -> x+amount) accountName accounts)
withdraw :: String -> Int -> Bank -> (Int,Bank)
withdraw accountName amount (Bank accounts) =
let balance = Map.findWithDefault 0 accountName accounts -- balance is 0 for a nonexistant account
withdrawal = min amount balance -- can't withdraw over balance
newAccounts = Map.adjust (\x -> x-withdrawal) accountName accounts
in (withdrawal, Bank newAccounts)
-- `BankOp a` is an operation that transforms a Bank value, while returning a value of type `a`
data BankOp a = BankOp (Bank -> (a,Bank))
-- running a BankOp on a Bank
runBankOp :: BankOp a -> Bank -> (a,Bank)
runBankOp (BankOp f) bank = f bank
-- Running one BankOp after another
(+>>) :: BankOp a -> BankOp b -> BankOp b
op1 +>> op2 = BankOp combined
where combined bank = let (_,bank1) = runBankOp op1 bank
in runBankOp op2 bank1
-- Running a parameterized BankOp, using the value returned by a previous BankOp
-- The implementation is a bit tricky but it's enough to understand how +> is used for now.
(+>) :: BankOp a -> (a -> BankOp b) -> BankOp b
op +> parameterized = BankOp combined
where combined bank = let (a,bank1) = runBankOp op bank
in runBankOp (parameterized a) bank1
-- Make a BankOp out of deposit. There is no return value so we use ().
depositOp :: String -> Int -> BankOp ()
depositOp accountName amount = BankOp depositHelper
where depositHelper bank = ((), deposit accountName amount bank)
-- Make a BankOp out of withdraw. Note how
-- withdraw accountName amount :: Bank -> (Int,Bank)
-- is almost a BankOp already!
withdrawOp :: String -> Int -> BankOp Int
withdrawOp accountName amount = BankOp (withdraw accountName amount)
-- distribute amount to two accounts
distributeOp :: String -> String -> Int -> BankOp ()
distributeOp to1 to2 amount =
depositOp to1 half
+>>
depositOp to2 rest
where half = div amount 2
rest = amount - half
-- withdraw up to 100 units from one account, and distribute it evenly among two accounts
shareOp :: String -> String -> String -> BankOp ()
shareOp from to1 to2 =
withdrawOp from 100
+>
distributeOp to1 to2
+9
View File
@@ -0,0 +1,9 @@
import Network.HTTP
import Control.Monad
main = do
rsp <- simpleHTTP (getRequest "http://httpbin.org/base64/aGFza2VsbCBmb3IgZXZlcgo=")
body <- getResponseBody rsp
forM_ (words body) $ \w -> do
putStr "word: "
putStrLn w
+40
View File
@@ -0,0 +1,40 @@
module Examples.ReadTypes where
import Control.Monad (forM)
import Data.List (isInfixOf, isSuffixOf)
import System.Directory (listDirectory, doesDirectoryExist)
-- a line is a type signature if it contains :: but does not contain =
isTypeSignature :: String -> Bool
isTypeSignature s = not (isInfixOf "=" s) && isInfixOf "::" s
-- return list of types for a .hs file
readTypesFile :: FilePath -> IO [String]
readTypesFile file
| isSuffixOf ".hs" file = do content <- readFile file
let ls = lines content
return (filter isTypeSignature ls)
| otherwise = return []
-- list children of directory, prepend directory name
qualifiedChildren :: String -> IO [String]
qualifiedChildren path = do childs <- listDirectory path
return (map (\name -> path++"/"++name) childs)
-- get type signatures for all entries in given directory
-- note mutual recursion with readTypes
readTypesDir :: String -> IO [String]
readTypesDir path = do childs <- qualifiedChildren path
typess <- forM childs readTypes
return (concat typess)
-- recursively read types contained in a file or directory
-- note mutual recursion with readTypesDir
readTypes :: String -> IO [String]
readTypes path = do isDir <- doesDirectoryExist path
if isDir then readTypesDir path else readTypesFile path
-- main is the IO action that gets run when you run the program
main :: IO ()
main = do ts <- readTypes "."
mapM_ putStrLn ts
+1
View File
@@ -0,0 +1 @@
module Mooc.VeryLimitedPrelude (Int,Integer,Bool(..),Num(..),otherwise,undefined) where
+162
View File
@@ -0,0 +1,162 @@
module Set10a where
import Data.Char
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: Given a list, produce a new list where each element of the
-- original list repeats twice.
--
-- Make sure your function works with infinite lists.
--
-- Examples:
-- doublify [7,1,6] ==> [7,7,1,1,6,6]
-- take 10 (doublify [0..]) ==> [0,0,1,1,2,2,3,3,4,4]
doublify :: [a] -> [a]
doublify = todo
------------------------------------------------------------------------------
-- Ex 2: Implement the function interleave that takes two lists and
-- produces a new list that takes elements alternatingly from both
-- lists like this:
--
-- interleave [1,2,3] [4,5,6] ==> [1,4,2,5,3,6]
--
-- If one list runs out of elements before the other, just keep adding
-- elements from the other list.
--
-- Make sure your function also works with infinite lists.
--
-- Examples:
-- interleave [1,2,3] [4,5,6] ==> [1,4,2,5,3,6]
-- interleave [1,2] [4,5,6,7] ==> [1,4,2,5,6,7]
-- take 10 (interleave [7,7,7] [1..]) ==> [7,1,7,2,7,3,4,5,6,7]
-- take 10 (interleave [1..] (repeat 0)) ==> [1,0,2,0,3,0,4,0,5,0]
interleave :: [a] -> [a] -> [a]
interleave = todo
------------------------------------------------------------------------------
-- Ex 3: Deal out cards. Given a list of cards (strings), and a list
-- of players (strings), deal out the cards to the players in a cycle.
--
-- Make sure your function works with infinite inputs as well!
--
-- Example:
-- deal ["Hercule","Ariadne"] ["Ace","Joker","Heart"]
-- ==> [("Ace","Hercule"),("Joker","Ariadne"),("Heart","Hercule")]
-- take 4 (deal ["a","b","c"] (map show [0..]))
-- ==> [("0","a"),("1","b"),("2","c"),("3","a")]
-- deal ("you":(repeat "me")) ["1","2","3","4"]
-- ==> [("1","you"),("2","me"),("3","me"),("4","me")]
--
-- Hint: remember the functions cycle and zip?
deal :: [String] -> [String] -> [(String,String)]
deal = todo
------------------------------------------------------------------------------
-- Ex 4: Given two lists, xs and ys, and an element z, generate an
-- infinite list that consists of
--
-- * the elements of xs
-- * z
-- * the elements of ys
-- * z
-- * the elements of xs
-- * ... and so on
--
-- Examples:
-- take 20 (alternate "abc" "def" ',') ==> "abc,def,abc,def,abc,"
-- take 10 (alternate [1,2] [3,4,5] 0) ==> [1,2,0,3,4,5,0,1,2,0]
alternate :: [a] -> [a] -> a -> [a]
alternate xs ys z = todo
------------------------------------------------------------------------------
-- Ex 5: Check if the length of a list is at least n. Make sure your
-- function works for infinite inputs.
--
-- Examples:
-- lengthAtLeast 2 [1,2,3] ==> True
-- lengthAtLeast 7 [1,2,3] ==> False
-- lengthAtLeast 10 [0..] ==> True
lengthAtLeast :: Int -> [a] -> Bool
lengthAtLeast = todo
------------------------------------------------------------------------------
-- Ex 6: The function chunks should take in a list, and a number n,
-- and return all sublists of length n of the original list.
--
-- Make sure your function works with infinite inputs. The function
-- lengthAtLeast can help with this.
--
-- Examples:
-- chunks 2 [1,2,3,4] ==> [[1,2],[2,3],[3,4]]
-- take 4 (chunks 3 [0..]) ==> [[0,1,2],[1,2,3],[2,3,4],[3,4,5]]
chunks :: Int -> [a] -> [[a]]
chunks = todo
------------------------------------------------------------------------------
-- Ex 7: Define a newtype called IgnoreCase, that wraps a value of
-- type String. Define an `Eq` instance for IgnoreCase so that it
-- compares strings in a case-insensitive way.
--
-- To help the tests, also implement the function
-- ignorecase :: String -> IgnoreCase
--
-- Hint: remember Data.Char.toLower
--
-- Examples:
-- ignorecase "abC" == ignoreCase "ABc" ==> True
-- ignorecase "acC" == ignoreCase "ABc" ==> False
data IgnoreCase = Todo
------------------------------------------------------------------------------
-- Ex 8: Here's the Room type and some helper functions from the
-- course material. Define a cyclic Room structure like this:
--
-- * maze1 has the description "Maze"
-- * The direction "Left" goes to maze2
-- * "Right" goes to maze3
-- * maze2 has the description "Deeper in the maze"
-- * "Left" goes to maze3
-- * "Right" goes to maze1
-- * maze3 has the description "Elsewhere in the maze"
-- * "Left" goes to maze1
-- * "Right" goes to maze2
--
-- The variable maze should point to the room maze1.
--
-- Examples:
-- play maze ["Left","Left","Left"]
-- ==> ["Maze","Deeper in the maze","Elsewhere in the maze","Maze"]
-- play maze ["Right","Right","Right","Right"]
-- ==> ["Maze","Elsewhere in the maze","Deeper in the maze","Maze","Elsewhere in the maze"]
-- play maze ["Left","Left","Right"]
-- ==> ["Maze","Deeper in the maze","Elsewhere in the maze","Deeper in the maze"]
data Room = Room String [(String,Room)]
-- Do not modify describe, move or play. The tests will use the
-- original definitions of describe, move and play regardless of your
-- modifications.
describe :: Room -> String
describe (Room s _) = s
move :: Room -> String -> Maybe Room
move (Room _ directions) direction = lookup direction directions
play :: Room -> [String] -> [String]
play room [] = [describe room]
play room (d:ds) = case move room d of Nothing -> [describe room]
Just r -> describe room : play r ds
maze :: Room
maze = todo
+168
View File
@@ -0,0 +1,168 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set10aTest where
import Mooc.Test
import Mooc.Th
import Control.Exception (evaluate, try, SomeException)
import Data.Char
import Data.List
import Language.Haskell.TH
import Test.QuickCheck
import Test.QuickCheck.Monadic
import Set10a hiding (describe,move,play)
main = score tests
tests = [(1,"doublify",[ex1_finite, ex1_infinite])
,(2,"interleave",[ex2_finite, ex2_infinite_1, ex2_infinite_2])
,(3,"deal",[ex3_examples, ex3_finite, ex3_infinite_1, ex3_infinite_2])
,(4,"alternate",[ex4_examples, ex4])
,(5,"lenghtAtLeast",[ex5_finite, ex5_infinite])
,(6,"chunks",[ex6_finite, ex6_infinite])
,(7,"IgnoreCase",[ex7_type, ex7_works])
,(8,"maze",[ex8_1, ex8_2])]
-- -- -- --
ex1_finite =
forAllBlind (choose (0,10)) $ \n ->
forAllBlind (choose ('a','z')) $ \c ->
forAllBlind (choose ('a','z')) $ \d ->
$(testing [|doublify (replicate n c ++ [d])|]) (?==(replicate (2*n) c ++ [d,d]))
ex1_infinite =
forAllBlind (choose (0,100)) $ \n ->
forAllBlind (choose (0,1000)) $ \i ->
counterexample ("With n = "++show n) $
$(testing' [|doublify [n..]|]) $ \was ->
counterexample (" Index "++show i) $
was !! i ?== n + div i 2
evens (x:xs) = odds xs
evens [] = []
odds (x:xs) = x:evens xs
odds [] = []
ex2_finite = forAll_ $ \(is::[Integer]) ->
forAll_ $ \(rest::[Integer]) ->
let as = odds is
bs = evens is
in conjoin [$(testing [|interleave as bs|]) (?==is)
,if length as > length bs
then $(testing [|interleave (as++rest) bs|]) (?==is++rest)
else $(testing [|interleave as (bs++rest)|]) (?==is++rest)]
ex2_infinite_1 = forAll_ $ \(i::Integer,j::Integer) ->
counterexample ("with i = " ++ show i ++ ", j = " ++ show j) $
$(testing' [|take 10 (interleave (repeat i) (repeat j))|]) (?==take 10 (cycle [i,j]))
ex2_infinite_2 = forAll_ $ \(x::Integer) ->
forAll_ $ \(Positive i) ->
counterexample ("with x = " ++ show x) $
$(testing' [|interleave [0..] (repeat x)|]) $ \res ->
counterexample (" element at index " ++ show i) $
res !! i == if odd i then x else fromIntegral (div i 2)
ex3_examples =
conjoin [$(testing [|deal ["Hercule","Ariadne"] ["Ace","Joker","Heart"]|]) (?==[("Ace","Hercule"),("Joker","Ariadne"),("Heart","Hercule")])
,$(testing [|deal ["Hercule","Ariadne"] e|]) (?==[])]
where e = [] :: [String]
word = listOf1 (choose ('a','z'))
ex3_finite = forAllShrink_ (listOf1 word) $ \names ->
forAllShrink_ (listOf1 word) $ \cards ->
and [not (null names), not (null cards)] ==>
$(testing [|deal names cards|]) (?==[(cards!!i, names!!(mod i (length names))) | i <- [0..length cards - 1]])
ex3_infinite_1 = forAllShrink_ (listOf1 word) $ \names ->
not (null names) ==>
forAllBlind (choose (length names, 10*length names)) $ \n ->
counterexample ("With n = "++show n++", names = "++show names) $
$(testing' [|take n (deal names (map show [0..]))|]) (?==[(show i, names!!(mod i (length names))) | i <- [0..n - 1]])
ex3_infinite_2 =
$(testing' [|take 10 (deal (repeat "me") (repeat "card"))|]) (?==replicate 10 ("card","me"))
ex4_examples = conjoin [$(testing' [|take 20 (alternate "abc" "def" ',')|]) (?=="abc,def,abc,def,abc,")
,$(testing' [|take 10 (alternate [1,2] [3,4,5] 0)|]) (?==[1,2,0,3,4,5,0,1,2,0])]
ex4 = forAllBlind (choose (1,3)) $ \n ->
forAllBlind (choose (1,6)) $ \m ->
forAll_ $ \(NonNegative i) ->
$(testing [|alternate (replicate n 1) (replicate m 1) 0|]) $ \was ->
counterexample (" Index "++show i) $
(was !! i ?== if mod i (2+n+m) `elem` [n,n+1+m] then 0 else 1)
ex5_finite = forAll_ $ \(is::[Int]) ->
forAll_ $ \(NonNegative n) ->
$(testing [|lengthAtLeast n is|]) (?==(length is >= n))
ex5_infinite = forAll_ $ \(Positive (i::Int)) ->
forAll_ $ \(NonNegative n) ->
counterexample ("With n = " ++ show n ++ ", i = " ++ show i) $
$(testing' [|lengthAtLeast n (repeat i)|]) (?==True)
ex6_finite = forAllBlind (choose (1,6)) $ \n ->
forAllShrink_ (listOf word) $ \ws ->
$(testing [|chunks n ws|]) (?==[[ws!!i | i <- [j..j+n-1]] | j <- [0..length ws - n]])
ex6_infinite = forAllBlind (choose (1,10)) $ \n ->
forAllBlind (choose (1,25)) $ \k ->
counterexample ("With k = "++show k++", n = "++show n) $
$(testing' [|take k (chunks n [0..])|]) (?==[[j..j+n-1] | j <- [0..k-1]])
shuffleCase w = (do s <- vectorOf (length w) (elements [toLower,toUpper])
return (zipWith ($) s w)) `suchThat` (/=w)
ex7_type = $(do let s = "IgnoreCase"
n <- lookupTypeName s
case n of
Nothing -> [|counterexample ("Type "++s++" not defined!") False|]
Just n -> do info <- reify n
case info of TyConI (NewtypeD _ _ _ _ _ _) -> [|property True|]
_ -> [|counterexample ("Definition "++s++" is not a newype declaration!") False|])
ex7_works =
$(hasType "ignorecase" [t|String -> IgnoreCase|]) $ \ignorecase ->
$(withInstance "Eq" "IgnoreCase" [|(==)|]) $ \((==)::IgnoreCase->IgnoreCase->Bool) ->
property $ do
w1 <- word
w2 <- shuffleCase w1
w3 <- word
let t :: String -> String -> Bool -> Property
t x y exp = counterexample ("ignorecase " ++ show x ++ " == ignorecase " ++ show y) $ (ignorecase x == ignorecase y) ?== exp
return $ conjoin [t w1 w1 True
,t w1 w2 True
,t w2 w1 True
,t (w1++w3) w2 False
,t w2 (w1++w3) False
,t w1 (w2++w3) False
,t (w2++w3) w1 False]
describe :: Room -> String
describe (Room s _) = s
move :: Room -> String -> Maybe Room
move (Room _ directions) direction = lookup direction directions
play :: Room -> [String] -> [String]
play room [] = [describe room]
play room (d:ds) = case move room d of Nothing -> [describe room]
Just r -> describe room : play r ds
ex8_1 = forAllShrink_ (choose (0,20)) $ \i ->
counterexample ("with i = " ++ show i) $
conjoin [$(testing' [|play maze (replicate i "Left")|]) (?==take (i+1) (cycle ["Maze","Deeper in the maze","Elsewhere in the maze"]))
,$(testing' [|play maze (replicate i "Right")|]) (?==take (i+1) (cycle ["Maze","Elsewhere in the maze","Deeper in the maze"]))]
ex8_2 = forAllShrinkBlind (listOf (elements ["Left","Right"])) subterms $ \dirs ->
let cnt = sum (map (\d -> case d of "Left" -> 1; "Right" -> -1) dirs)
answer = ["Maze","Deeper in the maze","Elsewhere in the maze"] !! mod cnt 3
in counterexample ("with dirs = " ++ show dirs) $
$(testing' [|last (play maze dirs)|]) (?==answer)
+90
View File
@@ -0,0 +1,90 @@
-- This exercise set hides most of Prelude. You only have access to
-- the Bool, Int and list types, and pattern matching.
{-# LANGUAGE NoImplicitPrelude #-}
module Set10b where
import Mooc.VeryLimitedPrelude
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: Define the operator ||| that works like ||, but forces its
-- _right_ argument instead of the left one.
--
-- Examples:
-- False ||| False ==> False
-- True ||| False ==> True
-- undefined ||| True ==> True
-- False ||| undefined ==> an error!
(|||) :: Bool -> Bool -> Bool
x ||| y = todo
------------------------------------------------------------------------------
-- Ex 2: Define the function boolLength, that returns the length of a
-- list of booleans and forces all of the elements
--
-- Examples:
-- boolLength [False,True,False] ==> 3
-- boolLength [False,undefined] ==> an error!
--
-- Note that with the ordinary length function,
-- length [False,undefined] ==> 2
boolLength :: [Bool] -> Int
boolLength xs = todo
------------------------------------------------------------------------------
-- Ex 3: Define the function validate which, given a predicate and a
-- value, evaluates to the value. However, validate should also force the
-- result of `predicate value`, even though it is not used.
--
-- Examples:
-- validate even 3 ==> 3
-- validate odd 3 ==> 3
-- validate undefined 3 ==> an error!
-- validate (\x -> undefined) 3 ==> an error!
validate :: (a -> Bool) -> a -> a
validate predicate value = todo
------------------------------------------------------------------------------
-- Ex 4: Even though we can't implement the generic seq function
-- ourselves, we can implement it manually for specific datatypes.
--
-- The type class MySeq contains the method myseq which is supposed to
-- work like the built-in seq function. Implement the given MySeq
-- instances.
--
-- Just like in the course material, we use the special value
-- `undefined` here to illustrate what myseq evaluates. The tests for
-- this exercise also use undefined.
--
-- Examples:
-- myseq True 0 ==> 0
-- myseq (not True) 0 ==> 0
-- myseq (undefined :: Bool) 0
-- ==> *** Exception: Prelude.undefined
-- myseq (3::Int) True ==> True
-- myseq (undefined::Int) True
-- ==> *** Exception: Prelude.undefined
-- myseq [1,2] 'z' ==> 'z'
-- myseq [undefined] 'z' ==> 'z' -- [undefined] is in WHNF
-- myseq (1:undefined) 'z' ==> 'z' -- 1:undefined is in WHNF
-- myseq (undefined:[2,3]) 'z' ==> 'z' -- undefined:[2,3] is in WHNF
-- myseq [1..] 'z' ==> 'z'
-- myseq (undefined::[Int])
-- ==> *** Exception: Prelude.undefined
class MySeq a where
myseq :: a -> b -> b
instance MySeq Bool where
myseq = todo
instance MySeq Int where
myseq = todo
instance MySeq [a] where
myseq = todo
+71
View File
@@ -0,0 +1,71 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set10bTest where
import Mooc.Test
import Mooc.Th
import Control.Exception (evaluate, try, SomeException)
import Data.List
import Test.QuickCheck
import Test.QuickCheck.Monadic
import Set10b
main = score tests
tests = [(1,"|||",[imports, ex1_normal, ex1_undefined])
,(2,"boolLength",[imports, ex2_normal, ex2_undefined])
,(3,"validate",[imports, ex3_normal, ex3_fail])
,(4,"myseq",[imports, ex4_bool, ex4_int, ex4_list_ok, ex4_list_fail])
]
-- -- -- -- --
imports = $(importsOnly "Set10b" ["GHC.Num", "GHC.Base", "GHC.Classes", "GHC.Types", "GHC.Err",
"Mooc.Todo", "Mooc.VeryLimitedPrelude"])
ex1_normal = forAll_ $ \(a,b) ->
$(testing [|a ||| b|]) (?==(a||b))
ex1_undefined =
counterexample ("undefined ||| True") $ (errorWithoutStackTrace "You forced your left argument!"|||True) == True
ex2_normal = forAll_ $ \bs -> boolLength bs === length bs
ex2_undefined = forAll_ $ \bs ->
counterexample ("boolLength ("++show bs++"++[undefined,True])") $
shouldFail (boolLength (bs++[undefined,True]))
ex3_normal = forAll_ $ \(n::Int) ->
counterexample ("validate even "++show n) $
validate even n ?== n
ex3_fail = conjoin [counterexample "validate undefined 'c'" $ shouldFail (validate undefined 'c')
,counterexample "validate (\\x -> undefined) \"foo\"" $ shouldFail (validate (\x -> undefined) "foo")]
ex4_bool = $(withInstance "MySeq" "Bool" [|myseq :: Bool -> a -> a|]) $ \myseq ->
forAll_ $ \(i::Int) ->
conjoin [$(testing [|myseq True i|]) (?==i)
,$(testing [|myseq False i|]) (?==i)
,counterexample ("myseq (undefined::Bool) " ++ show i) $ shouldFail (myseq (undefined::Bool) i)]
ex4_int = $(withInstance "MySeq" "Int" [|myseq :: Int -> a -> a|]) $ \myseq ->
forAll_ $ \(i::Int,b::Bool) ->
conjoin [$(testing [|myseq i b|]) (?==b)
,counterexample ("myseq (undefined::Int) " ++ show b) $ shouldFail (myseq (undefined::Int) b)]
ex4_list_ok = $(withInstance1 "MySeq" "[]" [|myseq :: [Int] -> a -> a|]) $ \myseq ->
forAll_ $ \(is::[Int]) ->
forAll_ $ \(i::Int) ->
forAllBlind (choose ('a','z')) $ \c ->
$(testing [|myseq is c|]) (?==c)
.&&.
conjoin' [counterexample ("myseq (undefined:" ++ show is ++") " ++ show c) $ counterexample " should not fail" $ (myseq (undefined:is) c ?== c)
,counterexample ("myseq (" ++ show is ++ "++[undefined]) " ++ show c) $ counterexample " should not fail" $ (myseq (is++[undefined]) c ?== c)
,counterexample ("myseq (" ++ show i ++ ":undefined) " ++ show c) $ counterexample " should not fail" $ (myseq (i:undefined) c ?== c)]
ex4_list_fail = $(withInstance1 "MySeq" "[]" [|myseq :: [Int] -> a -> a|]) $ \myseq ->
forAllBlind (choose ('a','z')) $ \c ->
counterexample ("myseq (undefined::[Int]) "++show c) $ shouldFail (myseq (undefined::[Int]) c)
+143
View File
@@ -0,0 +1,143 @@
module Set11a where
import Control.Monad
import Data.List
import System.IO
import Mooc.Todo
-- Lecture 11:
-- * The IO type
-- * do-notation
--
-- Useful functions / operations:
-- * putStrLn
-- * getLine
-- * readLn
-- * replicateM
-- * readFile
-- * lines
------------------------------------------------------------------------------
-- Ex 1: define an IO operation hello that prints two lines. The
-- first line should be HELLO and the second one WORLD
hello :: IO ()
hello = todo
------------------------------------------------------------------------------
-- Ex 2: define the IO operation greet that takes a name as an
-- argument and prints a line "HELLO name".
greet :: String -> IO ()
greet name = todo
------------------------------------------------------------------------------
-- Ex 3: define the IO operation greet2 that reads a name from the
-- keyboard and then greets that name like the in the previous
-- exercise.
--
-- Try to use the greet operation in your solution.
greet2 :: IO ()
greet2 = todo
------------------------------------------------------------------------------
-- Ex 4: define the IO operation readWords n which reads n lines from
-- the user and produces them as a list, in alphabetical order.
--
-- Example in GHCi:
-- Set11> readWords 3
-- bob
-- alice
-- carl
-- ["alice","bob","carl"]
readWords :: Int -> IO [String]
readWords n = todo
------------------------------------------------------------------------------
-- Ex 5: define the IO operation readUntil f, which reads lines from
-- the user and returns them as a list. Reading is stopped when f
-- returns True for a line. (The value for which f returns True is not
-- returned.)
--
-- Example in GHCi:
-- *Set11> readUntil (=="STOP")
-- bananas
-- garlic
-- pakchoi
-- STOP
-- ["bananas","garlic","pakchoi"]
readUntil :: (String -> Bool) -> IO [String]
readUntil f = todo
------------------------------------------------------------------------------
-- Ex 6: given n, print the numbers from n to 0, one per line
countdownPrint :: Int -> IO ()
countdownPrint n = todo
------------------------------------------------------------------------------
-- Ex 7: isums n should read n numbers from the user (one per line) and
-- 1) after each number, print the running sum up to that number
-- 2) finally, produce the sum of all numbers
--
-- Example:
-- 1. run `isums 3`
-- 2. user enters '3', should print '3'
-- 3. user enters '5', should print '8' (3+5)
-- 4. user enters '1', should print '9' (3+5+1)
-- 5. produces 9
isums :: Int -> IO Int
isums n = todo
------------------------------------------------------------------------------
-- Ex 8: when is a useful function, but its first argument has type
-- Bool. Write a function that behaves similarly but the first
-- argument has type IO Bool.
whenM :: IO Bool -> IO () -> IO ()
whenM cond op = todo
------------------------------------------------------------------------------
-- Ex 9: implement the while loop. while condition operation should
-- run operation as long as condition returns True.
--
-- Examples:
-- -- prints nothing
-- while (return False) (putStrLn "IMPOSSIBLE")
--
-- -- prints YAY! as long as the user keeps answering Y
-- while ask (putStrLn "YAY!")
-- used in an example
ask :: IO Bool
ask = do putStrLn "Y/N?"
line <- getLine
return $ line == "Y"
while :: IO Bool -> IO () -> IO ()
while cond op = todo
------------------------------------------------------------------------------
-- Ex 10: given a string and an IO operation, print the string, run
-- the IO operation, print the string again, and finally return what
-- the operation returned.
--
-- Note! the operation should be run only once
--
-- Examples:
-- debug "CIAO" (return 3)
-- - prints two lines that contain CIAO
-- - returns the value 3
-- debug "BOOM" getLine
-- 1. prints "BOOM"
-- 2. reads a line from the user
-- 3. prints "BOOM"
-- 4. returns the line read from the user
debug :: String -> IO a -> IO a
debug s op = todo
+104
View File
@@ -0,0 +1,104 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set11aTest where
import Mooc.Test
import Mooc.Th
import Control.Monad
import Data.List
import Test.QuickCheck
import Set11a hiding (ask)
main = score tests
tests = precondition imports
[(1,"hello",[ex1_hello])
,(2,"greet",[ex2_greet])
,(3,"greet2",[ex3_greet2])
,(4,"readWords",[ex4_readWords])
,(5,"readUntil",[ex5_readUntil])
,(6,"countdownPrint",[ex6])
,(7,"isums",[ex7_isums])
,(8,"whenM",[ex8_whenM_True, ex8_whenM_False])
,(9,"while",[ex9_example, ex9_False])
,(10,"debug",[ex10_debug])]
-- -- -- -- --
imports = $(importsOnly "Set11a" ["Control.Monad","Data.List","Data.Foldable","Prelude","Data.OldList","System.IO"
,"GHC.Num", "GHC.Base", "GHC.Classes", "GHC.Show", "GHC.Types", "GHC.Err"
,"Mooc.Todo"])
ex1_hello =
$(testing [|hello|]) . withNoInput $
checkOutput (?== "HELLO\nWORLD\n")
word = listOf1 (choose ('a','z'))
ex2_greet = forAllBlind word $ \name ->
$(testing [|greet name|]) . withNoInput $
checkOutput (?== ("HELLO "++name++"\n"))
ex3_greet2 = forAllBlind word $ \name ->
$(testing [|greet2|]) . withInput (name++"\n") $
checkOutput (?== ("HELLO "++name++"\n"))
ex4_readWords =
forAllBlind (listOf1 word) $ \words ->
$(testing [|readWords (length words - 1)|]) . withInput (unlines words) $
checkResult (?== sort (init words))
ex5_readUntil =
forAllBlind word $ \end ->
forAllBlind (listOf1 (word `suchThat` (/=end))) $ \words ->
counterexample ("readUntil (=="++show end++")") $
($ readUntil (==end)) $
withInput (unlines $ words ++ [end]) $
checkResult (?==words)
ex6 =
forAllBlind (choose (0,40)) $ \n ->
$(testing [|countdownPrint n|]) . withNoInput $
checkOutput (?== unlines (map show [n,n-1..0]))
ex7_isums =
forAllBlind (listOf1 (choose (-10,10))) $ \nums ->
$(testing [|isums (length nums)|]) . withInput (unlines $ map show nums) $
check (?==unlines (map show $ scanl1 (+) nums)) (?==sum nums)
ex8_whenM_True =
forAllBlind (choose (0::Int,10)) $ \i ->
counterexample ("with i = " ++ show i) $
$(testing' [|whenM (return True) (print i)|]) . withNoInput $
checkOutput (?== show i++"\n")
ex8_whenM_False =
forAllBlind (choose (0::Int,10)) $ \i ->
counterexample ("with i = " ++ show i) $
$(testing' [|whenM (return False) (print i)|]) . withNoInput $
checkOutput (?== "")
ask :: IO Bool
ask = do putStrLn "Y/N?"
line <- getLine
return $ line == "Y"
ex9_example =
forAllBlind (choose (0,10)) $ \i ->
$(testing' [|while ask (putStrLn "YAY!")|]) . withInput (unlines $ replicate i "Y" ++ ["N"]) $
checkOutput (?== unlines (concat (replicate i ["Y/N?","YAY!"]) ++ ["Y/N?"]))
ex9_False =
$(testing' [|while (return False) (putStrLn "IMPOSSIBLE")|]) . withNoInput $
checkOutput (?== "")
ex10_debug =
forAllBlind word $ \message ->
forAllBlind word $ \output ->
forAllBlind word $ \result ->
counterexample ("debug "++show message++" (do putStrLn "++show output++"; return "++show result++")") $
($ (debug message (putStrLn output >> return result))) . withNoInput $
check (?== unlines [message,output,message]) (?== result)
+195
View File
@@ -0,0 +1,195 @@
module Set11b where
import Control.Monad
import Data.List
import Data.IORef
import System.IO
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: Given an IORef String and a list of Strings, update the value
-- in the IORef by appending to it all the strings in the list, in
-- order.
--
-- Example:
-- *Set11b> r <- newIORef "x"
-- *Set11b> appendAll r ["foo","bar","quux"]
-- *Set11b> readIORef r
-- "xfoobarquux"
appendAll :: IORef String -> [String] -> IO ()
appendAll = todo
------------------------------------------------------------------------------
-- Ex 2: Given two IORefs, swap the values stored in them.
--
-- Example:
-- *Set11b> x <- newIORef "x"
-- *Set11b> y <- newIORef "y"
-- *Set11b> swapIORefs x y
-- *Set11b> readIORef x
-- "y"
-- *Set11b> readIORef y
-- "x"
swapIORefs :: IORef a -> IORef a -> IO ()
swapIORefs = todo
------------------------------------------------------------------------------
-- Ex 3: sometimes one bumps into IO operations that return IO
-- operations. For instance the type IO (IO Int) means an IO operation
-- that returns an IO operation that returns an Int.
--
-- Implement the function doubleCall which takes an operation op and
-- 1. runs op
-- 2. runs the operation returned by op
-- 3. returns the value returned by this operation
--
-- Examples:
-- - doubleCall (return (return 3)) is the same as return 3
--
-- - let op :: IO (IO [String])
-- op = do l <- readLn
-- return $ replicateM l getLine
-- in doubleCall op
--
-- works just like
--
-- do l <- readLn
-- replicateM l getLine
doubleCall :: IO (IO a) -> IO a
doubleCall op = todo
------------------------------------------------------------------------------
-- Ex 4: implement the analogue of function composition (the (.)
-- operator) for IO operations. That is, take an operation op1 of type
-- a -> IO b
-- an operation op2 of type
-- c -> IO a
-- and a value of type
-- c
-- and returns an operation op3 of type
-- IO b
--
-- op3 should of course
-- 1. take the value of type c and pass it to op2
-- 2. take the resulting value (of type a) and pass it to op1
-- 3. return the result (of type b)
compose :: (a -> IO b) -> (c -> IO a) -> c -> IO b
compose op1 op2 c = todo
------------------------------------------------------------------------------
-- Ex 5: Implement the operation mkCounter that produces the IO operations
-- inc :: IO () and get :: IO Int. These operations should work like this:
--
-- get returns the number of times inc has been called
--
-- In other words, a simple stateful counter. Use an IORef to store the count.
--
-- Note: this is an IO operation that produces two IO operations. Thus
-- the type of mkCounter is IO (IO (), IO Int).
--
-- This exercise is tricky. Feel free to leave it until later.
--
-- An example of how mkCounter works in GHCi:
--
-- *Set11b> (inc,get) <- mkCounter
-- *Set11b> inc
-- *Set11b> inc
-- *Set11b> get
-- 2
-- *Set11b> inc
-- *Set11b> inc
-- *Set11b> get
-- 4
mkCounter :: IO (IO (), IO Int)
mkCounter = todo
------------------------------------------------------------------------------
-- Ex 6: Reading lines from a file. The module System.IO defines
-- operations for Handles, which represent open files that can be read
-- from or written to. Here are some functions that might be useful:
--
-- * hGetLine :: Handle -> IO String
-- Reads one line from the Handle. Will fail if the Handle is at the
-- end of the file
-- * hIsEOF :: Handle -> IO String
-- Produces True if the Handle is at the end of the file.
-- * hGetContents :: Handle -> IO String
-- Reads content from Handle until the end of the file.
--
-- Implement the function hFetchLines which returns the contents of
-- the given handle as a sequence of lines.
--
-- There are multiple ways to implement this function. You can either
-- read the lines one by one, or read the whole file and then worry
-- about splitting lines. Both approaches are fine, and you can even
-- try out both!
--
-- Example:
-- *Set11b> h <- openFile "Set11b.hs" ReadMode
-- *Set11b> ls <- hFetchLines h
-- *Set11b> take 3 ls
-- ["module Set11b where","","import Control.Monad"]
hFetchLines :: Handle -> IO [String]
hFetchLines = todo
------------------------------------------------------------------------------
-- Ex 7: Given a Handle and a list of line indexes, produce the lines
-- at those indexes from the file.
--
-- Line indexing starts from 1.
--
-- Here too, there are multiple ways to implement this. You can try
-- using hFetchLines, or writing out a loop that gets lines from the
-- handle.
hSelectLines :: Handle -> [Int] -> IO [String]
hSelectLines h nums = todo
------------------------------------------------------------------------------
-- Ex 8: In this exercise we see how a program can be split into a
-- pure part that does all of the work, and a simple IO wrapper that
-- drives the pure logic.
--
-- Implement the function interact' that takes a pure function f of
-- type
-- (String, st) -> (Bool, String, st)
-- and a starting state of type st and returns an IO operation of type
-- IO st
--
-- interact' should read a line from the user, feed the line and the
-- current state to f. f then returns a boolean, a string to print and
-- a new state. The string is printed, and if the boolean is True, we
-- continue running with the new state. If the boolean is False, the
-- execution has ended and the state should be returned.
--
-- Example:
-- *Set11b> interact' counter 1
-- print
-- 1
-- inc
-- done
-- inc
-- done
-- print
-- 3
-- quit
-- bye bye
-- 3
-- *Set11b>
-- This is used in the example above. Don't change it!
counter :: (String,Integer) -> (Bool,String,Integer)
counter ("inc",n) = (True,"done",n+1)
counter ("print",n) = (True,show n,n)
counter ("quit",n) = (False,"bye bye",n)
interact' :: ((String,st) -> (Bool,String,st)) -> st -> IO st
interact' f state = todo
+145
View File
@@ -0,0 +1,145 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set11aTest where
import Mooc.Test
import Mooc.Th
import Control.Monad
import Data.List
import Data.IORef
import GHC.IO.Handle
import System.Directory
import System.IO
import Test.QuickCheck
import Test.QuickCheck.Monadic
import Set11b hiding (counter)
main = score tests
tests = [(1,"appendAll",[ex1])
,(2,"swapIORefs",[ex2])
,(3,"doubleCall",[ex3_doubleCall, ex3_doubleCall_2])
,(4,"composeIO",[ex4_composeIO_1, ex4_composeIO_2])
,(5,"mkCounter",[ex5_mkCounter])
,(6,"hFetchLines",[ex6])
,(7,"hSelectLines",[ex7_hSelectLines])
,(8,"interact'",[ex8_interact_terminates, ex8_interact_example, ex8_interact_loop])]
-- -- -- -- --
word = listOf1 (choose ('a','z'))
ex1 = forAllBlind word $ \init ->
forAllBlind (listOf word) $ \ws ->
counterexample ("appendAll ref " ++ show ws) $
counterexample (" Initial value of ref was: " ++ show init) $
monadicIO $ do ref <- run $ newIORef init
run $ appendAll ref ws
out <- run $ readIORef ref
stop_ $ counterexample " Final value in ref" $ out ?== concat (init:ws)
ex2 = forAllBlind word $ \w1 ->
forAllBlind word $ \w2 ->
counterexample "swapIORefs r1 r2" $
counterexample (" Initial value of r1: "++show w1) $
counterexample (" Initial value of r2: "++show w2) $
monadicIO $ do r1 <- run $ newIORef w1
r2 <- run $ newIORef w2
run $ swapIORefs r1 r2
o1 <- run $ readIORef r1
o2 <- run $ readIORef r2
stop_ $ conjoin [counterexample " readIORef r1" $ o1 ?== w2
,counterexample " readIORef r2" $ o2 ?== w1]
ex3_doubleCall =
forAllBlind (choose (0,20::Int)) $ \i ->
counterexample ("doubleCall (return (return "++show i++"))") $
($ doubleCall (return (return i))) . withNoInput $
check (?=="") (?==i)
ex3_doubleCall_2 =
forAllBlind word $ \w1 ->
forAllBlind word $ \w2 ->
counterexample ("doubleCall (do putStrLn "++show w1++"; return (putStrLn "++show w2++"))") $
($ doubleCall (do putStrLn w1; return (putStrLn w2))) . withNoInput $
check (?==(w1++"\n"++w2++"\n")) (?==())
ex4_composeIO_1 =
forAllBlind word $ \w ->
forAllBlind word $ \v ->
counterexample ("compose putStrLn (\\x -> do putStrLn x; getLine) " ++ show w) $
($ compose putStrLn (\x -> do putStrLn x; getLine) w) . withInput (v++"\n") $
checkOutput (?==w++"\n"++v++"\n")
ex4_composeIO_2 =
forAll_ $ \(i::Int) ->
counterexample ("compose (\\x -> return (x*2)) (\\y -> return (y+1)) " ++ show i) $
($ compose (return . (*2)) (return . (+1)) i) . withNoInput $
checkResult (?== (i+1)*2)
ex5_mkCounter = forAllBlind (choose (0,20)) $ \n ->
counterexample "(inc,get) <- mkCounter" $
counterexample (" Called inc "++show n++" times, then called get") $
monadicIO $ do m <- run $ do (i,g) <- mkCounter
replicateM_ n i
g
stop_ $ m ?== n
ex6 = forAllBlind (listOf1 word) $ \lines ->
counterexample ("Contents of handle h:\n"++unlines lines) $
counterexample "hFetchLines h" $
monadicIO $ do
dir <- run $ getTemporaryDirectory
(_,h) <- run $ openTempFile dir "hSelectLines.in"
run $ hPutStr h $ unlines lines
run $ hSeek h AbsoluteSeek 0
outs <- run $ hFetchLines h
stop_ $ outs ?== lines
ex7_hSelectLines =
forAllBlind (listOf1 word) $ \lines ->
forAllBlind (fmap (nub.sort) . listOf1 $ choose (1,length lines)) $ \inds ->
counterexample ("Contents of handle h:\n"++unlines lines) $
counterexample ("hSelectLines h "++show inds) $
monadicIO $ do
dir <- run $ getTemporaryDirectory
(path,h) <- run $ openTempFile dir "hSelectLines.in"
run $ hPutStr h $ unlines lines
run $ hSeek h AbsoluteSeek 0
outs <- run $ hSelectLines h inds
stop_ $ counterexample (" was: "++show outs) $
conjoin [counterexample "Length of result" $ length outs ?== length inds
,conjoin [counterexample ("result!!"++show i) $ outs!!i ?== lines!!((inds!!i)-1)
| i <- [0..length inds-1]]]
counter :: (String,Integer) -> (Bool,String,Integer)
counter ("inc",n) = (True,"done",n+1)
counter ("print",n) = (True,show n,n)
counter ("quit",n) = (False,"bye bye",n)
ex8_interact_terminates =
forAllBlind word $ \w1 ->
forAllBlind word $ \w2 ->
forAllBlind (choose (0::Int,100)) $ \state ->
counterexample ("let f (input,state) = (False,input,state) in interact' f "++show state) $
($ let f (input,state) = (False,input,state) in interact' f state) . withInput (unlines [w1,w2]) $
check (?==(w1++"\n")) (?==state)
ex8_interact_example =
$(testing' [|interact' counter 1|]) . withInput (unlines ["print","inc","inc","print","quit"]) $
check (?==unlines ["1","done","done","3","bye bye"]) (?==3)
ex8_interact_loop =
forAllBlind (choose (0::Int,100)) $ \state ->
forAllBlind (choose (0::Int,5)) $ \steps ->
forAllBlind word $ \w ->
forAllBlind word $ \end ->
let input = unlines $ replicate steps w ++ [end]
output = unlines $ map show [state..state+steps]
in counterexample ("let f (input,state) = (input=="++show w++",show state,state+1) in interact' f "++show state) $
($ let f (input,state) = (input==w,show state,state+1) in interact' f state) . withInput input $
check (?==output) (?==state+steps+1)
+212
View File
@@ -0,0 +1,212 @@
module Set12 where
import Data.Functor
import Data.Foldable
import Data.List
import Data.Monoid
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: Implement the function incrementAll that takes a functor
-- value containing numbers and increments each number inside by one.
--
-- Examples:
-- incrementAll [1,2,3] ==> [2,3,4]
-- incrementAll (Just 3.0) ==> Just 4.0
incrementAll :: (Functor f, Num n) => f n -> f n
incrementAll x = todo
------------------------------------------------------------------------------
-- Ex 2: Sometimes one wants to fmap multiple levels deep. Implement
-- the functions fmap2 and fmap3 that map over nested functors.
--
-- Examples:
-- fmap2 on [[Int]]:
-- fmap2 negate [[1,2],[3]]
-- ==> [[-1,-2],[-3]]
-- fmap2 on [Maybe String]:
-- fmap2 head [Just "abcd",Nothing,Just "efgh"]
-- ==> [Just 'a',Nothing,Just 'e']
-- fmap3 on [[[Int]]]:
-- fmap3 negate [[[1,2],[3]],[[4],[5,6]]]
-- ==> [[[-1,-2],[-3]],[[-4],[-5,-6]]]
-- fmap3 on Maybe [Maybe Bool]
-- fmap3 not (Just [Just False, Nothing])
-- ==> Just [Just True,Nothing]
fmap2 :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
fmap2 = todo
fmap3 :: (Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))
fmap3 = todo
------------------------------------------------------------------------------
-- Ex 3: below you'll find a type Result that works a bit like Maybe,
-- but there are two different types of "Nothings": one with and one
-- without an error description.
--
-- Implement the instance Functor Result
data Result a = MkResult a | NoResult | Failure String
deriving Show
instance Functor Result where
fmap f result = todo
------------------------------------------------------------------------------
-- Ex 4: Here's a reimplementation of the Haskell list type. You might
-- remember it from Set6. Implement the instance Functor List.
--
-- Example:
-- fmap (+2) (LNode 0 (LNode 1 (LNode 2 Empty)))
-- ==> LNode 2 (LNode 3 (LNode 4 Empty))
data List a = Empty | LNode a (List a)
deriving Show
instance Functor List where
------------------------------------------------------------------------------
-- Ex 5: Here's another list type. This type every node contains two
-- values, so it's a type for a list of pairs. Implement the instance
-- Functor TwoList.
--
-- Example:
-- fmap (+2) (TwoNode 0 1 (TwoNode 2 3 TwoEmpty))
-- ==> TwoNode 2 3 (TwoNode 4 5 TwoEmpty)
data TwoList a = TwoEmpty | TwoNode a a (TwoList a)
deriving Show
instance Functor TwoList where
------------------------------------------------------------------------------
-- Ex 6: Count all occurrences of a given element inside a Foldable.
--
-- Hint: you might find some useful functions from Data.Foldable.
-- Check the docs! Or then you can just implement count directly.
--
-- Examples:
-- count True [True,False,True] ==> 2
-- count 'c' (Just 'c') ==> 1
count :: (Eq a, Foldable f) => a -> f a -> Int
count = todo
------------------------------------------------------------------------------
-- Ex 7: Return all elements that are in two Foldables, as a list.
--
-- Examples:
-- inBoth "abcd" "fobar" ==> "ab"
-- inBoth [1,2] (Just 2) ==> [2]
-- inBoth Nothing [3] ==> []
inBoth :: (Foldable f, Foldable g, Eq a) => f a -> g a -> [a]
inBoth = todo
------------------------------------------------------------------------------
-- Ex 8: Implement the instance Foldable List.
--
-- Remember what the minimal complete definitions for Foldable were:
-- you should only need to implement one function.
--
-- After defining the instance, you'll be able to compute:
-- sum (LNode 1 (LNode 2 (LNode 3 Empty))) ==> 6
-- length (LNode 1 (LNode 2 (LNode 3 Empty))) ==> 3
instance Foldable List where
------------------------------------------------------------------------------
-- Ex 9: Implement the instance Foldable TwoList.
--
-- After defining the instance, you'll be able to compute:
-- sum (TwoNode 0 1 (TwoNode 2 3 TwoEmpty)) ==> 6
-- length (TwoNode 0 1 (TwoNode 2 3 TwoEmpty)) ==> 4
instance Foldable TwoList where
------------------------------------------------------------------------------
-- Ex 10: (Tricky!) Fun a is a type that wraps a function Int -> a.
-- Implement a Functor instance for it.
--
-- Figuring out what the Functor instance should do is most of the
-- puzzle.
data Fun a = Fun (Int -> a)
runFun :: Fun a -> Int -> a
runFun (Fun f) x = f x
instance Functor Fun where
------------------------------------------------------------------------------
-- Ex 11: (Tricky!) You'll find the binary tree type from Set 5b
-- below. We'll implement a `Foldable` instance for it!
--
-- Implementing `foldr` directly for the Tree type is complicated.
-- However, there is another method in Foldable we can define instead:
--
-- foldMap :: Monoid m => (a -> m) -> Tree a -> m
--
-- There's a default implementation for `foldr` in Foldable that uses
-- `foldMap`.
--
-- Instead of implementing `foldMap` directly, we can build it with
-- these functions:
--
-- fmap :: (a -> m) -> Tree a -> Tree m
-- sumTree :: Monoid m => Tree m -> m
--
-- So your task is to define a `Functor` instance and the `sumTree`
-- function.
--
-- Examples:
-- using the [] Monoid with the (++) operation:
-- sumTree Leaf :: [a]
-- ==> []
-- sumTree (Node [3,4,5] (Node [1,2] Leaf Leaf) (Node [6] Leaf Leaf))
-- ==> [1,2,3,4,5,6]
-- using the Sum Monoid
-- sumTree Leaf :: Sum Int
-- ==> Sum 0
-- sumTree (Node (Sum 3) (Node (Sum 2) Leaf Leaf) (Node (Sum 1) Leaf Leaf))
-- ==> Sum 6
--
-- Once you're done, foldr should operate like this:
-- foldr (:) [] Leaf ==> []
-- foldr (:) [] (Node 2 (Node 1 Leaf Leaf) (Node 3 Leaf Leaf)) ==> [1,2,3]
--
-- foldr (:) [] (Node 4 (Node 2 (Node 1 Leaf Leaf)
-- (Node 3 Leaf Leaf))
-- (Node 5 Leaf
-- (Node 6 Leaf Leaf)))
-- ==> [1,2,3,4,5,6]
--
-- The last example more visually:
--
-- .4.
-- / \
-- 2 5 ====> 1 2 3 4 5 6
-- / \ \
-- 1 3 6
data Tree a = Leaf | Node a (Tree a) (Tree a)
deriving Show
instance Functor Tree where
fmap = todo
sumTree :: Monoid m => Tree m -> m
sumTree = todo
instance Foldable Tree where
foldMap f t = sumTree (fmap f t)
------------------------------------------------------------------------------
-- Bonus! If you enjoyed the two last exercises (not everybody will),
-- you'll like the `loeb` function:
--
-- https://github.com/quchen/articles/blob/master/loeb-moeb.md
+226
View File
@@ -0,0 +1,226 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
module Set12Test where
import Mooc.Test
import Mooc.Th
import Data.List
import Data.Monoid
import Test.QuickCheck hiding (Result,Fun,Failure)
import Set12
main = score tests
tests = [(1,"incrementAll",[ex1_list, ex1_just, ex1_nothing])
,(2,"fmap23",[ex2_fmap2_examples, ex2_fmap3_examples])
,(3,"Functor Result",[ex3_num, ex3_empties])
,(4,"Functor List",[ex4_num, ex4_bool])
,(5,"Functor TwoList",[ex5_num, ex5_bool])
,(6,"count",[ex6_list, ex6_maybe])
,(7,"inBoth",[ex7_list, ex7_maybe])
,(8,"Foldable List",[ex8_bool, ex8_num])
,(9,"Foldable TwoList",[ex9_bool, ex9_num])
,(10,"Fun",[ex10_1, ex10_2])
,(11,"Foldable Tree",[ex11_fmap_even, ex11_fmap_plus, ex11_sumTree_int, ex11_sumTree_list])]
-- -- -- -- -- --
ex1_list =
forAll_ $ \(xs::[Int]) ->
$(testing [|incrementAll xs|]) (?== map (+1) xs)
ex1_just =
forAll_ $ \(i::Int) ->
$(testing [|incrementAll (Just i)|]) (?== Just (i+1))
ex1_nothing = $(testing [|incrementAll (Nothing::Maybe Int)|]) (?== Nothing)
ex2_fmap2_examples =
conjoin [$(testing' [|fmap2 negate [[1,2],[3]]|]) (?==[[-1,-2],[-3]])
,$(testing' [|fmap2 head [Just "abcd",Nothing,Just "efgh"]|]) (?==[Just 'a',Nothing,Just 'e'])]
ex2_fmap3_examples =
conjoin [$(testing' [|fmap3 negate [[[1,2],[3]],[[4],[5,6]]]|]) (?==[[[-1,-2],[-3]],[[-4],[-5,-6]]])
,$(testing' [|fmap3 not (Just [Just False, Nothing])|]) (?==Just [Just True,Nothing])]
deriving instance Eq a => Eq (Result a)
ex3_num =
forAll_ $ \(k::Int) ->
counterexample ("fmap (+1) (MkResult "++show k++")") $
fmap (+(1::Int)) (MkResult k) ?== MkResult (k+1)
ex3_empties =
$(testing' [|fmap not NoResult|]) (?== NoResult)
.&.
$(testing' [|fmap not (Failure "oh no.")|]) (?== Failure "oh no.")
.&.
$(testing' [|fmap not (Failure "Mein Gott!")|]) (?== Failure "Mein Gott!")
deriving instance Eq a => Eq (List a)
toList = foldr LNode Empty
ex4_num =
forAll_ $ \(xs::[Int]) ->
let l = toList xs
in counterexample ("fmap (+1) ("++show l++")") $
fmap (+1) l ?== toList (map (+1) xs)
ex4_bool =
forAll_ $ \(bs::[Bool]) ->
let l = toList bs in
counterexample ("fmap not ("++show l++")") $
fmap not l ?== toList (map not bs)
deriving instance Eq a => Eq (TwoList a)
toTwoList :: [a] -> TwoList a
toTwoList [] = TwoEmpty
toTwoList (x:y:xs) = TwoNode x y (toTwoList xs)
ex5_num =
forAll_ $ \(xs::[Int]) ->
even (length xs) ==>
let l = toTwoList xs
in counterexample ("fmap (+1) ("++show l++")") $
fmap (+1) l ?== toTwoList (map (+1) xs)
ex5_bool =
forAll_ $ \(bs::[Bool]) ->
even (length bs) ==>
let l = toTwoList bs in
counterexample ("fmap not ("++show l++")") $
fmap not l ?== toTwoList (map not bs)
ex6_list =
forAll_ $ \(bs::[Bool]) ->
forAll_ $ \b ->
$(testing [|count b bs|]) (?==length (filter (==b) bs))
ex6_maybe =
forAllBlind (choose ('a','z')) $ \c ->
forAllBlind (choose ('a','z') `suchThat` (/=c)) $ \d ->
conjoin [$(testing [|count c n|]) (?==0)
,$(testing [|count c (Just c)|]) (?==1)
,$(testing [|count d (Just c)|]) (?==0)]
where n = Nothing :: Maybe Char
ex7_list =
forAll_ $ \(is::[Int]) ->
forAll_ $ \(js::[Int]) ->
$(testing [|inBoth (nub is) (nub js)|]) (?==intersect (nub is) (nub js))
ex7_maybe =
forAll_ $ \(i::Int) ->
forAll_ $ \j ->
conjoin [$(testing [|inBoth (Just i) (Just j)|]) (?==if i==j then [i] else [])
,$(testing [|inBoth (Just i) (Just i)|]) (?==[i])
,$(testing [|inBoth (Just i) n|]) (?==[])]
where n = Nothing :: Maybe Int
ex8_bool =
forAll_ $ \(xs::[Bool]) ->
let l = toList xs
in counterexample ("foldr (:) [] ("++show l++")") $
foldr (:) [] l ?== xs
ex8_num =
forAll_ $ \(NonEmpty (is::[Int])) ->
let l = toList is
in $(testing [|minimum l|]) (?==minimum is)
ex9_bool =
forAll_ $ \(xs::[Bool]) ->
even (length xs) ==>
let l = toTwoList xs
in counterexample ("foldr (:) [] ("++show l++")") $
foldr (:) [] l ?== xs
ex9_num =
forAll_ $ \(NonEmpty (is::[Int])) ->
even (length is) ==>
let l = toTwoList is
in $(testing [|minimum l|]) (?==minimum is)
ex10_1 =
forAll_ $ \(i::Int) ->
counterexample ("runFun (fmap not (Fun even)) "++show i) $
runFun (fmap not (Fun even)) i ?== odd i
ex10_2 =
forAll_ $ \(i::Int) ->
counterexample ("runFun (fmap (*2) (Fun (\\i -> i))) "++show i) $
runFun (fmap (*2) (Fun id)) i ?== 2*i
deriving instance Eq a => Eq (Tree a)
ex11_fmap_even = conjoin
[$(testing' [|fmap even Leaf|]) (?==Leaf)
,$(testing' [|fmap even (Node 3 Leaf Leaf)|]) (?==Node False Leaf Leaf)
,$(testing' [|fmap even (Node 2 Leaf Leaf)|]) (?==Node True Leaf Leaf)
,$(testing' [|fmap even (Node 2 (Node 3 Leaf Leaf) Leaf)|]) (?==Node True (Node False Leaf Leaf) Leaf)
,$(testing' [|fmap even (Node 2 (Node 3 Leaf Leaf) (Node 4 Leaf Leaf))|]) (?==Node True (Node False Leaf Leaf) (Node True Leaf Leaf))]
trees :: Int -> Gen (Tree Int, Tree Int)
trees 0 = return (Leaf,Leaf)
trees n = do
i <- choose (0,10)
let j = i+2
nleft <- choose (0,n-1)
nright <- choose (0,n-1)
(iLeft,jLeft) <- trees nleft
(iRight,jRight) <- trees nright
return (Node i iLeft iRight, Node j jLeft jRight)
m_fmap n = forAllBlind (trees n) $ \(from,to) ->
counterexample ("fmap (+2) ("++show from++")") $
fmap (+2) from ?== to
ex11_fmap_plus = conjoin [m_fmap 0
,m_fmap 1
,m_fmap 2
,m_fmap 3
,m_fmap 4]
treeAndSum 0 = return (0,Leaf)
treeAndSum n = do
(lsum,l) <- treeAndSum (n-1)
(rsum,r) <- treeAndSum (n-1)
val <- choose (0,10::Int)
return (val+rsum+lsum, Node (Sum val) l r)
m_treeSum_Sum n = forAllBlind (treeAndSum n) $ \(s,t) ->
$(testing [|sumTree t|]) (?==Sum s)
ex11_sumTree_int = conjoin [m_treeSum_Sum 0
,m_treeSum_Sum 1
,m_treeSum_Sum 2
,m_treeSum_Sum 3]
split :: [a] -> Gen ([a],[a])
split xs = do
i <- choose (0,length xs-1)
return $ (take i xs, drop i xs)
listToTree 0 xs = return (Node xs Leaf Leaf)
listToTree n xs = frequency
[(1,return (Node xs Leaf Leaf))
,(4,do
(left,rest) <- split xs
(me,right) <- split rest
l <- listToTree (n-1) left
r <- listToTree (n-1) right
return $ Node me l r)]
m_sumTree_list n = forAll_ $ \(is::[Int]) ->
forAllBlind (listToTree n is) $ \tree ->
$(testing [|sumTree tree|]) (?==is)
ex11_sumTree_list = conjoin [m_sumTree_list 0
,m_sumTree_list 1
,m_sumTree_list 2
,m_sumTree_list 3]
+267
View File
@@ -0,0 +1,267 @@
module Set13a where
import Mooc.Todo
import Control.Monad
import Control.Monad.State
import Data.Char
import Data.List
import qualified Data.Map as Map
import Examples.Bank
------------------------------------------------------------------------------
-- Ex 1: Your task is to help implement the function readName that
-- given a string like "Forename Surname" produces the pair
-- ("Forname", "Surname"). readName should fail (return Nothing) in
-- the following cases:
--
-- 1. the input string doesn't contain a space
-- 2. one of the names contains numbers
-- 3. one of the names doesn't start with a capital letter
--
-- The function readNames has already been implemented using the ?>
-- operator from the course material. You need to define the helper
-- functions split, checkNumber and checkCapitals so that readNames
-- works correctly.
(?>) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing ?> _ = Nothing -- In case of failure, propagate failure
Just x ?> f = f x -- In case of sucess, run the next computation
-- DO NOT touch this definition!
readNames :: String -> Maybe (String,String)
readNames s =
split s
?>
checkNumber
?>
checkCapitals
-- split should split a string into two words. If the input doesn't
-- contain a space, Nothing should be returned
--
-- (NB! There are obviously other corner cases like the inputs " " and
-- "a b c", but you don't need to worry about those here)
split :: String -> Maybe (String,String)
split = todo
-- checkNumber should take a pair of two strings and return them
-- unchanged if they don't contain numbers. Otherwise Nothing is
-- returned.
checkNumber :: (String, String) -> Maybe (String, String)
checkNumber = todo
-- checkCapitals should take a pair of two strings and return them
-- unchanged if both start with a capital letter. Otherwise Nothing is
-- returned.
checkCapitals :: (String, String) -> Maybe (String, String)
checkCapitals (for,sur) = todo
------------------------------------------------------------------------------
-- Ex 2: Given a list of players and their scores (as [(String,Int)]),
-- and two player names, return the name of the player who has more
-- points (wrapped in a Just), or Nothing if either of the players
-- doesn't exist.
--
-- In the case of a draw, prefer the first player.
--
-- Use the function
-- lookup :: Eq a => a -> [(a, b)] -> Maybe b
-- and either do-notation (easier) or ?> chaining (trickier!)
--
-- Examples:
-- winner [("ender",13),("orson",6),("scott",5)] "ender" "orson"
-- ==> Just "ender"
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "ender"
-- ==> Just "ender"
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "scott"
-- ==> Just "orson"
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "ridley"
-- ==> Nothing
-- winner [("a",1),("b",1)] "a" "b"
-- ==> Just "a"
winner :: [(String,Int)] -> String -> String -> Maybe String
winner scores player1 player2 = todo
------------------------------------------------------------------------------
-- Ex 3: given a list of indices and a list of values, return the sum
-- of the values in the given indices. You should fail if any of the
-- indices is too large or too small.
--
-- Use the Maybe monad, i.e. the >>= operator or do-notation.
--
-- Hint! implement a function safeIndex :: [a] -> Int -> Maybe a
--
-- Examples:
-- selectSum [0..10] [4,6,9]
-- Just 19
-- selectSum [0..10] [4,6,9,20]
-- Nothing
selectSum :: Num a => [a] -> [Int] -> Maybe a
selectSum xs is = todo
------------------------------------------------------------------------------
-- Ex 4: Here is the Logger monad from the course material. Implement
-- the operation countAndLog which produces the number of elements
-- from the given list that fulfil the given predicate. Additionally,
-- countAndLog should log all elements that fulfil the predicate
-- (using show to turn them into strings).
--
-- Examples:
-- countAndLog even [0,1,2,3,4,5]
-- ==> Logger ["0","2","4"] 3
data Logger a = Logger [String] a
deriving (Show, Eq)
msg :: String -> Logger ()
msg s = Logger [s] ()
instance Functor Logger where
fmap f (Logger l a) = Logger l (f a)
instance Monad Logger where
return x = Logger [] x
Logger la a >>= f = Logger (la++lb) b
where Logger lb b = f a
-- This is an Applicative instance that works for any monad, you
-- can just ignore it for now. We'll get back to Applicative later.
instance Applicative Logger where
pure = return
(<*>) = ap
countAndLog :: Show a => (a -> Bool) -> [a] -> Logger Int
countAndLog = todo
------------------------------------------------------------------------------
-- Ex 5: You can find the Bank and BankOp code from the course
-- material in the module Examples.Bank (file
-- exercises/Examples/Bank.hs), which has been imported into this
-- namespace.
--
-- Implement a BankOp balance that produces the balance of the given
-- account. Produce 0 if the account does not exist. The balance
-- operation shouldn't change the state of the Bank. The functions
-- from Data.Map are available under the prefix Map.
exampleBank :: Bank
exampleBank = (Bank (Map.fromList [("harry",10),("cedric",7),("ginny",1)]))
balance :: String -> BankOp Int
balance accountName = todo
------------------------------------------------------------------------------
-- Ex 6: Using the operations balance, withdrawOp and depositOp, and
-- chaining (+>), implement the BankOp rob, which transfers all the
-- money from one account to another account.
--
-- Examples:
-- runBankOp (balance "harry") exampleBank
-- ==> (10,Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
-- runBankOp (balance "sean") exampleBank
-- ==> (0,Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
-- runBankOp (rob "cedric" "ginny") exampleBank
-- ==> ((),Bank (fromList [("cedric",0),("ginny",8),("harry",10)]))
-- runBankOp (rob "sean" "ginny") exampleBank
-- ==> ((),Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
rob :: String -> String -> BankOp ()
rob from to = todo
------------------------------------------------------------------------------
-- Ex 7: using the State monad, write the operation update that first
-- multiplies the state by 2 and then adds one to it. The state has
-- type Int.
--
-- Example:
-- runState update 3
-- ==> ((),7)
update :: State Int ()
update = todo
------------------------------------------------------------------------------
-- Ex 8: Checking that parentheses are balanced with the State monad.
--
-- Do this by implementing the function paren, which updates the state
-- based on a single character. A '(' should increase the state, and a
-- ')' should decrease the state. If the state goes to -1 (there are
-- more closing than opening parentheses), it should stay there to
-- indicate that a parenthesis error was encountered.
--
-- After you've implemented paren, the given definition of parensMatch
-- should work.
--
-- Examples:
-- runState (paren '(') 3 ==> (4,())
-- runState (paren ')') 3 ==> (2,())
-- runState (paren ')') 0 ==> (-1,())
-- runState (paren ')') (-1) ==> (-1,())
-- runState (paren '(') (-1) ==> (-1,())
-- parensMatch "()" ==> True
-- parensMatch "(" ==> False
-- parensMatch "())" ==> False
-- parensMatch "(()(()()))" ==> True
-- parensMatch "(()((()))" ==> False
-- parensMatch "(()))(" ==> False
paren :: Char -> State Int ()
paren = todo
parensMatch :: String -> Bool
parensMatch s = count == 0
where (_,count) = runState (mapM_ paren s) 0
------------------------------------------------------------------------------
-- Ex 9: using a state of type [(a,Int)] we can keep track of the
-- numbers of occurrences of elements of type a. For instance
-- [('a',1),('x',3)] means that we've seen one 'a' and three 'x's.
--
-- Implement a State monad operation count that registers the
-- occurrence of the given value.
--
-- That is, the operation `count x` should fetch the pair `(x,n)` from
-- the state, and replace it with the pair `(x,n+1)`. If no such pair
-- is found, the operation should add `(x,1)` to the state.
--
-- Examples:
-- runState (count True) []
-- ==> ((),[(True,1)])
-- runState (count 7) []
-- ==> ((),[(7,1)])
-- runState (count 'a') [('a',1),('b',3)]
-- ==> ((),[('a',2),('b',3)])
-- runState (count 'a' >> count 'b' >> count 'a') []
-- ==> ((),[('a',2),('b',1)])
--
-- PS. The order of the list of pairs doesn't matter
count :: Eq a => a -> State [(a,Int)] ()
count x = return ()
------------------------------------------------------------------------------
-- Ex 10: Implement the operation occurrences, which
-- 1. runs the count operation on each element in the input list
-- 2. finally produces the number of different items stored in the
-- state
--
-- In other words, use the state monad to count how many unique values
-- occur in a list.
--
-- Examples:
-- runState (occurrences [True,True,True,False,False]) []
-- ==> (2,[(True,3),(False,2)])
-- runState (occurrences [5,5,6,6,5,6,7]) []
-- ==> (3,[(5,3),(6,3),(7,1)])
-- runState (occurrences [True,False]) [(True,1)]
-- ==> (2,[(True,2),(False,1)])
-- runState (occurrences [4,7]) [(2,1),(3,1)]
-- ==> (4,[(2,1),(3,1),(4,1),(7,1)])
occurrences :: (Eq a) => [a] -> State [(a,Int)] Int
occurrences xs = todo
+229
View File
@@ -0,0 +1,229 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
module Set13aTest where
import Mooc.Test
import Mooc.Th
import Control.Monad.State
import Data.Char
import Data.List
import qualified Data.Map as Map
import Test.QuickCheck
import Examples.Bank
import Set13a
main = score tests
tests = [(1,"readNames",[ex1_ok, ex1_fail])
,(2,"winner",[ex2_small, ex2_big, ex2_fail])
,(3,"selectSum",[ex3_ok, ex3_fail])
,(4,"countAndLog",[ex4])
,(5,"balance",[ex5_balance_examples, ex5_balance_ok, ex5_balance_nok])
,(6,"rob",[ex6_rob_examples, ex6_rob])
,(7,"State update",[ex7])
,(8,"parensMatch",[ex8_paren, ex8_parensMatch])
,(9,"State count",[ex9])
,(10,"State occurrences",[ex10_1, ex10_2])
]
-- -- -- -- -- -- --
word = do fst <- choose ('A','Z')
rest <- listOf (choose ('a','z'))
return $ fst:rest
bad = do a <- choose ('A','Z')
b <- word
c <- elements "0123456789"
d <- word
return $ a:b++c:d
ex1_ok =
forAllBlind word $ \for ->
forAllBlind word $ \sur ->
let str = for++" "++sur
in $(testing [|readNames str|])
(?==Just (for,sur))
m_ex1_fail s =
$(testing [|readNames s|]) (?== Nothing)
ex1_fail =
forAllBlind word $ \for ->
forAllBlind word $ \sur ->
forAllBlind bad $ \b ->
conjoin [m_ex1_fail (for ++ sur),
m_ex1_fail (map toLower for ++ " " ++ sur),
m_ex1_fail (for ++ " " ++ map toLower sur),
m_ex1_fail (for ++ b ++ " " ++ sur),
m_ex1_fail (for ++ " " ++ sur ++ b)]
ex2_small =
forAllBlind word $ \p1 ->
forAllBlind (word `suchThat` (/=p1)) $ \p2 ->
forAllBlind (choose (1,20)) $ \s1 ->
forAllBlind (choose (0,s1)) $ \s2 ->
forAllBlind (shuffle [(p1,s1),(p2,s2)]) $ \inp ->
conjoin [$(testing [|winner inp p1 p2|]) (?==Just p1)
,s2 < s1 ==> $(testing [|winner inp p2 p1|]) (?==Just p1)]
ex2_big =
forAllBlind word $ \w ->
forAllBlind (choose (10,100)) $ \s ->
forAllBlind (nub <$> listOf1 (word`suchThat`(/=w))) $ \names ->
forAllBlind (vectorOf (length names) (choose (0,s-1))) $ \scores ->
forAllBlind (elements names) $ \other ->
forAllBlind (shuffle ((w,s):zip names scores)) $ \inp ->
conjoin [$(testing [|winner inp other w|]) (?==Just w)
,$(testing [|winner inp w other|]) (?==Just w)]
ex2_fail =
forAllBlind (nub <$> listOf1 word) $ \names ->
forAllBlind (vectorOf (length names) (choose (0,100))) $ \scores ->
forAllBlind (elements names) $ \ok ->
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok1 ->
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok2 ->
let inp = zip names scores
in conjoin $[$(testing [|winner inp ok nok1|]) (?==Nothing)
,$(testing [|winner inp nok1 ok|]) (?==Nothing)
,$(testing [|winner inp nok1 nok2|]) (?==Nothing)]
ex3_ok = forAll_ $ \(as::[Int]) ->
forAllBlind (shuffle (zip [0..] as)) $ \pairs ->
forAllShrink_ (sublistOf pairs) $ \selected ->
$(testing [|selectSum as (map fst selected)|]) (?==Just (sum $ map snd selected))
ex3_fail = property $ do
as <- arbitrary :: Gen [Int]
is <- listOf (choose (0,length as - 1))
b <- elements [-1,length as]
inp <- shuffle (b:is)
return $ $(testing [|selectSum as inp|]) (?==Nothing)
ex4 = property $ do
i <- choose (0::Int,10)
is <- listOf (choose (0,10) `suchThat` (/=i))
n <- choose (0,5)
input <- shuffle (replicate n i ++ is)
return $ counterexample ("countAndLog (=="++show i++") "++show input) $
countAndLog (==i) input ?== Logger (replicate n (show i)) n
ex5_balance_examples =
conjoin [$(testing' [|runBankOp (balance "harry") exampleBank|]) (?==(10,exampleBank))
,$(testing' [|runBankOp (balance "sean") exampleBank|]) (?==(0,exampleBank))]
bank = do
names <- nub <$> listOf1 word
bals <- vectorOf (length names) (choose (0,100))
return $ Map.fromList (zip names bals)
ex5_balance_ok = forAllBlind bank $ \b ->
forAllBlind (elements (Map.keys b)) $ \account ->
let bank = Bank b
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
out?==(b Map.! account, bank)
ex5_balance_nok = forAllBlind bank $ \b ->
forAllBlind (word `suchThat` (not.flip elem (Map.keys b))) $ \account ->
let bank = Bank b
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
out?==(0,bank)
ex6_rob_examples =
conjoin [$(testing' [|runBankOp (rob "cedric" "ginny") exampleBank|])
(?==((),Bank (Map.fromList [("cedric",0),("ginny",8),("harry",10)])))
,$(testing' [|runBankOp (rob "sean" "ginny") exampleBank|])
(?==((),Bank (Map.fromList [("cedric",7),("ginny",1),("harry",10)])))]
ex6_rob = property $ do
from <- word
to <- word `suchThat` (/=from)
others <- listOf (word `suchThat` (not.flip elem [from,to]))
balf <- choose (0,100)
balt <- choose (0,100)
bals <- vectorOf (length others) (choose (0,100))
let run from to bank exp = $(testing' [|runBankOp (rob from to) bank|]) $ \out ->
counterexample (" with bank = " ++ show bank++"\n from = "++show from++"\n to = "++show to) $
out ?== ((),exp)
return $ conjoin [run from to
(Bank . Map.fromList $ (from,balf):(to,balt):zip others bals)
(Bank . Map.fromList $ (from,0):(to,balf+balt):zip others bals)
,run from to
(Bank . Map.fromList $ (to,balt):zip others bals)
(Bank . Map.fromList $ (to,balt):zip others bals)]
ex7 = forAll_ $ \i ->
counterexample ("runState update "++show i) $
runState update i ?== ((),2*i+1)
ex8_paren =
forAll_ $ \(NonNegative i) ->
conjoin [counterexample ("runState (paren '(') "++show i) $
runState (paren '(') i ?== ((),i+1)
,counterexample ("runState (paren ')') "++show i) $
runState (paren ')') i ?== ((),i-1)
,$(testing' [|runState (paren '(') (-1)|]) (?==((),-1))
,$(testing' [|runState (paren ')') (-1)|]) (?==((),-1))]
genMatch = frequency [(3,return "()"),
(1,(\x -> "("++x++")") <$> genMatch),
(1,(++) <$> genMatch <*> genMatch)]
flop ')' = '('
flop '(' = ')'
breakMatch s = do i <- choose (0,length s - 1)
let (pre,x:suf) = splitAt i s
elements [pre++suf, pre++flop x:suf]
filterMatch s = do x <- elements "()"
n <- choose (1,length s)
return $ s \\ replicate n x
ex8_parensMatch =
forAllBlind genMatch $ \match ->
conjoin [$(testing [|parensMatch match|]) (?==True)
,forAllBlind (breakMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)
,forAllBlind (filterMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)]
ex9 = property $ do
is <- fmap nub $ listOf1 (choose ('a','z') :: Gen Char)
fs <- vectorOf (length is) (choose (1,2048))
let assocs = zip is fs
x <- elements is
y <- choose ('0','z') `suchThat` \y -> not (elem y is)
let Just cx = lookup x assocs
s x = counterexample ("runState (count "++show x++") "++show assocs) . counterexample " Final state"
return $ conjoin [s y $
hasElements ((y,1):assocs) (execState (count y) assocs)
,s x $
hasElements ((x,cx+1):delete (x,cx) assocs) (execState (count x) assocs)]
ex10_1 =
forAllShrink_ (nub <$> listOf (choose ('a','z'))) $ \cs ->
forAllBlind (vectorOf (length cs) (choose (1,3))) $ \ns ->
let expanded = concat (zipWith replicate ns cs)
in forAllBlind (shuffle expanded) $ \input ->
counterexample ("runState (occurrences "++show input++") []") $
let out@(x,s) = runState (occurrences input) []
in counterexample (" Was: " ++ show out) $
conjoin [counterexample "Produced value" $ x ?== length cs
,counterexample "Final state" $ hasElements (zip cs ns) s]
ex10_2 =
forAllShrink_ (nub <$> listOf (choose (10,100))) $ \xs ->
forAllBlind (vectorOf (length xs) (choose (1,3))) $ \ns ->
forAllBlind (choose (0::Int,9)) $ \x ->
forAllBlind (choose (1,20)) $ \n0 ->
forAllBlind (choose (1,20)) $ \n ->
let state = zip xs ns++[(x,n0)]
input = replicate n x
in counterexample ("runState (occurrences "++show input++") "++show state) $
let out@(ret,s) = runState (occurrences input) state
in counterexample (" Was: " ++ show out) $
conjoin [counterexample "Produced value" $ ret ?== length xs + 1
,counterexample "Final state" $ hasElements ((x,n+n0):zip xs ns) s]
+325
View File
@@ -0,0 +1,325 @@
module Set13b where
import Mooc.Todo
import Control.Monad
import Control.Monad.State
import Data.Char
import Data.List
------------------------------------------------------------------------------
-- Ex 1: implement the function ifM, that takes three monadic
-- operations. If the first of the operations returns True, the second
-- operation should be run. Otherwise the third operation should be
-- run.
--
-- Note the polymorphic `Monad m =>` type signature. Your operation
-- should work on all monads, and thus needs to be implemented with
-- Monad operations like do and >>=. Don't try to pattern match on
-- Maybes.
--
-- Examples (test is defined below):
-- In the Maybe Monad:
-- ifM (Just True) (Just '1') (Just '2') ==> Just '1'
-- ifM (Just False) (Just '1') (Just '2') ==> Just '2'
-- ifM Nothing (Just '1') (Just '2') ==> Nothing
-- ifM (Just True) (Just '1') Nothing ==> Just '1'
-- In the State Monad (test is defined below):
-- runState (ifM get (return 'a') (return 'b')) False
-- ==> ('b',False)
-- runState (put 11 >> ifM test (return 'a') (return 'b')) 0
-- ==> ('b',11)
-- runState (put 9 >> ifM test (return 'a') (return 'b')) 0
-- ==> ('a',9)
test :: State Int Bool
test = do
x <- get
return (x<10)
ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM opBool opThen opElse = todo
------------------------------------------------------------------------------
-- Ex 2: the standard library function Control.Monad.mapM defines a
-- monadic map operation. Some examples of using it (safeDiv is defined
-- below):
--
-- mapM (safeDiv 10.0) [1.0,5.0,2.0] => Just [10.0,2.0,5.0]
-- mapM (safeDiv 10.0) [1.0,0.0,2.0] => Nothing
--
-- Your task is to implement the function mapM2 that works like mapM,
-- but there are two lists and the operation takes two arguments. More
-- concretely, running `mapM2 op xs ys` should run `op`, giving it the
-- first element of xs and the first element of ys. Then, it should
-- run `op` on the second elements of xs and ys, and so forth.
-- Finally, all the values produced by `op` are returned, in order, as
-- a list.
--
-- If the lists are of different length, you can stop processing them
-- once the shorter one ends.
--
-- Examples:
-- mapM2 safeDiv [6.0,10.0,12.0] [3.0,2.0,4.0]
-- ==> Just [2.0,5.0,3.0]
-- mapM2 safeDiv [6.0,10.0,12.0] [3.0,0.0,4.0]
-- ==> Nothing
-- mapM2 (\x y -> Just (x+y)) [1,2,3] [6,7]
-- ==> Just [7,9]
-- runState (mapM2 perhapsIncrement [True,False,True] [1,2,4]) 0
-- ==> ([(),(),()],5)
-- Do not change safeDiv or perhapsIncrement, they're used by the
-- examples & test outputs.
safeDiv :: Double -> Double -> Maybe Double
safeDiv x 0.0 = Nothing
safeDiv x y = Just (x/y)
perhapsIncrement :: Bool -> Int -> State Int ()
perhapsIncrement True x = modify (+x)
perhapsIncrement False _ = return ()
mapM2 :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
mapM2 op xs ys = todo
------------------------------------------------------------------------------
-- Ex 3: Finding paths.
--
-- In this exercise, you'll process mazes, described as lists like this:
maze1 :: [(String,[String])]
maze1 = [("Entry",["Pit","Corridor 1"])
,("Pit",[])
,("Corridor 1",["Entry","Dead end"])
,("Dead end",["Corridor 1"])
,("Corridor 2",["Corridor 3"])
,("Corridor 3",["Corridor 2"])]
-- This means that you can get from Entry to Pit or Corridor 1, and
-- from Corridor 1 you can get back to Entry or the Dead end, and so
-- forth. Here's a drawing of what maze1 looks like. Note how you
-- can't get out of the Pit, and Corridors 2 and 3 aren't connected to
-- the Entry.
--
-- Entry <--> Corridor 1 <--> Dead end
-- |
-- v Corridor 2 <--> Corridor 3
-- Pit
--
-- Your task is to implement the function path that checks if there is
-- a path from one location to another.
--
-- path maze1 "Entry" "Pit" ==> True
-- path maze1 "Entry" "Dead end" ==> True
-- path maze1 "Pit" "Entry" ==> False
-- path maze1 "Entry" "Corridor 2" ==> False
--
-- To implement path, we'll need some helper functions. We'll work in
-- the State monad, with a state of type [String]. This tracks which
-- places we've been to.
--
-- The operation `visit maze place1` should work like this:
-- * if place1 is in the state (i.e. we've visited it before), do nothing
-- * otherwise, add place1 to the state (it has now been visited), and:
-- * for all neighbouring places of place1, run visit
--
-- PS. You might recognize this as a Depth-First Search, but if you
-- haven't heard the term, don't worry.
--
-- Examples:
-- runState (visit maze1 "Pit") []
-- ==> ((),["Pit"])
-- runState (visit maze1 "Corridor 2") []
-- ==> ((),["Corridor 3","Corridor 2"])
-- runState (visit maze1 "Entry") []
-- ==> ((),["Dead end","Corridor 1","Pit","Entry"])
-- runState (visit maze1 "Entry") ["Corridor 1"]
-- ==> ((),["Pit","Entry","Corridor 1"])
visit :: [(String,[String])] -> String -> State [String] ()
visit maze place = todo
-- Now you should be able to implement path using visit. If you run
-- visit on a place using an empty state, you'll get a state that
-- lists all the places that are reachable from the starting place.
path :: [(String,[String])] -> String -> String -> Bool
path maze place1 place2 = todo
------------------------------------------------------------------------------
-- Ex 4: Given two lists, ks and ns, find numbers i and j from ks,
-- such that their sum i+j=n is in ns. Return all such triples
-- (i,j,n).
--
-- Use the list monad!
--
-- Examples:
-- findSum2 [1,2,3,4] [6,7]
-- ==> [(2,4,6),(3,3,6),(3,4,7),(4,2,6),(4,3,7)]
--
-- PS. The tests don't care about the order of results.
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
findSum2 ks ns = todo
------------------------------------------------------------------------------
-- Ex 5: compute all possible sums of elements from the given
-- list. Use the list monad.
--
-- Hint! a list literal like [True,False] or [x,0] can be useful when
-- combined with do-notation!
--
-- The order of the returned list does not matter and it may contain
-- duplicates.
--
-- Examples:
-- allSums []
-- ==> [0]
-- allSums [1]
-- ==> [1,0]
-- allSums [1,2,4]
-- ==> [7,3,5,1,6,2,4,0]
allSums :: [Int] -> [Int]
allSums xs = todo
------------------------------------------------------------------------------
-- Ex 6: the standard library defines the function
--
-- foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
--
-- This function behaves like foldr, but the operation used is
-- monadic. foldM f acc xs works by running f for each element in xs,
-- giving it also the result of the previous invocation of f.
--
-- Your task is to implement the functions f1 and f2 so that the
-- functions sumBounded and sumNotTwice work.
--
-- Do not change the definitions of sumBounded and sumNotTwice. The
-- tests have their own copies of the definitions anyway.
-- sumBounded computes the sum of a list. However if the sum at any
-- point during the execution goes over the given bound, Nothing is
-- returned.
--
-- Examples:
-- sumBounded 5 [1,2,1,-2,3]
-- ==> Just 5
-- sumBounded 5 [1,2,3,1,-2] -- 1+2+3=6 which results in Nothing
-- ==> Nothing
sumBounded :: Int -> [Int] -> Maybe Int
sumBounded k xs = foldM (f1 k) 0 xs
f1 :: Int -> Int -> Int -> Maybe Int
f1 k acc x = todo
-- sumNotTwice computes the sum of a list, but counts only the first
-- occurrence of each value.
--
-- Examples:
-- sumNotTwice [1,2,3] ==> 6
-- sumNotTwice [1,1,2,3,2,2,3] ==> 6
-- sumNotTwice [3,-2,3] ==> 1
-- sumNotTwice [1,2,-2,3] ==> 4
sumNotTwice :: [Int] -> Int
sumNotTwice xs = fst $ runState (foldM f2 0 xs) []
f2 :: Int -> Int -> State [Int] Int
f2 acc x = todo
------------------------------------------------------------------------------
-- Ex 7: here is the Result type from Set12. Implement a Monad Result
-- instance that behaves roughly like the Monad Maybe instance.
--
-- That is,
-- 1. MkResult behave like Just
-- 2. If part of computation produces NoResult, the whole computation
-- produces NoResult (just like Nothing)
-- 3. Similarly, if we get a Failure "reason" value, the whole
-- computation produces Failure "reason"
--
-- Examples:
-- MkResult 1 >> Failure "boom" >> MkResult 2
-- ==> Failure "boom"
-- MkResult 1 >> NoResult >> Failure "not reached"
-- ==> NoResult
-- MkResult 1 >>= (\x -> MkResult (x+1))
-- ==> MkResult 2
data Result a = MkResult a | NoResult | Failure String deriving (Show,Eq)
instance Functor Result where
-- The same Functor instance you used in Set12 works here.
fmap = todo
-- This is an Applicative instance that works for any monad, you
-- can just ignore it for now. We'll get back to Applicative later.
instance Applicative Result where
pure = return
(<*>) = ap
instance Monad Result where
-- implement return and >>=
return = todo
(>>=) = todo
------------------------------------------------------------------------------
-- Ex 8: Here is the type SL that combines the State and Logger
-- types. Implement an instance Monad SL, that behaves like the
-- combination of State and Logger. That is, state is propagated from
-- one operation to the next, and log messages are stored in the order
-- they are produced.
--
-- To simplify the type signatures, the type of the state has been set
-- to Int, instead of being a parameter like in the standard State
-- monad.
--
-- This is a tough one, probably the hardest exercise on this course!
-- You can come back to it later if you don't get it now.
--
-- You might find it easier to start with the Functor instance
--
-- Examples:
-- runSL (putSL 2 >> msgSL "hello" >> getSL) 0
-- ==> (2,2,["hello"])
-- runSL (replicateM_ 5 (modifySL (+1) >> getSL >>= \x -> msgSL ("got "++show x))) 1
-- ==> ((),6,["got 2","got 3","got 4","got 5","got 6"])
data SL a = SL (Int -> (a,Int,[String]))
-- Run an SL operation with the given starting state
runSL :: SL a -> Int -> (a,Int,[String])
runSL (SL f) state = f state
-- Write a log message
msgSL :: String -> SL ()
msgSL msg = SL (\s -> ((),s,[msg]))
-- Fetch the state
getSL :: SL Int
getSL = SL (\s -> (s,s,[]))
-- Overwrite the state
putSL :: Int -> SL ()
putSL s' = SL (\s -> ((),s',[]))
-- Modify the state
modifySL :: (Int->Int) -> SL ()
modifySL f = SL (\s -> ((),f s,[]))
instance Functor SL where
-- implement fmap
fmap = todo
-- This is an Applicative instance that works for any monad, you
-- can just ignore it for now. We'll get back to Applicative later.
instance Applicative SL where
pure = return
(<*>) = ap
instance Monad SL where
-- implement return and >>=
return = todo
(>>=) = todo
+269
View File
@@ -0,0 +1,269 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
module Set13bTest where
import Mooc.Test
import Mooc.Th
import Control.Monad.State
import qualified Data.Bits
import Data.Char
import Data.Either
import Data.Function
import Data.List
import qualified Data.Map as Map
import Test.QuickCheck hiding (Result,Failure)
import Examples.Bank
import Set13b hiding (perhapsIncrement,sumBounded,sumNotTwice)
main = score tests
tests = [(1,"ifM",[ex1_maybe, ex1_state])
,(2,"mapM2",[ex2_maybe, ex2_state])
,(3,"path",[ex3_visit_examples, ex3_visit_tree, ex3_visit_linear, ex3_visit
,ex3_path_examples, ex3_path_linear, ex3_path])
,(4,"findSum2", [ex4_simple, ex4])
,(5,"allSums", [ex5_bits])
,(6,"foldM", [ex6_sumBounded_ok, ex6_sumBounded_fail, ex6_sumNotTwice])
,(7,"Monad Result", [ex7])
,(8,"Monad SL", [ex8_fmap_1, ex8_fmap_2, ex8_1, ex8_2, ex8_stress])]
-- -- -- -- -- -- --
ex1_maybe =
forAll_ $ \(c::Char) ->
forAll_ $ \(d::Char) ->
forAll_ $ \(b::Bool) ->
let nc = Nothing :: Maybe Char
nb = Nothing :: Maybe Bool
in conjoin [$(testing [|ifM (Just b) (Just c) (Just d)|]) (?==Just (if b then c else d))
,$(testing [|ifM (Just b) (Just c) nc|]) (?==if b then Just c else Nothing)
,$(testing [|ifM (Just b) nc (Just d)|]) (?==if b then Nothing else Just d)
,$(testing [|ifM nb (Just c) (Just d)|]) (?==Nothing)]
ex1_state =
conjoin [$(testing' [|runState (ifM get (return 'a') (return 'b')) True|]) (?==('a',True))
,$(testing' [|runState (ifM get (return 'a') (return 'b')) False|]) (?==('b',False))]
ex2_maybe =
forAll_ $ \(as::[Int]) ->
forAll_ $ \(bs::[Int]) ->
let z = zipWith (-) as bs
res = if all (/=0) z then Just z else Nothing
in counterexample ("mapM2 (\\x y -> if x == y then Nothing else Just (x-y)) "++show as++" "++show bs) $
mapM2 (\x y -> if x == y then Nothing else Just (x-y)) as bs ?== res
perhapsIncrement :: Bool -> Int -> State Int ()
perhapsIncrement True x = modify (+x)
perhapsIncrement False _ = return ()
ex2_state =
forAll_ $ \(bs::[Bool]) ->
forAll_ $ \(is::[Int]) ->
counterexample ("runState (mapM2 perhapsIncrement "++show bs++" "++show is++") 0") $
runState (mapM2 perhapsIncrement bs is) 0 ?== (zipWith (\_ _ -> ()) is bs, sum $ zipWith (\b i -> if b then i else 0) bs is)
ex3_visit_examples = conjoin [$(testing' [|runState (visit maze1 "Pit") []|]) (?==((),["Pit"]))
,$(testing' [|runState (visit maze1 "Corridor 2") []|]) (?==((),["Corridor 3","Corridor 2"]))
,$(testing' [|runState (visit maze1 "Entry") []|]) (?==((),["Dead end","Corridor 1","Pit","Entry"]))
,$(testing' [|runState (visit maze1 "Entry") ["Corridor 1"]|]) (?==((),["Pit","Entry","Corridor 1"]))]
genTree 0 name = return [(name,[])]
genTree height name = do
n <- choose (1,3)
children <- nub <$> vectorOf n ((:name) <$> choose ('a','z'))
rest <- concat <$> forM children (genTree (height-1))
return $ (name,children):rest
shrinkTree xs = do pair@(x,_) <- xs
return $ map (\(n,ns) -> (n,delete x ns)) $ delete pair xs
ex3_visit_tree = forAllBlind (choose (1::Int,4)) $ \depth ->
forAllShrinkBlind (genTree depth "0") shrinkTree $ \maze ->
let root = fst (head maze)
in counterexample ("runState (visit "++show maze++" "++show root++") []") $
within timeLimit $
($ runState (visit maze root) []) . was $ \(_,state) ->
counterexample " Final state" $
hasElements (map fst maze) state
ex3_visit_linear = forAllBlind (choose (2::Int,6)) $ \n ->
forAllBlind (choose (0,n-1)) $ \start ->
forAllBlind (choose (start,n)) $ \end ->
let maze = [(show i,[show (i+1)]) | i <- [0..n-1]]++[(show n,[])]
sstart = show start
send = show end
in counterexample ("runState (visit "++show maze++" "++show sstart++") ["++show send++"]") $
within timeLimit $
($ runState (visit maze sstart) [send]) . was $ \(_,state) ->
counterexample " Final state" $
hasElements (map show [start..end]) state
genConn :: [String] -> [String] -> Gen [(String,String)]
genConn nodes [] = return []
genConn nodes todo = do
u <- elements todo
v <- elements $ nodes \\ todo
rest <- genConn nodes (delete u todo)
return $ (u,v):(v,u):rest
genGraph :: [String] -> Gen [(String,String)]
genGraph nodes = do
base <- genConn nodes (tail nodes)
ns <- vectorOf 3 (elements nodes)
return $ (ns!!0,ns!!1):(ns!!1,ns!!2):base
adj :: [(String,String)] -> [(String,[String])]
adj = map (simpl.unzip) . groupBy ((==)`on`fst) . sort . nub
where simpl (x:_,ys) = (x,ys)
ex3_visit = property $ do
n1 <- choose (1,5)
n2 <- choose (1,4)
names <- shuffle $ map show [1..n1+n2]
let (names1,names2) = splitAt n1 names
g1 <- genGraph names1
g2 <- genGraph names2
let maze = adj (g1++g2)
return $ counterexample ("runState (visit "++show maze++" "++head names1++") []") $
within timeLimit $
($ runState (visit maze (head names1)) []) . was $ \(_,state) ->
counterexample " Final state" $
hasElements names1 state
ex3_path_examples =
conjoin [$(testing' [|path maze1 "Entry" "Pit"|]) (?==True)
,$(testing' [|path maze1 "Entry" "Dead end"|]) (?==True)
,$(testing' [|path maze1 "Pit" "Entry"|]) (?==False)
,$(testing' [|path maze1 "Entry" "Corridor 2"|]) (?==False)]
ex3_path_linear = forAllBlind (choose (2::Int,6)) $ \n ->
forAllBlind (choose (0,n)) $ \start ->
forAllBlind (choose (0,n)) $ \end ->
let maze = [(show i,[show (i+1)]) | i <- [0..n-1]]++[(show n,[])]
sstart = show start
send = show end
in $(testing [|path maze sstart send|]) (?==(start<=end))
ex3_path = property $ do
n1 <- choose (1,5)
n2 <- choose (1,5)
names <- shuffle $ map show [1..n1+n2]
let (names1,names2) = splitAt n1 names
g1 <- genGraph names1
g2 <- genGraph names2
let maze = adj (g1++g2)
from <- elements names
to <- elements names
return $ $(testing [|path maze from to|]) (?==(elem from names1 == elem to names1))
ex4_simple =
conjoin [$(testing [|findSum2 [6,1] [7]|]) (hasElements [(1,6,7),(6,1,7)])
,$(testing [|findSum2 [6,1] [8]|]) (?==[])
,$(testing [|findSum2 [2,1] [4]|]) (hasElements [(2,2,4)])
,$(testing [|findSum2 [1,2,3,4] [6,7]|]) (hasElements [(2,4,6),(3,3,6),(3,4,7),(4,2,6),(4,3,7)])]
ex4 = forAllShrink_ (choose (1, 10)) $ \n ->
(n>0 ==>) $
property $ do
step <- choose (1,5)
start <- choose (1,100)
let vals = [start,start+step..start+step*(n-1)]
i1 <- choose (0,length vals-1)
--i2 <- choose (0,n)
let v1 = (vals!!i1)*2
lim1 = min i1 (length vals-1-i1)
triples1 = [(vals!!(i1-k),vals!!(i1+k),v1) | k <- [-lim1..lim1]]
return $ $(testing [|findSum2 vals [v1]|]) (hasElements triples1)
ex5_bits = forAllShrink_ (choose (1::Int,9)) $ \n ->
let vals = 0:map (\x -> 2^x) [0..n]
all = nub $ [0..2^(n+1)-1]
in conjoin [forAllBlind (elements vals) $ \del ->
del > 0 ==>
$(testing [|allSums (delete del vals)|]) (hasElementsDuplicates (filter ((==0).(Data.Bits..&.del)) all))
,$(testing [|allSums vals|]) (hasElementsDuplicates all)]
m is = maximum (scanl1 (+) is)
sumBounded :: Int -> [Int] -> Maybe Int
sumBounded k xs = foldM (f1 k) 0 xs
ex6_sumBounded_ok =
forAllShrink_ (listOf1 (choose (-10,10))) $ \is ->
forAllBlind (choose (0,3)) $ \diff ->
let k = m is + diff
in $(testing [|sumBounded k is|]) (?==Just (sum is))
ex6_sumBounded_fail =
forAllBlind (listOf1 (choose (-10,10))) $ \is ->
forAllBlind (choose (1::Int,3)) $ \diff ->
let k = m is - diff
in $(testing [|sumBounded k is|]) (?==Nothing)
sumNotTwice :: [Int] -> Int
sumNotTwice xs = fst $ runState (foldM f2 0 xs) []
ex6_sumNotTwice =
forAllShrink_ (listOf1 (choose (-5,5))) $ \is ->
$(testing [|sumNotTwice is|]) (?==sum (nub is))
ex7 =
let op :: Int -> Result Int
op i = if i>3 then Failure "big" else return (i+1)
s = "let op i = if (i>3) then Failure \"big\" else return (i+1) in "
in conjoin [counterexample' (s++" MkResult 1 >>= op") $
(MkResult 1 >>= op) ?== MkResult 2,
counterexample' (s++" MkResult 4 >>= op") $
(MkResult 4 >>= op) ?== Failure "big",
counterexample' (s++" Fail \"foo\" >>= op") $
(Failure "foo" >>= op) ?== Failure "foo",
counterexample' (s++" NoResult >>= op") $
(NoResult >>= op) ?== NoResult]
word = listOf1 (choose ('a','z'))
ex8_fmap_1 = property $
do i <- choose (0,10)
let op = fmap (+1) getSL
return $ counterexample ("runSL (fmap (+1) getSL) " ++ show i) $
runSL op i ?== (i+1,i,[])
ex8_fmap_2 = property $
do m <- word
s <- choose (0,10)
let op = fmap (const True) (msgSL m)
return $ counterexample ("runSL (fmap (const True) (msgSL "++show m++")) "++show s) $
runSL op s ?== (True,s,[m])
ex8_1 = property $
do i <- choose (0,10)
let op = putSL i >> getSL >>= \i -> msgSL (show i)
s = "putSL "++show i++" >> getSL >>= \\i -> msgSL (show i)"
return $ counterexample ("runSL ("++s++") 1") $ runSL op 1 ?== ((),i,[show i])
ex8_2 = property $
do msg <- word
msg2 <- word
i <- choose (0,10)
j <- choose (0,10)
let op = do msgSL msg
x <- getSL
msgSL (msg2++show x)
putSL (x+i)
return x
s = "op = \ndo msgSL "++show msg++"\n x <- getSL\n msgSL ("++show msg2++"++show x)\n putSL (x+"++show i++")\n return x"
return $ counterexample (s++"\n\nrunSL op "++show j) $ runSL op j ?== (j,j+i,[msg,msg2++show j])
ex8_stress =
forAll_ $ \ops ->
let m (Left i) = modifySL (+i)
m (Right s) = msgSL s
s (Left i) = "modifySL (+"++show i++")"
s (Right m) = "msgSL "++show m
op = mapM_ m ops
desc = "runSL ("++intercalate " >> " (map s ops)++") 0"
(incs,msgs) = partitionEithers ops
state = sum incs
in counterexample desc $ runSL op 0 ?== ((),state,msgs)
+216
View File
@@ -0,0 +1,216 @@
-- Welcome to the first exercise set of part 2 of the Haskell Mooc!
-- Edit this file according to the instructions, and check your
-- answers with
--
-- stack runhaskell Set9aTest.hs
--
-- You can also play around with your answers in GHCi with
--
-- stack ghci Set9a.hs
module Set9a where
import Data.List
import Data.Ord
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: Implement a function workload that takes in the number of
-- exercise a student has to finish, and another number that counts
-- the number of hours each exercise takes.
--
-- If the total number of hours needed for all exercises is over 100,
-- return "Holy moly!" if it is under 10, return "Piece of cake!".
-- Otherwise return "Ok."
workload :: Int -> Int -> String
workload nExercises hoursPerExercise = todo
------------------------------------------------------------------------------
-- Ex 2: Implement the function echo that builds a string like this:
--
-- echo "hello!" ==> "hello!, ello!, llo!, lo!, o!, !, "
-- echo "ECHO" ==> "ECHO, CHO, HO, O, "
-- echo "X" ==> "X, "
-- echo "" ==> ""
--
-- Hint: use recursion
echo :: String -> String
echo = todo
------------------------------------------------------------------------------
-- Ex 3: A country issues some banknotes. The banknotes have a serial
-- number that can be used to check if the banknote is valid. For a
-- banknote to be valid, either
-- * the third and fifth digits need to be the same
-- * or the fourth and sixth digits need to be the same
--
-- Given a list of bank note serial numbers (strings), count how many
-- are valid.
countValid :: [String] -> Int
countValid = todo
------------------------------------------------------------------------------
-- Ex 4: Find the first element that repeats two or more times _in a
-- row_ in the input list. Return a Nothing value if no element repeats.
--
-- Examples:
-- repeated [1,2,3] ==> Nothing
-- repeated [1,2,2,3,3] ==> Just 2
-- repeated [1,2,1,2,3,3] ==> Just 3
repeated :: Eq a => [a] -> Maybe a
repeated = todo
------------------------------------------------------------------------------
-- Ex 5: A laboratory has been collecting measurements. Some of the
-- measurements have failed, so the lab is using the type
-- Either String Int
-- to track the measurements. A Left value represents a failed measurement,
-- while a Right value represents a succesful one.
--
-- Compute the sum of all succesful measurements. If there are
-- succesful measurements, return the sum wrapped in a Right, but if
-- there are none, return Left "no data".
--
-- Examples:
-- sumSuccess [Right 1, Left "it was a snake!", Right 3]
-- ==> Right 4
-- sumSuccess [Left "lab blew up", Left "I was sick"]
-- ==> Left "no data"
-- sumSuccess []
-- ==> Left "no data"
sumSuccess :: [Either String Int] -> Either String Int
sumSuccess = todo
------------------------------------------------------------------------------
-- Ex 6: A combination lock can either be open or closed. The lock
-- also remembers a code. A closed lock can only be opened with the
-- right code. The code of an open lock can be changed.
--
-- Implement a datatype Lock and the functions isOpen, open, lock,
-- changeCode and the constant aLock as instructed below.
--
-- Examples:
-- isOpen aLock ==> False
-- isOpen (lock aLock) ==> False
-- isOpen (open "1234" aLock) ==> True
-- isOpen (lock (open "1234" aLock)) ==> False
-- isOpen (open "1235" aLock) ==> False
-- isOpen (lock (open "1235" aLock)) ==> False
-- isOpen (open "1234" (changeCode "0000" aLock)) ==> True
-- isOpen (open "0000" (changeCode "0000" aLock)) ==> False
-- isOpen (open "0000" (lock (changeCode "0000" (open "1234" aLock)))) ==> True
-- isOpen (open "1234" (lock (changeCode "0000" (open "1234" aLock)))) ==> False
data Lock = LockUndefined
deriving Show
-- aLock should be a locked lock with the code "1234"
aLock :: Lock
aLock = todo
-- isOpen returns True if the lock is open
isOpen :: Lock -> Bool
isOpen = todo
-- open tries to open the lock with the given code. If the code is
-- wrong, nothing happens.
open :: String -> Lock -> Lock
open = todo
-- lock closes a lock. If the lock is already closed, nothing happens.
lock :: Lock -> Lock
lock = todo
-- changeCode changes the code of an open lock. If the lock is closed,
-- nothing happens.
changeCode :: String -> Lock -> Lock
changeCode = todo
------------------------------------------------------------------------------
-- Ex 7: Here's a type Text that just wraps a String. Implement an Eq
-- instance for Text that ignores all white space (space characters
-- and line returns).
--
-- Examples
-- Text "abc" == Text "abc" ==> True
-- Text "a bc" == Text "ab c\n" ==> True
-- Text "abc" == Text "abcd" ==> False
-- Text "a bc" == Text "ab d\n" ==> False
data Text = Text String
deriving Show
------------------------------------------------------------------------------
-- Ex 8: We can represent functions or mappings as lists of pairs.
-- For example the list [("bob",13),("mary",8)] means that "bob" maps
-- to 13 and "mary" maps to 8.
--
-- Implement _composition_ for mappings like this. You compose two
-- mappings by looking up each result of the first mapping in the
-- second mapping.
--
-- You may assume there are no repeated first elements of tuples in
-- the argument lists, that is.
--
-- The ordering of the output doesn't matter.
--
-- Hint: remember the function `lookup` from Prelude?
--
-- Examples:
-- composing two mappings of size 1:
-- compose [("a",1)] [(1,True)]
-- ==> [("a",True)]
-- nonmatching mappings get ignored:
-- compose [("a",1),("b",2)] [(3,False),(4,True)]
-- ==> []
-- a more complex example: note how "omicron" and "c" are ignored
-- compose [("a","alpha"),("b","beta"),("c","gamma")] [("alpha",1),("beta",2),("omicron",15)]
-- ==> [("a",1),("b",2)]
compose :: (Eq a, Eq b) => [(a,b)] -> [(b,c)] -> [(a,c)]
compose = todo
------------------------------------------------------------------------------
-- Ex 9: Reorder a list using an [(Int,Int)] mapping.
--
-- Given a list of mappings [(from,to)], reorder the list so that the element
-- at the first index (from) goes to the second index (to). You may assume
-- that the list is ordered with respect to the first index (e.g.
-- [(0,0),(1,1),(2,2)], [(0,1),(1,0),(2,2)], [(0,1),(1,2),(2,0)], etc.). You
-- may also assume that for a list of length n, every number from 0 to n - 1
-- (inclusive) appears exactly once as the first index (from) and once as the
-- second index (to).
--
-- (Mappings of this kind are known as permutations in math, see
-- https://en.wikipedia.org/wiki/Permutation)
--
-- Implement the function permute that performs the reordering.
--
-- Examples:
-- permute [(0,0),(1,1)] [True, False] ==> [True, False]
-- permute [(0,1),(1,0)] [True, False] ==> [False, True]
-- permute [(0,0),(1,1),(2,2),(3,3),(4,4)] "curry" ==> "curry"
-- permute [(0,4),(1,3),(2,2),(3,1),(4,0)] "curry" ==> "yrruc"
-- permute [(0,2),(1,1),(2,0),(3,3),(4,4)] "curry" ==> "rucry"
-- permute [(0,2),(1,1),(2,0)] (permute [(0,2),(1,1),(2,0)] "foo")
-- ==> "foo"
-- permute [(0,1),(1,0),(2,2)] (permute [(0,0),(1,2),(2,1)] [9,3,5])
-- ==> [5,9,3]
-- permute [(0,0),(1,2),(2,1)] (permute [(0,1),(1,0),(2,2)] [9,3,5])
-- ==> [3,5,9]
-- permute ([(0,0),(1,2),(2,1)] `compose` [(0,1),(1,0),(2,2)]) [9,3,5]
-- ==> [5,9,3]
-- permute ([(0,1),(1,0),(2,2)] `compose` [(0,0),(1,2),(2,1)]) [9,3,5]
-- ==> [3,5,9]
type Permutation = [(Int,Int)]
permute :: Permutation -> [a] -> [a]
permute = todo
+206
View File
@@ -0,0 +1,206 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set9aTest where
import Mooc.Test
import Mooc.Th
import Data.List
import Data.List.NonEmpty (NonEmpty)
import Test.QuickCheck
import Set9a
main = score tests
tests = [(1,"workload",[ex1_small, ex1_medium, ex1_big])
,(2,"echo",[ex2_examples, ex2_random])
,(3,"countValid",[ex3])
,(4,"repeated",[ex4_unrepeated_int, ex4_repeated_char, ex4_repeated_int])
,(5,"sumSuccess",[ex5])
,(6,"Lock",[ex6_examples, ex6_gen])
,(7,"Eq Text",[ex7])
,(8,"compose",[ex8_one_one, ex8_many_one, ex8_bijection, ex8_surjective])
,(9,"permute",[ex9_id, ex9_compose])
]
-- -- -- -- --
ex1_small = forAllBlind (choose (1,10)) $ \n ->
forAllBlind (choose (0,div 9 n)) $ \h ->
$(testing [|workload n h|]) (?=="Piece of cake!")
ex1_medium = forAllBlind (choose (1,20)) $ \n ->
forAllBlind (choose (div 10 n+1, div 99 n)) $ \h ->
counterexample (show (div 10 n+1, div 99 n)) $
$(testing [|workload n h|]) (?=="Ok.")
ex1_big = forAllBlind (choose (1,100)) $ \n ->
forAllBlind (choose (div 100 n+1,101)) $ \h ->
$(testing [|workload n h|]) (?=="Holy moly!")
ex2_examples = conjoin' [$(testing [|echo "hello!"|]) (?=="hello!, ello!, llo!, lo!, o!, !, ")
,$(testing [|echo "ECHO"|]) (?=="ECHO, CHO, HO, O, ")
,$(testing [|echo "X"|]) (?=="X, ")
,$(testing [|echo ""|]) (?=="")]
word = listOf1 (choose ('a','z'))
ex2_random = forAllBlind word $ \w ->
$(testing [|echo w|]) . was $ \v ->
conjoin [counterexample " number of ',' characters" $ (length (filter (==',') v)) ?== length w
,counterexample " length of string" $ length v ?== div (length w * (length w + 1)) 2 + 2 * length w
,let prefix = w ++ ", " ++ tail w in counterexample (" should start with "++show prefix) $ prefix `isPrefixOf` v]
digit = choose ('0','9')
valid = do
a <- digit
b <- digit
c <- digit
d <- digit
x <- digit
rest <- listOf digit
elements [a:b:x:c:x:d:rest
,a:b:c:x:d:x:rest]
invalid = do
a <- digit
b <- digit
c <- digit
d <- digit
e <- digit `suchThat` (/=c)
f <- digit `suchThat` (/=d)
rest <- listOf digit
return $ a:b:c:d:e:f:rest
ex3 = forAllShrinkBlind (listOf valid) subterms $ \vs ->
forAllShrinkBlind (listOf invalid) subterms $ \is ->
forAllBlind (shuffle (vs++is)) $ \ns ->
$(testing [|countValid ns|]) (?==length vs)
ex4_unrepeated_int = forAll_ $ \ls ->
$(testing [|repeated (nub (ls :: [Int]))|]) (?==Nothing)
ex4_repeated_char = forAllBlind (listOf1 (choose ('a','z'))) $ \cs' ->
let cs = nub cs'
in forAllBlind (choose (0,length cs - 1)) $ \i ->
let c = cs!!i
input = take i cs ++ c : drop i cs
in $(testing [|repeated input|]) (?==Just c)
ex4_repeated_int = forAll_ $ \(NonEmpty prefix') ->
forAll_ $ \suffix ->
let prefix = nub prefix'
chosen = last prefix :: Int
in $(testing [|repeated (prefix ++ chosen : suffix)|]) (?==Just chosen)
ex5 = property $ do
is <- arbitrary
ws <- listOf word
input <- shuffle (map Left ws ++ map Right is)
return $ $(testing [|sumSuccess input|]) (?==if null is then Left "no data" else Right (sum is))
ex6_examples = conjoin
[$(testing' [|isOpen aLock|]) (?== False)
,$(testing' [|isOpen (lock aLock)|]) (?== False)
,$(testing' [|isOpen (open "1234" aLock)|]) (?== True)
,$(testing' [|isOpen (lock (open "1234" aLock))|]) (?== False)
,$(testing' [|isOpen (open "1235" aLock)|]) (?== False)
,$(testing' [|isOpen (lock (open "1235" aLock))|]) (?== False)
,$(testing' [|isOpen (open "1234" (changeCode "0000" aLock))|]) (?== True)
,$(testing' [|isOpen (open "0000" (changeCode "0000" aLock))|]) (?== False)
,$(testing' [|isOpen (open "0000" (lock (changeCode "0000" (open "1234" aLock))))|]) (?== True)
,$(testing' [|isOpen (open "1234" (lock (changeCode "0000" (open "1234" aLock))))|]) (?== False)]
ex6_gen = property $ do
code <- vectorOf 5 digit
wrong <- vectorOf 5 digit `suchThat` (/=code)
return $
counterexample ("with code = " ++ show code) $
conjoin [$(testing' [|isOpen (changeCode code (open "1234" aLock))|]) (?== True)
,$(testing' [|isOpen (lock (changeCode code (open "1234" aLock)))|]) (?== False)
,$(testing' [|isOpen (lock (lock (changeCode code (open "1234" aLock))))|]) (?== False)
,$(testing' [|isOpen (open code (lock (changeCode code (open "1234" aLock))))|]) (?== True)
,$(testing' [|isOpen (open code (open code (lock (changeCode code (open "1234" aLock)))))|]) (?== True)]
.&&.
counterexample ("with wrong = " ++ show wrong)
(conjoin [$(testing' [|isOpen (open wrong (lock (changeCode code (open "1234" aLock))))|]) (?== False)
,$(testing' [|isOpen (open code (lock (changeCode code (changeCode wrong (open "1234" aLock)))))|]) (?== True)
,$(testing' [|isOpen (open wrong (lock (changeCode code (changeCode wrong (open "1234" aLock)))))|]) (?== False)
,$(testing' [|isOpen (open wrong (open code (lock (changeCode code (open "1234" aLock)))))|]) (?== True)
,$(testing' [|isOpen (open code (open wrong (lock (changeCode code (open "1234" aLock)))))|]) (?== True)])
spacify [] = elements [" ","\n",""]
spacify (c:cs) = frequency [(8, fmap (c:) (spacify cs))
,(2, fmap (' ':) (spacify (c:cs)))
,(1, fmap ('\n':) (spacify (c:cs)))]
change [] = do
c <- choose ('a','z')
return [c]
change (c:cs) = oneof [fmap (:cs) $ choose ('a','z') `suchThat` (/=c)
,fmap (c:) $ change cs]
ex7 = $(withInstance "Eq" "Text" [|(==) :: Text -> Text -> Bool|]) $ \(==) ->
property $ do
bare <- word
v1 <- spacify bare
v2 <- spacify bare
wrong <- change v2
return $ conjoin [$(testing [|Text bare == Text v1|]) (?==True)
,$(testing [|Text v1 == Text bare|]) (?==True)
,$(testing [|Text v1 == Text v1|]) (?==True)
,$(testing [|Text v1 == Text v2|]) (?==True)
,$(testing [|Text wrong == Text v2|]) (?==False)
,$(testing [|Text bare == Text wrong|]) (?==False)]
ex8_one_one = forAll_ $ \(x::Int) ->
forAll_ $ \(y::Char) ->
forAll_ $ \(z::String) ->
$(testing [|compose [(x,y)] [(y,z)]|]) (?==[(x,z)])
ex8_many_one = forAll_ $ \(x::Int) ->
forAll_ $ \(y::String) ->
forAll_ $ \(z::Int) ->
forAll_ $ \pairs ->
let pairs' = (x,y):filter (\(k,v) -> k/=x && v/=y) pairs
in forAllBlind (shuffle pairs') $ \pairs'' ->
$(testing [|compose pairs'' [(y,z)]|]) (?==[(x,z)])
ex8_bijection = forAllShrink_ (choose (1,10)) $ \n ->
forAllBlind (shuffle [1..n::Int]) $ \ys ->
forAllBlind (shuffle [1..n::Int]) $ \zs ->
forAllBlind (shuffle (zip [1..n] ys)) $ \xys ->
forAllBlind (shuffle (zip ys zs)) $ \yzs ->
$(testing [|compose xys yzs|]) (hasElements (zip [1..n] zs))
ex8_surjective = forAllShrink_ (choose (2,5)) $ \n ->
forAllShrink_ (choose (2,5)) $ \k ->
forAllBlind (vector n) $ \(output::[Int]) ->
let xs = take (n*k) ['a'..]
xys = zip xs (cycle [1..n])
yzs = zip [1..n] output
expected = zip xs (cycle output)
in forAllBlind (shuffle xys) $ \xys' ->
forAllBlind (shuffle yzs) $ \yzs' ->
$(testing [|compose xys' yzs'|]) (hasElements expected)
ex9_id = property $ do
n <- choose (1,5)
let id = [(i,i) | i <- [0..n-1]]
xs <- shuffle (take n "abcdefghij")
return $ $(testing [|permute id xs|]) (?== xs)
ex9_compose = property $ do
n <- choose (2,5)
p <- return . zip [0..n-1] =<< shuffle [0..n-1]
q <- return . zip [0..n-1] =<< shuffle [0..n-1]
xs <- shuffle (take n "abcdefghij")
return $ counterexample
("permute (compose p q) xs == permute q (permute p xs) failed:\n\
\ p was " ++ show p ++ "\n q was " ++ show q ++ ", and\n xs \
\was " ++ show xs ++ ";\n permute (compose p q) xs evaluated to " ++
show (permute (compose p q) xs) ++ ",\n while \
\permute q (permute p xs) evaluated to " ++
show (permute q (permute p xs)))
(permute (compose p q) xs == permute q (permute p xs))
+377
View File
@@ -0,0 +1,377 @@
module Set9b where
import Mooc.Todo
import Data.List
--------------------------------------------------------------------------------
-- Ex 1: In this exercise set, we'll solve the N Queens problem step by step.
-- N Queens is a generalisation of the Eight Queens problem described in
-- Wikipedia: https://en.wikipedia.org/wiki/Eight_queens_puzzle
--
-- We'll be working with a two-dimensional coordinate system for indexing the
-- queens on a chessboard of arbitrary size. (1,1) represents the top left
-- corner. (1,2) is the next square on the top row, (1,3) is the one after that,
-- (2,1) is the first square on the second row, (2,2) is the second square in
-- the second row, and so on. In general, the coordinates are of the form
-- (row,column). The idea is that the following arrangement of queens on a 8x8
-- board will be encoded as the list [(1,8),(2,6),(3,4),(5,7)] of coordinates:
--
-- .......Q
-- .....Q..
-- ...Q....
-- ........
-- ......Q.
-- ........
-- ........
-- ........
--
-- The first exercise is warmup. We'll define two helper functions that we're
-- going to use later: nextRow, and nextCol. nextRow increases the row by one
-- and sets column to 1. nextCol only increases the column by one. (By analogy,
-- nextRow works like line break and carriage return while nextCol works like
-- the space bar in a typewriter.)
--
-- Examples:
-- nextRow (1,1) ==> (2,1)
-- nextRow (4,7) ==> (5,1)
-- nextCol (1,1) ==> (1,2)
-- nextCol (4,7) ==> (4,8)
--
-- Before we start, remember type aliases? We define some of them just to make
-- the roles of different function arguments clearer without adding syntactical
-- overhead:
type Row = Int
type Col = Int
type Coord = (Row, Col)
nextRow :: Coord -> Coord
nextRow (i,j) = todo
nextCol :: Coord -> Coord
nextCol (i,j) = todo
--------------------------------------------------------------------------------
-- Ex 2: Implement the function prettyPrint that, given the size of the
-- chessboard and a list of distinct coordinates of queens, prints the
-- chessboard with the queens on it. Empty squares must be printed as '.'s and
-- queens as 'Q's. The special line break character '\n' must be appended to the
-- end of each row.
--
-- Examples:
-- prettyPrint 3 [(1,1),(2,3),(3,2)] ==> "Q..\n..Q\n.Q.\n"
-- prettyPrint 3 [(2,3),(1,1),(3,2)] ==> "Q..\n..Q\n.Q.\n"
-- prettyPrint 3 [(1,3),(2,1),(3,2)] ==> "..Q\nQ..\n.Q.\n"
--
-- To see how the result looks like with the line breaks correctly printed, use
-- putStrLn in GHCI. To open this module in GHCI, run 'stack ghci Set9b.hs'.
--
-- Examples:
-- *Set9b> putStrLn $ prettyPrint 4 [(1,1),(1,4),(4,1),(4,4)]
-- Q..Q
-- ....
-- ....
-- Q..Q
--
-- *Set9b> putStrLn $ prettyPrint 4 [(4,4),(1,4),(1,1),(4,1)]
-- Q..Q
-- ....
-- ....
-- Q..Q
--
-- *Set9b> putStrLn $ prettyPrint 7 [(1,1),(2,3),(3,5),(4,7),(5,2),(6,4),(7,6)]
-- Q......
-- ..Q....
-- ....Q..
-- ......Q
-- .Q.....
-- ...Q...
-- .....Q.
--
-- Hint: Remember the function elem? elem x xs checks if the list xs contains
-- the element x, e.g. elem 1 [2,5,1] ==> True, elem 1 [2,5,2] ==> False.
--
-- Challenge: Try defining prettyPrint without elem by just iterating over all
-- coordinates one at a time. (For those who've had a course in data structures
-- and algorithms, this challenge is about finding an O(n^2) solution in terms
-- of the width (or height) n of the chess board; the naïve solution with elem
-- takes O(n^3) time. Just ignore the previous sentence, if you're not familiar
-- with the O-notation.)
prettyPrint :: Size -> [Coord] -> String
prettyPrint = todo
--------------------------------------------------------------------------------
-- Ex 3: The task in this exercise is to define the relations sameRow, sameCol,
-- sameDiag, and sameAntidiag that check whether or not two coordinates of the
-- form (i,j) :: (Row, Col) on a table of indeterminate size are on the same
-- column, diagonal (top left to bottom right), or antidiagonal (bottom left to
-- top right) respectively. Indeterminate size of the table means that these
-- relations should work for tables of all sizes. (You may assume that all
-- coordinates will be positive.)
--
-- Examples:
-- sameRow (1,1) (1,1) ==> True
-- sameRow (1,1) (2,1) ==> False
-- sameRow (1,1) (1,2) ==> True
-- sameCol (1,1) (4,1) ==> True
-- sameCol (1,1) (4,2) ==> False
-- sameDiag (1,1) (2,2) ==> True
-- sameDiag (1,1) (1,2) ==> False
-- sameAntidiag (1,1) (1,2) ==> False
-- sameAntidiag (2,10) (5,7) ==> True
-- sameAntidiag (500,5) (5,500) ==> True
sameRow :: Coord -> Coord -> Bool
sameRow (i,j) (k,l) = todo
sameCol :: Coord -> Coord -> Bool
sameCol (i,j) (k,l) = todo
sameDiag :: Coord -> Coord -> Bool
sameDiag (i,j) (k,l) = todo
sameAntidiag :: Coord -> Coord -> Bool
sameAntidiag (i,j) (k,l) = todo
--------------------------------------------------------------------------------
-- Ex 4: In chess, a queen may capture another piece in the same row, column,
-- diagonal, or antidiagonal in one step. This danger zone, where pieces can be
-- captured by a queen (indicated here with the character '#') looks like this:
--
-- .#.#.#..
-- ..###...
-- ###Q####
-- ..###...
-- .#.#.#..
-- #..#..#.
-- ...#...#
-- ...#....
--
-- For multiple queens, the danger zone is the union of the danger zones for
-- individual queens. This means that all coordinates belonging to the danger
-- zones of one or more individual queens also belongs to the collective danger
-- zone of all queens on the board. For example, if we add a second queen to the
-- coordinates (4,6), the danger zone grows:
--
-- .###.#..
-- ..####.#
-- ###Q####
-- #####Q##
-- .#.####.
-- #..#.###
-- ..##.#.#
-- .#.#.#..
--
-- Implement the function danger that checks if a coordinate belongs to the
-- collective danger zone of the given list of (coordinates of) queens.
-- Graphically speaking, we want to check if the square at the given coordinates
-- looks like '.' rather than '#'. (You may assume that the given coordinate
-- will be different from all the coordinates in the stack.)
--
-- Examples:
-- danger (5,2) [] ==> False
-- danger (5,2) [(1,2)] ==> True
-- danger (5,2) [(4,3)] ==> True
-- danger (4,5) [(3,4),(4,6)] ==> True
-- danger (5,3) [(3,4),(4,6)] ==> False
-- danger (5,3) [(3,4),(4,6),(7,5),(6,2),(8,1)] ==> True
--
-- Hint: Use the relations of the previous exercise!
--
-- Lists of coordinates of queens will be later used in a First in Last Out
-- (LIFO) manner, so we give this type the alias Stack:
-- https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
type Size = Int
type Candidate = Coord
type Stack = [Coord]
danger :: Candidate -> Stack -> Bool
danger = todo
--------------------------------------------------------------------------------
-- Ex 5: In this exercise, the task is to write a modified version of
-- prettyPrint that marks those empty squares with '#' that are in the
-- collective danger zone of the given stack of queens. You may assume that
-- none of the queens in the stack are in the danger zone of another queen.
--
-- Examples:
-- *Set9b> putStrLn $ prettyPrint2 3 []
-- ...
-- ...
-- ...
--
-- *Set9b> putStrLn $ prettyPrint2 4 [(1,2),(2,4)]
-- #Q##
-- ###Q
-- .###
-- .#.#
--
-- *Set9b> putStrLn $ prettyPrint2 9 [(5,5)]
-- #...#...#
-- .#..#..#.
-- ..#.#.#..
-- ...###...
-- ####Q####
-- ...###...
-- ..#.#.#..
-- .#..#..#.
-- #...#...#
--
-- (For those that did the challenge in exercise 2, there's probably no O(n^2)
-- solution to this version. Any working solution is okay in this exercise.)
prettyPrint2 :: Size -> Stack -> String
prettyPrint2 = todo
--------------------------------------------------------------------------------
-- Ex 6: Now that we can check if a piece can be safely placed into a square in
-- the chessboard, it's time to write the first piece of the actual solution.
--
-- Given the size of the chessboard and a stack, the function fixFirst
-- should take the queen on the top of the stack, and if it is in in
-- danger, move it right (in the direction of increasing columns)
-- until it is not in danger.
--
-- If no safe spot is found for the queen, fixFirst should return Nothing.
--
-- Examples:
-- fixFirst 5 [(1,1)] ==> Just [(1,1)]
-- fixFirst 5 [(3,4)] ==> Just [(3,4)]
-- fixFirst 5 [(1,1),(1,5)] ==> Nothing
-- fixFirst 5 [(1,1),(3,3)] ==> Just [(1,2),(3,3)]
-- fixFirst 5 [(1,3),(3,3)] ==> Just [(1,4),(3,3)]
-- fixFirst 5 [(2,1),(3,3)] ==> Just [(2,1),(3,3)]
-- fixFirst 8 [(8,1),(1,1)] ==> Just [(8,2),(1,1)]
-- fixFirst 8 [(4,1),(3,4),(4,6)] ==> Nothing
-- fixFirst 8 [(6,1),(3,4),(4,6)] ==> Just [(6,2),(3,4),(4,6)]
-- fixFirst 8 [(5,1),(3,8),(4,6),(7,5),(6,2),(8,1)] ==> Nothing
--
-- Hint: Remember prettyPrint and prettyPrint2? They might be useful
-- for debugging. For example we can run this to see what's happening
-- in that last example. The whole fifth row is in danger zone.
--
-- putStrLn $ prettyPrint2 8 [(3,8),(4,6),(7,5),(6,2),(8,1)]
-- ###.####
-- ##.#####
-- #######Q
-- #####Q##
-- ########
-- #Q######
-- ####Q###
-- Q#######
fixFirst :: Size -> Stack -> Maybe Stack
fixFirst n s = todo
--------------------------------------------------------------------------------
-- Ex 7: We need two helper functions for stack management.
--
-- * continue moves on to a new row. It pushes a new candidate to the
-- top of the stack (front of the list). The new candidate should be
-- at the beginning of the next row with respect to the queen
-- previously on top of the stack.
--
-- * backtrack moves back to the previous row. It removes the top
-- element of the stack, and adjusts the new top element so that it
-- is in the next column.
--
-- Examples:
-- continue [(1,1)] ==> [(2,1),(1,1)]
-- continue [(2,3),(1,1)] ==> [(3,1),(2,3),(1,1)]
-- backtrack [(8,1),(7,5),(6,2),(4,6),(3,4)] ==> [(7,6),(6,2),(4,6),(3,4)]
--
-- Hint: Remember nextRow and nextCol? Use them!
continue :: Stack -> Stack
continue s = todo
backtrack :: Stack -> Stack
backtrack s = todo
--------------------------------------------------------------------------------
-- Ex 8: Let's take a step. Our algorithm solves the problem (in a
-- greedy manner) one row at a time, backtracking when needed. The
-- reason why we need backtracking is the following. We can greedily
-- put the queens to (1,1) and (2,3) and end up with no safe spot on
-- the third row:
--
-- Q###
-- ##Q#
-- ####
-- #.##
--
-- However if we backtrack and move the queen from (2,3) to (2,4), we
-- are able to place the third queen:
--
-- Q###
-- ###Q
-- #.##
-- ##.#
--
-- Implement the function step that takes the size of a board and a
-- stack, and tries to fix the position of the queen on the top of the
-- stack (using fixFirst). If a new position is found, the function
-- should call continue to return a stack with a new candidate. If a
-- safe position is not found, the function should call backtrack to
-- return a new stack.
--
-- Examples:
--
-- The first candidate is safe so we continue directly:
-- step 4 [(1,1)] ==> [(2,1),(1,1)]
--
-- Q... Q...
-- .... ==> Q...
-- .... ....
-- .... ....
--
-- The second candidate needs to be adjusted a bit before a third is added:
-- step 4 [(2,1),(1,1)] ==> [(3,1),(2,3),(1,1)]
--
-- Q... Q...
-- Q... ==> ..Q.
-- .... Q...
-- .... ....
--
-- No safe position is found for the third queen so we backtrack:
-- step 4 [(3,1),(2,3),(1,1)] ==> [(2,4),(1,1)]
--
-- Q... Q...
-- ..Q. ==> ...Q
-- Q... ....
-- .... ....
--
-- The new position of the second queen is ok so we move to the third row:
-- step 4 [(2,4),(1,1)] ==> [(3,1),(2,4),(1,1)]
--
-- Q... Q...
-- ...Q ==> ...Q
-- .... Q...
-- .... ....
--
-- More examples:
-- step 8 [(3,9),(4,6),(7,5),(6,2),(8,1)] ==> [(4,7),(7,5),(6,2),(8,1)]
-- step 8 [(4,7),(7,5),(6,2),(8,1)] ==> [(5,1),(4,7),(7,5),(6,2),(8,1)]
step :: Size -> Stack -> Stack
step = todo
--------------------------------------------------------------------------------
-- Ex 8: Let's solve our puzzle! The function finish takes a partial
-- solution (stack) and repeatedly step until a complete solution is
-- found.
--
-- Reminder: a complete solution has n queens that don't threaten each
-- other. One easy way to know you have a valid solution is when step
-- adds the (n+1)th queen.
--
-- After this, it's just a matter of calling `finish n [(1,1)]` to
-- solve the n queens problem.
finish :: Size -> Stack -> Stack
finish = todo
solve :: Size -> Stack
solve n = finish n [(1,1)]
+414
View File
@@ -0,0 +1,414 @@
{-# LANGUAGE TemplateHaskell #-}
module Set9bTest where
import Mooc.Test
import Mooc.Th
import Data.List
import qualified Data.Set as S
import Test.QuickCheck
import Set9b
main = score tests
tests = [ (1, "warmup", [ ex1_nextRow, ex1_nextCol ])
, (2, "prettyPrint", [ ex2_examples, ex2_size, ex2_content, ex2_comm
, ex2_correctness ])
, (3, "relations", [ ex3_sameCol_pos, ex3_sameCol_neg
, ex3_sameDiag_pos, ex3_sameDiag_neg
, ex3_sameAntidiag_pos, ex3_sameAntidiag_neg ])
, (4, "danger", [ ex4_danger, ex4_danger_neg ])
, (5, "prettyPrint2", [ ex5_size, ex5_content, ex5_comm
, ex5_correctness ])
, (6, "fixFirst", [ ex6_fixFirst_safeZone, ex6_fixFirst_dangerZone ])
, (7, "stackOps", [ ex7_continue, ex7_backtrack ])
, (8, "nqueens_step", [ ex8_step_4, ex8_step_continue, ex8_step_backtrack ])
, (9, "nqueens_finish", [ ex9_finish_small, ex9_finish_medium, ex9_finish_large ])
]
-- -- -- -- --
size :: Coord -> Size
size (i,j) = foldr max 0 [8, i, j]
coord :: Gen (Int, Int)
coord = do
(Positive i, Positive j) <- arbitrary :: Gen (Positive Int, Positive Int)
return (i, j)
boundedCoord :: Size -> Gen Coord
boundedCoord n = do
i <- choose (1,n)
j <- choose (1,n)
return (i,j)
board :: Gen (Size, [Coord])
board = do
n <- choose (5,10)
k <- choose (1,10)
xs <- vectorOf k (boundedCoord n)
let xs' = nub xs
return (n, xs')
dangerZone :: Size -> Coord -> [Coord]
dangerZone n (i,j) =
let dis = [-i + 1 .. n - i]
djs = [-j + 1 .. n - j]
in [ (i + di, j + dj)
| di <- dis, dj <- djs
, di == dj || di == -dj || di * dj == 0
]
safeZone :: Size -> Coord -> [Coord]
safeZone n (i,j) =
let dis = [-i + 1 .. n - i]
djs = [-j + 1 .. n - j]
in [ (i + di, j + dj)
| di <- dis, dj <- djs
, di /= dj, di /= -dj, di * dj /= 0
]
full :: Size -> [Coord]
full n = [(i,j) | i <- [1..n], j <- [1..n]]
queens :: Size -> Int -> Gen ([Coord], [Coord], [Coord])
queens n 0 = return ([], [], full n)
queens n k = do
(qs, dz, sz) <- queens n (k - 1)
case sz of
[] -> return (qs, dz, sz)
_ -> do q <- elements sz
let qs' = q:qs
let dz' = dz `union` dangerZone n q
let sz' = sz `intersect` safeZone n q
return (qs', dz', sz')
stack :: Gen Stack
stack = do
cs <- listOf1 arbitrary :: Gen [(Positive Int, Positive Int)]
return $ map (\(Positive i, Positive j) -> (i,j)) cs
--------------------------------------------------------------------------------
ex1_nextRow = property $ do
(i,j) <- coord
return $ $(testing [| nextRow (i,j) |]) (?== (i + 1, 1))
ex1_nextCol = property $ do
(i,j) <- coord
return $ $(testing [| nextCol (i,j) |]) (?== (i, j + 1))
--------------------------------------------------------------------------------
ex2_examples = conjoin [$(testing [|prettyPrint 3 [(1,1),(2,3),(3,2)]|]) (?=="Q..\n..Q\n.Q.\n")
,$(testing [|prettyPrint 3 [(2,3),(1,1),(3,2)]|]) (?=="Q..\n..Q\n.Q.\n")
,$(testing [|prettyPrint 3 [(1,3),(2,1),(3,2)]|]) (?=="..Q\nQ..\n.Q.\n")]
ex2_size = property $ do
(n, xs) <- board
let ys = lines $ prettyPrint n xs
return $ $(testing [| prettyPrint n xs |]) $ \out ->
let ys = lines out
in conjoin [ counterexample " number of lines in output" $
length ys ?== n
, counterexample " length of output lines" $
map length ys ?== replicate n n ]
ex2_content = property $ do
(n, xs) <- board
let ys = prettyPrint n xs
return $ $(testing [| prettyPrint n xs |]) $ \out ->
counterexample " characters in output" $
sort (nub out) ?== (if null xs then "\n." else "\n.Q")
ex2_comm = property $ do
(n, xs) <- board
xs' <- shuffle xs
return $ counterexample
("prettyPrint " ++ show n ++ " " ++ show xs ++ " == " ++
"prettyPrint " ++ show n ++ " " ++ show xs' ++
"\n Expected: True\n Was: False")
(prettyPrint n xs == prettyPrint n xs')
ex2_correctness = property $ do
(n, xs) <- board
let m = S.fromList xs
let ys = lines $ prettyPrint n xs
let check _ [] = True
check (i,j) ("":rows) = check (i + 1, 1) rows
check (i,j) ((char:row):rows)
| char == 'Q' = S.member (i,j) m && check (i, j + 1) (row:rows)
| char == '.' = (not (S.member (i,j) m)) && check (i, j + 1) (row:rows)
| otherwise = False
return $ counterexample
("prettyPrint " ++ show n ++ " " ++ show xs ++
" didn't mark the queens and/or empty cells correctly.\n" ++
"The return value was:\n " ++ show (prettyPrint n xs))
(check (1,1) ys)
--------------------------------------------------------------------------------
ex3_sameCol_pos = property $ do
(i,j) <- coord
let xs = [(i + k, j) | k <- [0..9]]
x <- elements xs
y <- elements xs
return $ $(testing [| sameCol x y |]) (?== True)
ex3_sameCol_neg = property $ do
(i,j) <- coord
let xs = [(i, j + k) | k <- [1..10]]
x <- elements xs
return $ $(testing [| sameCol (i,j) x |]) (?== False)
ex3_sameDiag_pos = property $ do
(i,j) <- coord
let xs = [(i + k, j + k) | k <- [0..9]]
x <- elements xs
y <- elements xs
return $ $(testing [| sameDiag x y |]) (?== True)
ex3_sameDiag_neg = property $ do
(i,j) <- coord
let xs = [(i, j + k) | k <- [1..10]]
x <- elements xs
return $ $(testing [| sameDiag (i,j) x |]) (?== False)
ex3_sameAntidiag_pos = property $ do
(i,j) <- coord
let xs = [ (i - k, j + k) | k <- [0..min i 10] ]
x <- elements xs
y <- elements xs
return $ $(testing [| sameAntidiag x y |]) (?== True)
ex3_sameAntidiag_neg = property $ do
(i,j) <- coord
let xs = [(i, j + k) | k <- [1..10]]
x <- elements xs
return $ $(testing [| sameAntidiag (i,j) x |]) (?== False)
--------------------------------------------------------------------------------
ex4_danger = property $ do
(i,j) <- coord
let n = size (i,j)
let xs = dangerZone n (i,j)
x <- elements xs
return $ $(testing [| danger x [(i,j)] |]) (?== True)
ex4_danger_neg = property $ do
(i,j) <- coord
let n = size (i,j)
let xs = safeZone n (i,j)
x <- elements xs
return $ $(testing [| danger x [(i,j)] |]) (?== False)
--------------------------------------------------------------------------------
ex5_size = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, _, _) <- queens n k
return $ $(testing [| prettyPrint2 n qs |]) $ \out ->
let ys = lines out
in conjoin [ counterexample " number of lines in output" $
length ys ?== n
, counterexample " length of output lines" $
map length ys ?== replicate n n ]
ex5_content = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, _, _) <- queens n k
return $ $(testing [| prettyPrint2 n qs |]) $ \out ->
counterexample " characters in output" $
sort (nub out) ?== (if null qs then "\n." else "\n#.Q")
ex5_comm = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, dz, _) <- queens n k
qs' <- shuffle qs
return $ counterexample
("prettyPrint2 " ++ show n ++ " " ++ show qs ++ " == " ++
"prettyPrint2 " ++ show n ++ " " ++ show qs' ++
"\n Expected: True\n Was: False")
(prettyPrint2 n qs == prettyPrint2 n qs')
ex5_correctness = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, dz, _) <- queens n k
let q = S.fromList qs
let d = S.fromList dz
let xs = lines $ prettyPrint2 n qs
let check _ [] = True
check (i,j) ("":rows) = check (i + 1, 1) rows
check (i,j) ((char:row):rows)
| char == 'Q' = S.member (i,j) q &&
check (i, j + 1) (row:rows)
| char == '#' = not (S.member (i,j) q) &&
S.member (i,j) d &&
check (i, j + 1) (row:rows)
| char == '.' = not (S.member (i,j) q) &&
not (S.member (i,j) d) &&
check (i, j + 1) (row:rows)
| otherwise = False
return $ counterexample
("prettyPrint2 " ++ show n ++ " " ++ show qs ++
" didn't mark the queens and/or empty cells correctly.\n" ++
"The return value was:\n " ++ show (prettyPrint2 n qs))
(check (1,1) xs)
--------------------------------------------------------------------------------
ex6_fixFirst_safeZone = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, dz, sz) <- queens n k
case sz of
[] -> return $ property True
_ -> do q <- elements sz
return $ $(testing [| fixFirst n (q:qs) |]) (?== Just (q:qs))
ex6_fixFirst_dangerZone = property $ do
n <- choose (5,10) :: Gen Int
let k = n `div` 2
(qs, dz, sz) <- queens n k
q@(i,j) <- elements dz
return $ $(testing [| fixFirst n (q:qs) |]) $ \x -> case x of
x@(Just (q':qs')) -> conjoin [
counterexample
(" returned " ++ show x ++ ", but\n " ++ show q' ++
" is in danger")
(q' `elem` sz)
, counterexample
(" returned " ++ show x ++ ", but\n " ++ show qs' ++
" was not " ++ show qs)
(qs' == qs) ]
x@(Just []) -> counterexample
(" returned " ++ show x ++ ", but the list was empty")
False
Nothing -> counterexample
(" returned Nothing, but there were safe squares on row " ++ show i ++
": " ++ show (intersect row sz))
(all (`elem` dz) row)
where row = [(i,k) | k <- [j .. n]]
--------------------------------------------------------------------------------
ex7_continue = property $ do
cs <- stack
let input = show cs
case continue cs of
[] -> return $ counterexample
("continue " ++ input ++ " returned []")
False
cs' -> return $ conjoin
[ counterexample
("length (continue " ++ input ++ ")")
(length cs' ?== length cs + 1)
, counterexample
("fst (head (continue " ++ input ++ "))")
(fst (head cs') ?== fst (head cs) + 1)
, counterexample
("snd (head (continue " ++ input ++ ")) should be positive, but \
\it was " ++ show (snd (head cs')))
(snd (head cs') >= 1)
, counterexample
("tail (continue " ++ input ++ ")")
(tail cs' ?== cs)
]
ex7_backtrack = property $ do
cs <- stack `suchThat` ((>1).length)
let input = show cs
case backtrack cs of
[] -> return $ counterexample
("backtrack " ++ input ++ " returned []")
False
cs' -> return $ conjoin
[ counterexample
("length (backtrack " ++ input ++ ")")
(length cs' ?== length cs - 1)
, counterexample
("(head (backtrack " ++ input ++ "))")
((head cs') ?== (fst (cs!!1), snd (cs!!1) + 1))
, counterexample
("tail (backtrack " ++ input ++ ")")
(tail cs' ?== tail (tail cs))
]
--------------------------------------------------------------------------------
steps_4 = [[(1,1)]
,[(2,1),(1,1)]
,[(3,1),(2,3),(1,1)]
,[(2,4),(1,1)]
,[(3,1),(2,4),(1,1)]
,[(4,1),(3,2),(2,4),(1,1)]
,[(3,3),(2,4),(1,1)]
,[(2,5),(1,1)]
,[(1,2)]
,[(2,1),(1,2)]
,[(3,1),(2,4),(1,2)]
,[(4,1),(3,1),(2,4),(1,2)]
,[(5,1),(4,3),(3,1),(2,4),(1,2)]]
ex8_step_4 = conjoin [$(testing [|step 4 from|]) (?==to) | (from,to) <- zip steps_4 (tail steps_4)]
ex8_step_continue = property $ do
n <- choose (5,10)
k <- choose (1,n-1)
(qs, dz, sz) <- queens n k
let row = succ (fst (head qs))
d = map snd $ filter ((==row).fst) dz
s = map snd $ filter ((==row).fst) sz
return $ not (null s) ==> do
safec <- elements s
let priors = takeWhile (`elem`d) [safec-1,safec-2..]
col <- elements (safec:priors)
return $ $(testing [|step n ((row,col):qs)|]) . was $ \res ->
conjoin [counterexample (" length") (length res ?== length qs + 2)
,counterexample (" index 1") ((res!!1) ?== (row,safec))
,counterexample (" end of list") (drop 2 res ?== qs)]
ex8_step_backtrack = property $ do
n <- choose (5,10)
k <- choose (div n 2,n-1)
(qs, dz, sz) <- queens n k
let row = succ (fst (head qs))
d = map snd $ filter ((==row).fst) dz
end = takeWhile (`elem`d) [n,n-1..]
return $ not (null end) ==> do
col <- elements end
return $ $(testing [|step n ((row,col):qs)|]) . was $ \res ->
conjoin [counterexample (" length") (length res ?== length qs)
,counterexample (" first element") (head res ?== nextCol (head qs))
,counterexample (" end of list") (tail res ?== tail qs)]
--------------------------------------------------------------------------------
m_finish_sol sol = forAllBlind (elements (init (tails sol))) $ \pre ->
$(testing [|finish (length sol) pre|]) (?==sol)
ex9_finish_small = conjoin [$(testing [|finish 4 [(1,1)]|]) (?==[(4,3),(3,1),(2,4),(1,2)])
,m_finish_sol [(4,2),(3,4),(2,1),(1,3)]
,m_finish_sol [(4,2),(3,4),(2,1),(1,3)]
,m_finish_sol [(5,4),(4,2),(3,5),(2,3),(1,1)]
,m_finish_sol [(5,5),(4,3),(3,1),(2,4),(1,2)]
,m_finish_sol [(5,5),(4,2),(3,4),(2,1),(1,3)]
,m_finish_sol [(5,2),(4,5),(3,3),(2,1),(1,4)]
,m_finish_sol [(5,3),(4,1),(3,4),(2,2),(1,5)]]
m_finish_n n = $(testing [|finish n [(1,1)]|]) . was $ \qs ->
conjoin [ counterexample " length of list" $ length qs ?== n
, counterexample " queens outside board" $ [] ==? [(i,j) | (i,j) <- qs, i<1 || i>n || j<1 || j>n]
, let sz = foldr intersect (full n) . map (\q -> q : safeZone n q) $ qs
in counterexample " these queens can capture each other: " $ (qs \\ sz) ?== []
]
ex9_finish_medium = forAllBlind (choose (5,10)) m_finish_n
ex9_finish_large = forAllBlind (choose (10,14)) m_finish_n
+118
View File
@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="157.248pt" height="73.297pt" viewBox="0 0 157.248 73.297" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 1.171875 -2.171875 C 1.171875 -3.796875 1.984375 -4.21875 2.515625 -4.21875 C 2.609375 -4.21875 3.234375 -4.203125 3.578125 -3.84375 C 3.171875 -3.8125 3.109375 -3.515625 3.109375 -3.390625 C 3.109375 -3.125 3.296875 -2.9375 3.5625 -2.9375 C 3.828125 -2.9375 4.03125 -3.09375 4.03125 -3.40625 C 4.03125 -4.078125 3.265625 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.34375 -3.390625 0.34375 -2.15625 C 0.34375 -0.875 1.328125 0.109375 2.484375 0.109375 C 3.8125 0.109375 4.140625 -1.09375 4.140625 -1.1875 C 4.140625 -1.28125 4.03125 -1.28125 4 -1.28125 C 3.921875 -1.28125 3.890625 -1.25 3.875 -1.1875 C 3.59375 -0.265625 2.9375 -0.140625 2.578125 -0.140625 C 2.046875 -0.140625 1.171875 -0.5625 1.171875 -2.171875 Z M 1.171875 -2.171875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 4.140625 -3.34375 C 4.390625 -3.984375 4.90625 -3.984375 5.0625 -3.984375 L 5.0625 -4.296875 C 4.828125 -4.28125 4.546875 -4.265625 4.3125 -4.265625 C 4.140625 -4.265625 3.671875 -4.28125 3.453125 -4.296875 L 3.453125 -3.984375 C 3.765625 -3.984375 3.921875 -3.8125 3.921875 -3.5625 C 3.921875 -3.453125 3.90625 -3.4375 3.859375 -3.3125 L 2.84375 -0.875 L 1.75 -3.546875 C 1.703125 -3.65625 1.6875 -3.6875 1.6875 -3.734375 C 1.6875 -3.984375 2.046875 -3.984375 2.25 -3.984375 L 2.25 -4.296875 C 1.984375 -4.28125 1.328125 -4.265625 1.15625 -4.265625 C 0.890625 -4.265625 0.484375 -4.28125 0.1875 -4.296875 L 0.1875 -3.984375 C 0.671875 -3.984375 0.859375 -3.984375 1 -3.640625 L 2.5 0 C 2.4375 0.125 2.296875 0.453125 2.25 0.59375 C 2.03125 1.140625 1.75 1.828125 1.109375 1.828125 C 1.0625 1.828125 0.828125 1.828125 0.640625 1.640625 C 0.953125 1.609375 1.03125 1.390625 1.03125 1.21875 C 1.03125 0.96875 0.84375 0.8125 0.609375 0.8125 C 0.40625 0.8125 0.1875 0.9375 0.1875 1.234375 C 0.1875 1.6875 0.609375 2.046875 1.109375 2.046875 C 1.734375 2.046875 2.140625 1.46875 2.375 0.90625 Z M 4.140625 -3.34375 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 1.765625 -6.921875 L 0.328125 -6.8125 L 0.328125 -6.5 C 1.03125 -6.5 1.109375 -6.4375 1.109375 -5.9375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.65625 -0.015625 1.1875 -0.03125 1.4375 -0.03125 C 1.6875 -0.03125 2.171875 -0.015625 2.546875 0 L 2.546875 -0.3125 C 1.875 -0.3125 1.765625 -0.3125 1.765625 -0.75 Z M 1.765625 -6.921875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-4">
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-5">
<path style="stroke:none;" d="M 2.71875 -4.453125 C 2.71875 -4.71875 2.546875 -4.984375 2.1875 -4.984375 C 1.984375 -4.984375 1.84375 -4.890625 1.78125 -4.828125 C 1.78125 -4.8125 1.765625 -4.796875 1.75 -4.796875 C 1.734375 -4.796875 1.734375 -4.9375 1.734375 -4.96875 C 1.734375 -5.296875 1.796875 -6.015625 2.4375 -6.625 C 2.546875 -6.75 2.546875 -6.765625 2.546875 -6.796875 C 2.546875 -6.875 2.5 -6.90625 2.453125 -6.90625 C 2.34375 -6.90625 1.515625 -6.15625 1.515625 -4.96875 C 1.515625 -4.375 1.75 -3.921875 2.1875 -3.921875 C 2.53125 -3.921875 2.71875 -4.203125 2.71875 -4.453125 Z M 4.640625 -4.453125 C 4.640625 -4.71875 4.46875 -4.984375 4.109375 -4.984375 C 3.921875 -4.984375 3.78125 -4.890625 3.71875 -4.828125 C 3.703125 -4.8125 3.703125 -4.796875 3.6875 -4.796875 C 3.671875 -4.796875 3.671875 -4.9375 3.671875 -4.96875 C 3.671875 -5.296875 3.734375 -6.015625 4.359375 -6.625 C 4.484375 -6.75 4.484375 -6.765625 4.484375 -6.796875 C 4.484375 -6.875 4.4375 -6.90625 4.390625 -6.90625 C 4.28125 -6.90625 3.453125 -6.15625 3.453125 -4.96875 C 3.453125 -4.375 3.6875 -3.921875 4.109375 -3.921875 C 4.46875 -3.921875 4.640625 -4.203125 4.640625 -4.453125 Z M 4.640625 -4.453125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-6">
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-7">
<path style="stroke:none;" d="M 2.078125 -1.9375 C 2.296875 -1.890625 3.109375 -1.734375 3.109375 -1.015625 C 3.109375 -0.515625 2.765625 -0.109375 1.984375 -0.109375 C 1.140625 -0.109375 0.78125 -0.671875 0.59375 -1.53125 C 0.5625 -1.65625 0.5625 -1.6875 0.453125 -1.6875 C 0.328125 -1.6875 0.328125 -1.625 0.328125 -1.453125 L 0.328125 -0.125 C 0.328125 0.046875 0.328125 0.109375 0.4375 0.109375 C 0.484375 0.109375 0.5 0.09375 0.6875 -0.09375 C 0.703125 -0.109375 0.703125 -0.125 0.890625 -0.3125 C 1.328125 0.09375 1.78125 0.109375 1.984375 0.109375 C 3.125 0.109375 3.59375 -0.5625 3.59375 -1.28125 C 3.59375 -1.796875 3.296875 -2.109375 3.171875 -2.21875 C 2.84375 -2.546875 2.453125 -2.625 2.03125 -2.703125 C 1.46875 -2.8125 0.8125 -2.9375 0.8125 -3.515625 C 0.8125 -3.875 1.0625 -4.28125 1.921875 -4.28125 C 3.015625 -4.28125 3.078125 -3.375 3.09375 -3.078125 C 3.09375 -2.984375 3.1875 -2.984375 3.203125 -2.984375 C 3.34375 -2.984375 3.34375 -3.03125 3.34375 -3.21875 L 3.34375 -4.234375 C 3.34375 -4.390625 3.34375 -4.46875 3.234375 -4.46875 C 3.1875 -4.46875 3.15625 -4.46875 3.03125 -4.34375 C 3 -4.3125 2.90625 -4.21875 2.859375 -4.1875 C 2.484375 -4.46875 2.078125 -4.46875 1.921875 -4.46875 C 0.703125 -4.46875 0.328125 -3.796875 0.328125 -3.234375 C 0.328125 -2.890625 0.484375 -2.609375 0.75 -2.390625 C 1.078125 -2.140625 1.359375 -2.078125 2.078125 -1.9375 Z M 2.078125 -1.9375 "/>
</symbol>
<symbol overflow="visible" id="glyph0-8">
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-9">
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-10">
<path style="stroke:none;" d="M 1.53125 -5.875 C 1.53125 -6.46875 1.28125 -6.921875 0.859375 -6.921875 C 0.515625 -6.921875 0.328125 -6.65625 0.328125 -6.390625 C 0.328125 -6.125 0.5 -5.859375 0.859375 -5.859375 C 1.0625 -5.859375 1.203125 -5.96875 1.25 -6.015625 C 1.265625 -6.046875 1.28125 -6.046875 1.28125 -6.046875 C 1.3125 -6.046875 1.3125 -5.90625 1.3125 -5.875 C 1.3125 -5.546875 1.234375 -4.828125 0.609375 -4.21875 C 0.484375 -4.09375 0.484375 -4.078125 0.484375 -4.046875 C 0.484375 -3.984375 0.53125 -3.9375 0.59375 -3.9375 C 0.703125 -3.9375 1.53125 -4.6875 1.53125 -5.875 Z M 3.453125 -5.875 C 3.453125 -6.46875 3.21875 -6.921875 2.796875 -6.921875 C 2.4375 -6.921875 2.265625 -6.65625 2.265625 -6.390625 C 2.265625 -6.125 2.4375 -5.859375 2.796875 -5.859375 C 2.984375 -5.859375 3.125 -5.96875 3.1875 -6.015625 C 3.203125 -6.046875 3.203125 -6.046875 3.21875 -6.046875 C 3.234375 -6.046875 3.234375 -5.90625 3.234375 -5.875 C 3.234375 -5.546875 3.171875 -4.828125 2.546875 -4.21875 C 2.421875 -4.09375 2.421875 -4.078125 2.421875 -4.046875 C 2.421875 -3.984375 2.46875 -3.9375 2.515625 -3.9375 C 2.625 -3.9375 3.453125 -4.6875 3.453125 -5.875 Z M 3.453125 -5.875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-11">
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-12">
<path style="stroke:none;" d="M 1.90625 -4.453125 C 1.90625 -4.71875 1.75 -4.984375 1.390625 -4.984375 C 1.1875 -4.984375 1.046875 -4.890625 0.984375 -4.828125 C 0.984375 -4.8125 0.96875 -4.796875 0.953125 -4.796875 C 0.9375 -4.796875 0.9375 -4.9375 0.9375 -4.96875 C 0.9375 -5.296875 1 -6.015625 1.640625 -6.625 C 1.75 -6.75 1.75 -6.765625 1.75 -6.796875 C 1.75 -6.875 1.703125 -6.90625 1.65625 -6.90625 C 1.546875 -6.90625 0.71875 -6.15625 0.71875 -4.96875 C 0.71875 -4.375 0.953125 -3.921875 1.390625 -3.921875 C 1.734375 -3.921875 1.90625 -4.203125 1.90625 -4.453125 Z M 1.90625 -4.453125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-13">
<path style="stroke:none;" d="M 2.046875 -5.875 C 2.046875 -6.46875 1.8125 -6.921875 1.390625 -6.921875 C 1.03125 -6.921875 0.859375 -6.65625 0.859375 -6.390625 C 0.859375 -6.125 1.03125 -5.859375 1.390625 -5.859375 C 1.578125 -5.859375 1.71875 -5.96875 1.78125 -6.015625 C 1.796875 -6.046875 1.796875 -6.046875 1.8125 -6.046875 C 1.828125 -6.046875 1.828125 -5.90625 1.828125 -5.875 C 1.828125 -5.546875 1.765625 -4.828125 1.140625 -4.21875 C 1.015625 -4.09375 1.015625 -4.078125 1.015625 -4.046875 C 1.015625 -3.984375 1.0625 -3.9375 1.109375 -3.9375 C 1.21875 -3.9375 2.046875 -4.6875 2.046875 -5.875 Z M 2.046875 -5.875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-14">
<path style="stroke:none;" d="M 1.90625 -3.765625 C 1.90625 -4.0625 1.671875 -4.296875 1.390625 -4.296875 C 1.09375 -4.296875 0.859375 -4.0625 0.859375 -3.765625 C 0.859375 -3.484375 1.09375 -3.234375 1.390625 -3.234375 C 1.671875 -3.234375 1.90625 -3.484375 1.90625 -3.765625 Z M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-15">
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
</symbol>
</g>
</defs>
<g id="surface1">
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="3.321" y="39.139"/>
<use xlink:href="#glyph0-2" x="7.748379" y="39.139"/>
<use xlink:href="#glyph0-1" x="13.00664" y="39.139"/>
<use xlink:href="#glyph0-3" x="17.434019" y="39.139"/>
<use xlink:href="#glyph0-4" x="20.201629" y="39.139"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="27.946555" y="39.139"/>
<use xlink:href="#glyph0-6" x="32.927855" y="39.139"/>
<use xlink:href="#glyph0-7" x="37.909155" y="39.139"/>
<use xlink:href="#glyph0-8" x="41.838404" y="39.139"/>
<use xlink:href="#glyph0-9" x="47.373625" y="39.139"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-10" x="51.195278" y="39.139"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-11" x="75.926" y="39.139"/>
<use xlink:href="#glyph0-12" x="79.800455" y="39.139"/>
<use xlink:href="#glyph0-6" x="82.568065" y="39.139"/>
<use xlink:href="#glyph0-13" x="87.549365" y="39.139"/>
<use xlink:href="#glyph0-14" x="90.316976" y="39.139"/>
<use xlink:href="#glyph0-15" x="93.084586" y="39.139"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-11" x="104.798" y="10.793"/>
<use xlink:href="#glyph0-12" x="108.672455" y="10.793"/>
<use xlink:href="#glyph0-7" x="111.440065" y="10.793"/>
<use xlink:href="#glyph0-13" x="115.369315" y="10.793"/>
<use xlink:href="#glyph0-14" x="118.136925" y="10.793"/>
<use xlink:href="#glyph0-15" x="120.904535" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-11" x="132.342" y="39.139"/>
<use xlink:href="#glyph0-12" x="136.216455" y="39.139"/>
<use xlink:href="#glyph0-8" x="138.984065" y="39.139"/>
<use xlink:href="#glyph0-13" x="144.519286" y="39.139"/>
<use xlink:href="#glyph0-14" x="147.286896" y="39.139"/>
<use xlink:href="#glyph0-15" x="150.054507" y="39.139"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-11" x="104.854" y="67.486"/>
<use xlink:href="#glyph0-12" x="108.728455" y="67.486"/>
<use xlink:href="#glyph0-9" x="111.496065" y="67.486"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-13" x="115.317719" y="67.486"/>
<use xlink:href="#glyph0-14" x="118.085329" y="67.486"/>
<use xlink:href="#glyph0-15" x="120.852939" y="67.486"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 29.950219 0.0005625 L 42.200219 0.0005625 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.194314 1.594313 C -1.096658 0.996656 0.00099875 0.0982188 0.297874 0.0005625 C 0.00099875 -0.101 -1.096658 -0.995531 -1.194314 -1.593187 " transform="matrix(1,0,0,-1,71.94822,36.649)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 58.96975 8.500563 C 60.051781 16.453688 64.102563 21.688063 71.106469 24.551344 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.196589 1.594396 C -1.095787 0.997796 0.00041427 0.0989642 0.301146 0.00111983 C -0.000438865 -0.0984224 -1.095804 -0.996384 -1.197467 -1.59426 " transform="matrix(0.92848,-0.38002,-0.38002,-0.92848,100.85363,12.09595)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 98.551781 24.727125 C 105.977563 21.688063 110.028344 16.453688 111.047875 8.953688 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195717 1.592423 C -1.095615 0.995823 -0.00039703 0.0985073 0.297263 -0.00104224 C 0.000389063 -0.0985566 -1.094776 -0.997497 -1.195606 -1.594358 " transform="matrix(0.1348,0.99165,0.99165,-0.1348,140.7969,27.69336)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.110375 -8.499437 C 110.012719 -16.468187 105.946313 -21.706469 98.918969 -24.56975 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195342 1.594526 C -1.094949 0.994081 -0.000119528 0.0979331 0.300979 0.00052249 C -0.000645038 -0.0995886 -1.097397 -0.994901 -1.194527 -1.594821 " transform="matrix(-0.92848,0.37822,0.37822,0.92848,128.66988,61.21771)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 71.586938 -24.741625 C 64.133813 -21.706469 60.067406 -16.468187 59.03225 -8.956469 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195362 1.595896 C -1.096801 0.9954 0.00108287 0.0998119 0.298511 -0.000206965 C 0.00101106 -0.101074 -1.095391 -0.998 -1.197185 -1.594559 " transform="matrix(-0.13647,-0.99165,-0.99165,0.13647,88.78272,45.60464)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

+190
View File
@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="321.677pt" height="185.575pt" viewBox="0 0 321.677 185.575" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 1.90625 -3.765625 C 1.90625 -4.0625 1.671875 -4.296875 1.390625 -4.296875 C 1.09375 -4.296875 0.859375 -4.0625 0.859375 -3.765625 C 0.859375 -3.484375 1.09375 -3.234375 1.390625 -3.234375 C 1.671875 -3.234375 1.90625 -3.484375 1.90625 -3.765625 Z M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
</symbol>
<symbol overflow="visible" id="glyph1-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph1-1">
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
</symbol>
<symbol overflow="visible" id="glyph1-2">
<path style="stroke:none;" d="M 4.6875 -3.765625 C 4.703125 -3.8125 4.71875 -3.875 4.71875 -3.9375 C 4.71875 -4.109375 4.609375 -4.203125 4.4375 -4.203125 C 4.34375 -4.203125 4.0625 -4.140625 4.03125 -3.78125 C 3.84375 -4.140625 3.5 -4.40625 3.09375 -4.40625 C 1.96875 -4.40625 0.734375 -3.015625 0.734375 -1.578125 C 0.734375 -0.59375 1.328125 0 2.046875 0 C 2.640625 0 3.109375 -0.46875 3.203125 -0.578125 L 3.21875 -0.5625 C 3.015625 0.3125 2.890625 0.734375 2.890625 0.75 C 2.84375 0.84375 2.515625 1.828125 1.453125 1.828125 C 1.265625 1.828125 0.9375 1.8125 0.65625 1.71875 C 0.953125 1.640625 1.0625 1.375 1.0625 1.203125 C 1.0625 1.046875 0.953125 0.859375 0.6875 0.859375 C 0.46875 0.859375 0.15625 1.03125 0.15625 1.4375 C 0.15625 1.84375 0.515625 2.046875 1.46875 2.046875 C 2.71875 2.046875 3.4375 1.265625 3.59375 0.671875 Z M 3.40625 -1.28125 C 3.34375 -1.015625 3.109375 -0.765625 2.890625 -0.578125 C 2.6875 -0.40625 2.375 -0.21875 2.078125 -0.21875 C 1.578125 -0.21875 1.4375 -0.734375 1.4375 -1.140625 C 1.4375 -1.609375 1.71875 -2.796875 2 -3.296875 C 2.265625 -3.78125 2.6875 -4.1875 3.109375 -4.1875 C 3.765625 -4.1875 3.90625 -3.375 3.90625 -3.328125 C 3.90625 -3.28125 3.890625 -3.21875 3.875 -3.1875 Z M 3.40625 -1.28125 "/>
</symbol>
<symbol overflow="visible" id="glyph2-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph2-1">
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
</symbol>
<symbol overflow="visible" id="glyph2-2">
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
</symbol>
<symbol overflow="visible" id="glyph2-3">
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
</symbol>
<symbol overflow="visible" id="glyph3-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph3-1">
<path style="stroke:none;" d="M 0.84375 -0.4375 C 0.828125 -0.34375 0.78125 -0.171875 0.78125 -0.15625 C 0.78125 0 0.90625 0.0625 1.015625 0.0625 C 1.140625 0.0625 1.25 -0.015625 1.296875 -0.078125 C 1.328125 -0.140625 1.375 -0.375 1.421875 -0.515625 C 1.453125 -0.640625 1.53125 -0.96875 1.5625 -1.140625 C 1.609375 -1.296875 1.65625 -1.453125 1.6875 -1.609375 C 1.765625 -1.890625 1.78125 -1.953125 1.984375 -2.234375 C 2.171875 -2.515625 2.5 -2.875 3.03125 -2.875 C 3.421875 -2.875 3.4375 -2.515625 3.4375 -2.390625 C 3.4375 -1.96875 3.140625 -1.203125 3.03125 -0.90625 C 2.953125 -0.703125 2.921875 -0.640625 2.921875 -0.53125 C 2.921875 -0.15625 3.21875 0.0625 3.578125 0.0625 C 4.28125 0.0625 4.578125 -0.890625 4.578125 -1 C 4.578125 -1.09375 4.5 -1.09375 4.46875 -1.09375 C 4.375 -1.09375 4.375 -1.046875 4.34375 -0.96875 C 4.1875 -0.40625 3.875 -0.125 3.609375 -0.125 C 3.453125 -0.125 3.421875 -0.21875 3.421875 -0.375 C 3.421875 -0.53125 3.46875 -0.625 3.59375 -0.9375 C 3.671875 -1.15625 3.953125 -1.890625 3.953125 -2.28125 C 3.953125 -2.953125 3.421875 -3.078125 3.046875 -3.078125 C 2.46875 -3.078125 2.078125 -2.71875 1.875 -2.4375 C 1.828125 -2.921875 1.421875 -3.078125 1.125 -3.078125 C 0.828125 -3.078125 0.671875 -2.859375 0.578125 -2.703125 C 0.421875 -2.4375 0.328125 -2.046875 0.328125 -2 C 0.328125 -1.921875 0.421875 -1.921875 0.453125 -1.921875 C 0.546875 -1.921875 0.546875 -1.9375 0.59375 -2.125 C 0.703125 -2.53125 0.84375 -2.875 1.109375 -2.875 C 1.296875 -2.875 1.34375 -2.71875 1.34375 -2.53125 C 1.34375 -2.40625 1.28125 -2.140625 1.21875 -1.953125 C 1.171875 -1.765625 1.109375 -1.484375 1.078125 -1.328125 Z M 0.84375 -0.4375 "/>
</symbol>
<symbol overflow="visible" id="glyph4-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph4-1">
<path style="stroke:none;" d="M 4.421875 -6.3125 C 4.5625 -6.3125 4.8125 -6.3125 4.8125 -6.609375 C 4.8125 -6.921875 4.578125 -6.921875 4.421875 -6.921875 L 2.609375 -6.921875 C 2.28125 -6.921875 2.21875 -6.828125 2.21875 -6.515625 L 2.21875 0.421875 C 2.21875 0.734375 2.265625 0.828125 2.609375 0.828125 L 4.421875 0.828125 C 4.5625 0.828125 4.8125 0.828125 4.8125 0.53125 C 4.8125 0.21875 4.578125 0.21875 4.421875 0.21875 L 2.90625 0.21875 L 2.90625 -6.3125 Z M 4.421875 -6.3125 "/>
</symbol>
<symbol overflow="visible" id="glyph4-2">
<path style="stroke:none;" d="M 3.015625 -6.515625 C 3.015625 -6.8125 2.953125 -6.921875 2.609375 -6.921875 L 0.8125 -6.921875 C 0.65625 -6.921875 0.40625 -6.921875 0.40625 -6.625 C 0.40625 -6.3125 0.640625 -6.3125 0.8125 -6.3125 L 2.328125 -6.3125 L 2.328125 0.21875 L 0.8125 0.21875 C 0.65625 0.21875 0.40625 0.21875 0.40625 0.515625 C 0.40625 0.828125 0.640625 0.828125 0.8125 0.828125 L 2.609375 0.828125 C 2.9375 0.828125 3.015625 0.734375 3.015625 0.421875 Z M 3.015625 -6.515625 "/>
</symbol>
<symbol overflow="visible" id="glyph5-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph5-1">
<path style="stroke:none;" d="M 17.984375 -8.109375 C 19.03125 -7.21875 20.296875 -6.5625 21.109375 -6.1875 C 20.21875 -5.796875 19 -5.15625 17.984375 -4.28125 L 2.25 -4.28125 C 1.828125 -4.28125 1.359375 -4.28125 1.359375 -3.796875 C 1.359375 -3.296875 1.8125 -3.296875 2.234375 -3.296875 L 16.875 -3.296875 C 15.6875 -2.15625 14.390625 0.03125 14.390625 0.34375 C 14.390625 0.625 14.71875 0.625 14.875 0.625 C 15.0625 0.625 15.234375 0.625 15.34375 0.421875 C 15.859375 -0.515625 16.546875 -1.828125 18.171875 -3.265625 C 19.875 -4.78125 21.53125 -5.453125 22.828125 -5.828125 C 23.25 -5.96875 23.265625 -6 23.3125 -6.046875 C 23.375 -6.078125 23.375 -6.140625 23.375 -6.1875 C 23.375 -6.25 23.375 -6.296875 23.34375 -6.34375 L 23.265625 -6.390625 C 23.21875 -6.421875 23.1875 -6.4375 22.71875 -6.59375 C 19.375 -7.578125 16.90625 -9.84375 15.515625 -12.484375 C 15.234375 -12.984375 15.21875 -13.015625 14.875 -13.015625 C 14.71875 -13.015625 14.390625 -13.015625 14.390625 -12.734375 C 14.390625 -12.421875 15.65625 -10.265625 16.875 -9.09375 L 2.234375 -9.09375 C 1.8125 -9.09375 1.359375 -9.09375 1.359375 -8.59375 C 1.359375 -8.109375 1.828125 -8.109375 2.25 -8.109375 Z M 17.984375 -8.109375 "/>
</symbol>
</g>
</defs>
<g id="surface1">
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="24.404" y="10.792"/>
<use xlink:href="#glyph0-2" x="28.278455" y="10.792"/>
<use xlink:href="#glyph0-3" x="31.046065" y="10.792"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="3.321" y="52.219"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-1" x="9.014" y="53.713"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4.251844 -8.499781 L -18.056531 -36.109156 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="45.664" y="53.312"/>
<use xlink:href="#glyph0-2" x="49.538455" y="53.312"/>
<use xlink:href="#glyph0-3" x="52.306065" y="53.312"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 4.252063 -8.499781 L 17.009875 -34.019312 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="24.58" y="94.738"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-2" x="30.274" y="96.233"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 17.009875 -51.023219 L 3.205188 -78.628687 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="66.924" y="95.831"/>
<use xlink:href="#glyph0-2" x="70.798455" y="95.831"/>
<use xlink:href="#glyph0-3" x="73.566065" y="95.831"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25.509875 -51.023219 L 38.271594 -76.538844 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="45.84" y="137.258"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-3" x="51.534" y="138.752"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 38.271594 -93.54275 L 24.463 -121.148219 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="88.183" y="138.351"/>
<use xlink:href="#glyph0-2" x="92.057455" y="138.351"/>
<use xlink:href="#glyph0-3" x="94.825065" y="138.351"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 46.771594 -93.54275 L 59.533313 -119.058375 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="66.623" y="179.778"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph3-1" x="72.317" y="181.272"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 59.529406 -136.062281 L 45.724719 -163.66775 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph4-1" x="109.471" y="181.424"/>
<use xlink:href="#glyph4-2" x="114.701365" y="181.424"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 68.029406 -136.062281 L 81.345812 -162.687281 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph5-1" x="144.827" y="97.888"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="222.829" y="10.792"/>
<use xlink:href="#glyph0-2" x="226.703455" y="10.792"/>
<use xlink:href="#glyph0-3" x="229.471065" y="10.792"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="197.531" y="51.997"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="205.95936" y="51.997"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-1" x="211.655" y="53.492"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.177844 -8.499781 L 180.482531 -35.8865 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="244.089" y="53.312"/>
<use xlink:href="#glyph0-2" x="247.963455" y="53.312"/>
<use xlink:href="#glyph0-3" x="250.731065" y="53.312"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 202.677844 -8.499781 L 215.439562 -34.019312 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="218.79" y="94.517"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="227.21836" y="94.517"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-2" x="232.915" y="96.011"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.439562 -51.023219 L 201.74425 -78.406031 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="265.349" y="95.831"/>
<use xlink:href="#glyph0-2" x="269.223455" y="95.831"/>
<use xlink:href="#glyph0-3" x="271.991065" y="95.831"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 223.939562 -51.023219 L 236.697375 -76.538844 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="240.05" y="137.037"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="248.47836" y="137.037"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-3" x="254.174" y="138.531"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 236.697375 -93.54275 L 223.002062 -120.925562 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="286.609" y="138.351"/>
<use xlink:href="#glyph0-2" x="290.483455" y="138.351"/>
<use xlink:href="#glyph0-3" x="293.251065" y="138.351"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 245.197375 -93.54275 L 257.959094 -119.058375 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="260.833" y="179.556"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="269.26136" y="179.556"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph3-1" x="274.957" y="181.051"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 257.959094 -136.062281 L 244.263781 -163.449 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph4-1" x="307.896" y="181.424"/>
<use xlink:href="#glyph4-2" x="313.126365" y="181.424"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 266.455188 -136.062281 L 279.771594 -162.687281 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

+193
View File
@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256.353pt" height="142.641pt" viewBox="0 0 256.353 142.641" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 2.3125 -6.671875 C 2.21875 -6.796875 2.21875 -6.8125 2.03125 -6.8125 L 0.328125 -6.8125 L 0.328125 -6.5 L 0.625 -6.5 C 0.765625 -6.5 0.96875 -6.484375 1.109375 -6.484375 C 1.34375 -6.453125 1.359375 -6.4375 1.359375 -6.25 L 1.359375 -1.046875 C 1.359375 -0.78125 1.359375 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.671875 -0.015625 1.171875 -0.03125 1.5 -0.03125 C 1.828125 -0.03125 2.3125 -0.015625 2.65625 0 L 2.65625 -0.3125 C 1.640625 -0.3125 1.640625 -0.78125 1.640625 -1.046875 L 1.640625 -6.234375 C 1.6875 -6.1875 1.6875 -6.171875 1.734375 -6.109375 L 5.796875 -0.125 C 5.890625 -0.015625 5.90625 0 5.96875 0 C 6.109375 0 6.109375 -0.0625 6.109375 -0.265625 L 6.109375 -5.765625 C 6.109375 -6.03125 6.109375 -6.5 7.140625 -6.5 L 7.140625 -6.8125 C 6.78125 -6.796875 6.296875 -6.78125 5.96875 -6.78125 C 5.640625 -6.78125 5.15625 -6.796875 4.8125 -6.8125 L 4.8125 -6.5 C 5.828125 -6.5 5.828125 -6.03125 5.828125 -5.765625 L 5.828125 -1.5 Z M 2.3125 -6.671875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 4.6875 -2.140625 C 4.6875 -3.40625 3.703125 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.28125 -3.375 0.28125 -2.140625 C 0.28125 -0.84375 1.3125 0.109375 2.484375 0.109375 C 3.6875 0.109375 4.6875 -0.875 4.6875 -2.140625 Z M 2.5 -0.140625 C 2.0625 -0.140625 1.625 -0.34375 1.359375 -0.8125 C 1.109375 -1.25 1.109375 -1.859375 1.109375 -2.21875 C 1.109375 -2.609375 1.109375 -3.140625 1.34375 -3.578125 C 1.609375 -4.03125 2.078125 -4.25 2.484375 -4.25 C 2.921875 -4.25 3.34375 -4.03125 3.609375 -3.59375 C 3.875 -3.171875 3.875 -2.59375 3.875 -2.21875 C 3.875 -1.859375 3.875 -1.3125 3.65625 -0.875 C 3.421875 -0.421875 2.984375 -0.140625 2.5 -0.140625 Z M 2.5 -0.140625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-4">
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-5">
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-6">
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
</symbol>
<symbol overflow="visible" id="glyph0-7">
<path style="stroke:none;" d="M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-8">
<path style="stroke:none;" d="M 5.796875 -2.578125 L 5.546875 -2.578125 C 5.4375 -1.5625 5.296875 -0.3125 3.546875 -0.3125 L 2.734375 -0.3125 C 2.265625 -0.3125 2.25 -0.375 2.25 -0.703125 L 2.25 -6.015625 C 2.25 -6.359375 2.25 -6.5 3.1875 -6.5 L 3.515625 -6.5 L 3.515625 -6.8125 C 3.15625 -6.78125 2.25 -6.78125 1.84375 -6.78125 C 1.453125 -6.78125 0.671875 -6.78125 0.328125 -6.8125 L 0.328125 -6.5 L 0.5625 -6.5 C 1.328125 -6.5 1.359375 -6.390625 1.359375 -6.03125 L 1.359375 -0.78125 C 1.359375 -0.421875 1.328125 -0.3125 0.5625 -0.3125 L 0.328125 -0.3125 L 0.328125 0 L 5.515625 0 Z M 5.796875 -2.578125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-9">
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-10">
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph1-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph1-1">
<path style="stroke:none;" d="M 4.6875 -3.765625 C 4.703125 -3.8125 4.71875 -3.875 4.71875 -3.9375 C 4.71875 -4.109375 4.609375 -4.203125 4.4375 -4.203125 C 4.34375 -4.203125 4.0625 -4.140625 4.03125 -3.78125 C 3.84375 -4.140625 3.5 -4.40625 3.09375 -4.40625 C 1.96875 -4.40625 0.734375 -3.015625 0.734375 -1.578125 C 0.734375 -0.59375 1.328125 0 2.046875 0 C 2.640625 0 3.109375 -0.46875 3.203125 -0.578125 L 3.21875 -0.5625 C 3.015625 0.3125 2.890625 0.734375 2.890625 0.75 C 2.84375 0.84375 2.515625 1.828125 1.453125 1.828125 C 1.265625 1.828125 0.9375 1.8125 0.65625 1.71875 C 0.953125 1.640625 1.0625 1.375 1.0625 1.203125 C 1.0625 1.046875 0.953125 0.859375 0.6875 0.859375 C 0.46875 0.859375 0.15625 1.03125 0.15625 1.4375 C 0.15625 1.84375 0.515625 2.046875 1.46875 2.046875 C 2.71875 2.046875 3.4375 1.265625 3.59375 0.671875 Z M 3.40625 -1.28125 C 3.34375 -1.015625 3.109375 -0.765625 2.890625 -0.578125 C 2.6875 -0.40625 2.375 -0.21875 2.078125 -0.21875 C 1.578125 -0.21875 1.4375 -0.734375 1.4375 -1.140625 C 1.4375 -1.609375 1.71875 -2.796875 2 -3.296875 C 2.265625 -3.78125 2.6875 -4.1875 3.109375 -4.1875 C 3.765625 -4.1875 3.90625 -3.375 3.90625 -3.328125 C 3.90625 -3.28125 3.890625 -3.21875 3.875 -3.1875 Z M 3.40625 -1.28125 "/>
</symbol>
<symbol overflow="visible" id="glyph1-2">
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
</symbol>
<symbol overflow="visible" id="glyph2-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph2-1">
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
</symbol>
<symbol overflow="visible" id="glyph2-2">
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
</symbol>
<symbol overflow="visible" id="glyph2-3">
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
</symbol>
<symbol overflow="visible" id="glyph2-4">
<path style="stroke:none;" d="M 3.6875 -1.140625 L 3.6875 -1.390625 L 2.90625 -1.390625 L 2.90625 -4.5 C 2.90625 -4.640625 2.90625 -4.703125 2.765625 -4.703125 C 2.671875 -4.703125 2.640625 -4.703125 2.578125 -4.59375 L 0.265625 -1.390625 L 0.265625 -1.140625 L 2.328125 -1.140625 L 2.328125 -0.578125 C 2.328125 -0.328125 2.328125 -0.25 1.75 -0.25 L 1.5625 -0.25 L 1.5625 0 C 1.921875 -0.015625 2.359375 -0.03125 2.609375 -0.03125 C 2.875 -0.03125 3.3125 -0.015625 3.671875 0 L 3.671875 -0.25 L 3.484375 -0.25 C 2.90625 -0.25 2.90625 -0.328125 2.90625 -0.578125 L 2.90625 -1.140625 Z M 2.375 -3.9375 L 2.375 -1.390625 L 0.53125 -1.390625 Z M 2.375 -3.9375 "/>
</symbol>
</g>
</defs>
<g id="surface1">
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="87.593" y="10.793"/>
<use xlink:href="#glyph0-2" x="95.06495" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="100.325203" y="10.793"/>
<use xlink:href="#glyph0-4" x="105.860423" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="113.605349" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="117.481" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="125.90936" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-1" x="131.605" y="12.287"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="136.074" y="10.793"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="16.727" y="53.313"/>
<use xlink:href="#glyph0-2" x="24.19895" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="29.459203" y="53.313"/>
<use xlink:href="#glyph0-4" x="34.994423" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="42.739349" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="46.615" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="55.04336" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-2" x="60.739" y="54.807"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="65.208" y="53.313"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14.169438 -8.502688 L -56.704594 -34.018313 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-7" x="3.321" y="93.867"/>
<use xlink:href="#glyph0-7" x="6.08861" y="93.867"/>
<use xlink:href="#glyph0-7" x="8.856221" y="93.867"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -77.950688 -51.022219 L -102.931156 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-7" x="74.187" y="93.867"/>
<use xlink:href="#glyph0-7" x="76.95461" y="93.867"/>
<use xlink:href="#glyph0-7" x="79.722221" y="93.867"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -63.782719 -51.022219 L -38.80225 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="158.459" y="53.313"/>
<use xlink:href="#glyph0-2" x="165.93095" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="171.191203" y="53.313"/>
<use xlink:href="#glyph0-4" x="176.726423" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="184.471349" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="188.347" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="196.77536" y="53.313"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-3" x="202.471" y="54.807"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="206.941" y="53.313"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14.1665 -8.502688 L 56.701656 -34.018313 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-7" x="145.053" y="93.867"/>
<use xlink:href="#glyph0-7" x="147.82061" y="93.867"/>
<use xlink:href="#glyph0-7" x="150.588221" y="93.867"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 63.783687 -51.022219 L 38.803219 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="193.892" y="95.832"/>
<use xlink:href="#glyph0-2" x="201.36395" y="95.832"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="206.624203" y="95.832"/>
<use xlink:href="#glyph0-4" x="212.159423" y="95.832"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="219.904349" y="95.832"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="223.78" y="95.832"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-2" x="232.20836" y="95.832"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-4" x="237.904" y="97.327"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="242.374" y="95.832"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 77.951656 -51.022219 L 99.217281 -76.537844 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-8" x="187.108" y="139.32"/>
<use xlink:href="#glyph0-4" x="193.334625" y="139.32"/>
<use xlink:href="#glyph0-9" x="197.762004" y="139.32"/>
<use xlink:href="#glyph0-10" x="202.743304" y="139.32"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 101.576656 -93.54175 L 86.553219 -120.580813 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-8" x="234.352" y="139.32"/>
<use xlink:href="#glyph0-4" x="240.578625" y="139.32"/>
<use xlink:href="#glyph0-9" x="245.006004" y="139.32"/>
<use xlink:href="#glyph0-10" x="249.987304" y="139.32"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.021969 -93.54175 L 126.045406 -120.580813 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

+148
View File
@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256.353pt" height="141.866pt" viewBox="0 0 256.353 141.866" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 2.3125 -6.671875 C 2.21875 -6.796875 2.21875 -6.8125 2.03125 -6.8125 L 0.328125 -6.8125 L 0.328125 -6.5 L 0.625 -6.5 C 0.765625 -6.5 0.96875 -6.484375 1.109375 -6.484375 C 1.34375 -6.453125 1.359375 -6.4375 1.359375 -6.25 L 1.359375 -1.046875 C 1.359375 -0.78125 1.359375 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.671875 -0.015625 1.171875 -0.03125 1.5 -0.03125 C 1.828125 -0.03125 2.3125 -0.015625 2.65625 0 L 2.65625 -0.3125 C 1.640625 -0.3125 1.640625 -0.78125 1.640625 -1.046875 L 1.640625 -6.234375 C 1.6875 -6.1875 1.6875 -6.171875 1.734375 -6.109375 L 5.796875 -0.125 C 5.890625 -0.015625 5.90625 0 5.96875 0 C 6.109375 0 6.109375 -0.0625 6.109375 -0.265625 L 6.109375 -5.765625 C 6.109375 -6.03125 6.109375 -6.5 7.140625 -6.5 L 7.140625 -6.8125 C 6.78125 -6.796875 6.296875 -6.78125 5.96875 -6.78125 C 5.640625 -6.78125 5.15625 -6.796875 4.8125 -6.8125 L 4.8125 -6.5 C 5.828125 -6.5 5.828125 -6.03125 5.828125 -5.765625 L 5.828125 -1.5 Z M 2.3125 -6.671875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 4.6875 -2.140625 C 4.6875 -3.40625 3.703125 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.28125 -3.375 0.28125 -2.140625 C 0.28125 -0.84375 1.3125 0.109375 2.484375 0.109375 C 3.6875 0.109375 4.6875 -0.875 4.6875 -2.140625 Z M 2.5 -0.140625 C 2.0625 -0.140625 1.625 -0.34375 1.359375 -0.8125 C 1.109375 -1.25 1.109375 -1.859375 1.109375 -2.21875 C 1.109375 -2.609375 1.109375 -3.140625 1.34375 -3.578125 C 1.609375 -4.03125 2.078125 -4.25 2.484375 -4.25 C 2.921875 -4.25 3.34375 -4.03125 3.609375 -3.59375 C 3.875 -3.171875 3.875 -2.59375 3.875 -2.21875 C 3.875 -1.859375 3.875 -1.3125 3.65625 -0.875 C 3.421875 -0.421875 2.984375 -0.140625 2.5 -0.140625 Z M 2.5 -0.140625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-4">
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-5">
<path style="stroke:none;" d="M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-6">
<path style="stroke:none;" d="M 5.796875 -2.578125 L 5.546875 -2.578125 C 5.4375 -1.5625 5.296875 -0.3125 3.546875 -0.3125 L 2.734375 -0.3125 C 2.265625 -0.3125 2.25 -0.375 2.25 -0.703125 L 2.25 -6.015625 C 2.25 -6.359375 2.25 -6.5 3.1875 -6.5 L 3.515625 -6.5 L 3.515625 -6.8125 C 3.15625 -6.78125 2.25 -6.78125 1.84375 -6.78125 C 1.453125 -6.78125 0.671875 -6.78125 0.328125 -6.8125 L 0.328125 -6.5 L 0.5625 -6.5 C 1.328125 -6.5 1.359375 -6.390625 1.359375 -6.03125 L 1.359375 -0.78125 C 1.359375 -0.421875 1.328125 -0.3125 0.5625 -0.3125 L 0.328125 -0.3125 L 0.328125 0 L 5.515625 0 Z M 5.796875 -2.578125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-7">
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
</symbol>
<symbol overflow="visible" id="glyph0-8">
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph1-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph1-1">
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
</symbol>
<symbol overflow="visible" id="glyph2-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph2-1">
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
</symbol>
<symbol overflow="visible" id="glyph2-2">
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
</symbol>
<symbol overflow="visible" id="glyph2-3">
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
</symbol>
<symbol overflow="visible" id="glyph2-4">
<path style="stroke:none;" d="M 3.6875 -1.140625 L 3.6875 -1.390625 L 2.90625 -1.390625 L 2.90625 -4.5 C 2.90625 -4.640625 2.90625 -4.703125 2.765625 -4.703125 C 2.671875 -4.703125 2.640625 -4.703125 2.578125 -4.59375 L 0.265625 -1.390625 L 0.265625 -1.140625 L 2.328125 -1.140625 L 2.328125 -0.578125 C 2.328125 -0.328125 2.328125 -0.25 1.75 -0.25 L 1.5625 -0.25 L 1.5625 0 C 1.921875 -0.015625 2.359375 -0.03125 2.609375 -0.03125 C 2.875 -0.03125 3.3125 -0.015625 3.671875 0 L 3.671875 -0.25 L 3.484375 -0.25 C 2.90625 -0.25 2.90625 -0.328125 2.90625 -0.578125 L 2.90625 -1.140625 Z M 2.375 -3.9375 L 2.375 -1.390625 L 0.53125 -1.390625 Z M 2.375 -3.9375 "/>
</symbol>
</g>
</defs>
<g id="surface1">
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="95.682" y="10.239"/>
<use xlink:href="#glyph0-2" x="103.15395" y="10.239"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="108.414203" y="10.239"/>
<use xlink:href="#glyph0-4" x="113.949423" y="10.239"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="121.696" y="10.239"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-1" x="127.39" y="11.734"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="24.816" y="52.759"/>
<use xlink:href="#glyph0-2" x="32.28795" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="37.548203" y="52.759"/>
<use xlink:href="#glyph0-4" x="43.083423" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="50.83" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-2" x="56.524" y="54.253"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -12.872563 -7.726906 L -57.993656 -34.793312 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="3.321" y="93.092"/>
<use xlink:href="#glyph0-5" x="6.08861" y="93.092"/>
<use xlink:href="#glyph0-5" x="8.856221" y="93.092"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -77.306156 -50.246437 L -102.931156 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="74.187" y="93.092"/>
<use xlink:href="#glyph0-5" x="76.95461" y="93.092"/>
<use xlink:href="#glyph0-5" x="79.722221" y="93.092"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -64.42725 -50.246437 L -38.80225 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="166.549" y="52.759"/>
<use xlink:href="#glyph0-2" x="174.02095" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="179.281203" y="52.759"/>
<use xlink:href="#glyph0-4" x="184.816423" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="192.562" y="52.759"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-3" x="198.256" y="54.253"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 12.873531 -7.726906 L 57.994625 -34.793312 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-5" x="145.053" y="93.092"/>
<use xlink:href="#glyph0-5" x="147.82061" y="93.092"/>
<use xlink:href="#glyph0-5" x="150.588221" y="93.092"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 64.428219 -50.246437 L 38.803219 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="201.982" y="95.279"/>
<use xlink:href="#glyph0-2" x="209.45395" y="95.279"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="214.714203" y="95.279"/>
<use xlink:href="#glyph0-4" x="220.249423" y="95.279"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="227.995" y="95.279"/>
</g>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph2-4" x="233.689" y="96.773"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 77.303219 -50.246437 L 99.865719 -77.312844 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="187.108" y="138.545"/>
<use xlink:href="#glyph0-4" x="193.334625" y="138.545"/>
<use xlink:href="#glyph0-7" x="197.762004" y="138.545"/>
<use xlink:href="#glyph0-8" x="202.743304" y="138.545"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 102.006344 -92.765969 L 86.553219 -120.582375 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="234.352" y="138.545"/>
<use xlink:href="#glyph0-4" x="240.578625" y="138.545"/>
<use xlink:href="#glyph0-7" x="245.006004" y="138.545"/>
<use xlink:href="#glyph0-8" x="249.987304" y="138.545"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 110.592281 -92.765969 L 126.045406 -120.582375 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

+3291
View File
File diff suppressed because it is too large Load Diff