@@ -25,13 +25,16 @@ internal static class QuantityRelationsParser
25
25
///
26
26
/// The format of a relation definition is "Quantity.Unit operator Quantity.Unit = Quantity.Unit" (See examples below).
27
27
/// "double" can be used as a unitless operand.
28
- /// "1" can be used as the left operand to define inverse relations.
28
+ /// "1" can be used as the result operand to define inverse relations.
29
+ ///
30
+ /// Division relations are inferred from multiplication relations,
31
+ /// but this can be skipped if the string ends with "NoInferredDivision".
29
32
/// </summary>
30
33
/// <example>
31
34
/// [
32
- /// "Power.Watt = ElectricPotential.Volt * ElectricCurrent.Ampere",
33
- /// "Speed.MeterPerSecond = Length.Meter / Duration.Second ",
34
- /// "ReciprocalLength.InverseMeter = 1 / Length.Meter"
35
+ /// "1 = Length.Meter * ReciprocalLength.InverseMeter"
36
+ /// "Power.Watt = ElectricPotential.Volt * ElectricCurrent.Ampere ",
37
+ /// "Mass.Kilogram = MassConcentration.KilogramPerCubicMeter * Volume.CubicMeter -- NoInferredDivision",
35
38
/// ]
36
39
/// </example>
37
40
/// <param name="rootDir">Repository root directory.</param>
@@ -61,7 +64,7 @@ public static void ParseAndApplyRelations(string rootDir, Quantity[] quantities)
61
64
62
65
// We can infer division relations from multiplication relations.
63
66
relations . AddRange ( relations
64
- . Where ( r => r . Operator is "*" )
67
+ . Where ( r => r is { Operator : "*" , NoInferredDivision : false } )
65
68
. Select ( r => r with
66
69
{
67
70
Operator = "/" ,
@@ -73,9 +76,6 @@ public static void ParseAndApplyRelations(string rootDir, Quantity[] quantities)
73
76
// Skip division between equal quantities because the ratio is already generated as part of the Arithmetic Operators.
74
77
. Where ( r => r . LeftQuantity != r . RightQuantity )
75
78
. ToList ( ) ) ;
76
-
77
- // Remove inferred relation "MassConcentration = Mass / Volume" because it duplicates "Density = Mass / Volume"
78
- relations . RemoveAll ( r => r is { Operator : "/" , ResultQuantity . Name : "MassConcentration" , LeftQuantity . Name : "Mass" , RightQuantity . Name : "Volume" } ) ;
79
79
80
80
// Sort all relations to keep generated operators in a consistent order.
81
81
relations . Sort ( ) ;
@@ -91,6 +91,18 @@ public static void ParseAndApplyRelations(string rootDir, Quantity[] quantities)
91
91
var list = string . Join ( "\n " , duplicates ) ;
92
92
throw new UnitsNetCodeGenException ( $ "Duplicate inferred relations:\n { list } ") ;
93
93
}
94
+
95
+ var ambiguous = relations
96
+ . GroupBy ( r => $ "{ r . LeftQuantity . Name } { r . Operator } { r . RightQuantity . Name } ")
97
+ . Where ( g => g . Count ( ) > 1 )
98
+ . Select ( g => g . Key )
99
+ . ToList ( ) ;
100
+
101
+ if ( ambiguous . Any ( ) )
102
+ {
103
+ var list = string . Join ( "\n " , ambiguous ) ;
104
+ throw new UnitsNetCodeGenException ( $ "Ambiguous inferred relations:\n { list } \n \n Hint: you could use NoInferredDivision in the definition file.") ;
105
+ }
94
106
95
107
foreach ( var quantity in quantities )
96
108
{
@@ -140,7 +152,7 @@ private static QuantityRelation ParseRelation(string relationString, IReadOnlyDi
140
152
{
141
153
var segments = relationString . Split ( ' ' ) ;
142
154
143
- if ( segments is not [ _, "=" , _, "*" , _] )
155
+ if ( segments is not [ _, "=" , _, "*" , _, .. ] )
144
156
{
145
157
throw new Exception ( $ "Invalid relation string: { relationString } ") ;
146
158
}
@@ -165,6 +177,7 @@ private static QuantityRelation ParseRelation(string relationString, IReadOnlyDi
165
177
166
178
return new QuantityRelation
167
179
{
180
+ NoInferredDivision = segments . Contains ( "NoInferredDivision" ) ,
168
181
Operator = @operator ,
169
182
LeftQuantity = leftQuantity ,
170
183
LeftUnit = leftUnit ,
0 commit comments