CollectionUtil.java

  1. package org.drip.numerical.common;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  * Copyright (C) 2018 Lakshmi Krishnamurthy
  9.  * Copyright (C) 2017 Lakshmi Krishnamurthy
  10.  * Copyright (C) 2016 Lakshmi Krishnamurthy
  11.  * Copyright (C) 2015 Lakshmi Krishnamurthy
  12.  * Copyright (C) 2014 Lakshmi Krishnamurthy
  13.  * Copyright (C) 2013 Lakshmi Krishnamurthy
  14.  * Copyright (C) 2012 Lakshmi Krishnamurthy
  15.  *
  16.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  17.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  18.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  19.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  20.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  21.  *      and computational support.
  22.  *  
  23.  *      https://lakshmidrip.github.io/DROP/
  24.  *  
  25.  *  DROP is composed of three modules:
  26.  *  
  27.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  28.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  29.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  30.  *
  31.  *  DROP Product Core implements libraries for the following:
  32.  *  - Fixed Income Analytics
  33.  *  - Loan Analytics
  34.  *  - Transaction Cost Analytics
  35.  *
  36.  *  DROP Portfolio Core implements libraries for the following:
  37.  *  - Asset Allocation Analytics
  38.  *  - Asset Liability Management Analytics
  39.  *  - Capital Estimation Analytics
  40.  *  - Exposure Analytics
  41.  *  - Margin Analytics
  42.  *  - XVA Analytics
  43.  *
  44.  *  DROP Computational Core implements libraries for the following:
  45.  *  - Algorithm Support
  46.  *  - Computation Support
  47.  *  - Function Analysis
  48.  *  - Model Validation
  49.  *  - Numerical Analysis
  50.  *  - Numerical Optimizer
  51.  *  - Spline Builder
  52.  *  - Statistical Learning
  53.  *
  54.  *  Documentation for DROP is Spread Over:
  55.  *
  56.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  57.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  58.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  59.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  60.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  61.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  62.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  63.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  64.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  65.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  66.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  67.  *
  68.  *  Licensed under the Apache License, Version 2.0 (the "License");
  69.  *      you may not use this file except in compliance with the License.
  70.  *  
  71.  *  You may obtain a copy of the License at
  72.  *      http://www.apache.org/licenses/LICENSE-2.0
  73.  *  
  74.  *  Unless required by applicable law or agreed to in writing, software
  75.  *      distributed under the License is distributed on an "AS IS" BASIS,
  76.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  77.  *  
  78.  *  See the License for the specific language governing permissions and
  79.  *      limitations under the License.
  80.  */

  81. /**
  82.  * <i>CollectionUtil</i> implements generic utility functions used in DROP modules. Some of the functions it
  83.  * exposes are:
  84.  *
  85.  * <br><br>
  86.  *  <ul>
  87.  *      <li>
  88.  *          Map Merging Functionality
  89.  *      </li>
  90.  *      <li>
  91.  *          Map Key Functionality - key-value flatteners, key prefixers
  92.  *      </li>
  93.  *      <li>
  94.  *          Decompose/transform List/Set/Array Contents
  95.  *      </li>
  96.  *      <li>
  97.  *          Multi-Dimensional Map Manipulator Routines
  98.  *      </li>
  99.  *      <li>
  100.  *          Construct n-derivatives array from Slope
  101.  *      </li>
  102.  *      <li>
  103.  *          Collate Wengerts to a bigger Wengert
  104.  *      </li>
  105.  *  </ul>
  106.  *
  107.  * <br><br>
  108.  *  <ul>
  109.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  110.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  111.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical">Numerical Quadrature, Differentiation, Eigenization, Linear Algebra, and Utilities</a></li>
  112.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical/common">Primitives/Array Manipulate Format Display Utilities</a></li>
  113.  *  </ul>
  114.  * <br><br>
  115.  *
  116.  * @author Lakshmi Krishnamurthy
  117.  */

  118. public class CollectionUtil {

  119.     /**
  120.      * Prefix the keys in the input map, and return them in a new map
  121.      *
  122.      * @param mapIn Input map
  123.      * @param strPrefix The prefix
  124.      *
  125.      * @return Map containing the prefixed entries
  126.      */

  127.     public static final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> PrefixKeys (
  128.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> mapIn,
  129.         final java.lang.String strPrefix)
  130.     {
  131.         if (null == mapIn || null == mapIn.entrySet() || null == strPrefix || strPrefix.isEmpty())
  132.             return null;

  133.         org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> mapOut = new
  134.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>();

  135.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : mapIn.entrySet()) {
  136.             if (null != me.getKey() && !me.getKey().isEmpty())
  137.                 mapOut.put (strPrefix + me.getKey(), me.getValue());
  138.         }

  139.         return mapOut;
  140.     }

  141.     /**
  142.      * Merge two maps
  143.      *
  144.      * @param map1 Map 1
  145.      * @param map2 Map 2
  146.      *
  147.      * @return The merged map
  148.      */

  149.     public static final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> MergeMaps (
  150.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map1,
  151.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map2)
  152.     {
  153.         if (null == map1 && null == map2) return null;

  154.         if (null == map1 && null != map2) return map2;

  155.         if (null != map1 && null == map2) return map1;

  156.         org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> mapOut = new
  157.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>();

  158.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : map1.entrySet())
  159.             mapOut.put (me.getKey(), me.getValue());

  160.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : map2.entrySet())
  161.             mapOut.put (me.getKey(), me.getValue());

  162.         return mapOut;
  163.     }

  164.     /**
  165.      * Merge the secondary map onto the main map
  166.      *
  167.      * @param mapMain Main Map
  168.      * @param mapToAdd Secondary Map to Add
  169.      *
  170.      * @return True - If successfully merged with main
  171.      */

  172.     public static final boolean MergeWithMain (
  173.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> mapMain,
  174.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> mapToAdd)
  175.     {
  176.         if (null == mapMain || null == mapMain.entrySet() || null == mapToAdd || null ==
  177.             mapToAdd.entrySet())
  178.             return false;

  179.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : mapToAdd.entrySet())
  180.             mapMain.put (me.getKey(), me.getValue());

  181.         return true;
  182.     }

  183.     /**
  184.      * Flatten an input 2D string/double map into a delimited string array
  185.      *
  186.      * @param map2DSD 2D String/Double map
  187.      * @param strKVDelimiter Element delimiter
  188.      * @param strRecordDelimiter Record delimiter
  189.      *
  190.      * @return Flattened map string
  191.      */

  192.     public static final java.lang.String TwoDSDMapToFlatString (
  193.         final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map2DSD,
  194.         final java.lang.String strKVDelimiter,
  195.         final java.lang.String strRecordDelimiter)
  196.     {
  197.         if (null == map2DSD || 0 == map2DSD.size() || null == map2DSD.entrySet() || null == strKVDelimiter ||
  198.             strKVDelimiter.isEmpty() || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  199.             return "";

  200.         boolean bFirstEntry = true;

  201.         java.lang.StringBuffer sb = new java.lang.StringBuffer();

  202.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : map2DSD.entrySet()) {
  203.             if (null == me || null == me.getKey() || me.getKey().isEmpty()) continue;

  204.             if (bFirstEntry)
  205.                 bFirstEntry = false;
  206.             else
  207.                 sb.append (strRecordDelimiter);

  208.             sb.append (me.getKey() + strKVDelimiter + me.getValue());
  209.         }

  210.         return sb.toString();
  211.     }

  212.     /**
  213.      * Flatten a 3D SSD map structure onto a string array
  214.      *
  215.      * @param map3DSD 3D SSD map
  216.      * @param strMultiLevelKeyDelimiter Multi Level KeyDelimiter
  217.      * @param strKVDelimiter Key-Value Delimiter
  218.      * @param strRecordDelimiter Record Delimiter
  219.      *
  220.      * @return Flattened String
  221.      */

  222.     public static final java.lang.String ThreeDSDMapToFlatString (
  223.         final
  224.             org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>
  225.                 map3DSD,
  226.         final java.lang.String strMultiLevelKeyDelimiter,
  227.         final java.lang.String strKVDelimiter,
  228.         final java.lang.String strRecordDelimiter)
  229.     {
  230.         if (null == map3DSD || 0 == map3DSD.size() || null == map3DSD.entrySet() || null ==
  231.             strMultiLevelKeyDelimiter || strMultiLevelKeyDelimiter.isEmpty() || null == strKVDelimiter ||
  232.                 strKVDelimiter.isEmpty() || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  233.             return null;

  234.         boolean bFirstEntry = true;

  235.         java.lang.StringBuffer sb = new java.lang.StringBuffer();

  236.         for (java.util.Map.Entry<java.lang.String,
  237.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>> meOut : map3DSD.entrySet()) {
  238.             if (null == meOut || null == meOut.getValue() || null == meOut.getValue().entrySet()) continue;

  239.             for (java.util.Map.Entry<java.lang.String, java.lang.Double> meIn : meOut.getValue().entrySet())
  240.             {
  241.                 if (null == meIn || null == meIn.getKey() || meIn.getKey().isEmpty()) continue;

  242.                 if (bFirstEntry)
  243.                     bFirstEntry = false;
  244.                 else
  245.                     sb.append (strRecordDelimiter);

  246.                 sb.append (meOut.getKey() + strMultiLevelKeyDelimiter + meIn.getKey() + strKVDelimiter +
  247.                     meIn.getValue());
  248.             }
  249.         }

  250.         return sb.toString();
  251.     }

  252.     /**
  253.      * Flatten a 4D SSSD map structure onto a string array
  254.      *
  255.      * @param map4DSD 4D SSSD map
  256.      * @param strMultiLevelKeyDelimiter Multi Level KeyDelimiter
  257.      * @param strKVDelimiter Key-Value Delimiter
  258.      * @param strRecordDelimiter Record Delimiter
  259.      *
  260.      * @return Flattened String
  261.      */

  262.     public static final java.lang.String FourDSDMapToFlatString (
  263.         final
  264.             org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>>
  265.                 map4DSD,
  266.         final java.lang.String strMultiLevelKeyDelimiter,
  267.         final java.lang.String strKVDelimiter,
  268.         final java.lang.String strRecordDelimiter)
  269.     {
  270.         if (null == map4DSD || 0 == map4DSD.size() || null == map4DSD.entrySet() || null ==
  271.             strMultiLevelKeyDelimiter || strMultiLevelKeyDelimiter.isEmpty() || null == strKVDelimiter ||
  272.                 strKVDelimiter.isEmpty() || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  273.             return null;

  274.         boolean bFirstEntry = true;

  275.         java.lang.StringBuffer sb = new java.lang.StringBuffer();

  276.         for (java.util.Map.Entry<java.lang.String,org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>>
  277.             meOut : map4DSD.entrySet()) {
  278.             if (null == meOut || null == meOut.getValue() || null == meOut.getValue().entrySet() || null ==
  279.                 meOut.getKey() || meOut.getKey().isEmpty())
  280.                 continue;

  281.             for (java.util.Map.Entry<java.lang.String,
  282.                 org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>> meIn :
  283.                     meOut.getValue().entrySet()) {
  284.                 if (null == meIn || null == meIn.getValue() || null == meIn.getValue().entrySet() || null ==
  285.                     meIn.getKey() || meIn.getKey().isEmpty())
  286.                     continue;

  287.                 for (java.util.Map.Entry<java.lang.String, java.lang.Double> me : meIn.getValue().entrySet())
  288.                 {
  289.                     if (null == me || null == me.getKey() || me.getKey().isEmpty()) continue;

  290.                     if (bFirstEntry)
  291.                         bFirstEntry = false;
  292.                     else
  293.                         sb.append (strRecordDelimiter);

  294.                     sb.append (meOut.getKey() + strMultiLevelKeyDelimiter + meIn.getKey() +
  295.                         strMultiLevelKeyDelimiter + me.getKey() + strKVDelimiter + me.getValue());
  296.                 }
  297.             }
  298.         }

  299.         return sb.toString();
  300.     }

  301.     /**
  302.      * Turn a flattened 2D (string, double) string sequence into its corresponding map
  303.      *
  304.      * @param str2DMap Flattened 2D array input
  305.      * @param strKVDelimiter Key-Value delimiter string
  306.      * @param strRecordDelimiter Record delimiter string
  307.      * @param bSkipNullValue Indicates whether NULL Values are to be skipped
  308.      * @param strNULLString NULL string
  309.      *
  310.      * @return [String, double] map
  311.      */

  312.     public static final org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>
  313.         FlatStringTo2DSDMap (
  314.             final java.lang.String str2DMap,
  315.             final java.lang.String strKVDelimiter,
  316.             final java.lang.String strRecordDelimiter,
  317.             final boolean bSkipNullValue,
  318.             final java.lang.String strNULLString)
  319.     {
  320.         if (null == str2DMap || str2DMap.isEmpty() || null == strNULLString || strNULLString.isEmpty() ||
  321.             strNULLString.equalsIgnoreCase (str2DMap) || null == strKVDelimiter || strKVDelimiter.isEmpty()
  322.                 || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  323.             return null;

  324.         java.lang.String[] astrRecord = org.drip.numerical.common.StringUtil.Split (str2DMap,
  325.             strRecordDelimiter);

  326.         if (null == astrRecord || 0 == astrRecord.length) return null;

  327.         org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map2D = new
  328.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>();

  329.         for (int i = 0; i < astrRecord.length; ++i) {
  330.             if (null == astrRecord[i] || astrRecord[i].isEmpty() || strNULLString.equalsIgnoreCase
  331.                 (astrRecord[i]))
  332.                 continue;

  333.             java.lang.String[] astrKVPair = org.drip.numerical.common.StringUtil.Split (astrRecord[i],
  334.                 strKVDelimiter);
  335.            
  336.             if (null == astrKVPair || 2 != astrKVPair.length || null == astrKVPair[0] ||
  337.                 astrKVPair[0].isEmpty() || strNULLString.equalsIgnoreCase (astrKVPair[0]) || (bSkipNullValue
  338.                     && (null == astrKVPair[1] || astrKVPair[1].isEmpty() || strNULLString.equalsIgnoreCase
  339.                         (astrKVPair[1]))))
  340.                 continue;

  341.             map2D.put (astrKVPair[0], java.lang.Double.parseDouble (astrKVPair[1]));
  342.         }

  343.         if (0 == map2D.size()) return null;

  344.         return map2D;
  345.     }

  346.     /**
  347.      * Turn a flattened 3D (string, string, double) string sequence into its corresponding map
  348.      *
  349.      * @param str3DMap Flattened 3D array input
  350.      * @param strMultiLevelKeyDelimiter Multi-level key delimiter string
  351.      * @param strKVDelimiter Key-Value delimiter string
  352.      * @param strRecordDelimiter Record delimiter string
  353.      * @param bSkipNullValue Indicates whether NULL Values are to be skipped
  354.      * @param strNULLString NULL string
  355.      *
  356.      * @return [String, [String, double]] map
  357.      */

  358.     public static final
  359.         org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>
  360.             FlatStringTo3DSDMap (
  361.                 final java.lang.String str3DMap,
  362.                 final java.lang.String strMultiLevelKeyDelimiter,
  363.                 final java.lang.String strKVDelimiter,
  364.                 final java.lang.String strRecordDelimiter,
  365.                 final boolean bSkipNullValue,
  366.                 final java.lang.String strNULLString)
  367.     {
  368.         if (null == str3DMap || str3DMap.isEmpty() || null == strNULLString || strNULLString.isEmpty() ||
  369.             strNULLString.equalsIgnoreCase (str3DMap) || null == strKVDelimiter || strKVDelimiter.isEmpty()
  370.                 || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  371.             return null;

  372.         java.lang.String[] astrRecord = org.drip.numerical.common.StringUtil.Split (str3DMap, strRecordDelimiter);

  373.         if (null == astrRecord || 0 == astrRecord.length) return null;

  374.         org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>
  375.             map3D = new
  376.                 org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>();

  377.         for (int i = 0; i < astrRecord.length; ++i) {
  378.             if (null == astrRecord[i] || astrRecord[i].isEmpty()) continue;

  379.             java.lang.String[] astrKVPair = org.drip.numerical.common.StringUtil.Split (astrRecord[i], strKVDelimiter);
  380.            
  381.             if (null == astrKVPair || 2 != astrKVPair.length || null == astrKVPair[0] ||
  382.                 astrKVPair[0].isEmpty() || strNULLString.equalsIgnoreCase (astrKVPair[0]) || (bSkipNullValue
  383.                     && (null == astrKVPair[1] || astrKVPair[1].isEmpty() || strNULLString.equalsIgnoreCase
  384.                         (astrKVPair[1]))))
  385.                 continue;

  386.             java.lang.String[] astrKeySet = org.drip.numerical.common.StringUtil.Split (astrKVPair[0],
  387.                 strMultiLevelKeyDelimiter);
  388.            
  389.             if (null == astrKeySet || 2 != astrKeySet.length || null == astrKeySet[0] ||
  390.                 astrKeySet[0].isEmpty() || strNULLString.equalsIgnoreCase (astrKeySet[0]) || null ==
  391.                     astrKeySet[1] || astrKeySet[1].isEmpty() || strNULLString.equalsIgnoreCase
  392.                         (astrKeySet[1]))
  393.                 continue;

  394.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map2D = map3D.get
  395.                 (astrKeySet[0]);

  396.             if (null == map2D)
  397.                 map2D = new org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>();

  398.             map2D.put (astrKeySet[1], java.lang.Double.parseDouble (astrKVPair[1]));

  399.             map3D.put (astrKeySet[0], map2D);
  400.         }

  401.         if (0 == map3D.size()) return null;

  402.         return map3D;
  403.     }

  404.     /**
  405.      * Turn a flattened 4D (string, string, string, double) string sequence into its corresponding map
  406.      *
  407.      * @param str4DMap Flattened 4D array input
  408.      * @param strMultiLevelKeyDelimiter Multi-level key delimiter string
  409.      * @param strKVDelimiter Key-Value delimiter string
  410.      * @param strRecordDelimiter Record delimiter string
  411.      * @param bSkipNullValue Indicates whether NULL Values are to be skipped
  412.      * @param strNULLString NULL string
  413.      *
  414.      * @return [String, [String, [String, double]]] map
  415.      */

  416.     public static final
  417.         org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>>
  418.             FlatStringTo4DSDMap (
  419.                 final java.lang.String str4DMap,
  420.                 final java.lang.String strMultiLevelKeyDelimiter,
  421.                 final java.lang.String strKVDelimiter,
  422.                 final java.lang.String strRecordDelimiter,
  423.                 final boolean bSkipNullValue,
  424.                 final java.lang.String strNULLString)
  425.     {
  426.         if (null == str4DMap || str4DMap.isEmpty() || null == strNULLString || strNULLString.isEmpty() ||
  427.             strNULLString.equalsIgnoreCase (str4DMap) || null == strKVDelimiter || strKVDelimiter.isEmpty()
  428.                 || null == strRecordDelimiter || strRecordDelimiter.isEmpty())
  429.             return null;

  430.         java.lang.String[] astrRecord = org.drip.numerical.common.StringUtil.Split (str4DMap, strRecordDelimiter);

  431.         if (null == astrRecord || 0 == astrRecord.length) return null;

  432.         org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>>
  433.             map4D = new
  434.                 org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>>();

  435.         for (int i = 0; i < astrRecord.length; ++i) {
  436.             if (null == astrRecord[i] || astrRecord[i].isEmpty() || strNULLString.equalsIgnoreCase
  437.                 (astrRecord[i]))
  438.                 continue;

  439.             java.lang.String[] astrKVPairOut = org.drip.numerical.common.StringUtil.Split (astrRecord[i],
  440.                 strKVDelimiter);
  441.            
  442.             if (null == astrKVPairOut || 2 != astrKVPairOut.length || null == astrKVPairOut[0] ||
  443.                 astrKVPairOut[0].isEmpty() || strNULLString.equalsIgnoreCase (astrKVPairOut[0]) ||
  444.                     (bSkipNullValue && (null == astrKVPairOut[1] || astrKVPairOut[1].isEmpty() ||
  445.                         strNULLString.equalsIgnoreCase (astrKVPairOut[1]))))
  446.                 continue;

  447.             java.lang.String[] astrKeySet = org.drip.numerical.common.StringUtil.Split (astrKVPairOut[0],
  448.                 strMultiLevelKeyDelimiter);
  449.            
  450.             if (null == astrKeySet || 3 != astrKeySet.length || null == astrKeySet[0] ||
  451.                 astrKeySet[0].isEmpty() || strNULLString.equalsIgnoreCase (astrKeySet[0]) || null ==
  452.                     astrKeySet[1] || astrKeySet[1].isEmpty() || strNULLString.equalsIgnoreCase
  453.                         (astrKeySet[1]) || null == astrKeySet[2] || astrKeySet[2].isEmpty() ||
  454.                             strNULLString.equalsIgnoreCase (astrKeySet[2]))
  455.                 continue;

  456.             org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>
  457.                 map3D = map4D.get (astrKeySet[0]);

  458.             if (null == map3D)
  459.                 map3D = new
  460.                     org.drip.analytics.support.CaseInsensitiveTreeMap<org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>>();

  461.             org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double> map2D = map3D.get
  462.                 (astrKeySet[1]);

  463.             if (null == map2D)
  464.                 map2D = new org.drip.analytics.support.CaseInsensitiveTreeMap<java.lang.Double>();

  465.             map2D.put (astrKeySet[2], java.lang.Double.parseDouble (astrKVPairOut[1]));

  466.             map3D.put (astrKeySet[1], map2D);

  467.             map4D.put (astrKeySet[0], map3D);
  468.         }

  469.         if (0 == map4D.size()) return null;

  470.         return map4D;
  471.     }

  472.     /**
  473.      * Populate an array of derivatives using the input slope (and setting the other to zero)
  474.      *
  475.      * @param iNumDerivs Number of Derivatives to be populated
  476.      * @param dblSlope Slope
  477.      *
  478.      * @return Array of derivatives
  479.      */

  480.     public static final double[] DerivArrayFromSlope (
  481.         final int iNumDerivs,
  482.         final double dblSlope)
  483.     {
  484.         if (0 >= iNumDerivs || !org.drip.numerical.common.NumberUtil.IsValid (dblSlope)) return null;

  485.         double[] adblDeriv = new double[iNumDerivs];

  486.         for (int i = 0; i < iNumDerivs; ++i)
  487.             adblDeriv[i] = (0 == i) ? dblSlope : 0.;

  488.         return adblDeriv;
  489.     }

  490.     /**
  491.      * Append the Wengert Jacobians inside the list onto one single composite
  492.      *
  493.      * @param lsWJ List of Wengert Jacobians
  494.      *
  495.      * @return The Composite Wengert Jacobian
  496.      */

  497.     public static final org.drip.numerical.differentiation.WengertJacobian AppendWengert (
  498.         final java.util.List<org.drip.numerical.differentiation.WengertJacobian> lsWJ)
  499.     {
  500.         if (null == lsWJ || 0 == lsWJ.size()) return null;

  501.         int iNumQuote = 0;
  502.         int iQuoteCursor = 0;
  503.         org.drip.numerical.differentiation.WengertJacobian wjCombined = null;

  504.         for (org.drip.numerical.differentiation.WengertJacobian wj : lsWJ)
  505.             if (null != wj) iNumQuote += wj.numParameters();

  506.         try {
  507.             wjCombined = new org.drip.numerical.differentiation.WengertJacobian (1, iNumQuote);
  508.         } catch (java.lang.Exception e) {
  509.             e.printStackTrace();

  510.             return null;
  511.         }

  512.         for (org.drip.numerical.differentiation.WengertJacobian wj : lsWJ) {
  513.             if (null == wj) continue;

  514.             int iNumParams = wj.numParameters();

  515.             for (int i = 0; i < iNumParams; ++i) {
  516.                 try {
  517.                     if (!wjCombined.accumulatePartialFirstDerivative (0, iQuoteCursor++, wj.firstDerivative
  518.                         (0, i)))
  519.                         return null;
  520.                 } catch (java.lang.Exception e) {
  521.                     e.printStackTrace();

  522.                     return null;
  523.                 }
  524.             }
  525.         }

  526.         return wjCombined;
  527.     }
  528. }