From 9023fec356b94bf1f312b22c3cf65430c11008cb Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 21 Dec 2022 14:21:50 +0100 Subject: [PATCH 01/28] Adding mandatory AoC step exception in the filter and adding warnings for not importing mandatory AoC steps- --- ifrs17/Import/Importers.ipynb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index f9015f90..7ece7baf 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -69,6 +69,7 @@ "\n // Dimensions", "\n public Dictionary EstimateType;", "\n public Dictionary AmountType; ", + "\n public HashSet MandatoryAocSteps;", "\n public HashSet AocTypeMap;", "\n private HashSet estimateTypes;", "\n private HashSet amountTypes;", @@ -124,6 +125,7 @@ "\n ReportingNode = reportingNodes.First();", "\n", "\n var aocConfigurationByAocStep = await dataSource.LoadAocStepConfigurationAsync(args.Year, args.Month);", + "\n MandatoryAocSteps = aocConfigurationByAocStep.Where(x => x.DataType == DataType.Mandatory).Select(x => new AocStep(x.AocType, x.Novelty)).ToHashSet();", "\n AocTypeMap = args.ImportFormat switch {", "\n ImportFormats.Cashflow => aocConfigurationByAocStep.Where(x => x.InputSource.Contains(InputSource.Cashflow) &&", "\n !new DataType[]{DataType.Calculated, DataType.CalculatedTelescopic}.Contains(x.DataType) )", @@ -1020,11 +1022,10 @@ "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(RawVariable.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray();", "\n ", - "\n // Filter out empty raw variables for AocType != CL", - "\n //TODO: extend this check for all mandatory step and not just for CL", + "\n // Filter out empty raw variables for AocType \\not\\in MandatoryAocSteps", "\n if(args.Scenario == null) {", "\n values = values.Prune();", - "\n if(values.Length == 0 && aocType != AocTypes.CL) return null;", + "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", "\n }", "\n ", "\n var item = new RawVariable {", @@ -1067,6 +1068,16 @@ "\n var log = await ParseCashflowsToWorkspaceAsync(dataSet, mainArgs, workspace);", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", "\n", + "\n var messagesByIdentityProperties = workspace.Query()", + "\n .GroupBy(x => string.Join(\", \", typeof(RawVariable).GetIdentityProperties()", + "\n .Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name))", + "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")", + "\n .ToHashSet()),", + "\n x => new AocStep(x.AocType, x.Novelty),", + "\n (properties, aocSteps) => storage.MandatoryAocSteps.Except(aocSteps)", + "\n .Select(x => $\"The AoC step ({x.AocType}, {x.Novelty}) is not imported for ({properties}).\" ) );", + "\n foreach(var messages in messagesByIdentityProperties) foreach (var message in messages) ApplicationMessage.Log(Warning.Generic, message);", + "\n ", "\n foreach (var args in targetArgs) {", "\n log = log.Merge(await CalculateAndUploadVariablesAsync(args, workspace, args == mainArgs));", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", @@ -1316,4 +1327,4 @@ "outputs": [] } ] -} +} \ No newline at end of file From b66839825af240191d056b4864a4fa4843938dd0 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 22 Dec 2022 12:28:36 +0100 Subject: [PATCH 02/28] Including Andreas feedback --- ifrs17/Import/Importers.ipynb | 159 +++++++++++++++++++++------------- 1 file changed, 100 insertions(+), 59 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 7ece7baf..8beb9cc2 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -410,30 +410,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "markdown", - "source": [ - "## Validation for Active Data Node States" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public async Task ValidateForDataNodeStateActiveAsync(IWorkspace workspace, Dictionary dataNodes) where T : BaseDataRecord", - "\n{ ", - "\n foreach(var item in (await workspace.Query().ToArrayAsync()).GroupBy(x => x.DataNode))", - "\n if(!dataNodes.ContainsKey(item.First().DataNode))", - "\n ApplicationMessage.Log(Error.InactiveDataNodeState, item.First().DataNode);", - "\n}", - "\n" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "markdown", "source": [ @@ -511,6 +487,100 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "# Validations" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Validation for Active Data Node States" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public async Task ValidateForDataNodeStateActiveAsync(IWorkspace workspace, Dictionary dataNodes) where T : BaseDataRecord", + "\n{ ", + "\n foreach(var item in (await workspace.Query().ToArrayAsync()).GroupBy(x => x.DataNode))", + "\n if(!dataNodes.ContainsKey(item.First().DataNode))", + "\n ApplicationMessage.Log(Error.InactiveDataNodeState, item.First().DataNode);", + "\n}", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Validate for Data Node States Logic" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public async static Task ValidateDataNodeStatesAsync(this IWorkspace workspace, Dictionary persistentDataNodeByDataNode)", + "\n{", + "\n foreach(var importedDataNodeState in await workspace.Query().ToArrayAsync())", + "\n {", + "\n if(persistentDataNodeByDataNode.TryGetValue(importedDataNodeState.DataNode, out var currentPersistentDataNode))", + "\n {", + "\n if(importedDataNodeState.State < currentPersistentDataNode.State)", + "\n ApplicationMessage.Log(Error.ChangeDataNodeState, importedDataNodeState.DataNode, ", + "\n currentPersistentDataNode.State.ToString(), ", + "\n importedDataNodeState.State.ToString());", + "\n", + "\n if(importedDataNodeState.State == currentPersistentDataNode.State)", + "\n await workspace.DeleteAsync(importedDataNodeState);", + "\n }", + "\n }", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Validate for Mandatory Aoc Steps" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public IEnumerable<(string Properties, IEnumerable AocSteps)> ValidateForMandatoryAocSteps(IDataSet dataSet, IWorkspace workspace, HashSet mandatoryAocSteps)", + "\n{", + "\n return workspace.Query().ToList()", + "\n .GroupBy(x => string.Join(\", \", typeof(RawVariable).GetIdentityProperties()", + "\n .Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name))", + "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")", + "\n .ToHashSet()),", + "\n x => new AocStep(x.AocType, x.Novelty),", + "\n (properties, aocSteps) => (properties, aocSteps)", + "\n );", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ @@ -777,30 +847,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "code", - "source": [ - "public async static Task ValidateDataNodeStatesAsync(this IWorkspace workspace, Dictionary persistentDataNodeByDataNode)", - "\n{", - "\n foreach(var importedDataNodeState in await workspace.Query().ToArrayAsync())", - "\n {", - "\n if(persistentDataNodeByDataNode.TryGetValue(importedDataNodeState.DataNode, out var currentPersistentDataNode))", - "\n {", - "\n if(importedDataNodeState.State < currentPersistentDataNode.State)", - "\n ApplicationMessage.Log(Error.ChangeDataNodeState, importedDataNodeState.DataNode, ", - "\n currentPersistentDataNode.State.ToString(), ", - "\n importedDataNodeState.State.ToString());", - "\n", - "\n if(importedDataNodeState.State == currentPersistentDataNode.State)", - "\n await workspace.DeleteAsync(importedDataNodeState);", - "\n }", - "\n }", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "code", "source": [ @@ -1044,6 +1090,10 @@ "\n }, ImportFormats.Cashflow", "\n ).WithTarget(workspace).ExecuteAsync();", "\n ", + "\n var missingAocStepsByIdentityProperties = ValidateForMandatoryAocSteps(dataSet, workspace, parsingStorage.MandatoryAocSteps);", + "\n foreach(var aocSteps in missingAocStepsByIdentityProperties) ", + "\n foreach(var aocStep in aocSteps.AocSteps) ApplicationMessage.Log(Warning.MandatoryAocStepMissing, aocStep.AocType, aocStep.Novelty, aocSteps.Properties);", + "\n", "\n await ValidateForDataNodeStateActiveAsync(workspace, parsingStorage.DataNodeDataBySystemName);", "\n return Activity.Finish().Merge(importLog);", "\n}" @@ -1067,21 +1117,12 @@ "\n var workspace = Workspace.CreateNew();", "\n var log = await ParseCashflowsToWorkspaceAsync(dataSet, mainArgs, workspace);", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", - "\n", - "\n var messagesByIdentityProperties = workspace.Query()", - "\n .GroupBy(x => string.Join(\", \", typeof(RawVariable).GetIdentityProperties()", - "\n .Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name))", - "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")", - "\n .ToHashSet()),", - "\n x => new AocStep(x.AocType, x.Novelty),", - "\n (properties, aocSteps) => storage.MandatoryAocSteps.Except(aocSteps)", - "\n .Select(x => $\"The AoC step ({x.AocType}, {x.Novelty}) is not imported for ({properties}).\" ) );", - "\n foreach(var messages in messagesByIdentityProperties) foreach (var message in messages) ApplicationMessage.Log(Warning.Generic, message);", - "\n ", + "\n ", "\n foreach (var args in targetArgs) {", "\n log = log.Merge(await CalculateAndUploadVariablesAsync(args, workspace, args == mainArgs));", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", "\n }", + "\n await DataSource.UpdateAsync(dataSet.RepeatOnce());", "\n return Activity.Finish().Merge(log); ", "\n});" ], From 68d140a0366b1e461111716f0d78ebe117720187 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 22 Dec 2022 13:01:50 +0100 Subject: [PATCH 03/28] Adding a warning for missing aoc steps import. --- ifrs17/Constants/Validations.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 64a58f8c..6d793bd9 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -51,7 +51,7 @@ "source": [ "public enum Warning {", "\n // Import", - "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations,", + "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations, MandatoryAocStepMissing,", "\n // Default", "\n Generic", "\n}; " @@ -184,6 +184,7 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", + "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[3]}.\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", From fcc7e3fbe5fcce3571cbf189d969a2ab8158f850 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 22 Dec 2022 14:37:27 +0100 Subject: [PATCH 04/28] Removing bugs --- ifrs17/Constants/Validations.ipynb | 2 +- ifrs17/Import/Importers.ipynb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 6d793bd9..258274dd 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -184,7 +184,7 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", - "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[3]}.\",", + "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}.\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 8beb9cc2..cdf89415 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -573,7 +573,7 @@ "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")", "\n .ToHashSet()),", "\n x => new AocStep(x.AocType, x.Novelty),", - "\n (properties, aocSteps) => (properties, aocSteps)", + "\n (properties, aocSteps) => (properties, mandatoryAocSteps.Except(aocSteps))", "\n );", "\n}" ], @@ -1122,7 +1122,6 @@ "\n log = log.Merge(await CalculateAndUploadVariablesAsync(args, workspace, args == mainArgs));", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", "\n }", - "\n await DataSource.UpdateAsync(dataSet.RepeatOnce());", "\n return Activity.Finish().Merge(log); ", "\n});" ], From e381ba9ce113c05bb0649f2f607b27ce5189f7c4 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 22 Dec 2022 14:59:33 +0100 Subject: [PATCH 05/28] Aesthetics --- ifrs17/Import/Importers.ipynb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index cdf89415..1c8fe084 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -567,11 +567,10 @@ "source": [ "public IEnumerable<(string Properties, IEnumerable AocSteps)> ValidateForMandatoryAocSteps(IDataSet dataSet, IWorkspace workspace, HashSet mandatoryAocSteps)", "\n{", + "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name));", "\n return workspace.Query().ToList()", - "\n .GroupBy(x => string.Join(\", \", typeof(RawVariable).GetIdentityProperties()", - "\n .Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name))", - "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")", - "\n .ToHashSet()),", + "\n .GroupBy(x => string.Join(\", \", identityProperties", + "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, aocSteps) => (properties, mandatoryAocSteps.Except(aocSteps))", "\n );", From 6ec9235047bd5ed882ff58b8e0d4f3579d13768c Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 23 Dec 2022 09:12:43 +0100 Subject: [PATCH 06/28] Andreas feedback implementation. --- ifrs17/Import/Importers.ipynb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 1c8fe084..33754552 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -508,7 +508,7 @@ { "cell_type": "code", "source": [ - "public async Task ValidateForDataNodeStateActiveAsync(IWorkspace workspace, Dictionary dataNodes) where T : BaseDataRecord", + "public async static Task ValidateForDataNodeStateActiveAsync(this IWorkspace workspace, Dictionary dataNodes) where T : BaseDataRecord", "\n{ ", "\n foreach(var item in (await workspace.Query().ToArrayAsync()).GroupBy(x => x.DataNode))", "\n if(!dataNodes.ContainsKey(item.First().DataNode))", @@ -565,15 +565,17 @@ { "cell_type": "code", "source": [ - "public IEnumerable<(string Properties, IEnumerable AocSteps)> ValidateForMandatoryAocSteps(IDataSet dataSet, IWorkspace workspace, HashSet mandatoryAocSteps)", + "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name));", - "\n return workspace.Query().ToList()", + "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", "\n .GroupBy(x => string.Join(\", \", identityProperties", "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")),", "\n x => new AocStep(x.AocType, x.Novelty),", - "\n (properties, aocSteps) => (properties, mandatoryAocSteps.Except(aocSteps))", + "\n (properties, aocSteps) => (Properties: properties, AocSteps: mandatoryAocSteps.Except(aocSteps))", "\n );", + "\n foreach(var aocSteps in missingAocStepsByIdentityProperties) ", + "\n foreach(var aocStep in aocSteps.AocSteps) ApplicationMessage.Log(Warning.MandatoryAocStepMissing, aocStep.AocType, aocStep.Novelty, aocSteps.Properties);", "\n}" ], "metadata": {}, @@ -1089,11 +1091,8 @@ "\n }, ImportFormats.Cashflow", "\n ).WithTarget(workspace).ExecuteAsync();", "\n ", - "\n var missingAocStepsByIdentityProperties = ValidateForMandatoryAocSteps(dataSet, workspace, parsingStorage.MandatoryAocSteps);", - "\n foreach(var aocSteps in missingAocStepsByIdentityProperties) ", - "\n foreach(var aocStep in aocSteps.AocSteps) ApplicationMessage.Log(Warning.MandatoryAocStepMissing, aocStep.AocType, aocStep.Novelty, aocSteps.Properties);", - "\n", - "\n await ValidateForDataNodeStateActiveAsync(workspace, parsingStorage.DataNodeDataBySystemName);", + "\n await workspace.ValidateForMandatoryAocSteps(dataSet, parsingStorage.MandatoryAocSteps);", + "\n await workspace.ValidateForDataNodeStateActiveAsync(parsingStorage.DataNodeDataBySystemName);", "\n return Activity.Finish().Merge(importLog);", "\n}" ], @@ -1191,7 +1190,7 @@ "\n }, ImportFormats.Actual", "\n ).WithTarget(workspace).ExecuteAsync();", "\n ", - "\n await ValidateForDataNodeStateActiveAsync(workspace, parsingStorage.DataNodeDataBySystemName);", + "\n await workspace.ValidateForDataNodeStateActiveAsync(parsingStorage.DataNodeDataBySystemName);", "\n return Activity.Finish().Merge(importLog);", "\n}" ], @@ -1296,7 +1295,7 @@ "\n foreach (var iv in invalidVariables)", "\n ApplicationMessage.Log(Error.MultipleTechnicalMarginOpening, $\"{iv.DataNode},{iv.AocType},{iv.Novelty}\");", "\n ", - "\n await ValidateForDataNodeStateActiveAsync(workspace, parsingStorage.DataNodeDataBySystemName);", + "\n await workspace.ValidateForDataNodeStateActiveAsync(parsingStorage.DataNodeDataBySystemName);", "\n targetPartitionByReportingNodeAndPeriodId = parsingStorage.TargetPartitionByReportingNodeAndPeriod.Id;", "\n return Activity.Finish().Merge(importLog);", "\n}" From 87ca9edab45706c40df24c1d6f22df6bd66682b2 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 09:01:37 +0100 Subject: [PATCH 07/28] Working on Expressions. --- ifrs17/Utils/EqualityComparers.ipynb | 105 +++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 243e73f9..65184ea3 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -183,6 +183,111 @@ "metadata": {}, "execution_count": 0, "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public class IdentityPropertyReader where T:BaseVariableIdentity {", + "\n private static Func identityReader;", + "\n ", + "\n private IdentityPropertyReader(){", + "\n identityReader = GetIdentityReader();", + "\n }", + "\n public static readonly IdentityPropertyReader Instance = new IdentityPropertyReader();", + "\n", + "\n private Func GetIdentityReader(){", + "\n return (x=>\" \");", + "\n var parameter = Expression.Parameter(typeof(T));", + "\n var identityProperties = typeof(T).GetIdentityProperties().Select(x=>x.Name).Where(x=> x!=\"AccidentYear\"&& x != \"AocType\" && x != \"Novelty\")", + "\n .SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", + "\n .ToArray();", + "\n if (identityProperties.Count() < 2) return (x=> \"\");", + "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), identityProperties[0], identityProperties[1]);", + "\n for (int i = 2; i < identityProperties.Count(); i++){", + "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, identityProperties[i]); ", + "\n }", + "\n return Expression.Lambda>(partialConcatExpression, parameter).Compile();", + "\n }", + "\n public string GetIdentityString(T x) => identityReader(x);", + "\n ", + "\n public static string concat(Object first, Object? second) => first.ToString()+second.ToString();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var a = new RawVariable(){AocType = \"CL\", Novelty = \"C\", DataNode = \"GIC1.1\", AmountType =\"CL\", EstimateType=\"BE\"};" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var parameter = Expression.Parameter(typeof(RawVariable));", + "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Where(x=>x!=\"AccidentYear\"&& x != \"AocType\" && x != \"Novelty\")", + "\n .SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", + "\n .ToArray();", + "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), identityProperties[0], identityProperties[1]);", + "\n for (int i = 2; i < identityProperties.Count(); i++){", + "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, identityProperties[i]); ", + "\n }" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var reader = Expression.Lambda>(partialConcatExpression, parameter).Compile();" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "reader(a)" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var reader2 = IdentityPropertyReader.Instance;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "reader2.GetIdentityString(a)" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "/////TODO: continue wiht this: you left of with the code working outside the class, not really inside. debug that and then check what to do with the non set properties... also accident year... happy new year!!" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] } ] } \ No newline at end of file From 41e8f8c18f40ef0ac50687d20bf206565d4b6fce Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 10:28:04 +0100 Subject: [PATCH 08/28] Making the reader function work. --- ifrs17/Utils/EqualityComparers.ipynb | 67 +++++++++++++++++----------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 65184ea3..5b98eea6 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -196,22 +196,34 @@ "\n public static readonly IdentityPropertyReader Instance = new IdentityPropertyReader();", "\n", "\n private Func GetIdentityReader(){", - "\n return (x=>\" \");", - "\n var parameter = Expression.Parameter(typeof(T));", - "\n var identityProperties = typeof(T).GetIdentityProperties().Select(x=>x.Name).Where(x=> x!=\"AccidentYear\"&& x != \"AocType\" && x != \"Novelty\")", - "\n .SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", - "\n .ToArray();", - "\n if (identityProperties.Count() < 2) return (x=> \"\");", - "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), identityProperties[0], identityProperties[1]);", - "\n for (int i = 2; i < identityProperties.Count(); i++){", - "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, identityProperties[i]); ", - "\n }", + "\n var parameter = Expression.Parameter(typeof(RawVariable));", + "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Where(x=> x != \"AocType\" && x != \"Novelty\").ToArray();", + "\n var expressionstToConcat = identityProperties.SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", + "\n .ToArray();", + "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), expressionstToConcat[0], expressionstToConcat[1]);", + "\n for (int i = 2; i < expressionstToConcat.Count(); i++){", + "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", + "\n if(i%2==1 && identityProperties[(int)Math.Floor((double)i/2)] == \"AccidentYear\"){", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat2\"), partialConcatExpression, expressionstToConcat[i]); ", + "\n } else{", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, expressionstToConcat[i]); ", + "\n }", + "\n } // i needed (imo) to do it like this, since int? gives problem as Object...", "\n return Expression.Lambda>(partialConcatExpression, parameter).Compile();", "\n }", "\n public string GetIdentityString(T x) => identityReader(x);", "\n ", - "\n public static string concat(Object first, Object? second) => first.ToString()+second.ToString();", + "\n public static string concat(Object? first, Object? second){", + "\n if(first == null) first = \"\";", + "\n if(second == null) second = \"\";", + "\n return first.ToString()+second.ToString();", + "\n }", + "\n ", + "\n public static string concat2(Object? first, int? second){", + "\n if(first == null) first = \"\";", + "\n if(second == null) return first.ToString();", + "\n return first.ToString()+second.ToString();", + "\n }", "\n}" ], "metadata": {}, @@ -221,7 +233,7 @@ { "cell_type": "code", "source": [ - "var a = new RawVariable(){AocType = \"CL\", Novelty = \"C\", DataNode = \"GIC1.1\", AmountType =\"CL\", EstimateType=\"BE\"};" + "var a = new RawVariable(){AccidentYear = null, AocType = \"CL\", Novelty = \"C\", DataNode = \"GIC1.1\", AmountType =\"CL\", EstimateType=\"BE\"};" ], "metadata": {}, "execution_count": 0, @@ -230,15 +242,7 @@ { "cell_type": "code", "source": [ - "var parameter = Expression.Parameter(typeof(RawVariable));", - "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Where(x=>x!=\"AccidentYear\"&& x != \"AocType\" && x != \"Novelty\")", - "\n .SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", - "\n .ToArray();", - "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), identityProperties[0], identityProperties[1]);", - "\n for (int i = 2; i < identityProperties.Count(); i++){", - "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, identityProperties[i]); ", - "\n }" + "var reader2 = IdentityPropertyReader.Instance;" ], "metadata": {}, "execution_count": 0, @@ -247,7 +251,7 @@ { "cell_type": "code", "source": [ - "var reader = Expression.Lambda>(partialConcatExpression, parameter).Compile();" + "reader2.GetIdentityString(a)" ], "metadata": {}, "execution_count": 0, @@ -256,7 +260,7 @@ { "cell_type": "code", "source": [ - "reader(a)" + "" ], "metadata": {}, "execution_count": 0, @@ -265,7 +269,7 @@ { "cell_type": "code", "source": [ - "var reader2 = IdentityPropertyReader.Instance;" + "" ], "metadata": {}, "execution_count": 0, @@ -274,7 +278,16 @@ { "cell_type": "code", "source": [ - "reader2.GetIdentityString(a)" + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" ], "metadata": {}, "execution_count": 0, @@ -283,7 +296,7 @@ { "cell_type": "code", "source": [ - "/////TODO: continue wiht this: you left of with the code working outside the class, not really inside. debug that and then check what to do with the non set properties... also accident year... happy new year!!" + "" ], "metadata": {}, "execution_count": 0, From f6a2617e8d54e3e97c6fbe4af452fb32270881c1 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 12:07:07 +0100 Subject: [PATCH 09/28] Implementing into Importers. --- ifrs17/Import/Importers.ipynb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index d36b59a9..d2b04bf5 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -567,10 +567,8 @@ "source": [ "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", - "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Where(y => y.Name!=\"AocType\" && y.Name != \"Novelty\" && dataSet.Tables[\"Cashflow\"].Columns.Select(x=>x.ColumnName).Contains(y.Name));", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => string.Join(\", \", identityProperties", - "\n .Select(y => $\"{y.Name}: {typeof(RawVariable).GetProperty(y.Name).GetValue(x)}\")),", + "\n .GroupBy(x => IdentityPropertyReader.Instance.GetIdentityString(x),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, aocSteps) => (Properties: properties, AocSteps: mandatoryAocSteps.Except(aocSteps))", "\n );", @@ -758,9 +756,8 @@ "\n .ExecuteAsync();", "\n ", "\n var portfolios = await workspace.Query().ToDictionaryAsync(x => x.SystemName);", - "\n", - "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables.Contains(nameof(GroupOfInsuranceContract)) && dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", - "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables.Contains(nameof(GroupOfReinsuranceContract)) && dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", + "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", + "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", "\n", "\n var importLogGroupOfContracts = await Import.FromDataSet(dataSet)", "\n .WithType((dataset, datarow) => {", From fbe5b8c22b160705c1c725fc6d71161972abb5a9 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 12:16:37 +0100 Subject: [PATCH 10/28] Reverting the changes from the merge. --- ifrs17/Import/Importers.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index d2b04bf5..9b79baae 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -756,8 +756,8 @@ "\n .ExecuteAsync();", "\n ", "\n var portfolios = await workspace.Query().ToDictionaryAsync(x => x.SystemName);", - "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", - "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", + "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables.Contains(nameof(GroupOfInsuranceContract)) && dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", + "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables.Contains(nameof(GroupOfReinsuranceContract)) && dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", "\n", "\n var importLogGroupOfContracts = await Import.FromDataSet(dataSet)", "\n .WithType((dataset, datarow) => {", From 60969fcff54d414b0426a77c12b4a801542f25aa Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 12:26:49 +0100 Subject: [PATCH 11/28] Cleanup. --- ifrs17/Utils/EqualityComparers.ipynb | 72 ---------------------------- 1 file changed, 72 deletions(-) diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 5b98eea6..52769956 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -229,78 +229,6 @@ "metadata": {}, "execution_count": 0, "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "var a = new RawVariable(){AccidentYear = null, AocType = \"CL\", Novelty = \"C\", DataNode = \"GIC1.1\", AmountType =\"CL\", EstimateType=\"BE\"};" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "var reader2 = IdentityPropertyReader.Instance;" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "reader2.GetIdentityString(a)" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] } ] } \ No newline at end of file From ddde87de2b82973e8a5764f914ee3b4a532a7e04 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 14:47:20 +0100 Subject: [PATCH 12/28] Andreas feedback implementation --- ifrs17/Import/Importers.ipynb | 6 +- ifrs17/Utils/EqualityComparers.ipynb | 39 +---------- ifrs17/Utils/IdentityPropertyReader.ipynb | 79 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 41 deletions(-) create mode 100644 ifrs17/Utils/IdentityPropertyReader.ipynb diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 9b79baae..e88ba341 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -570,10 +570,10 @@ "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", "\n .GroupBy(x => IdentityPropertyReader.Instance.GetIdentityString(x),", "\n x => new AocStep(x.AocType, x.Novelty),", - "\n (properties, aocSteps) => (Properties: properties, AocSteps: mandatoryAocSteps.Except(aocSteps))", + "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", - "\n foreach(var aocSteps in missingAocStepsByIdentityProperties) ", - "\n foreach(var aocStep in aocSteps.AocSteps) ApplicationMessage.Log(Warning.MandatoryAocStepMissing, aocStep.AocType, aocStep.Novelty, aocSteps.Properties);", + "\n foreach((var properties, var missingSteps) in missingAocStepsByIdentityProperties) ", + "\n foreach(var missingStep in missingSteps) ApplicationMessage.Log(Warning.MandatoryAocStepMissing, missingStep.AocType, missingStep.Novelty, properties);", "\n}" ], "metadata": {}, diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 52769956..2147dbe5 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -187,44 +187,7 @@ { "cell_type": "code", "source": [ - "public class IdentityPropertyReader where T:BaseVariableIdentity {", - "\n private static Func identityReader;", - "\n ", - "\n private IdentityPropertyReader(){", - "\n identityReader = GetIdentityReader();", - "\n }", - "\n public static readonly IdentityPropertyReader Instance = new IdentityPropertyReader();", - "\n", - "\n private Func GetIdentityReader(){", - "\n var parameter = Expression.Parameter(typeof(RawVariable));", - "\n var identityProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Where(x=> x != \"AocType\" && x != \"Novelty\").ToArray();", - "\n var expressionstToConcat = identityProperties.SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", - "\n .ToArray();", - "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), expressionstToConcat[0], expressionstToConcat[1]);", - "\n for (int i = 2; i < expressionstToConcat.Count(); i++){", - "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", - "\n if(i%2==1 && identityProperties[(int)Math.Floor((double)i/2)] == \"AccidentYear\"){", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat2\"), partialConcatExpression, expressionstToConcat[i]); ", - "\n } else{", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, expressionstToConcat[i]); ", - "\n }", - "\n } // i needed (imo) to do it like this, since int? gives problem as Object...", - "\n return Expression.Lambda>(partialConcatExpression, parameter).Compile();", - "\n }", - "\n public string GetIdentityString(T x) => identityReader(x);", - "\n ", - "\n public static string concat(Object? first, Object? second){", - "\n if(first == null) first = \"\";", - "\n if(second == null) second = \"\";", - "\n return first.ToString()+second.ToString();", - "\n }", - "\n ", - "\n public static string concat2(Object? first, int? second){", - "\n if(first == null) first = \"\";", - "\n if(second == null) return first.ToString();", - "\n return first.ToString()+second.ToString();", - "\n }", - "\n}" + "" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb new file mode 100644 index 00000000..3d9bed31 --- /dev/null +++ b/ifrs17/Utils/IdentityPropertyReader.ipynb @@ -0,0 +1,79 @@ +{ + "metadata": { + "authors": [], + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "code", + "source": [ + "#!import \"../DataModel/DataStructure\"", + "\nusing System;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public class IdentityPropertyReader where T:BaseVariableIdentity {", + "\n private static Func identityReader;", + "\n ", + "\n private IdentityPropertyReader(){", + "\n identityReader = GetIdentityReader();", + "\n }", + "\n public static readonly IdentityPropertyReader Instance = new IdentityPropertyReader();", + "\n", + "\n private Func GetIdentityReader(){", + "\n var parameter = Expression.Parameter(typeof(T));", + "\n var identityProperties = typeof(T).GetIdentityProperties().Select(x=>x.Name).Where(x=> x != \"AocType\" && x != \"Novelty\").ToArray();", + "\n var expressionstToConcat = identityProperties.SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", + "\n .ToArray();", + "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), expressionstToConcat[0], expressionstToConcat[1]);", + "\n for (int i = 2; i < expressionstToConcat.Count(); i++){", + "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", + "\n if(i%2==1 && identityProperties[(int)Math.Floor((double)i/2)] == \"AccidentYear\"){", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat2\"), partialConcatExpression, expressionstToConcat[i]); ", + "\n } else{", + "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, expressionstToConcat[i]); ", + "\n }", + "\n } // i needed (imo) to do it like this, since int? gives problem as Object...", + "\n return Expression.Lambda>(partialConcatExpression, parameter).Compile();", + "\n }", + "\n public string GetIdentityString(T x) => identityReader(x);", + "\n ", + "\n public static string concat(Object first, Object second) => first.ToString()+second.ToString();", + "\n ", + "\n public static string concat2(Object first, int? second){", + "\n if(second == null) return first.ToString();", + "\n return first.ToString()+second.ToString();", + "\n }", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file From 4e9f7ca3990f38b91bde7435e4030bb21636438a Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 3 Jan 2023 14:59:37 +0100 Subject: [PATCH 13/28] Adding imports. --- ifrs17/Utils/IdentityPropertyReader.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb index 3d9bed31..55487351 100644 --- a/ifrs17/Utils/IdentityPropertyReader.ipynb +++ b/ifrs17/Utils/IdentityPropertyReader.ipynb @@ -19,7 +19,8 @@ "cell_type": "code", "source": [ "#!import \"../DataModel/DataStructure\"", - "\nusing System;" + "\nusing System.Linq.Expressions;", + "\nusing static Systemorph.Vertex.Equality.IdentityPropertyExtensions;" ], "metadata": {}, "execution_count": 0, From 4be4dc4e155298bc11d2d5750af019fa1fe7fdd7 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 5 Jan 2023 16:10:28 +0100 Subject: [PATCH 14/28] Adaptations and aesthetics. --- ifrs17/Constants/Validations.ipynb | 2 +- ifrs17/Import/Importers.ipynb | 5 ++- ifrs17/Utils/IdentityPropertyReader.ipynb | 46 +++++++++++------------ 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 258274dd..cf1e4af5 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -184,7 +184,7 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", - "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}.\",", + "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index e88ba341..71e481d2 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -32,7 +32,8 @@ { "cell_type": "code", "source": [ - "#!import \"ImportScopeCalculation\"" + "#!import \"ImportScopeCalculation\"", + "\n#!import \"../Utils/IdentityPropertyReader\"" ], "metadata": {}, "execution_count": 0, @@ -568,7 +569,7 @@ "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => IdentityPropertyReader.Instance.GetIdentityString(x),", + "\n .GroupBy(x => IdentityPropertyReader.GetInstance(excludingProperties: new[]{\"AocType\", \"Novelty\"}).GetIdentityString(x),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb index 55487351..5cb75fce 100644 --- a/ifrs17/Utils/IdentityPropertyReader.ipynb +++ b/ifrs17/Utils/IdentityPropertyReader.ipynb @@ -29,38 +29,36 @@ { "cell_type": "code", "source": [ - "public class IdentityPropertyReader where T:BaseVariableIdentity {", - "\n private static Func identityReader;", + "public class IdentityPropertyReader where T : BaseVariableIdentity {", + "\n private Func identityReader;", + "\n private string[] propertiesExcluded;", "\n ", - "\n private IdentityPropertyReader(){", + "\n private IdentityPropertyReader(string[] props) {", + "\n propertiesExcluded = props;", "\n identityReader = GetIdentityReader();", "\n }", - "\n public static readonly IdentityPropertyReader Instance = new IdentityPropertyReader();", "\n", - "\n private Func GetIdentityReader(){", + "\n private static Dictionary> InstancesByExcludedProperties = new();", + "\n", + "\n private Func GetIdentityReader() {", "\n var parameter = Expression.Parameter(typeof(T));", - "\n var identityProperties = typeof(T).GetIdentityProperties().Select(x=>x.Name).Where(x=> x != \"AocType\" && x != \"Novelty\").ToArray();", - "\n var expressionstToConcat = identityProperties.SelectMany(x=> new Expression[]{Expression.Constant(x+\": \"), Expression.Property(parameter, x) })", - "\n .ToArray();", - "\n var partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), expressionstToConcat[0], expressionstToConcat[1]);", - "\n for (int i = 2; i < expressionstToConcat.Count(); i++){", - "\n if(i%2==0) partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, Expression.Constant(\", \"));", - "\n if(i%2==1 && identityProperties[(int)Math.Floor((double)i/2)] == \"AccidentYear\"){", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat2\"), partialConcatExpression, expressionstToConcat[i]); ", - "\n } else{", - "\n partialConcatExpression = Expression.Call(typeof(IdentityPropertyReader).GetMethod(\"concat\"), partialConcatExpression, expressionstToConcat[i]); ", - "\n }", - "\n } // i needed (imo) to do it like this, since int? gives problem as Object...", - "\n return Expression.Lambda>(partialConcatExpression, parameter).Compile();", + "\n var expression = typeof(T).GetIdentityProperties().Where(x => !propertiesExcluded.Contains(x.Name))", + "\n .SelectMany(x => new Expression[]{ Expression.Constant(x.Name.ToString()+\":\"),", + "\n Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(GetString)), Expression.Convert(Expression.Property(parameter, x.Name), typeof(Object))) }", + "\n ).Aggregate((x, y) => Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(IdentityPropertyReader.Concat)), x, y) );", + "\n return Expression.Lambda>(expression, parameter).Compile();", + "\n }", + "\n", + "\n public static IdentityPropertyReader GetInstance(params string[] excludingProperties) {", + "\n var key = string.Join(\",\", excludingProperties.OrderBy(x=>x));", + "\n if(!InstancesByExcludedProperties.TryGetValue(key, out var instance))", + "\n return InstancesByExcludedProperties[key] = new IdentityPropertyReader(excludingProperties);", + "\n return instance;", "\n }", "\n public string GetIdentityString(T x) => identityReader(x);", "\n ", - "\n public static string concat(Object first, Object second) => first.ToString()+second.ToString();", - "\n ", - "\n public static string concat2(Object first, int? second){", - "\n if(second == null) return first.ToString();", - "\n return first.ToString()+second.ToString();", - "\n }", + "\n public static string Concat(string first, string second) => first + \" \" + second;", + "\n public static string GetString(Object item) => (item == null) ? \"\" : item.ToString();", "\n}" ], "metadata": {}, From 9ca41364105613d6644520b08baac6cc5a290b21 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 5 Jan 2023 16:23:57 +0100 Subject: [PATCH 15/28] Simplifying the diff. --- ifrs17/Import/Importers.ipynb | 3 ++- ifrs17/Utils/EqualityComparers.ipynb | 9 --------- ifrs17/Utils/IdentityPropertyReader.ipynb | 9 --------- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 71e481d2..9a8b4dbe 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -757,6 +757,7 @@ "\n .ExecuteAsync();", "\n ", "\n var portfolios = await workspace.Query().ToDictionaryAsync(x => x.SystemName);", + "\n ", "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables.Contains(nameof(GroupOfInsuranceContract)) && dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables.Contains(nameof(GroupOfReinsuranceContract)) && dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", "\n", @@ -1114,7 +1115,7 @@ "\n var workspace = Workspace.CreateNew();", "\n var log = await ParseCashflowsToWorkspaceAsync(dataSet, mainArgs, workspace);", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", - "\n ", + "\n", "\n foreach (var args in targetArgs) {", "\n log = log.Merge(await CalculateAndUploadVariablesAsync(args, workspace, args == mainArgs));", "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 2147dbe5..243e73f9 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -183,15 +183,6 @@ "metadata": {}, "execution_count": 0, "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] } ] } \ No newline at end of file diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb index 5cb75fce..6480e954 100644 --- a/ifrs17/Utils/IdentityPropertyReader.ipynb +++ b/ifrs17/Utils/IdentityPropertyReader.ipynb @@ -64,15 +64,6 @@ "metadata": {}, "execution_count": 0, "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] } ] } \ No newline at end of file From 24b5aad66c66794eaa3c93a4764c76775b88dfb0 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 5 Jan 2023 16:26:32 +0100 Subject: [PATCH 16/28] Simplifying the diff. --- ifrs17/Import/Importers.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 9a8b4dbe..f8d69f1a 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -757,7 +757,7 @@ "\n .ExecuteAsync();", "\n ", "\n var portfolios = await workspace.Query().ToDictionaryAsync(x => x.SystemName);", - "\n ", + "\n", "\n var yieldCurveColumnGroupOfInsuranceContract = dataSet.Tables.Contains(nameof(GroupOfInsuranceContract)) && dataSet.Tables[nameof(GroupOfInsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfInsuranceContract.YieldCurveName));", "\n var yieldCurveColumnGroupOfReinsuranceContract = dataSet.Tables.Contains(nameof(GroupOfReinsuranceContract)) && dataSet.Tables[nameof(GroupOfReinsuranceContract)].Columns.Any(x => x.ColumnName == nameof(GroupOfReinsuranceContract.YieldCurveName));", "\n", From e6f6cb31ad2aa0a17f1335ae861383b75d265cae Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 6 Jan 2023 14:37:20 +0100 Subject: [PATCH 17/28] A fix. --- ifrs17/Utils/IdentityPropertyReader.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb index 6480e954..56273367 100644 --- a/ifrs17/Utils/IdentityPropertyReader.ipynb +++ b/ifrs17/Utils/IdentityPropertyReader.ipynb @@ -45,7 +45,7 @@ "\n var expression = typeof(T).GetIdentityProperties().Where(x => !propertiesExcluded.Contains(x.Name))", "\n .SelectMany(x => new Expression[]{ Expression.Constant(x.Name.ToString()+\":\"),", "\n Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(GetString)), Expression.Convert(Expression.Property(parameter, x.Name), typeof(Object))) }", - "\n ).Aggregate((x, y) => Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(IdentityPropertyReader.Concat)), x, y) );", + "\n ).Aggregate((x, y) => Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(IdentityPropertyReader.Concat)), x, y) );", "\n return Expression.Lambda>(expression, parameter).Compile();", "\n }", "\n", From b0582767143120b27a98d76a1173d191f54735c3 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Mon, 9 Jan 2023 11:40:29 +0100 Subject: [PATCH 18/28] Corrected merging conflicts. --- ifrs17/Import/Importers.ipynb | 68 +++++++---------------------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index cedbfd1b..fc06cc33 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -447,60 +447,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "markdown", - "source": [ - "## Get Target Args" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public async Task GetTargetArgsAsync(ImportArgs mainArgs)", - "\n{", - "\n var scenarioArgs = await DataSource.Query() ", - "\n .Where(x => x.ReportingNode == mainArgs.ReportingNode && x.Year == mainArgs.Year && x.Month == mainArgs.Month && x.Scenario != null)", - "\n .Select(x => new ImportArgs(x.ReportingNode, x.Year, x.Month, default(Periodicity), x.Scenario, ImportFormats.Cashflow)).ToArrayAsync();", - "\n var isMultipleArg = mainArgs.Scenario == null && scenarioArgs.Any();", - "\n var targetArgs = isMultipleArg", - "\n ? mainArgs.RepeatOnce().Concat(scenarioArgs)", - "\n : mainArgs.RepeatOnce();", - "\n", - "\n if (isMultipleArg) ApplicationMessage.Log(Warning.ScenarioReCalculations, String.Join(\", \", scenarioArgs.Select(x => x.Scenario)));", - "\n return targetArgs.ToArray();", - "\n} " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Validation for Active Data Node States" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public async Task ValidateForDataNodeStateActiveAsync(IWorkspace workspace, Dictionary dataNodes) where T : BaseDataRecord", - "\n{ ", - "\n foreach(var item in (await workspace.Query().ToArrayAsync()).GroupBy(x => x.DataNode))", - "\n if(!dataNodes.ContainsKey(item.First().DataNode))", - "\n ApplicationMessage.Log(Error.InactiveDataNodeState, item.First().DataNode);", - "\n}", - "\n" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "markdown", "source": [ @@ -997,6 +943,15 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "code", "source": [ @@ -1217,10 +1172,11 @@ "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(RawVariable.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray();", "\n ", - "\n // Filter out empty raw variables for AocType \\not\\in MandatoryAocSteps", + "\n // Filter out empty raw variables for AocType != CL", + "\n //TODO: extend this check for all mandatory step and not just for CL", "\n if(args.Scenario == null) {", "\n values = values.Prune();", - "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", + "\n if(values.Length == 0 && aocType != AocTypes.CL) return null;", "\n }", "\n ", "\n var item = new RawVariable {", From 6eba09b69380954577e7f762df83b48fed76a3e8 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Mon, 9 Jan 2023 11:53:24 +0100 Subject: [PATCH 19/28] Cleaning the diff (a bit). --- PresentValueSeries/CF_CH_2021_12.xlsx | Bin 22926 -> 22999 bytes PresentValueSeries/CF_DE_2021_12.xlsx | Bin 22827 -> 22896 bytes PresentValueSeries/CF_DE_2022_12.xlsx | Bin 28391 -> 28474 bytes PresentValueSeries/Cashflows.xlsx | Bin 22854 -> 22908 bytes .../Files/Parameters/YieldCurve.csv | 14 -- .../Files/Parameters/YieldCurve_2019_12.csv | 7 + .../Files/Parameters/YieldCurve_2020_1.csv | 7 + .../Files/Parameters/YieldCurve_2020_12.csv | 8 + .../Files/Parameters/YieldCurve_2020_3.csv | 8 + .../Files/Parameters/YieldCurve_2021_12.csv | 6 + .../Files/Parameters/YieldCurve_2021_3.csv | 7 + .../Files/Parameters/YieldCurve_2021_6.csv | 6 + .../InitSystemorphRefDataToMemory.ipynb | 18 +-- .../InitSystemorphToDatabase.ipynb | 9 +- ifrs17/Constants/Consts.ipynb | 10 ++ ifrs17/Constants/Validations.ipynb | 3 +- ifrs17/DataModel/DataStructure.ipynb | 25 --- ifrs17/Test/EqualityComparerTest.ipynb | 151 ++++++++++++++++++ ifrs17/Test/Tests.ipynb | 9 ++ ifrs17/Utils/EqualityComparers.ipynb | 21 ++- 20 files changed, 252 insertions(+), 57 deletions(-) delete mode 100644 ifrs17-template/Files/Parameters/YieldCurve.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2019_12.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2020_1.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2020_12.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2020_3.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2021_12.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2021_3.csv create mode 100644 ifrs17-template/Files/Parameters/YieldCurve_2021_6.csv create mode 100644 ifrs17/Test/EqualityComparerTest.ipynb diff --git a/PresentValueSeries/CF_CH_2021_12.xlsx b/PresentValueSeries/CF_CH_2021_12.xlsx index bdc502b9dee82ff54fd14ec993a5dcb9137e1824..a7156d0c7b89d207597c6b29ade0e56d0cb85ef7 100644 GIT binary patch delta 11942 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 delta 11847 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 b5_m*U6dDoyPG1z794xI*_fA>s?<@Zc#|(&x diff --git a/PresentValueSeries/CF_DE_2022_12.xlsx b/PresentValueSeries/CF_DE_2022_12.xlsx index fe5e13b8f35227c1478fbd6fd39d889cf5f337e7..cbcadc97b0f86c090d871db54c51a7e0829c321a 100644 GIT binary patch delta 17404 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 W_@OkxORu>d_`N38n{<`G68|670U>7q delta 11800 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.WithTarget(DataSource).ExecuteAsync()" + "var log = await Import.FromFile(\"../Files/Parameters/YieldCurve_2019_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync();", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_1.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_3.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_3.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_6.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog" ], "metadata": {}, "execution_count": 0, @@ -204,15 +211,6 @@ "metadata": {}, "execution_count": 0, "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] } ] } \ No newline at end of file diff --git a/ifrs17-template/Initialization/InitSystemorphToDatabase.ipynb b/ifrs17-template/Initialization/InitSystemorphToDatabase.ipynb index 65138c29..a8aea982 100644 --- a/ifrs17-template/Initialization/InitSystemorphToDatabase.ipynb +++ b/ifrs17-template/Initialization/InitSystemorphToDatabase.ipynb @@ -123,7 +123,14 @@ { "cell_type": "code", "source": [ - "await Import.FromFile(\"../Files/Parameters/YieldCurve.csv\").WithType().WithTarget(DataSource).ExecuteAsync()" + "var log = await Import.FromFile(\"../Files/Parameters/YieldCurve_2019_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync();", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_1.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_3.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2020_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_3.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_6.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog.Merge(await Import.FromFile(\"../Files/Parameters/YieldCurve_2021_12.csv\").WithFormat(ImportFormats.YieldCurve).WithTarget(DataSource).ExecuteAsync());", + "\nlog" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Constants/Consts.ipynb b/ifrs17/Constants/Consts.ipynb index ceb279db..08842d5a 100644 --- a/ifrs17/Constants/Consts.ipynb +++ b/ifrs17/Constants/Consts.ipynb @@ -63,6 +63,15 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "code", + "source": [ + "public const double YieldCurvePrecision = 1E-8;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ @@ -198,6 +207,7 @@ "\n public const string Opening = nameof(Opening); // Importer for Opening Balances (BOP Inforce of CSM/LC)", "\n public const string SimpleValue = nameof(SimpleValue); // Importer for Simple Values (pre-calculated direct import)", "\n", + "\n public const string YieldCurve = nameof(YieldCurve); // Importer for Yield Curve", "\n public const string DataNode = nameof(DataNode); // Importer for Data Node", "\n public const string DataNodeState = nameof(DataNodeState); // Importer for Data Node State", "\n public const string DataNodeParameter = nameof(DataNodeParameter); // Importer for Data Node Parameters", diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index cf1e4af5..64a58f8c 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -51,7 +51,7 @@ "source": [ "public enum Warning {", "\n // Import", - "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations, MandatoryAocStepMissing,", + "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations,", "\n // Default", "\n Generic", "\n}; " @@ -184,7 +184,6 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", - "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", diff --git a/ifrs17/DataModel/DataStructure.ipynb b/ifrs17/DataModel/DataStructure.ipynb index a9275444..2521b257 100644 --- a/ifrs17/DataModel/DataStructure.ipynb +++ b/ifrs17/DataModel/DataStructure.ipynb @@ -189,31 +189,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "markdown", - "source": [ - "The interface IHierarchy is used for modelling dimensions which have an hierarchical structure, such as [Amount Type](#amount-type)." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface IHierarchy", - "\n{", - "\n public string Name { get; init; }", - "\n ", - "\n public string Parent { get; init; }", - "\n ", - "\n public string Child { get; init; }", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "markdown", "source": [ diff --git a/ifrs17/Test/EqualityComparerTest.ipynb b/ifrs17/Test/EqualityComparerTest.ipynb new file mode 100644 index 00000000..444f18b3 --- /dev/null +++ b/ifrs17/Test/EqualityComparerTest.ipynb @@ -0,0 +1,151 @@ +{ + "metadata": { + "authors": [], + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

Equality Comparers Test

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Yield Curve" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"../Utils/EqualityComparers\"", + "\n#!import \"../Utils/TestHelper\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "using FluentAssertions;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var comparer = YieldCurveComparer.Instance(); " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var yc = new YieldCurve() {Currency = \"EUR\", ", + "\n Year = 2000,", + "\n Month = 1,", + "\n Name = default, ", + "\n Scenario = default, ", + "\n Values = new double[]{0.001, 0.002, 0.003, 0.004}};" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,yc).Should().BeTrue()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,null).Should().BeFalse()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,yc with { Month = 19}).Should().BeFalse()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,yc with { Year = 2001}).Should().BeFalse()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc, yc with {Year = 2001, Values = new[] { 0.002, 0.003, 0.004 } }).Should().BeTrue()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,yc with { Year = 1999}).Should().BeFalse()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "comparer.Equals(yc,yc with { Year = 1999, Values = new[] { 0.001, 0.001, 0.002, 0.003, 0.004 } }).Should().BeTrue()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Test/Tests.ipynb b/ifrs17/Test/Tests.ipynb index ef37f404..7a5e9882 100644 --- a/ifrs17/Test/Tests.ipynb +++ b/ifrs17/Test/Tests.ipynb @@ -50,6 +50,15 @@ "metadata": {}, "execution_count": 0, "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!eval-notebook \"EqualityComparerTest\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] } ] } \ No newline at end of file diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 243e73f9..488dc6a8 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -115,14 +115,25 @@ "\n{", "\n private YieldCurveComparer(){}", "\n", - "\n\tpublic bool Equals(YieldCurve x, YieldCurve y) => ", - "\n x.Year == y.Year && x.Month == y.Month && x.Scenario == y.Scenario && x.Currency == y.Currency && x.Id == y.Id && x.Values.SequenceEqual(y.Values, Precision);", + "\n public bool Equals(YieldCurve x, YieldCurve y)", + "\n {", + "\n if (x == null && y == null)", + "\n return true; ", + "\n if (x == null || y == null)", + "\n return false; ", + "\n if (!(x.Month == y.Month && x.Scenario == y.Scenario && x.Currency == y.Currency && x.Id == y.Id && x.Name == y.Name))", + "\n return false; ", + "\n if (x.Year == y.Year)", + "\n return x.Values.SequenceEqual(y.Values, YieldCurvePrecision); ", + "\n return x.Year > y.Year", + "\n ? x.Values.SequenceEqual(y.Values.Skip(x.Year - y.Year).ToArray(), YieldCurvePrecision)", + "\n : x.Values.Skip(y.Year - x.Year).ToArray().SequenceEqual(y.Values, YieldCurvePrecision);", + "\n }", "\n\t", - "\n\tpublic int GetHashCode (YieldCurve x) => 0;", + "\n public int GetHashCode (YieldCurve x) => 0;", "\n", "\n public static YieldCurveComparer Instance() => new YieldCurveComparer();", - "\n}", - "\n" + "\n}" ], "metadata": {}, "execution_count": 0, From e965b35a0eef0513b7cd31264bd3877f88e2828b Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Mon, 9 Jan 2023 11:56:28 +0100 Subject: [PATCH 20/28] Reseting a change. --- ifrs17/Constants/Validations.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 64a58f8c..cf1e4af5 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -51,7 +51,7 @@ "source": [ "public enum Warning {", "\n // Import", - "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations,", + "\n ActiveDataNodeWithCashflowBOPI, VariablesAlreadyImported, VariablesAlreadyCalculated, ScenarioReCalculations, MandatoryAocStepMissing,", "\n // Default", "\n Generic", "\n}; " @@ -184,6 +184,7 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", + "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", From 58a6f2425eb434947f77bd1b425cb9c5c0361496 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 11 Jan 2023 10:48:15 +0100 Subject: [PATCH 21/28] Implementing Daniels feedback. --- ifrs17/Constants/Validations.ipynb | 2 +- ifrs17/Import/Importers.ipynb | 6 +- ifrs17/Utils/IdentityPropertyReader.ipynb | 69 ----------------------- 3 files changed, 4 insertions(+), 73 deletions(-) delete mode 100644 ifrs17/Utils/IdentityPropertyReader.ipynb diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index cf1e4af5..44926627 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -184,7 +184,7 @@ "\n // Import", "\n (Warning.ActiveDataNodeWithCashflowBOPI , 1) => $\"Cash flow with AoC Type: {AocTypes.BOP} and Novelty: {Novelties.I} for Group of Contract {s[0]} is not allowed because previous period data are available.\",", "\n (Warning.ScenarioReCalculations , 1) => $\"The import of the current file for the Best Estimate scenario makes the result of dependent Scenarios out of date. Hence, the following Scenarios are recalculated: {s[0]}.\", ", - "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for {s[2]}\",", + "\n (Warning.MandatoryAocStepMissing , 3) => $\"The AoC step ({s[0]}, {s[1]}) is not imported for ({s[2]}).\",", "\n // Default", "\n (Warning.Generic , _) => $\"{s[0]}\",", "\n (_ , _) => $\"Warning not found.\"", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index fc06cc33..91068160 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -32,8 +32,7 @@ { "cell_type": "code", "source": [ - "#!import \"ImportScopeCalculation\"", - "\n#!import \"../Utils/IdentityPropertyReader\"" + "#!import \"ImportScopeCalculation\"" ], "metadata": {}, "execution_count": 0, @@ -600,8 +599,9 @@ "source": [ "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", + "\n var includedProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(new[]{\"AocType\", \"Novelty\"});", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => IdentityPropertyReader.GetInstance(excludingProperties: new[]{\"AocType\", \"Novelty\"}).GetIdentityString(x),", + "\n .GroupBy(x => string.Join(\", \", x.ToString().Split('{','}')[1].Split(',').Where(y=> includedProperties.Contains(y.Split('=')[0].Trim()))).Trim(),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", diff --git a/ifrs17/Utils/IdentityPropertyReader.ipynb b/ifrs17/Utils/IdentityPropertyReader.ipynb deleted file mode 100644 index 56273367..00000000 --- a/ifrs17/Utils/IdentityPropertyReader.ipynb +++ /dev/null @@ -1,69 +0,0 @@ -{ - "metadata": { - "authors": [], - "kernelspec": { - "display_name": "Formula Framework", - "language": "C#", - "name": "C#" - }, - "language_info": { - "file_extension": ".cs", - "mimetype": "text/plain", - "name": "C#" - } - }, - "nbformat": 4, - "nbformat_minor": 5, - "cells": [ - { - "cell_type": "code", - "source": [ - "#!import \"../DataModel/DataStructure\"", - "\nusing System.Linq.Expressions;", - "\nusing static Systemorph.Vertex.Equality.IdentityPropertyExtensions;" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public class IdentityPropertyReader where T : BaseVariableIdentity {", - "\n private Func identityReader;", - "\n private string[] propertiesExcluded;", - "\n ", - "\n private IdentityPropertyReader(string[] props) {", - "\n propertiesExcluded = props;", - "\n identityReader = GetIdentityReader();", - "\n }", - "\n", - "\n private static Dictionary> InstancesByExcludedProperties = new();", - "\n", - "\n private Func GetIdentityReader() {", - "\n var parameter = Expression.Parameter(typeof(T));", - "\n var expression = typeof(T).GetIdentityProperties().Where(x => !propertiesExcluded.Contains(x.Name))", - "\n .SelectMany(x => new Expression[]{ Expression.Constant(x.Name.ToString()+\":\"),", - "\n Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(GetString)), Expression.Convert(Expression.Property(parameter, x.Name), typeof(Object))) }", - "\n ).Aggregate((x, y) => Expression.Call(typeof(IdentityPropertyReader).GetMethod(nameof(IdentityPropertyReader.Concat)), x, y) );", - "\n return Expression.Lambda>(expression, parameter).Compile();", - "\n }", - "\n", - "\n public static IdentityPropertyReader GetInstance(params string[] excludingProperties) {", - "\n var key = string.Join(\",\", excludingProperties.OrderBy(x=>x));", - "\n if(!InstancesByExcludedProperties.TryGetValue(key, out var instance))", - "\n return InstancesByExcludedProperties[key] = new IdentityPropertyReader(excludingProperties);", - "\n return instance;", - "\n }", - "\n public string GetIdentityString(T x) => identityReader(x);", - "\n ", - "\n public static string Concat(string first, string second) => first + \" \" + second;", - "\n public static string GetString(Object item) => (item == null) ? \"\" : item.ToString();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file From 4becb4af57245e2cc196fa7176e85613d50fb06f Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 11 Jan 2023 11:00:39 +0100 Subject: [PATCH 22/28] Reverting some change. --- ifrs17/Import/Importers.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 91068160..71b7d3cf 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -1172,11 +1172,10 @@ "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(RawVariable.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray();", "\n ", - "\n // Filter out empty raw variables for AocType != CL", - "\n //TODO: extend this check for all mandatory step and not just for CL", + "\n // Filter out empty raw variables for AocStep \\not\\in MandatoryAocSteps", "\n if(args.Scenario == null) {", "\n values = values.Prune();", - "\n if(values.Length == 0 && aocType != AocTypes.CL) return null;", + "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", "\n }", "\n ", "\n var item = new RawVariable {", From 25677b8ebd966215770fc0af7ad9f2aeec081c77 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 11 Jan 2023 13:11:23 +0100 Subject: [PATCH 23/28] Improvement. --- ifrs17/Import/Importers.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 71b7d3cf..a0cd0371 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -599,7 +599,7 @@ "source": [ "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", - "\n var includedProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(new[]{\"AocType\", \"Novelty\"});", + "\n var includedProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(new[]{nameof(AocType), nameof(Novelty)});", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", "\n .GroupBy(x => string.Join(\", \", x.ToString().Split('{','}')[1].Split(',').Where(y=> includedProperties.Contains(y.Split('=')[0].Trim()))).Trim(),", "\n x => new AocStep(x.AocType, x.Novelty),", From 671c7dcc419e0af589ae66f4abbd99f9b6b993fd Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Tue, 17 Jan 2023 09:03:25 +0100 Subject: [PATCH 24/28] Replacing ToString for ToIdentityString. --- ifrs17/Import/Importers.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 88712aa6..63cf2da5 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -600,9 +600,9 @@ "source": [ "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{", - "\n var includedProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(new[]{nameof(AocType), nameof(Novelty)});", + "\n var excludedProperties = new[]{nameof(AocType), nameof(Novelty)};", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => string.Join(\", \", x.ToString().Split('{','}')[1].Split(',').Where(y=> includedProperties.Contains(y.Split('=')[0].Trim()))).Trim(),", + "\n .GroupBy(x => string.Join(\", \", x.ToIdentityString().Split(',').Where(y=> y != \" \" && !excludedProperties.Contains(y.Split(':')[0]))),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", From c84440db2f31abc6bb3626849d8c58a2b762b86a Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 25 Jan 2023 16:47:45 +0100 Subject: [PATCH 25/28] ToIdentityString update --- ifrs17/Utils/Extensions.ipynb | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index 9e335a22..3d988925 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -207,12 +207,13 @@ "cell_type": "code", "source": [ "using System.Text;", - "\npublic static string ToIdentityString(this T v) where T : class", + "\npublic static string ToIdentityString(this T v, string[] excludingProperties = null) where T : class", "\n{", + "\n if (excludingProperties == null) excludingProperties = new string[]{};", "\n StringBuilder sb = new StringBuilder();", "\n var propertyInfos = v.GetType()", "\n .GetProperties()", - "\n .Where(x => Attribute.IsDefined(x, typeof(IdentityPropertyAttribute)))", + "\n .Where(x => Attribute.IsDefined(x, typeof(IdentityPropertyAttribute)) && !excludingProperties.Contains(x.Name))", "\n .OrderByDescending(x => x.PropertyType.Name).ThenByDescending(x => x.Name)", "\n .Select(x => sb.Append(x.Name).Append(\":\").Append(v.GetType().GetProperty(x.Name)?.GetValue(v, null)).Append(\", \")).ToArray();", "\n return propertyInfos.Count() == 0? v.ToString() : propertyInfos.Select(p => p.ToString()).ToArray().Last();", @@ -222,6 +223,29 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "# ToString with including properties" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public static string ToPartialString(this T variable, string[] includingProperties) where T : BaseVariableIdentity", + "\n{", + "\n var propertiesRead = variable.ToString().Split('{', '}')[1].Split(',');", + "\n var propertiesFiltered = propertiesRead.Where(x=> includingProperties.Contains(x.Split('=')[0].Trim()));", + "\n return string.Join(\", \", propertiesFiltered);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "code", "source": [ From 28da5f89db01700c249016a7a0fa7acb6fdf7a6c Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Wed, 25 Jan 2023 17:05:24 +0100 Subject: [PATCH 26/28] Proposition 1 --- ifrs17/Import/Importers.ipynb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index a6cc0185..3a7e82f9 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -649,11 +649,13 @@ { "cell_type": "code", "source": [ - "public async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", - "\n{", + "using static Systemorph.Vertex.Equality.IdentityPropertyExtensions;", + "\npublic async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", + "\n{ ", "\n var excludedProperties = new[]{nameof(AocType), nameof(Novelty)};", + "\n var includingProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(excludedProperties).ToArray();", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => string.Join(\", \", x.ToIdentityString().Split(',').Where(y=> y != \" \" && !excludedProperties.Contains(y.Split(':')[0]))),", + "\n .GroupBy(x => x.ToPartialString(includingProperties: includingProperties),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", From 07fbccbfeb6e66d83d20df70741c27ac1bff680f Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 26 Jan 2023 08:38:05 +0100 Subject: [PATCH 27/28] Improvement --- ifrs17/Utils/Extensions.ipynb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index 3d988925..d894b09d 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -207,9 +207,8 @@ "cell_type": "code", "source": [ "using System.Text;", - "\npublic static string ToIdentityString(this T v, string[] excludingProperties = null) where T : class", + "\npublic static string ToIdentityString(this T v, params string[] excludingProperties) where T : class", "\n{", - "\n if (excludingProperties == null) excludingProperties = new string[]{};", "\n StringBuilder sb = new StringBuilder();", "\n var propertyInfos = v.GetType()", "\n .GetProperties()", From e52e3ac80f04c041577e6884aaf63f190a9b2c83 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Thu, 26 Jan 2023 10:36:41 +0100 Subject: [PATCH 28/28] some refactors --- ifrs17/Import/Importers.ipynb | 2 +- ifrs17/Utils/Extensions.ipynb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 3a7e82f9..93b6296e 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -655,7 +655,7 @@ "\n var excludedProperties = new[]{nameof(AocType), nameof(Novelty)};", "\n var includingProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(excludedProperties).ToArray();", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => x.ToPartialString(includingProperties: includingProperties),", + "\n .GroupBy(x => x.ToStringWith(properties: includingProperties),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index d894b09d..d23cd61e 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -234,11 +234,11 @@ { "cell_type": "code", "source": [ - "public static string ToPartialString(this T variable, string[] includingProperties) where T : BaseVariableIdentity", + "public static string ToStringWith(this T variable, string[] properties) where T : BaseVariableIdentity", "\n{", "\n var propertiesRead = variable.ToString().Split('{', '}')[1].Split(',');", - "\n var propertiesFiltered = propertiesRead.Where(x=> includingProperties.Contains(x.Split('=')[0].Trim()));", - "\n return string.Join(\", \", propertiesFiltered);", + "\n var propertiesFiltered = propertiesRead.Where(x=> properties.Contains(x.Split('=')[0].Trim()));", + "\n return string.Join(\", \", propertiesFiltered).Trim();", "\n}" ], "metadata": {},