/[ascend]/trunk/base/generic/compiler/relation_util.h
ViewVC logotype

Contents of /trunk/base/generic/compiler/relation_util.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1066 - (show annotations) (download) (as text)
Sun Jan 7 10:02:41 2007 UTC (17 years, 9 months ago) by johnpye
File MIME type: text/x-chdr
File size: 22608 byte(s)
Adding doxygen 'addtogroup' for Solver, Compiler, Integrator.
1 /* ASCEND modelling environment
2 Copyright (C) 1990 Karl Michael Westerberg, Thomas Guthrie Weidner Epperly
3 Copyright (C) 1993 Joseph James Zaher
4 Copyright (C) 1993, 1994 Benjamin Andrew Allan, Joseph James Zaher
5 Copyright (C) 1996 Benjamin Andrew Allan, Kenneth Tyner
6 Copyright (C) 2006 Carnegie Mellon University
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22 *//**
23 @file
24 Relation utility functions for Ascend.
25 This module defines the dimensionality checking and some other
26 auxillaries for Ascend.
27 *//*
28 Version: $Revision: 1.27 $
29 Version control file: $RCSfile: relation_util.h,v $
30 Date last modified: $Date: 1998/02/05 16:37:48 $
31 Last modified by: $Author: ballan $
32 */
33
34 #ifndef ASC_RELATION_UTIL_H
35 #define ASC_RELATION_UTIL_H
36
37 /** addtogroup compiler Compiler
38 @{
39 */
40
41 #include <utilities/ascConfig.h>
42 #include "fractions.h"
43 #include "compiler.h"
44 #include "functype.h"
45 #include "safe.h"
46 #include "dimen.h"
47 #include "expr_types.h"
48 #include "relation_type.h"
49 #include "instance_enum.h"
50
51 ASC_DLLSPEC int g_check_dimensions_noisy;
52 /**<
53 * If 0, warnings are suppressed. If 1, warnings are given
54 * from RelationCheckDimensions();
55 */
56
57 ASC_DLLSPEC int RelationCheckDimensions(struct Instance *relinst, dim_type *dimens);
58 /**<
59 * If a token relation, scans a relation in postfix and collects all dimensional
60 * information by applying each token. It returns a value of TRUE
61 * only if no real instances or real atom instances with wild
62 * dimensionality and no dimensional inconsistencies were encountered.
63 * If the return value is 2 rather than 1, then the dimensionality
64 * has been determined before.
65 * The address of an allocated dimension type is passed in so that
66 * the dimensions of the relation (or at least what the function
67 * thinks the dimensions ought to be) can be also obtained.
68 * If a blackbox, gets dim of lhs if not already set, as the rel dim.
69 *
70 * @NOTE THIS ONLY WORKS ON e_token and e_blackbox relations a
71 * and maybe in future e_opcode
72 * relations. rel is assumed to be valid when called. !!!
73 *
74 * @NOTE This brings in the asc_check_dimensions function from ascend_utils.
75 * 3/96 Ben Allan
76 */
77
78 ASC_DLLSPEC enum Expr_enum RelationRelop(CONST struct relation *rel);
79 /**<
80 * Return the type of the relation operator of the relation.
81 * Returns one of the following:
82 * <pre>
83 * e_equal equality constraint
84 * e_notequal non-equality contraint
85 * e_less less than contraint
86 * e_greater greater than contraint
87 * e_lesseq less than or equal contraint
88 * e_greatereq greater than or equal contraint
89 * e_maximize objective function to be maximized (rhs is empty)
90 * e_minimize objective function to be minimized (rhs is empty)
91 * </pre>
92 */
93
94 extern unsigned long NumberVariables(CONST struct relation *rel);
95 /**<
96 This will indicate the number of distinct real atoms to which this relation
97 points. This number contains both fixed and non-fixed atoms.
98 This routine is smart enough to deal with all the different relation types.
99 */
100
101 ASC_DLLSPEC struct Instance *RelationVariable(CONST struct relation *rel,
102 unsigned long varnum);
103 /**<
104 This will return the varnum'th variable.
105 This routine is smart enough to deal with all the different relation
106 types.
107
108 @param varnum variable index number, starts at one.
109 */
110
111 /*----------------------------------------------------------------------------
112 TOKENRELATION AND OPCODERELATION STUFF
113
114 It is the responsibility of the user of these routines to be aware
115 of the type of relation being used. Very little sanity checking is
116 done.
117 */
118
119 ASC_DLLSPEC struct BlackBoxCache *RelationBlackBoxCache(CONST struct relation *rel);
120 ASC_DLLSPEC struct BlackBoxData *RelationBlackBoxData(CONST struct relation *rel);
121
122 ASC_DLLSPEC unsigned long RelationLength(CONST struct relation *rel, int lhs);
123 /**<
124 Returns the number of terms on one side of the equation. If lhs!=0, does this
125 for the LHS. If lhs==0, does this for the RHS.
126 */
127
128 ASC_DLLSPEC CONST struct relation_term *RelationTerm(CONST struct relation *rel,
129 unsigned long pos,
130 int lhs);
131 /**<
132 Returns the term in position POS (base 1) on one side of the equation.
133 If lhs!=0, does this for the LHS. If lhs==0, does this for the RHS.
134
135 @NOTE A bizarre thing about this operator: 1 <= pos <= RelationLength(rel,lhs).
136 This is a holdover from gl_list days.
137 */
138
139 #ifdef NDEBUG
140 #define NewRelationTerm(r,p,l) \
141 A_TERM( (l)!=0 ? (&(RTOKEN(r).lhs[(p)])) : (&(RTOKEN(r).rhs[(p)])) )
142 #else
143 #define NewRelationTerm(r,p,l) NewRelationTermF((r),(p),(l))
144 #endif
145 /**<
146 Returns the term in position POS (base 0) on one side of the equation.
147 If lhs!=0, does this for the LHS. If lhs==0, does this for the RHS.
148
149 For this operator: 0 <= p < RelationLength(rel,lhs) as a C array.
150
151 @TODO Once Everybody gets their damn hands off RelationTerm, switch its
152 semantics and eliminate one of this pair.
153
154 @param r CONST struct relation*, the relation to query.
155 @param p unsigned long, the position to retrieve.
156 @param l int, flag for whether to return from the lhs or rhs.
157 @return The specified term as a CONST struct relation_term*.
158 @see NewRelationTermF()
159 */
160
161 extern CONST struct relation_term
162 *NewRelationTermF(CONST struct relation *rel, unsigned long apos, int lhs);
163 /**<
164 Implementation function for NewRelationTerm(). Do not call this
165 function directly.
166 */
167
168 #ifdef NDEBUG
169 #define RelationSideTerm(rs,p) A_TERM(&((rs)[(p)]))
170 #else
171 #define RelationSideTerm(rs,p) RelationSideTermF((rs),(p))
172 #endif
173 /**<
174 Return the term in position p of the side.
175 For this operator: 0 <= p < length of the side.
176
177 @param rs CONST union RelationTermUnion*, the relation to query.
178 @param p unsigned long, the position to retrieve.
179 @return The specified term as a CONST struct relation_term*.
180 @see RelationSideTermF()
181 */
182 extern CONST struct relation_term
183 *RelationSideTermF(CONST union RelationTermUnion *relside, unsigned long apos);
184 /**<
185 Implementation function for RelationSideTerm(). Do not call this
186 function directly - use RelationSideTerm() instead.
187 */
188
189 #ifdef NDEBUG
190 #define RelationTermType(rtp) ((rtp)->t)
191 #else
192 #define RelationTermType(rtp) RelationTermTypeF(rtp)
193 #endif
194 /**<
195 Return the type of the relation term.
196
197 @NOTE WARNING: if ALLOCATED_TESTS is active, term must be an allocated term;
198 automatic variables will cause an assert() to fail.
199 @param rtp CONST struct relation_term*, the term to query.
200 @return The type as an enum Expr_enum.
201 @see RelationTermTypeF()
202 */
203 ASC_DLLSPEC enum Expr_enum RelationTermTypeF(CONST struct relation_term *term);
204 /**<
205 Implementation function for RelationTermType(). Do not call this
206 function directly - use RelationTermType() instead.
207 */
208
209 ASC_DLLSPEC unsigned long TermVarNumber(CONST struct relation_term *term);
210 /**<
211 @return the index into the relations variable list.
212 */
213
214 ASC_DLLSPEC long TermInteger(CONST struct relation_term *term);
215 /**<
216 @return the integer value from a e_int type relation term.
217 */
218
219 ASC_DLLSPEC double TermReal(CONST struct relation_term *term);
220 /**<
221 @return the double value from a e_real type relation term.
222 */
223
224 extern double TermVariable(CONST struct relation *rel,
225 CONST struct relation_term *term);
226 /**<
227 @return the double value from a e_var type relation term.
228 */
229
230 ASC_DLLSPEC CONST dim_type *TermDimensions(CONST struct relation_term *term);
231 /**<
232 Return the dimensions of a e_real, e_int, or e_zero relation term type.
233 (e_int is always Dimensionless(); e_zero is always WildDimension().)
234 */
235
236 ASC_DLLSPEC CONST struct Func *TermFunc(CONST struct relation_term *term);
237 /**<
238 * Return the function pointer of a function operator.
239 */
240
241 ASC_DLLSPEC unsigned long RelationDepth(CONST struct relation *rel);
242 /**<
243 Return the depth of stack required to evaluate this relation.
244 */
245
246 /*------------------------------------------------------------------------
247 TOKENRELATION INFIX OPERATIONS
248 */
249
250 /*
251 The four defines following return term pointers.
252 struct relation_term *r, *t;
253 r = TermUniLeft(t); for example.
254
255 @TODO These should be implemented as functions which assert type
256 and revert to macros with NDEBUG.
257 */
258 #define TermUniLeft(t) ( ((struct RelationUnary *)t) -> left)
259 #define TermFuncLeft(t) ( ((struct RelationFunc *)t) -> left)
260 #define TermBinLeft(t) ( ((struct RelationBinary *)t) -> left)
261 #define TermBinRight(t) ( ((struct RelationBinary *)t) -> right)
262
263 extern struct relation_term *RelationINF_Lhs(CONST struct relation *rel);
264 /**<
265 Returns the lhs of an infix relation. This may be NULL,
266 if the relation has not been set for infix scanning.
267 */
268
269 extern struct relation_term *RelationINF_Rhs(CONST struct relation *rel);
270 /**<
271 Return the rhs of an infix relation. This may be NULL
272 if the relation has not been set up for infix scanning, or if
273 the relation is an objective relation.
274 */
275
276 extern int ArgsForRealToken(enum Expr_enum ex);
277 /**<
278 Return the number of args required for a token from a real equation.
279 */
280
281 /*------------------------------------------------------------------------
282 OPCODE RELATION PROCESSING
283 */
284
285 /**
286 @TODO What's that mean?
287 @TODO this stuff is not complete
288 */
289
290 #define OpCode_Lhs(r) ((int *)(ROPCODE(r).lhs))
291 #define OpCode_Rhs(r) ((int *)(ROPCODE(r).rhs))
292 #define OpCodeNumberArgs(r) (ROPCODE(r).nargs)
293 #define OpCodeConstants(r) ((double *)(ROPCODE(r).constants))
294
295 /*------------------------------------------------------------------------
296 BLACK BOX RELATION PROCESSING
297 */
298
299 /** @return the list of lists of argument names.
300 The result is identical for all members of an array of relations
301 built with a single external statement.
302 @param rel the source of the arguments.
303 */
304 extern struct gl_list_t *RelationBlackBoxArgNames(CONST struct relation *rel);
305
306 /** @return the data argument name.
307 The result is identical for all members of an array of relations
308 built with a single external statement.
309 @param rel the source of the arguments.
310 */
311 extern struct Name *RelationBlackBoxDataName(CONST struct relation *rel);
312
313 /** @return the C function table structure for the blackbox.
314 @param rel the source of the efunc.
315 */
316 extern struct ExternalFunc *RelationBlackBoxExtFunc(CONST struct relation *rel);
317
318 /*------------------------------------------------------------------------
319 GLASS BOX STUFF
320 */
321
322 /*
323 These will be called a lot so that they will all be made
324 macros. Double check that the same is true for the
325 ExternalFunc routines.
326 */
327 extern struct ExternalFunc *RelationGlassBoxExtFunc(CONST struct relation *rel);
328 extern int GlassBoxRelIndex(CONST struct relation *rel);
329 extern int *GlassBoxArgs(CONST struct relation *rel);
330
331 #define GlassBoxNumberArgs(r) (RGBOX(r).nargs)
332
333 /*-----------------------------------------------------------------------------
334 GENERAL STUFF FOR RELATIONS
335 */
336
337 extern CONST struct gl_list_t *RelationVarList(CONST struct relation *r);
338 /**<
339 Returns the unique incident variable list which is owned by the
340 relation. *DO NOT MODIFY*. It is for the convenience of those
341 desirous of a READ_ONLY look. It is a list of instance pointers, which may
342 be NULL.
343 All relation types will properly respond to this qurey.
344 */
345
346 ASC_DLLSPEC dim_type *RelationDim(CONST struct relation *rel);
347 /**<
348 Return the derived dimensionality of the relation.
349 Defaults to Wild.
350 */
351
352 ASC_DLLSPEC int SetRelationDim(struct relation *rel, CONST dim_type *d);
353 /**<
354 Set the dimensionality of the relation. return 0 unless there is a
355 problem (rel was null, for instance.)
356 */
357
358 ASC_DLLSPEC double RelationResidual(CONST struct relation *rel);
359 /**<
360 Return the residual of the relation.
361 */
362
363 extern void SetRelationResidual(struct relation *rel, double value);
364 /**<
365 Set the value of the relation residual.
366 */
367
368 extern double RelationMultiplier(CONST struct relation *rel);
369 /**<
370 Return the langrage multiplier of the relation. This will have some
371 hybrid dimensions that still needs to be decided, as it is a function
372 of the objective function(s).
373 */
374
375 extern void SetRelationMultiplier(struct relation *rel, double value);
376 /**<
377 Set the value of the relation langrage multiplier. This will have some
378 hybrid dimensions that still needs to be decided.
379 */
380
381 ASC_DLLSPEC int RelationIsCond(CONST struct relation *rel);
382 /**<
383 Return the value of the iscond flag of the relation.
384 If relation is NULL, returns 0.
385 */
386
387 extern void SetRelationIsCond(struct relation *rel);
388 /**<
389 Sets the value of the iscond field of the relation to 1
390 If relation is NULL, writes error message.
391 */
392
393 extern double RelationNominal(CONST struct relation *rel);
394 /**<
395 Return the nominal of the relation.
396 */
397
398 ASC_DLLSPEC void SetRelationNominal(struct relation *rel, double d);
399 /**<
400 Sets the value of the nominal field of the relation to the absolute
401 value of d, unless d is 0.0.
402 */
403
404 ASC_DLLSPEC double CalcRelationNominal(struct Instance *i);
405 /**<
406 Calculate the nominal of a relation.
407 Returns 0.0 if something went detectably wrong in the calculation,
408 otherwise calculates the absolute value of the maximum affine term
409 and returns it, given an instance which is a token relation. Other
410 relation types return the value 1.0.
411 Does not set the constant stored with the relation.
412
413 When opcode relations are fully supported,
414 this function should be made to work for them, too.
415
416 Art contends that the proper nominal for blackbox
417 relations is the nominal of the output variable, though this is
418 not implemented at present.
419
420 Art further contends that the proper nominal for glassbox relations
421 is the 2 norm of its gradient vector after fixed variables are
422 removed and free elements have been scaled by the variable nominals.
423 It should be noted that the glassbox scaling proposed by this method
424 is precisely what the Slv solvers used up to August 1995.
425 IMHO the glassbox generated should include code which knows
426 how to calculate relation nominals. -- BAA
427 */
428
429 extern void PrintRelationNominals(struct Instance *i);
430 /**<
431 Perform a visit-instance-tree starting at i and calc/print consts.
432 This function doesn't belong here.
433 */
434
435 extern char *tmpalloc(int nbytes);
436 /**<
437 Temporarily allocates a given number of bytes. The memory need
438 not be freed, but the next call to this function will reuse the
439 previous allocation. Memory returned will NOT be zeroed.
440 Calling with nbytes==0 will free any memory allocated.
441 */
442
443 #define tmpalloc_array(nelts,type) ((type *)tmpalloc((nelts)*sizeof(type)))
444 /**<
445 Creates an array of "nelts" objects, each with type "type".
446 */
447
448 /*------------------------------------------------------------------------------
449 RELATION EVALUATION STUFF
450
451 * These are for Token equations, though if they can be done
452 * for all equation types that's a plus.
453 * Supercedes the bleeding mess in calc.c, rel.c, relman.c which was
454 * very ugly. -- BAA 5/96
455 */
456
457 int RelationCalcResidualBinary(CONST struct relation *rel, double *res);
458 /**<
459 * Returns 0 if it calculates a valid residual, 1 if
460 * for any reason it cannot. Reasons include:
461 * - relation not token relation.
462 * - token relation not compiled to binary.
463 * - NaN/infinity result.
464 * - out of memory.
465 * If return is 1, then res will not have been changed.
466 * This function may raise SIGFPE it calls external code.
467 */
468
469 enum safe_err
470 RelationCalcResidualPostfixSafe(struct Instance *i, double *res);
471 /**<
472 * Sets *res to the value (leftside - rightside) of the relation.
473 * status != 0 (safe_ok = 0) implies a problem.
474 * This function is slower than RelationCalcResidual() because it does
475 * a lot of range checking AND a floating point trap.
476 */
477
478 int RelationCalcResidualPostfix(struct Instance *i, double *res);
479 /**<
480 * Sets *res to the value (leftside - rightside) of the relation.
481 * Uses postfix evaluation.
482 * status != 0 implies a problem.
483 * Notes: This function is a possible source of floating point
484 * exceptions and should not be used during compilation.
485 */
486
487 /*
488 * The following bit flags are used to build up the return
489 * status from RelationCalcExceptionsInfix.
490 * No provision is made for checking gradient elements --
491 * gradients are in principle an all or nothing affair.
492 */
493 #define RCE_BADINPUT -1 /**< called with non-token relation */
494 #define RCE_OK 0 /**< no error */
495 #define RCE_ERR_LHS 0x1 /**< left side evaluation error */
496 #define RCE_ERR_RHS 0x2 /**< right side evaluation error */
497 #define RCE_ERR_LHSGRAD 0x4 /**< left side gradient error */
498 #define RCE_ERR_RHSGRAD 0x8 /**< right side gradient error */
499 #define RCE_ERR_LHSINF 0x10 /**< left side returns Infinity */
500 #define RCE_ERR_RHSINF 0x20 /**< right side returns Infinity */
501 #define RCE_ERR_LHSNAN 0x40 /**< left side returns NaN */
502 #define RCE_ERR_RHSNAN 0x80 /**< right side returns NaN */
503
504 ASC_DLLSPEC int RelationCalcExceptionsInfix(struct Instance *i);
505 /**<
506 * Uses infix evaluation to check gradient and residual
507 * floating point exceptions.
508 * status != 0 implies a problem.
509 * Notes: This function is a possible source of floating point
510 * exceptions and should not be used during compilation.
511 * This function should not be called except inside the scope of a
512 * Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
513 * Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
514 * pair.
515 * Functions that report exceptions here may still be evaluated
516 * With the Safe relation evaluation routines in all but the most
517 * bizarre circumstances. The Safe results are necessarily approximate.
518 *
519 * @TODO (bug) At present, gradient checks are not implemented as the code
520 * required is messy. We need to rearrange CalcResidGrad().
521 */
522
523 int RelationCalcResidualInfix(struct Instance *i, double *res);
524 /**<
525 * Sets *res to the value (leftside - rightside) of the relation.
526 * Uses infix evaluation.
527 * Non-zero return value implies a problem.
528 * Notes: This function is a possible source of floating point
529 * exceptions and should not be used during compilation.
530 */
531
532 #define RelationCalcResidual(i,r) RelationCalcResidualPostfix(i,r)
533 #define RelationCalcResidualSafe(i,r) RelationCalcResidualPostfixSafe(i,r)
534
535 int RelationCalcGradient(struct Instance *i, double *grad);
536 /**<
537 This calculates the gradient of the relation df/dx (f = lhs-rhs)
538 where x is ALL entries in the relation's var list.
539 The var list is a gl_list_t indexed from 1 to length.
540 You must provide grad, the space to put the gradient, an array of
541 double of length matching the gl_list_t.
542 We will stuff df/dx[i] into grad[i-1], where i is the list position
543 in the relation's var list.
544
545 @return Non-zero return value implies a problem
546
547 @NOTE This function is a possible source of floating point
548 exceptions and should not be used during compilation.
549 */
550
551 enum safe_err RelationCalcGradientSafe(struct Instance *i, double *grad);
552 /**<
553 This calculates the gradient of the relation df/dx (f = lhs-rhs)
554 where x is ALL entries in the relation's var list.
555
556 This function is to RelationCalcGradient as
557 RelationCalcResidualSafe is to RelationCalcResidual.
558 Non-zero return value implies a problem.
559 */
560
561 int RelationCalcResidGrad(struct Instance *i, double *res, double *grad);
562 /**<
563 This function combines the Residual and Gradient calls, since these
564 may be done together at basically the cost of just one.
565 Non-zero return value implies a problem.
566
567 @NOTE This function is a possible source of floating point exceptions
568 and should not be used during compilation.
569 */
570
571 enum safe_err
572 RelationCalcResidGradSafe(struct Instance *i, double *res, double *grad);
573 /**<
574 This is the combined Safe version.
575 Non-zero return value implies a problem.
576 */
577
578 /*------------------------------------------------------------------------------
579 ROOT FINDING FUNCTIONS (deprecated?)
580 */
581
582 double *RelationFindRoots(struct Instance *i,
583 double lower_bound, double upper_bound,
584 double nominal, double tolerance,
585 unsigned long *varnum,
586 int *able,
587 int *nsolns);
588 /**<
589 RelationFindRoot WILL find a root if there is one. It is in charge of
590 trying every trick in the book. The user must pass in a pointer to a
591 struct relation. We require that the relation be of the type e_token with
592 relation->relop = e_equals and we will whine if it is not. The calling
593 function should check able and/or nsolns before accessing the information
594 in the soln_list.
595 - nsolns < 0 : severe problems, such as var not found; soln_list will be NULL
596 - nsolns = 0 : No solution found
597 - nsolns > 0 : The soln_status equals the number of roots found
598
599 @return NULL if success? 1 for success and 0 for failure?
600
601 @NOTE In general compiler functions return 0 for success but this function
602 returns 1 for success because success = 1 is the convention on the solver
603 side.
604
605 @TODO (we really should make a system wide convention for return values)
606
607 @NOTE The calling function should NOT free the soln_list.
608
609 @NOTE we should recycle the memory used for glob_rel
610
611 @NOTE This function is NOT thread safe because it uses an internal memory
612 recycle.
613
614 @NOTE Before shutting down the system, or as desired, call this as:
615 (void) RelationFindRoots(NULL,0,0,0,0,NULL,NULL,NULL);
616 in order to free this memory.
617
618 @TODO I think that this function might not really be used, or might only
619 be used by old solvers. Is that the case? -- JP
620 */
621
622 /*-----------------------------------------------------------------------------
623 BINTOKEN STUFF
624 */
625
626 struct gl_list_t *CollectTokenRelationsWithUniqueBINlessShares(
627 struct Instance *i, unsigned long maxlen);
628 /**<
629 Collect the token relation 'shares' in i which have not been compiled
630 (or at least attempted so) to binary form yet.
631 If more than maxlen are found, returns NULL instead. Presumably there
632 is some upper limit beyond which you don't want to know the answer to
633 this question. If none are found, returns a 0 length list.
634 Actually, it is not a share that is collected, but instead any
635 one of the relation instances which use the share is collected.
636 The list returned should be destroyed by the user (not its content,though).
637 */
638
639 /* @} */
640
641 #endif /* ASC_RELATION_UTIL_H */

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22