This file is indexed.

/usr/share/hol88-2.02.19940316/Library/window/win.ml is in hol88-library-source 2.02.19940316-35.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
% --------------------------------------------------------------------- %
%       Copyright (c) Jim Grundy 1992                                   %
%       All rights reserved                                             %
%                                                                       %
% Jim Grundy, hereafter referred to as `the Author', retains the        %
% copyright and all other legal rights to the Software contained in     %
% this file, hereafter referred to as `the Software'.                   %
%                                                                       %
% The Software is made available free of charge on an `as is' basis.    %
% No guarantee, either express or implied, of maintenance, reliability, %
% merchantability or suitability for any purpose is made by the Author. %
%                                                                       %
% The user is granted the right to make personal or internal use        %
% of the Software provided that both:                                   %
% 1. The Software is not used for commercial gain.                      %
% 2. The user shall not hold the Author liable for any consequences     %
%    arising from use of the Software.                                  %
%                                                                       %
% The user is granted the right to further distribute the Software      %
% provided that both:                                                   %
% 1. The Software and this statement of rights is not modified.         %
% 2. The Software does not form part or the whole of a system           %
%    distributed for commercial gain.                                   %
%                                                                       %
% The user is granted the right to modify the Software for personal or  %
% internal use provided that all of the following conditions are        %
% observed:                                                             %
% 1. The user does not distribute the modified software.                %
% 2. The modified software is not used for commercial gain.             %
% 3. The Author retains all rights to the modified software.            %
%                                                                       %
% Anyone seeking a licence to use this software for commercial purposes %
% is invited to contact the Author.                                     %
% --------------------------------------------------------------------- %
%============================================================================%
% CONTENTS: the core functional window inference system                      %
%============================================================================%
%$Id: win.ml,v 3.1 1993/12/07 14:15:19 jg Exp $%

% A window is a tuple with the following components.                        %
%   A theorem which records the progress of the window.                     %
%   A set of theorems, the hyps of which are set of hyptheses which can     %
%       appear in the window's theorem.                                     %
%   A set of theorems relavent to the window.                               %
%   A set of suppositions relavent to the window.                           %
%   A list of variables which are implicitly bound by this window.          %
%       (The closer to the front of the list the tighter the binding.)      %
lettype window = (thm # (thm list) # (thm list) # (goal list) # (term list));;

% Find the theorem being held by a window.                                  %
let win_thm ((th, _, _, _, _):window) = th;;

% Find the relation being preserved by a window.                            %
let relation ((th, _, _, _, _):window) = rator (rator (concl th));;

% Find the focus of a window.                                               %
let focus ((th, _, _, _, _):window) = rand (rator (concl th));;

% Find the original focus of a window.                                      %
let origin ((th, _, _, _, _):window) = rand (concl th);;

% Find the variables bound by a window.                                     %
let bound ((_, _, _, _, bnd):window) = bnd;;

% Find the hypotheses theorems a window.                                    %
let hyp_thms ((_, hyps, _, _, _):window) = hyps;;

% Find the hypotheses of a window.                                          %
let hypotheses ((_, hyps, _, _, _):window) = term_setify (flat (map hyp hyps));;

% Find the displayed hypotheses of a window.                                %
let disp_hypotheses ((_, hyps, _, _, _):window) =
    term_setify (subtract (map concl hyps) [true_tm]);;

% Find the _all_ hypotheses of a window.                                    %
let all_hypotheses w = term_union (hypotheses w) (disp_hypotheses w);;

% Find the hypotheses that have been used in a window.                      %
let used_hypotheses ((th, _, _, _, _):window) = hyp th;;

% Find the relavent theorems of a window.                                   %
let lemma_thms ((_, _, thms, _, _):window) = thms;;

% Find the suppositions of a window.                                        %
let suppositions ((_, _, _, sups, _):window) = sups;;

% Find the conjectures of a window.                                         %
let conjectures win = 
    let hyps = all_hypotheses win in
    let sups = suppositions win in
        term_setify (map snd (filter (\s. term_subset (fst s) hyps) sups));;

% Find the used conjectures of a window.                                    %
let used_conjectures win =
    let used = hyp (win_thm win) in
    let hyps = all_hypotheses win in
    filter (\t. not (term_mem t hyps)) used;;

% Find the lemmas of a window.                                              %
let lemmas win =
    let handcs = term_union (all_hypotheses win) (conjectures win) in
    let thms = lemma_thms win in
        term_setify (map concl (filter (\t. term_subset (hyp t) handcs) thms));;

% The context of a window.                                                  %
let context win =
    term_setify ((all_hypotheses win) @ (lemmas win) @ (conjectures win));;

% Start transforming "foc" to arrive at (hyps |- foc' rel foc).          %
% Call with create_win "rel foc" [hypotheses] [lemma_thms]               %
let make_win relfoc sups bnds hyps thms = 
    let rel = rator relfoc in
    let foc = rand relfoc in
        (
            (reflexive (mk_comb (mk_comb (rel, foc), foc))),
            (thm_setify hyps),
            (thm_setify thms),
            (goal_setify sups),
        bnds
        ):window;;

let create_win relfoc hyps = make_win relfoc [] [] (map ASSUME hyps);;

% Transform a window (as above) with function fn and return the theorem.    %
let transform relfoc hyps thms fn =
    win_thm (fn (create_win relfoc hyps thms));;

% Hand back, if possible, a theorem with conclusion c and hypotheses, a %
%   subset of the current hypotheses and conjectures.                   %
%   (Tries to avoid assumptions which are bound by the window.)         %
%   (The fewer unused conjectures the better)                           %
let get_thm c win = 
    if ((term_mem c (lemmas win)) or (term_mem c (disp_hypotheses win)))
    then
        let okhyps = term_union (used_hypotheses win) (hypotheses win) in
        let handcs = term_union (hypotheses win) (conjectures win) in
        let bnds = bound win in
        let thms = (lemma_thms win) @
                   (hyp_thms win) @
                   (map ASSUME (hypotheses win))
        in
        let potentials =
            filter
                (\th. (aconv (concl th) c) & (term_subset (hyp th) handcs))
                thms
        in
        let better (t1,t2) =
            let nh1 = filter (\h. not (term_mem h okhyps)) (hyp t1) in
            let nh2 = filter (\h. not (term_mem h okhyps)) (hyp t2) in
            let bh1 = filter (\h. not (null (intersect (frees h) bnds))) nh1 in
            let bh2 = filter (\h. not (null (intersect (frees h) bnds))) nh2 in
                if (length bh1) < (length bh2) then
                    true
                else if (length bh1) > (length bh2) then
                    false
                else % (length bh1) = (length bh2) %
                    if (length nh1) < (length nh2) then
                        true
                    else if (length nh1) > (length nh2) then
                        false
                    else % (length nh1) = (length nh2) %
                        if (dest_thm t1) = ([concl t1], concl t1) then
                            true
                        else if (dest_thm t2) = ([concl t2], concl t2) then
                            false
                        else % they are both just assumed. %
                            if (concl t1) = c then
                                true
                            else
                                false
        in
            best better potentials
    else
        ASSUME c;;

% Add a supposition to a window.                                            %
let add_suppose sup win = 
    let thms = lemma_thms win in
    letref sups = suppositions win in
        if  (not (exists (\s.better_goal s sup) sups)) &
            (not (exists (\s.better_goal s sup) (map dest_thm thms))) &
            (not (term_mem (snd sup) (true_tm.(fst sup))))
        then
        (
            letref newsups = goal_setify
            (sup.(sups @ (map dest_thm thms)))
        in
                while (not (goal_set_equal sups newsups)) do
                (
                    sups := newsups;
                    newsups :=
                        goal_setify
                (   sups
                            @   (flat (map (\s. map (prove_hyp s) sups) sups))
                            )
                );
            sups := filter (\s1.not (exists (\s2.better_goal s2 s1)
                                            (map dest_thm thms))) sups;
            (win_thm win, hyp_thms win, thms, sups, bound win)
        )
        else
            win;;

% Add a conjecture to the current window.                                   %
let conjecture tm win =
    add_suppose (hypotheses win, tm) win;;

% Add a theorem to a window's relavent theorems set.                    %
let add_theorem th win = 
    letref thms = lemma_thms win in
        if  (not (exists (\t.better_thm t th) (lemma_thms win))) &
            (not (term_mem (concl th) (true_tm.(hyp th))))
        then
        (
        let hypthms = subtract (hyp_thms win) thms in
            letref newthms = (thm_setify (th.(thms @ hypthms))) in
            letref sups = suppositions win in
            let hyps = hyp_thms win in
                while (not (thm_set_equal thms newthms)) do
                (
                    thms := newthms;
                    newthms :=
                        thm_setify
                            (   thms
                            @   (flat (map (\t. map (PROVE_HYP t) thms) thms))
                            )
                );
        thms := subtract thms hypthms;
                sups := filter (\s1. not (exists (\s2.better_goal s2 s1)
                                                 (map dest_thm thms))) sups;
                let newwin = (win_thm win, hyps, thms, sups, bound win) in
                letref win_th = win_thm newwin in
                letref kills = term_intersect (lemmas newwin)
                                              (used_conjectures newwin)
        in
                    while (not (null kills)) do
                    (
                        win_th := PROVE_HYP (get_thm (hd kills) newwin) win_th;
                        kills := tl kills
                    );
                    (win_th, hyps, thms, sups, bound win)
        )
        else
            win;;

% If the current focus is f and relation is s and the transformation    %
%   tr = (h |- g s f) where h is a subset of the current hyps and conjs %
%   and s is stronger than r then we transform the focus to g.          %
let transform_win tr win =
    let (th, hyps, thms, sups, bnds) = win in 
    letref ctr = tr in
    letref kills = term_intersect (hyp ctr)
                      ((lemmas win) @ (disp_hypotheses win))
    in
            while (not (null kills)) do
            (
                ctr := PROVE_HYP (get_thm (hd kills) win) ctr;
                kills := tl kills
            );
        if (not (term_subset (hyp ctr)
                 (term_union (hypotheses win) (conjectures win))))
            then
            failwith `Transformation has bad hypothese.`
        else
        (
            let r = rator (rator (concl th)) in
            let newth = transitive (CONJ (weaken r ctr) th) in
                (newth, hyps, thms, sups, bnds)
        );;

% If the current focus is f and relation is s and the transformation    %
% tr = (h |- !x1...xn. g' s f') where h is a subset of the current      %
% and s is stronger than r and f' can be matched to f after x1...xn     %
% have been specialised, then we transformt the focus to g              %
% (that is g' with the same instantiations applied to it).              %
let match_transform_win tr win =
    transform_win (PART_MATCH rand tr (focus win)) win;;

% Apply the conversion to the focus.                                        %
let convert_win (c : conv) win =
    transform_win (SYM (c (focus win))) win;;

% Apply an inference rule(thm -> thm) to the current focus.                 %
% Only works if the relation is "<==" or weaker.                            %
let rule_win inf win = 
    let f = focus win in
        (transform_win (IMP_PMI (DISCH f (inf (ASSUME f)))) win) 
        ? failwith `rule_win: only preserves <==`;;

% Apply an inference rule to the theorem of a window.                       %
let thm_rule_win inf (win : window) =
    let (res, hyps, thms, sups, bnds) = win in
    let rel = rator (rator (concl res)) in
    let res' = inf res in
    let rel' = rator (rator (concl res')) in
    let orig = rand (concl res) in
    let orig' = rand (concl res') in
    let used' = hyp res' in
        if (orig' = orig)
         & (mem rel (relative_strengths rel'))
         & (term_subset used' (term_union (hypotheses win) (conjectures win)))
        then
            (weaken rel res', hyps, thms, sups, bnds)
        else
            failwith `thm_rule_win`;;

% Apply an inference rule to the focus of a window.                         %
% Rule must take the focus f and return the theorem |- f' r f.              %
let foc_rule_win inf (win : window) =
    (transform_win (inf (focus win)) win)
    ? failwith `foc_rule_win`;;

% Apply a tactic to the current focus.                                      %
% Only works if the tactic results in just 1 subgoal.                       %
% Only works if the relation is "==>".                                      %
% Only works sometimes.                                                     %
let tactic_win (tac:tactic) win =
    (
        let ([(new_hyps, newfoc)], proof) = tac ((hypotheses win), (focus win))
        in
            transform_win (DISCH newfoc (proof [ASSUME newfoc])) win
    ) ? failwith `tactic_win` ;;


% Functions for rewriting the window.                                      %
let gen_rewrite_win rewrite_fun built_in_rewrites =
    let REWL_CONV = GEN_REWRITE_CONV rewrite_fun built_in_rewrites in
        convert_win o REWL_CONV ;;

% Basic rewriting functions.                                                %
let pure_rewrite_win = gen_rewrite_win TOP_DEPTH_CONV []
and rewrite_win = gen_rewrite_win TOP_DEPTH_CONV basic_rewrites
and pure_once_rewrite_win = gen_rewrite_win ONCE_DEPTH_CONV []
and once_rewrite_win = gen_rewrite_win ONCE_DEPTH_CONV basic_rewrites;;

% Assumption rewrite variants.                                              %
let pure_asm_rewrite_win thl win =
    pure_rewrite_win ((map ASSUME (context win)) @ thl) win
and asm_rewrite_win thl win =
    rewrite_win ((map ASSUME (context win)) @ thl) win
and pure_once_asm_rewrite_win thl win =
    pure_once_rewrite_win ((map ASSUME (context win)) @ thl) win
and once_asm_rewrite_win thl win =
    once_rewrite_win ((map ASSUME (context win)) @ thl) win ;;

% Filtered assumption rewriting.                                            %
let filter_pure_asm_rewrite_win f thl win =
    pure_rewrite_win ((map ASSUME (filter f (context win))) @ thl) win
and filter_asm_rewrite_win f thl win =
    rewrite_win ((map ASSUME (filter f (context win))) @ thl) win
and filter_pure_once_asm_rewrite_win f thl win =
    pure_once_rewrite_win ((map ASSUME (filter f (context win))) @ thl) win
and filter_once_asm_rewrite_win f thl win =
    once_rewrite_win ((map ASSUME (filter f (context win))) @ thl) win;;

% Transfer the supposition and theorem sets from one window to another.    %
let transfer_sups_thms ((_, _, thms1, sups1, bnd1):window)
                       ((res2, hyps2, _, _, _):window) =
    (res2, hyps2, thms1, sups1, bnd1);;

% Open a new window at the subterm pointed to by p.                        %
% Finds the _best_ list of window rules to use in order to follow the path %
% p starting from a window with focus f hypothese hyps and which preserves %
% relation rel.                                                            %
% One list of rules is _better_ than another if.                           %
% 1. The relationship being preserved in the child window is weaker.       %
% 2. There are more hypotheses available in the child window.              %
% 3. The rules used from the start were more _specific_ to this case.      %
%    A rule is more _specific_ than another if.                            %
%    1. It follows a longer path.                                          %
%    2. It preserves a weaker relationship in the parent.                  %
%    3. It preserves a weaker relationship in the child.                   %
% 4. The rules used from the start were more recently added to the         %
%    database.                                                             %
let open_win_basis (FOCUS_PATH p) w = 
    let path_of (p,_,_) = flat (map (\(l,_,_,_,_).l) p) in
    let shorter (r1, r2) = prefix (path_of r1) (path_of r2) in
    let break ths = 
        let (oldths, newths) = partition (\t. hyp t = [concl t]) ths in
        let adds = subtract (map concl newths) [true_tm] in
        let gots = adds @ (map concl oldths) in
        let hyps = filter
                    (\t. not (exists (\u. aconv t u) gots))
                    (flat (map hyp newths)) in
            oldths @ (map ASSUME (adds @ hyps))
    in
    letrec all_steps pth root rls cnt =     
        if null rls then
            []
        else
            let (psl, pwin, close) = root in
            let pfoc = focus pwin in
            let prel = relation pwin in
            let phyps = hyp_thms pwin in
            let plems = lemma_thms pwin in
            let psups = suppositions pwin in
            let pbnds = bound pwin in
            let (rpt, rapp, rcrel, rprel, rhyps, rbnds, rinf).trls = rls in
               if (rapp pfoc)
               & (mem (rprel pfoc prel) (relative_strengths prel))
               then
                   let cfoc = traverse rpt pfoc in
                   let crel = rcrel pfoc prel in 
                   let chyps = thm_setify (rhyps pfoc (break phyps)) in
                   let clems = plems in
                   let csups = psups in
                   let cbnds = pbnds @ (rbnds pfoc) in
                       (    psl@[(rpt, (rprel pfoc prel), crel, chyps, cnt)],
                            (make_win
                                (mk_comb (crel, cfoc)) csups cbnds chyps clems),
                            (\cwin.
                                close
                                    (transform_win
                                        (rinf pfoc (win_thm cwin))
                                        (transfer_sups_thms cwin pwin)))
                        ).(all_steps pth root trls (cnt + 1))
               else
                   all_steps pth root trls (cnt + 1)
    in
    letrec better_rules rl1 rl2 =
        if (null rl1) & (null rl2) then
            false 
        else
            let ((p1,rp1,rc1,h1,c1).t1) = rl1 in
            let ((p2,rp2,rc2,h2,c2).t2) = rl2 in
            if (length p1) > (length p2) then
                true
            else if (length p2) > (length p1) then
                false
            else % (length p1) = (length p2) %
                if mem rp2 (tl (relative_strengths rp1)) then
                    true
                else if mem rp1 (tl (relative_strengths rp2)) then
                    false
                else % the relations are equal or uncomparable %
                    if mem rc2 (tl (relative_strengths rc1)) then
                        true
                    else if mem rc1 (tl (relative_strengths rc2)) then
                        false
                    else % the relations are equal or uncomparable %
                        if (length h1) > (length h2) then
                            true
                        else if (length h2) > (length h1) then
                            false
                        else % (length h1) = (length h2) %
                        if c2 > c1 then
                            true
                        else if c1 > c2 then
                            false
                        else % c1 = c2 %
                            better_rules t1 t2
    in
    let better_route r1 r2 =
        let (psl1, w1, _) = r1 in
        let (psl2, w2, _) = r2 in
        let rel1  = relation w1 in
        let rel2  = relation w2 in
        let hyps1 = hypotheses w1 in
        let hyps2 = hypotheses w2 in
            if mem rel2 (tl (relative_strengths rel1)) then
                r1
            else if mem rel1 (tl (relative_strengths rel2)) then
                r2
            else % the relations are equal or uncomparable %
                if (length hyps1) > (length hyps2) then 
                    r1
                else if (length hyps2) > (length hyps1) then
                   r2
                else % (length hyps1) = (length hyps2) %
                    if better_rules psl1 psl2 then
                        r1
                    else
                        r2
        in
    letrec crush_routes =
        fun [rt]            .   [rt]
         |  (r1.r2.trts)    .
                if (path_of r1) = (path_of r2) then
                    crush_routes ((better_route r1 r2).trts)
                else
                    r1.(crush_routes (r2.trts))
    in
    let rel = relation w in
    let hyps = hyp_thms w in
    letref routes =
         [([(([] : path), rel, rel, hyps, 0)], w, (I:window->window))]
    in
    while not (path_of (hd routes) = p) do
    (
        let (hrts.trts) = routes in
        let rempth = (after (path_of hrts) p) in
        let steps = sort shorter
             (all_steps
                rempth hrts (search_rule rempth) 1)
        in
            if (null steps) then failwith `No applicable window rule!`;
            routes := merge shorter trts steps;
            routes := crush_routes routes
    );
    let ((_, subwin, closefn)._) = routes in
        (subwin, (C (K closefn)):(window -> window -> window));;

% Open a window on a selected lemma or hypothesis.                          %
let open_context_basis (CONTEXT_PATH (tm, p)) win = 
    if (term_mem tm (context win))
    then
    (
        let subwin1 =
            make_win
                (mk_comb (pmi_tm, tm))
                (suppositions win)
                []
                (hyp_thms win)
                (lemma_thms win)
        in
        let closefn1 w = (add_theorem (UNDISCH (PMI_IMP (win_thm w)))) o 
                 (transfer_sups_thms w)
        in
        let (subwin2, closefn2) = open_win_basis (FOCUS_PATH p) subwin1 in
        let closefn w = closefn1 (closefn2 w subwin1) in
            (subwin2, closefn)
    )
    else
        failwith `There is no such term in the context.`;;

% Open a window on either the focus or the context.                         %
let gen_open_basis =
    fun (FOCUS_PATH p)          .   open_win_basis (FOCUS_PATH p)
     |  (CONTEXT_PATH (tm,p))   .   open_context_basis (CONTEXT_PATH (tm,p));;

% Postulate a lemma, or prove a conjecture.                                 %
let establish_basis (CONTEXT_PATH (tm,[])) win = 
    let (bad_sups,good_sups) = partition (\(_,c). c = tm) (suppositions win) in
    let subwin =
        make_win
            (mk_comb (imp_tm, tm))
	    good_sups
	    []
	    (hyp_thms win)
            (lemma_thms win)
    and closefn w = if (focus w) = true_tm then
			(itlist add_suppose bad_sups) o
                        (add_theorem (MP (win_thm w) TRUTH)) o
                        (transfer_sups_thms w)
                    else
                        failwith `This lemma is not proved yet!`
    in
        (subwin, closefn);;

let open_win p subwinfn win = 
    let (subwin, closefn) = open_win_basis (FOCUS_PATH p) win in
        closefn (subwinfn subwin) win;;

let open_context tm p subwinfn win = 
    let (subwin, closefn) = open_context_basis (CONTEXT_PATH (tm,p)) win in
        closefn (subwinfn subwin) win;;

let gen_open_win wp subwinfn win = 
    let (subwin, closefn) = gen_open_basis wp win in
        closefn (subwinfn subwin) win;;

let establish tm subwinfn win = 
    let (subwin, closefn) = establish_basis (CONTEXT_PATH (tm,[])) win in
        closefn (subwinfn subwin) win;;