-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTP3.hs
More file actions
220 lines (166 loc) · 5.63 KB
/
TP3.hs
File metadata and controls
220 lines (166 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import Data.List
import Data.Ord
any' :: (a -> Bool) -> [a] -> Bool
any' p (x:xs) = p x || any' p xs
any' p [] = False
-- ZF expressions / liste en comprehension
rectangle :: [(Int,Int)]
rectangle = [ (x,y) | x<-[1..n], y <-[1..m] ]
where n = 3
m = 2
triangle :: [(Int,Int)]
triangle = [ (x,y) | x<-[1..n], y <-[1..m], y<=x ]
where n = 4
m = 5
triangle' :: [(Int,Int)]
triangle' = [ (x,y) | x<-[1..n], y <-[1..x] ]
where n = 4
m = 5
myQSort :: Ord a => [a] -> [a]
myQSort (x:xs) = myQSort [y | y <- xs, y<= x] ++ x : myQSort [ y | y <- xs, y>x ]
myQSort [] = []
-- but du TP : trouver les solutions pour le compte est bon
-- sous listes et permutations pour considerer les nombres utilises dans le calcul
-- sous liste
-- deja vu au bloc 2
sousListes :: [a] -> [[a]]
sousListes [] = [[]]
sousListes (x:xs) = ys ++ map (x:) ys
where ys = sousListes xs
injections :: a -> [a] -> [[a]]
injections y (x:xs) = (y:x:xs) : map (x:) (injections y xs)
injections y [] = [[y]]
permuts :: [a] -> [[a]]
permuts (x:xs) = concat (map (injections x) (permuts xs))
permuts [] = [[]]
permSousListes :: [a] -> [[a]]
permSousListes xs = [zs | ys <- sousListes xs, not (null ys), zs <- permuts ys]
partitionStricte :: [a] -> [([a],[a])]
partitionStricte [x1,x2] = [([x1],[x2])]
partitionStricte (x1:xs) = ([x1],xs) : map (\(ls,rs) -> (x1:ls,rs)) (partitionStricte xs)
-- I) generate and test (brute force)
data Op = Add | Sub | Mul | Div deriving Eq --deriving Show
instance Show Op where
show Add = "+"
show Sub = "-"
show Mul = "*"
show Div = "/"
validOp :: Op -> Int -> Int -> Bool
validOp Sub x y = x>y
validOp Div x y = y/=0 && x `mod` y==0
validOp _ _ _ = True
evalOp :: Op -> Int -> Int -> Int
evalOp Add x y = x+y
evalOp Sub x y = x-y
evalOp Mul x y = x*y
evalOp Div x y = x `div` y
data Exp = Val Int | App Op Exp Exp
deriving Show
-- step1: enumerate expressions
exps :: [Int] -> [Exp]
exps [n] = [Val n]
exps ns = [ App o g d
| (gs,ds) <- partitionStricte ns
, g <- exps gs
, d <- exps ds
, o <- [Add,Sub,Mul,Div]
]
-- step2: filter out invalid expressions
evalExp :: Exp -> Int
evalExp (App o l r) = evalOp o (evalExp l) (evalExp r)
evalExp (Val n) = n
validExp :: Exp -> Bool
validExp (Val n) = n>0
validExp (App o l r) = validExp l && validExp r && validOp o (evalExp l) (evalExp r)
solutions :: [Int] -> Int -> [Exp]
solutions nombres cible =
let ns = permSousListes nombres
es = concat (map exps ns)
es' = filter validExp es
es'' = filter (\e -> evalExp e ==cible) es'
in es''
test1 = solutions [1,3,7,10,25,50] 765
-- II) fusionner la generation et le filtrage des expressions invalides
exps2 :: [Int] -> [Exp]
exps2 [n] = [Val n]
exps2 ns = [ App o g d
| (gs,ds) <- partitionStricte ns
, g <- exps2 gs
, d <- exps2 ds
, o <- [Add,Sub,Mul,Div]
, validExp (App o g d)
]
solutions2 :: [Int] -> Int -> [Exp]
solutions2 nombres cible =
let ns = permSousListes nombres
es = concat (map exps2 ns)
es' = filter (\e -> evalExp e ==cible) es
in es'
test2 = solutions2 [1,3,7,10,25,50] 765
-- III) memoiser l'evaluation
data Exp' = Val' Int | App' Op Exp' Exp' Int
evalExp' :: Exp' -> Int
evalExp' (Val' n) = n
evalExp' (App' _ _ _ n) = n
exps3 :: [Int] -> [Exp']
exps3 [n] = [Val' n]
exps3 ns = [ App' o g d (evalOp o (evalExp' g) (evalExp' d))
| (gs, ds)<- partitionStricte ns
, g <- exps3 gs
, d <- exps3 ds
, o <- [Add,Sub,Mul,Div]
, validOp o (evalExp' g) (evalExp' d)
]
solutions3 :: [Int] -> Int -> [Exp']
solutions3 nombres cible =
let ns = permSousListes nombres
es = concat (map exps3 ns)
es' = filter (\e -> evalExp' e ==cible) es
in es'
test3 = solutions3 [1,3,7,10,25,50] 765
-- IV) exploiter des proprietes arithmetiques
-- pour reduire l'espace de recherche on ajoute les regles :
-- - pas de multiplication par 1
-- - pas de division par 1
-- - addition et multiplication commutatives (ne considerer qu'un sens (quand les deux operandes sont differents))
validOp' :: Op -> Int -> Int -> Bool
validOp' Sub x y = x>y
validOp' Div x y = y/=0 && x `mod` y==0 && y/=1
validOp' Mul x y = y/=1 && x/=1 && x<y
validOp' Add x y = x<y
exps4 :: [Int] -> [Exp']
exps4 [n] = [Val' n]
exps4 ns = [ App' o g d (evalOp o (evalExp' g) (evalExp' d))
| (gs, ds)<- partitionStricte ns
, g <- exps4 gs
, d <- exps4 ds
, o <- [Add,Sub,Mul,Div]
, validOp' o (evalExp' g) (evalExp' d)
]
solutions4 :: [Int] -> Int -> [Exp']
solutions4 nombres cible =
let ns = permSousListes nombres
es = concat (map exps4 ns)
es' = filter (\e -> evalExp' e ==cible) es
in es'
test4 = solutions4 [1,3,7,10,25,50] 765
-- nombre de solutions
nombreDeSolutions3 = length test3
nombreDeSolutions4 = length test4
-- V) ne retourner qu'une solution exacte ou bien la plus proche
solutions5 :: [Int] -> Int -> Exp'
solutions5 nombres cible =
let ns = permSousListes nombres
es = concat (map exps4 ns)
es' = head (sortOn (\e -> abs (evalExp' e - cible)) es)
in es'
test5 = solutions5 [1,3,7,10,25,50] 765
test6 = solutions5 [1,3,7,10,25,50] 831
-- VI) affichez les expressions sous forme infixe en evitant des parentheses inutiles
instance Show Exp' where
show (Val' n) = show n
show (App' o (Val' g) (Val' d) n) = show g ++ show o ++ show d
show (App' o g d n) | (o == Mul) || (o== Add) = show g ++ show o ++ show d
| otherwise = "(" ++ show g++")" ++ show o ++ "(" ++ show d++")"
-- VII) generalisez certaines fonctions avec de l'ordre superieur afin de reduire la duplication de code dans ce programme
-- misc : cherchez les solutions avec le moins d'operations en priorite