| 1 | % (c) 2009-2013 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(units_domain, [ same_units/1, | |
| 6 | same_units/2, | |
| 7 | lub/3, | |
| 8 | units_domain_multiplication/3, | |
| 9 | units_domain_multiplication_conversion/3, | |
| 10 | units_domain_division/3, | |
| 11 | units_domain_division_conversion/3, | |
| 12 | units_domain_subtraction_conversion/3, | |
| 13 | units_domain_addition_conversion/3, | |
| 14 | units_domain_power_of/3, | |
| 15 | units_domain_member/2, | |
| 16 | units_domain_relation/3, | |
| 17 | involved_in_constraint/1, | |
| 18 | power_of_multiply_units/3 | |
| 19 | ]). | |
| 20 | ||
| 21 | :- use_module(library(lists)). | |
| 22 | :- use_module(library(clpfd)). | |
| 23 | :- use_module(library(sets)). | |
| 24 | :- use_module(library(atts)). | |
| 25 | ||
| 26 | ||
| 27 | :- use_module(probsrc(self_check)). | |
| 28 | ||
| 29 | :- use_module(units_conversions). | |
| 30 | ||
| 31 | :- use_module(probsrc(module_information)). | |
| 32 | :- module_info(group,plugin_units). | |
| 33 | :- module_info(description,'Units Plugin: The abstract Domain.'). | |
| 34 | ||
| 35 | :- attribute mfactors/2, dfactors/2, pfactors/2, constraint/0. | |
| 36 | ||
| 37 | involved_in_constraint(X) :- var(X), !, get_atts(X, constraint). | |
| 38 | involved_in_constraint([H|T]) :- | |
| 39 | !, (involved_in_constraint(H) ; involved_in_constraint(T)). | |
| 40 | involved_in_constraint(Pred) :- | |
| 41 | !, Pred =.. [Head|Tail], | |
| 42 | Tail = [_|_], | |
| 43 | (involved_in_constraint(Head) ; involved_in_constraint(Tail)). | |
| 44 | ||
| 45 | add_constraint_marker(A,B) :- | |
| 46 | (var(A) -> put_atts(A, constraint) ; true), | |
| 47 | (var(B) -> put_atts(B, constraint) ; true). | |
| 48 | ||
| 49 | verify_attributes(Var, Value, Goal) :- | |
| 50 | % the variable might be the result of a multiplication | |
| 51 | % -> propagate inwards | |
| 52 | get_atts(Var, mfactors(A,B)), !, | |
| 53 | (var(Value) -> Goal = [] ; | |
| 54 | (A==B, var(A)) -> Goal=[power_of_multiply_units(2,A,Value)] ; | |
| 55 | (var(A), nonvar(B)) -> Goal=[units_domain_division(Value,B,A)] ; | |
| 56 | (var(B), nonvar(A)) -> Goal=[units_domain_division(Value,A,B)] ; | |
| 57 | otherwise -> Goal=[]). | |
| 58 | verify_attributes(Var, Value, Goal) :- | |
| 59 | % the variable might be the result of a division | |
| 60 | % -> propagate inwards | |
| 61 | get_atts(Var, dfactors(A,B)), !, | |
| 62 | (var(Value) -> Goal=[] ; | |
| 63 | (var(A), nonvar(B)) -> Goal=[units_domain_multiplication(Value,B,A)] ; | |
| 64 | (var(B), nonvar(A)) -> Goal=[units_domain_division(A,Value,B)] ; | |
| 65 | otherwise -> Goal=[]). | |
| 66 | verify_attributes(Var, Value, Goal) :- | |
| 67 | % the variable might be the result of a exponentiation | |
| 68 | % -> propagate inwards | |
| 69 | get_atts(Var, pfactors(A,B)), !, | |
| 70 | (var(Value) -> Goal=[] ; | |
| 71 | (var(A), nonvar(B)) -> Goal=[power_of_multiply_units(B,A,Value)] ; | |
| 72 | otherwise -> Goal=[]). | |
| 73 | % rescue constraint attribute when unifying | |
| 74 | verify_attributes(Var, Value, []) :- | |
| 75 | get_atts(Var, constraint), !, | |
| 76 | (var(Value) -> put_atts(Value, constraint) ; true). | |
| 77 | %verify_attributes(Var, Value, []) :- | |
| 78 | % not a result of multiplication or division | |
| 79 | % true. | |
| 80 | ||
| 81 | one_is_var(A,B) :- var(A) ; var(B). | |
| 82 | ||
| 83 | % special case "power_of": | |
| 84 | % A is the unit part of an integer. This might be a variable. | |
| 85 | units_domain_power_of(A,b(integer(B,_,_)),C) :- var(A), put_atts(A,constraint), put_atts(C, pfactors(A,B)), !. | |
| 86 | % B is a raw syntax element. if it is a known integer literal, compute exponent | |
| 87 | units_domain_power_of(A, b(integer(X),_,_),C) :- | |
| 88 | power_of_multiply_units(X,A,C), !. | |
| 89 | % A might be top containing a list of known units | |
| 90 | units_domain_power_of(top(A), b(integer(X),_,_),top(C)) :- | |
| 91 | maplist(power_of_multiply_units(X),A,C), !. | |
| 92 | % otherwise, we can not infer the unit anymore | |
| 93 | units_domain_power_of(_A,_B,top([])) :- !. | |
| 94 | ||
| 95 | power_of_multiply_units(_,[],[]). | |
| 96 | power_of_multiply_units(X,[[Factor1,Unit,Pow1]|T1],[[Factor2,Unit,Pow2]|T2]) :- | |
| 97 | Factor2 #= Factor1 * X, Pow2 #= Pow1 * X, | |
| 98 | power_of_multiply_units(X,T1,T2). | |
| 99 | ||
| 100 | % Conversions between units. Conversion_factor and conversion_add is supplied in its own module. | |
| 101 | ||
| 102 | units_domain_addition_conversion(_, X, _) :- var(X), !. | |
| 103 | units_domain_addition_conversion(b(integer(X),_,_), [Unit|Units], [Unit2|Units]) :- | |
| 104 | repeat_conversion_add(X,Unit2,Unit). | |
| 105 | units_domain_addition_conversion(BInt,[Unit|Units],[Unit|Units2]) :- | |
| 106 | units_domain_addition_conversion(BInt,Units,Units2). | |
| 107 | ||
| 108 | units_domain_subtraction_conversion(_, X, _) :- var(X), !. | |
| 109 | units_domain_subtraction_conversion(b(integer(X),_,_), [Unit|Units], [Unit2|Units]) :- | |
| 110 | repeat_conversion_add(X,Unit,Unit2). | |
| 111 | units_domain_subtraction_conversion(BInt,[Unit|Units],[Unit|Units2]) :- | |
| 112 | units_domain_subtraction_conversion(BInt,Units,Units2). | |
| 113 | ||
| 114 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(10),_,_), | |
| 115 | _,X),var(X))). | |
| 116 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(10),_,_), | |
| 117 | [[1,m,1]],X),X=[[0,m,1]])). | |
| 118 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(60),_,_), | |
| 119 | [[1,mins,1]],X),X=[[1,s,1]])). | |
| 120 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(10),_,_), | |
| 121 | [[1,m,1],[1,s,1]],X),X=[[0,m,1],[1,s,1]])). | |
| 122 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(10),_,_), | |
| 123 | [[1,s,1],[1,m,1]],X),X=[[1,s,1],[0,m,1]])). | |
| 124 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(60),_,_), | |
| 125 | [[1,m,1],[1,mins,1]],X),X=[[1,m,1],[1,s,1]])). | |
| 126 | :- assert_must_succeed((units_domain_multiplication_conversion(b(integer(60),_,_), | |
| 127 | [[1,mins,1],[1,m,1]],X),X=[[1,s,1],[1,m,1]])). | |
| 128 | units_domain_multiplication_conversion(_, X, _) :- var(X), !. | |
| 129 | units_domain_multiplication_conversion(b(integer(X),_,_), [Unit|Units], [Unit2|Units]) :- | |
| 130 | repeat_conversion_factor(X,Unit,Unit2). | |
| 131 | units_domain_multiplication_conversion(BInt,[Unit|Units],[Unit|Units2]) :- | |
| 132 | units_domain_multiplication_conversion(BInt,Units,Units2). | |
| 133 | ||
| 134 | :- assert_must_succeed((units_domain_division_conversion(b(integer(10),_,_), | |
| 135 | _,X),var(X))). | |
| 136 | :- assert_must_succeed((units_domain_division_conversion(b(integer(10),_,_), | |
| 137 | [[1,m,1]],X),X=[[2,m,1]])). | |
| 138 | units_domain_division_conversion(_, X, _) :- var(X), !. | |
| 139 | units_domain_division_conversion(b(integer(X),_,_), [Unit|Units], [Unit2|Units]) :- | |
| 140 | repeat_conversion_factor(X,Unit2,Unit). | |
| 141 | units_domain_division_conversion(BInt,[Unit|Units],[Unit|Units2]) :- | |
| 142 | units_domain_division_conversion(BInt,Units,Units2). | |
| 143 | ||
| 144 | repeat_conversion_factor(X,_,_) :- X < 1, !, fail. | |
| 145 | repeat_conversion_factor(1.0,Unit,Unit). | |
| 146 | repeat_conversion_factor(Factor,Unit,UnitOut) :- | |
| 147 | var(UnitOut) | |
| 148 | -> conversion_factor(Unit2,Factor2,Unit), | |
| 149 | FactorOut is Factor / Factor2, | |
| 150 | repeat_conversion_factor(FactorOut,Unit2,UnitOut) | |
| 151 | ; conversion_factor(UnitOut,Factor2,Unit2), | |
| 152 | FactorOut is Factor / Factor2, | |
| 153 | repeat_conversion_factor(FactorOut, Unit, Unit2). | |
| 154 | ||
| 155 | repeat_conversion_add(X,_,_) :- X < 0, !, fail. | |
| 156 | repeat_conversion_add(0,Unit,Unit). | |
| 157 | repeat_conversion_add(Factor,Unit,UnitOut) :- | |
| 158 | var(UnitOut) | |
| 159 | -> conversion_add(Unit2,Factor2,Unit), | |
| 160 | FactorOut is Factor - Factor2, | |
| 161 | repeat_conversion_add(FactorOut,Unit2,UnitOut) | |
| 162 | ; conversion_add(UnitOut,Factor2,Unit2), | |
| 163 | FactorOut is Factor - Factor2, | |
| 164 | repeat_conversion_add(FactorOut, Unit, Unit2). | |
| 165 | ||
| 166 | ||
| 167 | % Operations on Integers | |
| 168 | :- assert_must_succeed(units_domain_multiplication(top([]),[[1,m,1]],top([]))). | |
| 169 | :- assert_must_succeed(units_domain_multiplication(top([[[1,m,1]],[[2,m,1]]]),[[1,m,1]],top([[[2,m,2]],[[3,m,2]]]))). | |
| 170 | :- assert_must_succeed(units_domain_multiplication(top([[[1,m,1]],[[2,m,1]]]),top([[[1,m,1]],[[2,m,1]]]), | |
| 171 | top([[[2,m,2]],[[3,m,2]],[[3,m,2]],[[4,m,2]]]))). | |
| 172 | :- assert_must_succeed(units_domain_multiplication([[1,m,1]],[[1,m,1]],[[2,m,2]])). | |
| 173 | :- assert_must_succeed((units_domain_multiplication(A,B,C),var(A),var(B),var(C))). | |
| 174 | :- assert_must_succeed((units_domain_multiplication(_,[[1,m,1]],Y), var(Y))). | |
| 175 | :- assert_must_succeed((units_domain_multiplication([[1,m,1]],_,Y), var(Y))). | |
| 176 | :- assert_must_succeed(units_domain_multiplication([[1,m,1],[1,a,2]],[[1,m,1]],[[2,m,2],[1,a,2]])). | |
| 177 | :- assert_must_succeed((units_domain_multiplication([[0,m,1],[0,s,-1]],[[0,s,1]],Res), Res = [[0,m,1]])). | |
| 178 | units_domain_multiplication(A,B,C) :- one_is_var(A,B), !, add_constraint_marker(A,B), put_atts(C, mfactors(A,B)). | |
| 179 | units_domain_multiplication(top(A),top(B),top(C)) :- !, | |
| 180 | map_product(units_domain_multiplication,A,B,C). | |
| 181 | units_domain_multiplication(top(A),B,top(C)) :- !, | |
| 182 | maplist(units_domain_multiplication(B),A,C). | |
| 183 | units_domain_multiplication(A,top(B),top(C)) :- !, | |
| 184 | maplist(units_domain_multiplication(A),B,C). | |
| 185 | units_domain_multiplication(Op1,[],Op1) :- !. | |
| 186 | units_domain_multiplication([],Op2,Op2) :- !. | |
| 187 | units_domain_multiplication([[Factor1,Unit1,Pow1]|Units], UnitsOp2, Res2) :- !, | |
| 188 | (selectchk([Factor2,Unit1,Pow2],UnitsOp2,UnitsOp22) | |
| 189 | -> Factor3 is Factor1+Factor2, Pow3 is Pow1+Pow2, | |
| 190 | Res1 = [Factor3,Unit1,Pow3], units_domain_multiplication(Units,UnitsOp22,UnitsResult) | |
| 191 | ; Res1 = [Factor1,Unit1,Pow1], units_domain_multiplication(Units,UnitsOp2,UnitsResult) | |
| 192 | ), | |
| 193 | (Res1 = [0,_,0] -> Res2 = UnitsResult ; Res2 = [Res1|UnitsResult]). | |
| 194 | ||
| 195 | :- assert_must_succeed(units_domain_division(top([]),[[1,m,1]],top([]))). | |
| 196 | :- assert_must_succeed(units_domain_division([[1,m,1]],top([]),top([]))). | |
| 197 | :- assert_must_succeed(units_domain_division(top([[[1,m,1],[1,a,2]],[[1,m,1],[2,a,2]]]),[[1,m,1]],top([[[1,a,2]],[[2,a,2]]]))). | |
| 198 | :- assert_must_succeed(units_domain_division([[1,m,1]],top([[[1,m,2]],[[1,m,3]]]),top([[[0,m,-1]],[[0,m,-2]]]))). | |
| 199 | :- assert_must_succeed(units_domain_division(top([[[1,m,1]],[[2,m,1]]]),top([[[1,m,2]],[[1,m,3]]]), | |
| 200 | top([[[0,m,-1]],[[0,m,-2]],[[1,m,-1]],[[1,m,-2]]]))). | |
| 201 | :- assert_must_succeed(units_domain_division([[1,m,1]],[[1,m,1]],[])). | |
| 202 | :- assert_must_succeed(units_domain_division([[1,m,1],[1,a,2]],[[1,m,1]],[[1,a,2]])). | |
| 203 | :- assert_must_succeed(units_domain_division([[1,m,1]],[[1,m,1],[1,a,2]],[[-1,a,-2]])). | |
| 204 | :- assert_must_succeed((units_domain_division(A,B,C),var(A),var(B),var(C))). | |
| 205 | :- assert_must_succeed((units_domain_division(A,A,C),var(A),C==[])). | |
| 206 | :- assert_must_succeed((units_domain_division(_,[[1,m,1]],Y), var(Y))). | |
| 207 | :- assert_must_succeed((units_domain_division([[1,m,1]],_,Y), var(Y))). | |
| 208 | :- assert_must_succeed((units_domain_division([[0,m,1],[0,s,1]],[[0,s,1]],Res), Res = [[0,m,1]])). | |
| 209 | units_domain_division(A,B,C) :- var(A), A==B, !, C=[]. | |
| 210 | units_domain_division(A,B,C) :- one_is_var(A,B), !, add_constraint_marker(A,B), put_atts(C, dfactors(A,B)). | |
| 211 | units_domain_division(top(A),top(B),top(C)) :- | |
| 212 | !, map_product(units_domain_division,A,B,C). | |
| 213 | units_domain_division(top(A),B,top(C)) :- | |
| 214 | !, maplist(units_domain_division_reversed_arguments(B),A,C). | |
| 215 | units_domain_division(A,top(B),top(C)) :- | |
| 216 | !, maplist(units_domain_division(A),B,C). | |
| 217 | units_domain_division(Op1,[],Op1) :- !. | |
| 218 | units_domain_division([],Op2,Op3) :- !, | |
| 219 | division_reverse_signs(Op2,Op3). | |
| 220 | units_domain_division([[Factor1,Unit1,Pow1]|Units], UnitsOp2, Res2) :- !, | |
| 221 | (selectchk([Factor2,Unit1,Pow2],UnitsOp2,UnitsOp22) | |
| 222 | -> Factor3 is Factor1-Factor2, Pow3 is Pow1-Pow2, | |
| 223 | Res1 = [Factor3,Unit1,Pow3], units_domain_division(Units,UnitsOp22,UnitsResult) | |
| 224 | ; Res1 = [Factor1,Unit1,Pow1], units_domain_division(Units,UnitsOp2,UnitsResult) | |
| 225 | ), | |
| 226 | (Res1 = [0,_,0] -> Res2 = UnitsResult ; Res2 = [Res1|UnitsResult]). | |
| 227 | ||
| 228 | division_reverse_signs([],[]). | |
| 229 | division_reverse_signs([[Factor,Unit,Pow]|T],[[Factor2,Unit,Pow2]|T2]) :- | |
| 230 | Factor2 is -Factor, Pow2 is -Pow, | |
| 231 | division_reverse_signs(T,T2). | |
| 232 | ||
| 233 | % reverse argument order - for maplist | |
| 234 | units_domain_division_reversed_arguments(A,B,C) :- | |
| 235 | units_domain_division(B,A,C). | |
| 236 | ||
| 237 | % Operations on Sets | |
| 238 | :- assert_must_succeed(units_domain_member(type,set(type))). | |
| 239 | :- assert_must_fail(units_domain_member(integer([[1,m,1]]), set(integer([[2,m,1]])))). | |
| 240 | units_domain_member(A,B) :- set(A) = B, !. | |
| 241 | units_domain_member(rec(FieldsA),set(rec(FieldsB))) :- !, | |
| 242 | maplist(units_domain_member,FieldsA,FieldsB). | |
| 243 | units_domain_member(field(Name,A),field(Name,B)) :- !, | |
| 244 | units_domain_member(A,B). | |
| 245 | ||
| 246 | :- assert_must_succeed(units_domain_relation(set(type),set(type2),set(set(couple(type,type2))))). | |
| 247 | units_domain_relation(set(A),set(B),set(set(couple(A,B)))). | |
| 248 | ||
| 249 | ||
| 250 | ||
| 251 | % COMPARISON OF UNITS | |
| 252 | % same_units/1 checks if a list of units are equal | |
| 253 | % same_units/2 checks if two units are equal | |
| 254 | % lub/3 infers least upper bound - a common unit higher in the lattice than the first ones | |
| 255 | ||
| 256 | % same_units/2 - test cases | |
| 257 | :- assert_must_fail(same_units(type(_), other_type)). | |
| 258 | :- assert_must_fail(same_units(type(type2(_)), type(type3(_)))). | |
| 259 | :- assert_must_succeed(same_units(type([[1,m,1],[1,s,2]]), type([[1,s,2],[1,m,1]]))). | |
| 260 | :- assert_must_succeed(same_units(type([[-1,m,1],[1,s,2]]), type([[-1,s,2],[1,m,1]]))). | |
| 261 | :- assert_must_succeed(same_units(type([[2,m,1],[1,s,2]]), type([[2,s,2],[1,m,1]]))). | |
| 262 | :- assert_must_succeed(same_units(type([[-1,m,1],[0,s,2]]), type([[-2,s,2],[1,m,1]]))). | |
| 263 | :- assert_must_succeed(same_units(type(top([])), type(top([])))). | |
| 264 | :- assert_must_succeed(same_units(type(X), type(X))). | |
| 265 | ||
| 266 | % lub/3 - test cases | |
| 267 | :- assert_must_succeed(lub(type([[1,m,1],[1,s,2]]), type([[1,s,2],[1,m,1]]), type([[1,m,1],[1,s,2]]))). | |
| 268 | :- assert_must_succeed(lub(type([[-1,m,1],[1,s,2]]), type([[-1,s,2],[1,m,1]]), type([[-1,m,1],[1,s,2]]))). | |
| 269 | :- assert_must_succeed(lub(type(top([])), type([[1,m,1]]), type(top([[[1,m,1]]])))). | |
| 270 | :- assert_must_succeed(lub(type(top([])), type([[1,s,2],[1,m,1]]), type(top([[[1,s,2],[1,m,1]]])))). | |
| 271 | :- assert_must_succeed(lub(type([[1,m,1],[5,s,2]]), type(top([[[1,m,1]]])), type(top([[[1,m,1],[5,s,2]],[[1,m,1]]])))). | |
| 272 | :- assert_must_succeed(lub(type(X), type(X), type(X))). | |
| 273 | :- assert_must_succeed(lub([[3,m,1]],[[3,m,1],[0,h,-1]],top([[[3,m,1]],[[3,m,1],[0,h,-1]]]))). | |
| 274 | :- assert_must_succeed(lub(integer(_),integer(top([[[0,m,1]],[[0,m,1],[0,s,-1]],[[0,m,1]]])), | |
| 275 | integer(top([[[0,m,1]],[[0,m,1],[0,s,-1]],[[0,m,1]]])))). | |
| 276 | :- assert_must_succeed(lub(integer(top([[[0,m,1]],[[0,m,1],[0,s,-1]],[[0,m,1]]])),integer(_), | |
| 277 | integer(top([[[0,m,1]],[[0,m,1],[0,s,-1]],[[0,m,1]]])))). | |
| 278 | :- assert_must_succeed(lub(top([[[0,m,1]],[[0,m,1],[0,s,-1]]]),[[0,m,1],[0,s,-1]], | |
| 279 | top([[[0,m,1]],[[0,m,1],[0,s,-1]]]))). | |
| 280 | :- assert_must_succeed(lub([[0,m,1],[0,s,-1]],top([[[0,m,1]],[[0,m,1],[0,s,-1]]]), | |
| 281 | top([[[0,m,1]],[[0,m,1],[0,s,-1]]]))). | |
| 282 | :- assert_must_succeed(lub(top([[[0,m,1]],[[0,m,1],[0,s,-1]]]),top([[[0,m,1],[0,s,-1]],[[0,m,1]]]), | |
| 283 | top([[[0,m,1],[0,s,-1]],[[0,m,1]]]))). | |
| 284 | ||
| 285 | same_units([]). | |
| 286 | same_units([_]). | |
| 287 | same_units([A,B|T]) :- same_units(A,B), same_units([B|T]). | |
| 288 | % two units are identical, if the lub is again one of the two units | |
| 289 | same_units(A,B) :- lub(A,B,C), !, (A=C ; B=C). | |
| 290 | ||
| 291 | % lub/3 - implementation | |
| 292 | lub(A,B,C) :- A=B, !, B=C. | |
| 293 | lub(A,B,C) :- lub_domain_level(A,B,C), !. | |
| 294 | lub(top(A),top(B),top(C)) :- | |
| 295 | !, union(A,B,C). | |
| 296 | lub(top(A),B,top(C)) :- | |
| 297 | !, union(A,[B],C). | |
| 298 | lub(A,top(B),top(C)) :- | |
| 299 | !, union([A],B,C). | |
| 300 | lub(A,B,C) :- | |
| 301 | \+ is_list(A), \+ is_list(B), \+ is_list(C), | |
| 302 | A =.. [Type|ArgsA], | |
| 303 | B =.. [Type|ArgsB], | |
| 304 | lub_list(ArgsA,ArgsB,ArgsC), !, | |
| 305 | C =.. [Type|ArgsC]. | |
| 306 | lub(A,B,top([A,B])) :- !. | |
| 307 | ||
| 308 | lub_list([],[],[]). | |
| 309 | lub_list([H1|T1],[H2|T2],[H3|T3]) :- | |
| 310 | lub(H1,H2,H3), !, | |
| 311 | lub_list(T1,T2,T3). | |
| 312 | ||
| 313 | lub_domain_level(U1,U2,U3) :- | |
| 314 | check_factor(U1,U2,0,0), | |
| 315 | lub_domain_level2(U1,U2,U3). | |
| 316 | ||
| 317 | lub_domain_level2([],[],[]) :- !. | |
| 318 | lub_domain_level2([[Factor1,Unit1,Pow1]|Units], UnitsOp2,[[Factor1,Unit1,Pow1]|ResUnits]) :- | |
| 319 | selectchk([_Factor1,Unit1,Pow1],UnitsOp2,UnitsOp22), !, | |
| 320 | lub_domain_level2(Units,UnitsOp22,ResUnits). | |
| 321 | ||
| 322 | check_factor([],[],X,X). | |
| 323 | check_factor([[Factor1,_,_]|T1], [[Factor2,_,_]|T2],X,Y) :- | |
| 324 | !, X2 is X + Factor1, Y2 is Y + Factor2, check_factor(T1,T2,X2,Y2). |