Merge "Improve space substitution error correction."
diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp
index a06e7d0..450203d 100644
--- a/native/jni/src/suggest/core/policy/weighting.cpp
+++ b/native/jni/src/suggest/core/policy/weighting.cpp
@@ -119,7 +119,7 @@
         return weighting->getSubstitutionCost()
                 + weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
     case CT_NEW_WORD_SPACE_OMISSION:
-        return weighting->getNewWordSpatialCost(traverseSession, dicNode, inputStateG);
+        return weighting->getSpaceOmissionCost(traverseSession, dicNode, inputStateG);
     case CT_MATCH:
         return weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
     case CT_COMPLETION:
diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h
index bd6b3cf..863c4ea 100644
--- a/native/jni/src/suggest/core/policy/weighting.h
+++ b/native/jni/src/suggest/core/policy/weighting.h
@@ -57,7 +57,7 @@
             const DicTraverseSession *const traverseSession,
             const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0;
 
-    virtual float getNewWordSpatialCost(const DicTraverseSession *const traverseSession,
+    virtual float getSpaceOmissionCost(const DicTraverseSession *const traverseSession,
             const DicNode *const dicNode, DicNode_InputStateG *const inputStateG) const = 0;
 
     virtual float getNewWordBigramLanguageCost(
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index c715262..68a3645 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -160,8 +160,7 @@
             // TODO: Remove. Do not prune node here.
             const bool allowsErrorCorrections = TRAVERSAL->allowsErrorCorrections(&dicNode);
             // Process for handling space substitution (e.g., hevis => he is)
-            if (allowsErrorCorrections
-                    && TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) {
+            if (TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) {
                 createNextWordDicNode(traverseSession, &dicNode, true /* spaceSubstitution */);
             }
 
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
index 6a2db68..a6f9a8b 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
@@ -48,17 +48,17 @@
 const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.674f;
 const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.639f;
 const float ScoringParams::TRANSPOSITION_COST = 0.5608f;
-const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.334f;
+const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.33f;
+const float ScoringParams::SPACE_OMISSION_COST = 0.1f;
 const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.37972f;
 const float ScoringParams::SUBSTITUTION_COST = 0.3806f;
-const float ScoringParams::COST_NEW_WORD = 0.0314f;
 const float ScoringParams::COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE = 0.3224f;
 const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.1214f;
 const float ScoringParams::COST_FIRST_COMPLETION = 0.4836f;
 const float ScoringParams::COST_COMPLETION = 0.00624f;
 const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.0683f;
 const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.0362f;
-const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.4182f;
+const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.3482f;
 const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f;
 const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f;
 const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.095f;
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
index 731424f..b8f8895 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
@@ -56,9 +56,9 @@
     static const float INSERTION_COST_FIRST_CHAR;
     static const float TRANSPOSITION_COST;
     static const float SPACE_SUBSTITUTION_COST;
+    static const float SPACE_OMISSION_COST;
     static const float ADDITIONAL_PROXIMITY_COST;
     static const float SUBSTITUTION_COST;
-    static const float COST_NEW_WORD;
     static const float COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE;
     static const float DISTANCE_WEIGHT_LANGUAGE;
     static const float COST_FIRST_COMPLETION;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
index 8407717..1338ac8 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -150,9 +150,10 @@
         return cost + weightedDistance;
     }
 
-    float getNewWordSpatialCost(const DicTraverseSession *const traverseSession,
+    float getSpaceOmissionCost(const DicTraverseSession *const traverseSession,
             const DicNode *const dicNode, DicNode_InputStateG *inputStateG) const {
-        return ScoringParams::COST_NEW_WORD * traverseSession->getMultiWordCostMultiplier();
+        const float cost = ScoringParams::SPACE_OMISSION_COST;
+        return cost * traverseSession->getMultiWordCostMultiplier();
     }
 
     float getNewWordBigramLanguageCost(const DicTraverseSession *const traverseSession,
@@ -202,7 +203,10 @@
 
     AK_FORCE_INLINE float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession,
             const DicNode *const dicNode) const {
-        const float cost = ScoringParams::SPACE_SUBSTITUTION_COST + ScoringParams::COST_NEW_WORD;
+        const int inputIndex = dicNode->getInputIndex(0);
+        const float distanceToSpaceKey = traverseSession->getProximityInfoState(0)
+                ->getPointToKeyLength(inputIndex, KEYCODE_SPACE);
+        const float cost = ScoringParams::SPACE_SUBSTITUTION_COST * distanceToSpaceKey;
         return cost * traverseSession->getMultiWordCostMultiplier();
     }