diff --git a/ClassicGEC/ClassicGECBrowserIntegrationTests/ClassicGECBrowserIntegrationTests.fsproj b/ClassicGEC/ClassicGECBrowserIntegrationTests/ClassicGECBrowserIntegrationTests.fsproj
new file mode 100644
index 0000000..ac6c2fe
--- /dev/null
+++ b/ClassicGEC/ClassicGECBrowserIntegrationTests/ClassicGECBrowserIntegrationTests.fsproj
@@ -0,0 +1,24 @@
+
+
+
+
+ netcoreapp3.1
+ Exe
+ x64
+ x64
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ClassicGEC/ClassicGECBrowserIntegrationTests/Program.fs b/ClassicGEC/ClassicGECBrowserIntegrationTests/Program.fs
new file mode 100644
index 0000000..1651322
--- /dev/null
+++ b/ClassicGEC/ClassicGECBrowserIntegrationTests/Program.fs
@@ -0,0 +1,35 @@
+module Program
+
+open System
+open System.Diagnostics
+open Expecto
+open canopy
+open canopy.types
+open canopy.classic
+open Microsoft.Research.CRNIntegrationTestLib
+
+[]
+let main args =
+ let (dir,groups,timeout,args) = Program.separateArgsDist args
+
+ // Start a web server
+ printfn "Starting 'dotnet serve' on %s" dir
+ let serverProcess = Process.Start("dotnet", sprintf "serve -d %s" dir)
+ printfn "'dotnet serve' started, PID = %d" serverProcess.Id
+
+ let result =
+ try
+ let url = "http://localhost:8080"
+ BrowserSetup.configureCanopy timeout
+ let tests = Tests.tests groups Tests.Worker url
+ Program.run args tests
+ finally
+ printfn "Shutting down 'dotnet serve'..."
+ try serverProcess.Kill() with _ -> ()
+ canopy.classic.quit()
+
+ if System.Diagnostics.Debugger.IsAttached then
+ printf "Press any key to exit"
+ System.Console.ReadKey() |> ignore
+
+ result
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECBrowserIntegrationTests/paket.references b/ClassicGEC/ClassicGECBrowserIntegrationTests/paket.references
new file mode 100644
index 0000000..0d34aef
--- /dev/null
+++ b/ClassicGEC/ClassicGECBrowserIntegrationTests/paket.references
@@ -0,0 +1,9 @@
+group DOTNETCORE
+
+Canopy
+Expecto
+FSharp.Core
+Selenium.WebDriver
+Selenium.WebDriver.ChromeDriver
+Selenium.WebDriver.GeckoDriver.Win64
+Selenium.WebDriver.MicrosoftWebDriver
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCLI/App.config b/ClassicGEC/ClassicGECCLI/App.config
new file mode 100644
index 0000000..5481afc
--- /dev/null
+++ b/ClassicGEC/ClassicGECCLI/App.config
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCLI/AssemblyInfo.fs b/ClassicGEC/ClassicGECCLI/AssemblyInfo.fs
new file mode 100644
index 0000000..9eca9d1
--- /dev/null
+++ b/ClassicGEC/ClassicGECCLI/AssemblyInfo.fs
@@ -0,0 +1,41 @@
+namespace ClassicGECCLI.AssemblyInfo
+
+open System.Reflection
+open System.Runtime.CompilerServices
+open System.Runtime.InteropServices
+
+// Le informazioni generali relative a un assembly sono controllate dal seguente
+// set di attributi. Modificare i valori di questi attributi per modificare le informazioni
+// associate a un assembly.
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+
+// Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili
+// ai componenti COM. Se è necessario accedere a un tipo in questo assembly da
+// COM, impostare su true l'attributo ComVisible per tale tipo.
+[]
+
+// Se il progetto viene esposto a COM, il seguente GUID verrà utilizzato come ID della libreria dei tipi
+[]
+
+// Le informazioni sulla versione di un assembly sono costituite dai quattro valori seguenti:
+//
+// Versione principale
+// Versione secondaria
+// Numero di build
+// Revisione
+//
+// È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build
+// utilizzando l'asterisco (*) come illustrato di seguito:
+// []
+[]
+[]
+
+do
+ ()
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCLI/ClassicGECCLI.fsproj b/ClassicGEC/ClassicGECCLI/ClassicGECCLI.fsproj
new file mode 100644
index 0000000..30bbf0b
--- /dev/null
+++ b/ClassicGEC/ClassicGECCLI/ClassicGECCLI.fsproj
@@ -0,0 +1,37 @@
+
+
+
+ netcoreapp3.1
+ Exe
+ x64
+ True
+ true
+ ClassicGEC
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\Lib\Oslo.FSharp\Oslo.FSharp.dll
+
+
+
+ x64
+
+
+ x64
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCLI/Program.fs b/ClassicGEC/ClassicGECCLI/Program.fs
new file mode 100644
index 0000000..ff96f20
--- /dev/null
+++ b/ClassicGEC/ClassicGECCLI/Program.fs
@@ -0,0 +1,145 @@
+module Microsoft.Research.GEC.Classic
+
+open Microsoft.Research.CliLibrary
+open Microsoft.Research.CRNEngine
+open Argu
+
+type GECArgs =
+ | Parts of string
+ | Reactions of string
+ | DE
+ | MG of int
+ | CE
+
+with
+ interface IArgParserTemplate with
+ member s.Usage =
+ match s with
+ | Parts _ -> "Parts database"
+ | Reactions _ -> "Reactions database"
+ | DE -> "Enumerate possible constructs from the given parts and constraints."
+ | MG _ -> "Generate CRN model for the nth device enumerated by GEC."
+ | CE -> "Export the generated CRN model into an SVG image."
+
+
+let printSVG crn =
+ printf """"
+
+
+[]
+let main args =
+ // Enforce invariant culture (prevents issues with decimal separators on international systems).
+ System.Threading.Thread.CurrentThread.CurrentCulture <- System.Globalization.CultureInfo.InvariantCulture
+
+ // Start by extracting the parts and reactions databases from the argument list
+ let gec_parser = ArgumentParser.Create(programName = "ClassicGEC")
+ let gec_results = gec_parser.Parse(args, ignoreUnrecognized=true)
+ let dbParts =
+ match gec_results.TryGetResult Parts with
+ | Some f -> System.IO.File.ReadAllText f
+ | None -> Databases.defaultParts
+ let dbReactions =
+ match gec_results.TryGetResult Reactions with
+ | Some f -> System.IO.File.ReadAllText f
+ | None -> Databases.defaultReactions
+
+ // Here we assume that we are only interested in the first solution, equivalent to how the GUI handles inference from a GEC program
+ let parser code =
+ match Main.parse code with
+ | Program.t.ClassicGec _ ->
+ let solveResult = GECEngine.solveGEC (ref false) code dbParts dbReactions
+ let firstSolution = GECEngine.getCrnAssignment solveResult.graph solveResult.solution 0
+ firstSolution.model
+ | Program.t.LogicGec bundle ->
+ let cle = LogicGEC.cle
+ if gec_results.Contains DE
+ // generate all models
+ then
+ LogicGEC.enumerateDevices cle bundle.rules bundle.program
+ |> List.map (fun p -> p |> List.map (LogicGEC.Instruction.ToString cle) |> String.concat " | ")
+ |> List.iteri (fun i s -> printfn "Solution %i: %s" i s)
+
+ // return empty graph
+ { task = None
+ nodes = Map.empty
+ edges = Map.empty
+ expanded =false }
+
+ elif gec_results.Contains MG
+ then
+ let i = gec_results.GetResult MG
+
+ // get ith model
+ let solutions = LogicGEC.enumerateDevices cle bundle.rules bundle.program
+ let max = solutions.Length
+ if 0 <= i && i < max
+ then
+ // generate ith model
+ let sol = solutions.Item i
+ let crn = LogicGEC.generateCRN cle bundle.rules sol
+
+ // return IGraph with a single node
+ let crnSettings = Crn_settings.defaults.from_default_directive_list bundle.settings.directives
+
+ if gec_results.Contains CE
+ then printSVG crn
+ else
+ printf "%s" (crn.to_string ())
+ printfn "\n"
+ crn.all_species ()
+ |> List.iter (fun s -> match crn.attributes.TryFind s.name with
+ | None -> ()
+ | Some a -> printfn "%s = %s" a.name (a.structure |> String.filter (fun c -> c <> '"')))
+ { task = None
+ nodes = Map.ofList [sprintf "Model_%i" i, Model.create crnSettings [crn]]
+ edges = Map.empty
+ expanded =false }
+ else failwithf "Input index %i is out of bound, the total number of solutions found is %i" i max
+ else failwith "Please specify whether to do construct assembly or model generation for the given Logic GEC program."
+ // Call generic CLI program
+ try
+ let ret = Program.main parser args
+ ret
+ with e ->
+ match e with
+ | :? Parser.Exception as e -> match e.Errors with
+ | [| {row=r; column=c; text=t} |] -> printfn "Parsing error at %i, %i: expecting %s" r c t
+ -1
+ | _ -> raise e
+ | _ -> raise e
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCLI/paket.references b/ClassicGEC/ClassicGECCLI/paket.references
new file mode 100644
index 0000000..7decf61
--- /dev/null
+++ b/ClassicGEC/ClassicGECCLI/paket.references
@@ -0,0 +1,8 @@
+group DOTNETCORE
+
+#FsCheck
+#FsUnit.xUnit
+#xunit.core
+#xunit.runner.console
+#xunit.runner.visualstudio
+FSharp.Core
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECCli.sln b/ClassicGEC/ClassicGECCli.sln
new file mode 100644
index 0000000..ed030f5
--- /dev/null
+++ b/ClassicGEC/ClassicGECCli.sln
@@ -0,0 +1,118 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30225.117
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CRNEngineDotNet", "..\CRNEngine\CRNEngineDotNet\CRNEngineDotNet.fsproj", "{AE45211A-A65D-4827-A1F9-07A20EB0F154}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Filzbach.FSharp.Portable", "..\Filzbach.FSharp\Filzbach.FSharp.Portable.fsproj", "{2849368F-AC32-4D1E-B6D6-9C52261A5F2D}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ParserCombinators", "..\ParserCombinators\ParserCombinators\ParserCombinators.fsproj", "{DD8FEC26-6D1D-4642-A706-04070B6D5494}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SundialsSolver15", "..\SundialsSolver\SundialsSolver15\SundialsSolver15.vcxproj", "{866880DC-BF1E-4C12-8238-72E7EFF44AFB}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ReactionDiffusion", "..\PDESolvers\ReactionDiffusion\ReactionDiffusion.fsproj", "{529BEDB7-C73A-4A77-BFD9-1628D75C321B}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CRNEngineTests", "..\CRNEngine\CRNEngineTests\CRNEngineTests.fsproj", "{8E0427CB-DD8F-46BE-A5BC-C02CF55F152D}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CliLibrary", "..\CRNEngine\CliLibrary\CliLibrary.fsproj", "{EEF843A3-43F8-4E6B-AB7F-9ADE3A5AF022}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ClassicGECDotNet", "ClassicGECDotNet\ClassicGECDotNet.fsproj", "{74DDCD31-9968-4B9B-8E5D-F07EDB7CE332}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ClassicGECCLI", "ClassicGECCLI\ClassicGECCLI.fsproj", "{7B81A30F-F8A4-435D-A53A-9634C7A82686}"
+ ProjectSection(ProjectDependencies) = postProject
+ {866880DC-BF1E-4C12-8238-72E7EFF44AFB} = {866880DC-BF1E-4C12-8238-72E7EFF44AFB}
+ EndProjectSection
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ClassicGECDotNetTests", "ClassicGECDotNetTests\ClassicGECDotNetTests.fsproj", "{EEBFA61A-4235-4C7C-B801-D44958F9D21C}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSBOLWrapper", "..\FSBOLWrapper\FSBOLWrapper\FSBOLWrapper.fsproj", "{7D875457-2116-4222-89E0-A048792E1213}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MomentClosure", "..\MomentClosure\MomentClosure\MomentClosure.fsproj", "{40A82B6F-9447-4767-BD5B-8D870D3FACFF}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CRNEngineCloudLib", "..\CRNEngine\CRNEngineCloudLib\CRNEngineCloudLib.fsproj", "{B0C5BB1E-CC0C-4D9E-A56A-82891A09653E}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ClassicGECRunAllExamples", "ClassicGECRunAllExamples\ClassicGECRunAllExamples.fsproj", "{B9B04586-11D5-466C-8288-1BC62FC3C382}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ClassicGECTests", "ClassicGECTests\ClassicGECTests.fsproj", "{5B3B81C7-5B7C-460D-B109-5E063133C0AD}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "RulesDSD", "..\RulesDSD\RulesDSD\RulesDSD.fsproj", "{22DF9340-8F96-4FBE-8001-675E2E55CB54}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AE45211A-A65D-4827-A1F9-07A20EB0F154}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AE45211A-A65D-4827-A1F9-07A20EB0F154}.Debug|x64.Build.0 = Debug|Any CPU
+ {AE45211A-A65D-4827-A1F9-07A20EB0F154}.Release|x64.ActiveCfg = Release|Any CPU
+ {AE45211A-A65D-4827-A1F9-07A20EB0F154}.Release|x64.Build.0 = Release|Any CPU
+ {2849368F-AC32-4D1E-B6D6-9C52261A5F2D}.Debug|x64.ActiveCfg = Debug|x64
+ {2849368F-AC32-4D1E-B6D6-9C52261A5F2D}.Debug|x64.Build.0 = Debug|x64
+ {2849368F-AC32-4D1E-B6D6-9C52261A5F2D}.Release|x64.ActiveCfg = Release|x64
+ {2849368F-AC32-4D1E-B6D6-9C52261A5F2D}.Release|x64.Build.0 = Release|x64
+ {DD8FEC26-6D1D-4642-A706-04070B6D5494}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DD8FEC26-6D1D-4642-A706-04070B6D5494}.Debug|x64.Build.0 = Debug|Any CPU
+ {DD8FEC26-6D1D-4642-A706-04070B6D5494}.Release|x64.ActiveCfg = Release|Any CPU
+ {DD8FEC26-6D1D-4642-A706-04070B6D5494}.Release|x64.Build.0 = Release|Any CPU
+ {866880DC-BF1E-4C12-8238-72E7EFF44AFB}.Debug|x64.ActiveCfg = Debug|x64
+ {866880DC-BF1E-4C12-8238-72E7EFF44AFB}.Debug|x64.Build.0 = Debug|x64
+ {866880DC-BF1E-4C12-8238-72E7EFF44AFB}.Release|x64.ActiveCfg = Release|x64
+ {866880DC-BF1E-4C12-8238-72E7EFF44AFB}.Release|x64.Build.0 = Release|x64
+ {529BEDB7-C73A-4A77-BFD9-1628D75C321B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {529BEDB7-C73A-4A77-BFD9-1628D75C321B}.Debug|x64.Build.0 = Debug|Any CPU
+ {529BEDB7-C73A-4A77-BFD9-1628D75C321B}.Release|x64.ActiveCfg = Release|Any CPU
+ {529BEDB7-C73A-4A77-BFD9-1628D75C321B}.Release|x64.Build.0 = Release|Any CPU
+ {8E0427CB-DD8F-46BE-A5BC-C02CF55F152D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8E0427CB-DD8F-46BE-A5BC-C02CF55F152D}.Debug|x64.Build.0 = Debug|Any CPU
+ {8E0427CB-DD8F-46BE-A5BC-C02CF55F152D}.Release|x64.ActiveCfg = Release|Any CPU
+ {8E0427CB-DD8F-46BE-A5BC-C02CF55F152D}.Release|x64.Build.0 = Release|Any CPU
+ {EEF843A3-43F8-4E6B-AB7F-9ADE3A5AF022}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EEF843A3-43F8-4E6B-AB7F-9ADE3A5AF022}.Debug|x64.Build.0 = Debug|Any CPU
+ {EEF843A3-43F8-4E6B-AB7F-9ADE3A5AF022}.Release|x64.ActiveCfg = Release|Any CPU
+ {EEF843A3-43F8-4E6B-AB7F-9ADE3A5AF022}.Release|x64.Build.0 = Release|Any CPU
+ {74DDCD31-9968-4B9B-8E5D-F07EDB7CE332}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {74DDCD31-9968-4B9B-8E5D-F07EDB7CE332}.Debug|x64.Build.0 = Debug|Any CPU
+ {74DDCD31-9968-4B9B-8E5D-F07EDB7CE332}.Release|x64.ActiveCfg = Release|Any CPU
+ {74DDCD31-9968-4B9B-8E5D-F07EDB7CE332}.Release|x64.Build.0 = Release|Any CPU
+ {7B81A30F-F8A4-435D-A53A-9634C7A82686}.Debug|x64.ActiveCfg = Debug|x64
+ {7B81A30F-F8A4-435D-A53A-9634C7A82686}.Debug|x64.Build.0 = Debug|x64
+ {7B81A30F-F8A4-435D-A53A-9634C7A82686}.Release|x64.ActiveCfg = Release|x64
+ {7B81A30F-F8A4-435D-A53A-9634C7A82686}.Release|x64.Build.0 = Release|x64
+ {EEBFA61A-4235-4C7C-B801-D44958F9D21C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EEBFA61A-4235-4C7C-B801-D44958F9D21C}.Debug|x64.Build.0 = Debug|Any CPU
+ {EEBFA61A-4235-4C7C-B801-D44958F9D21C}.Release|x64.ActiveCfg = Release|Any CPU
+ {EEBFA61A-4235-4C7C-B801-D44958F9D21C}.Release|x64.Build.0 = Release|Any CPU
+ {7D875457-2116-4222-89E0-A048792E1213}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7D875457-2116-4222-89E0-A048792E1213}.Debug|x64.Build.0 = Debug|Any CPU
+ {7D875457-2116-4222-89E0-A048792E1213}.Release|x64.ActiveCfg = Release|Any CPU
+ {7D875457-2116-4222-89E0-A048792E1213}.Release|x64.Build.0 = Release|Any CPU
+ {40A82B6F-9447-4767-BD5B-8D870D3FACFF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {40A82B6F-9447-4767-BD5B-8D870D3FACFF}.Debug|x64.Build.0 = Debug|Any CPU
+ {40A82B6F-9447-4767-BD5B-8D870D3FACFF}.Release|x64.ActiveCfg = Release|Any CPU
+ {40A82B6F-9447-4767-BD5B-8D870D3FACFF}.Release|x64.Build.0 = Release|Any CPU
+ {B0C5BB1E-CC0C-4D9E-A56A-82891A09653E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B0C5BB1E-CC0C-4D9E-A56A-82891A09653E}.Debug|x64.Build.0 = Debug|Any CPU
+ {B0C5BB1E-CC0C-4D9E-A56A-82891A09653E}.Release|x64.ActiveCfg = Release|Any CPU
+ {B0C5BB1E-CC0C-4D9E-A56A-82891A09653E}.Release|x64.Build.0 = Release|Any CPU
+ {B9B04586-11D5-466C-8288-1BC62FC3C382}.Debug|x64.ActiveCfg = Debug|x64
+ {B9B04586-11D5-466C-8288-1BC62FC3C382}.Debug|x64.Build.0 = Debug|x64
+ {B9B04586-11D5-466C-8288-1BC62FC3C382}.Release|x64.ActiveCfg = Release|x64
+ {B9B04586-11D5-466C-8288-1BC62FC3C382}.Release|x64.Build.0 = Release|x64
+ {5B3B81C7-5B7C-460D-B109-5E063133C0AD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5B3B81C7-5B7C-460D-B109-5E063133C0AD}.Debug|x64.Build.0 = Debug|Any CPU
+ {5B3B81C7-5B7C-460D-B109-5E063133C0AD}.Release|x64.ActiveCfg = Release|Any CPU
+ {5B3B81C7-5B7C-460D-B109-5E063133C0AD}.Release|x64.Build.0 = Release|Any CPU
+ {22DF9340-8F96-4FBE-8001-675E2E55CB54}.Debug|x64.ActiveCfg = Debug|x64
+ {22DF9340-8F96-4FBE-8001-675E2E55CB54}.Debug|x64.Build.0 = Debug|x64
+ {22DF9340-8F96-4FBE-8001-675E2E55CB54}.Release|x64.ActiveCfg = Release|x64
+ {22DF9340-8F96-4FBE-8001-675E2E55CB54}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CD1A1B77-DF19-4175-9D30-1B36C117F584}
+ EndGlobalSection
+EndGlobal
diff --git a/ClassicGEC/ClassicGECDotNet/AssemblyInfo.fs b/ClassicGEC/ClassicGECDotNet/AssemblyInfo.fs
new file mode 100644
index 0000000..165ede8
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/AssemblyInfo.fs
@@ -0,0 +1,41 @@
+namespace ClassicGECDotNet.AssemblyInfo
+
+open System.Reflection
+open System.Runtime.CompilerServices
+open System.Runtime.InteropServices
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// []
+[]
+[]
+
+do
+ ()
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/ClassicGECDotNet.fsproj b/ClassicGEC/ClassicGECDotNet/ClassicGECDotNet.fsproj
new file mode 100644
index 0000000..2872911
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/ClassicGECDotNet.fsproj
@@ -0,0 +1,54 @@
+
+
+
+ netstandard2.0
+ x64
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\Lib\Oslo.FSharp\Oslo.FSharp.dll
+
+
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/Databases.fs b/ClassicGEC/ClassicGECDotNet/Databases.fs
new file mode 100644
index 0000000..a7f5efd
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/Databases.fs
@@ -0,0 +1,64 @@
+module Microsoft.Research.GEC.Databases
+
+let defaultParts = "i723017,pcr,codes(xylR;0.001)
+i723024, pcr, codes(phzM;0.001)
+e0040, pcr, codes(gfp;0.01)
+c0099, pcr, codes(cviR;0.01)
+i723025, pcr, codes(phzS;0.001)
+i723028, pcr, codes(pca;0.001)
+c0051, pcr, codes(cI;0.01)
+c0040, pcr, codes(tetR;0.01)
+c0080, pcr, codes(araC;0.01)
+c0012, pcr, codes(lacI;0.01)
+cunknown2, pcr, codes(unknown2;0.001)
+c0061, pcr, codes(luxI;0.01)
+c0062, pcr, codes(luxR;0.01)
+c0079, pcr, codes(lasR;0.01)
+c0078, pcr, codes(lasI;0.01)
+cunknown3, pcr, codes(ccdB;0.005)
+cunknown4, pcr, codes(ccdA;0.1)
+i723020, prom, pos(toluene::xylR;0.001; 0.001; 1.0); con(0.0001)
+r0051, prom, neg(cI; 1.0; 0.5; 0.00005); con(0.12)
+r0040, prom, neg(tetR; 1.0; 0.5; 0.00005); con(0.09)
+runknown1, prom, neg(unknown1; 1.0; 0.005; 0.001); con(0.04)
+r0080, prom, neg(araC; 1.0; 0.000001; 0.0001); pos(araC::arabinose; 0.001; 0.001; 1.0); con(0.1)
+r0011, prom, neg(lacI; 1.0; 0.5; 0.00005); con(0.1)
+r0062, prom, pos(lasR::m3OC12HSL; 1.0; 0.8; 0.1); pos(luxR::m3OC6HSL; 1.0; 0.8; 0.1); con(0.01)
+r0090, prom, pos(lasR::m3OC12HSL; 1.0; 0.8; 0.1); con(0.01)
+r0099, prom, pos(cviR::m3OC6HSL; 1.0; 0.8; 0.1); con(0.01)
+b0034, rbs, rate(0.1)
+b0015, ter
+cunknown5, pcr, codes(ccdA2; 10.0)
+runknown5, prom, con(10.0)
+j06504, pcr, codes(mCherry; 0.1)
+prpr, device, components[pr; rbs34; eyfp; ter1; pr; rbs34; ecfp; ter1]
+drPcat, device, components[pCat; rbs34; luxR; rbs34; lasR; ter1; pLas81; rbs34; eyfp; ter1; plux76; rbs34; ecfp; ter1]
+drRS100S32, device, components[pTet; rbss100; luxR; ter1; pLac; rbs32; lasR; ter1; pLas81; rbs34; eyfp; ter1; plux76; rbs34; ecfp; ter1]
+drR33S32, device, components[pTet; rbs33; luxR; ter1; pLac; rbs32; lasR; ter1; pLas81; rbs34; eyfp; ter1; plux76; rbs34; ecfp; ter1]
+drR33S175, device, components[pTet; rbs33; luxR; ter1; pLac; rbsS175; lasR; ter1; pLas81; rbs34; eyfp; ter1; plux76; rbs34; ecfp; ter1]
+relayP76LasI, device, components[pLux76; rbs900; lasI; l3s2p21]
+relayP81LuxI, device, components[pLas81; rbs32; luxI; l3s2p21]
+pBadYFP, device, components[pBad; rbs34; eyfp; l3s2p21]
+lactonase, device, components[pBad; rbs34; aiia; l3s2p21]"
+
+let defaultReactions = "toluene + xylR ->{1.0} toluene::xylR
+phzM ~ pca ->{1.0} metPCA
+phzS ~ metPCA ->{1.0} pyo
+luxR + m3OC6HSL ->{0.5} luxR::m3OC6HSL
+lasR + m3OC12HSL ->{0.5} lasR::m3OC12HSL
+cviR + m3OC6HSL ->{0.5} cviR::m3OC6HSL
+cviR + m3OC12HSL ->{0.5} cviR::m3OC12HSL
+luxI ~ ->{1.0} m3OC6HSL
+lasI ~ ->{1.0} m3OC12HSL
+ccdA ~ ccdB ->{1.0}
+c[m3OC6HSL] ->{0.5} m3OC6HSL
+m3OC6HSL ->{0.5} c[m3OC6HSL]
+c[m3OC12HSL] ->{0.5} m3OC12HSL
+m3OC12HSL ->{0.5} c[m3OC12HSL]
+luxR::m3OC6HSL ->{1.0} luxR + m3OC6HSL
+cviR::m3OC6HSL ->{1.0} cviR + m3OC6HSL
+cviR::m3OC12HSL ->{1.0} cviR + m3OC12HSL
+lasR::m3OC12HSL ->{1.0} lasR + m3OC12HSL
+ccdA2 ~ ccdB ->{0.00001}
+lacI + iptg ->{1.0} lacI::iptg
+tetR + aTc ->{1.0} tetR::aTc"
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/NumUtil.fs b/ClassicGEC/ClassicGECDotNet/NumUtil.fs
new file mode 100644
index 0000000..04b60db
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/NumUtil.fs
@@ -0,0 +1,24 @@
+module Microsoft.Research.GEC.NumUtil
+
+#if JavaScript
+
+open WebSharper
+[]
+#endif
+let isNum s = let d = ref 0.0 in (System.Double.TryParse(s, d))
+
+#if JavaScript
+[]
+#endif
+let parse_double s =
+ let d = ref 0.0 in
+ if System.Double.TryParse(s, d)
+ then !d
+ else System.Double.NaN
+
+[]
+let case_double f v s =
+ let d = parse_double s in
+ if System.Double.IsNaN d
+ then v
+ else f d
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/TransCrn.fs b/ClassicGEC/ClassicGECDotNet/TransCrn.fs
new file mode 100644
index 0000000..12e0a03
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/TransCrn.fs
@@ -0,0 +1,186 @@
+[]
+module Microsoft.Research.GEC.TransCrn
+
+open Microsoft.Research.GEC.Trans
+open Microsoft.Research.CRNEngine
+open Api
+
+open Parser
+
+let separator = "_"
+
+let spReplace (str:string) =
+ str.Replace("::","_")
+
+let private newStr = // ref (fun () -> "Fixme")
+ let count = ref 0
+ (fun () -> count := !count + 1; string !count)
+
+let rec newVar =
+ "sp" + newStr() + "_"
+
+let indexInitial (initial:Initial>) (str:string)=
+ //let newSpeciesName = newVar + ((spReplace initial.species.name) + separator + (spReplace str))
+ let newSpeciesName = ((spReplace initial.species.name) + separator + (spReplace str))
+ let newSpecies = Species.create(newSpeciesName)
+ let newInitial = {initial with species = newSpecies}
+ newInitial
+
+let indexReaction (reaction:Reaction) (str:string)=
+ let ncatalysts = reaction.catalysts |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace x.name) + separator + (spReplace str))
+ let newSpName = ((spReplace x.name) + separator + (spReplace str))
+ Species.create(newSpName))
+ let nreactants = reaction.reactants |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace x.name) + separator + (spReplace str))
+ let newSpName = ((spReplace x.name) + separator + (spReplace str))
+ Species.create(newSpName))
+ let nproducts = reaction.products |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace x.name) + separator + (spReplace str))
+ let newSpName = ((spReplace x.name) + separator + (spReplace str))
+ Species.create(newSpName))
+ let nreaction = {reaction with catalysts = ncatalysts; reactants = nreactants; products=nproducts}
+ nreaction
+
+let compInitial (initial:Initial>) (str:string) =
+ //let newSpName = newVar + ((spReplace str) + separator + (spReplace initial.species.name))
+ let newSpName = ((spReplace str) + separator + (spReplace initial.species.name))
+ let newSpecies = Species.create(newSpName)
+ let newInitial = {initial with species = newSpecies}
+ newInitial
+
+let compReaction (reaction:Reaction) (str:string)=
+ let ncatalysts = reaction.catalysts |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace str) + separator + (spReplace x.name))
+ let newSpName = ((spReplace str) + separator + (spReplace x.name))
+ Species.create(newSpName))
+ let nreactants = reaction.reactants |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace str) + separator + (spReplace x.name))
+ let newSpName = ((spReplace str) + separator + (spReplace x.name))
+ Species.create(newSpName))
+ let nproducts = reaction.products |> Mset.map (fun (x) ->
+ //let newSpName = newVar + ((spReplace str) + separator + (spReplace x.name))
+ let newSpName = ((spReplace str) + separator + (spReplace x.name))
+ Species.create(newSpName))
+
+ let nreaction = {reaction with catalysts = ncatalysts; reactants = nreactants; products=nproducts}
+ nreaction
+
+
+
+
+let createComplexSpecies (sp:string list) =
+ if sp.IsEmpty then
+ Species.create("")
+ else
+ //let species = sp |> List.reduce (fun a b -> (a + "-" + b)) |> Species.create
+ let species = sp |> List.reduce (fun a b ->
+ //newVar + ((spReplace a) + separator + (spReplace b))) |> Species.create
+ ((spReplace a) + separator + (spReplace b))) |> Species.create
+ species
+
+let createComplexSpeciesWithEmptyCheck (sp:string list) =
+ if sp.IsEmpty then
+ None
+ else
+ //let species = sp |> List.reduce (fun a b -> (newVar + ((spReplace a) + separator + (spReplace b)))) |> Species.create
+ let species = sp |> List.reduce (fun a b -> (((spReplace a) + separator + (spReplace b)))) |> Species.create
+ Some(species)
+
+let createComplexSpeciesList (sp:string list list) =
+ if sp.IsEmpty then
+ []
+ else
+ sp
+ |> List.map (fun(x) -> createComplexSpeciesWithEmptyCheck(x))
+ |> List.filter (fun x ->
+ match x with
+ | None -> false
+ | Some(_) -> true)
+ |> List.map (fun x -> x.Value)
+
+let createComplexCompSpecies (sp:string list) (comp:string)=
+ //let spName = sp |> List.reduce (fun a b -> (a + "-" + b))
+ let spName = sp |> List.reduce (fun a b -> ((spReplace a) + separator + (spReplace b)))
+ //let species = Species.create(comp + "[" + spName + "]")
+ //let newSpName = newVar + ((spReplace comp) + separator + spName)
+ let newSpName = ((spReplace comp) + separator + spName)
+ let species = Species.create(newSpName)
+ species
+
+let rec createCrnReactions (lbsProg:tLBSProg) (reactions:Reaction<_,_,_> list) (initials:Initial<_,_> list) =
+ match lbsProg with
+ | LBSPar(prog1,prog2) ->
+ let (reactions1,initials1) = createCrnReactions prog1 [] []
+ let (reactions2,initials2) = createCrnReactions prog2 [] []
+ ((reactions1@reactions2@reactions),(initials1@initials2@initials))
+ | LBSInitPop(initVal,value) ->
+ //let species = initVal |> List.reduce (fun a b -> (newVar + (spReplace a) + separator + (spReplace b))) |> Species.create
+ let species = initVal |> List.reduce (fun a b -> ((spReplace a) + separator + (spReplace b))) |> Species.create
+ let initial = Initial.create(false, (Expression.Float value), species, None, None)
+ (reactions,initial::initials)
+ | LBSCopy(index,prog) ->
+ let (reactions1,initials1) = createCrnReactions prog [] []
+ let rinitials = initials1 |> List.map (fun(x) -> indexInitial x (index.ToString()))
+ let rreactions = reactions1 |> List.map (fun(x) -> indexReaction x (index.ToString()))
+ (rreactions@reactions,rinitials@initials)
+ | LBSComp(comp,prog) ->
+ let (reactions1,initials1) = createCrnReactions prog [] []
+ let rinitials = initials1 |> List.map (fun(x) -> compInitial x comp)
+ let rreactions = reactions1 |> List.map (fun(x) -> compReaction x comp)
+ (rreactions@reactions,rinitials@initials)
+ | LBSCompDec(comp,prog) ->
+ let (reactions1,initials1) = createCrnReactions prog [] []
+ let rinitials = initials1 |> List.map (fun(x) -> compInitial x comp)
+ let rreactions = reactions1 |> List.map (fun(x) -> compReaction x comp)
+ (rreactions@reactions,rinitials@initials)
+ | LBSReac(enzymes,reactants,products,rate,massAction) ->
+ let rreactants = createComplexSpeciesList(reactants) //|> Mset.from_list
+ let renzymes = createComplexSpeciesList(enzymes) //|> Mset.from_list
+ let rproducts = createComplexSpeciesList(products) //|> Mset.from_list
+ if massAction then
+ //check if anything is empty
+ let reaction = Reaction.create(renzymes, rreactants, !-> (Expression.Key rate ), rproducts)
+ (reaction:: reactions,initials)
+ else
+ (*let baseIdParserNoSpaces = (Parser.many1Satisfy Parser.isLetter .>>. Parser.manySatisfy (fun c -> Parser.isLetter c || Parser.isDigit c || c = '_'|| c = '-' || c = '\'') |>> fun (a,b) -> a + b) > "an identifier"
+ let baseIdParser = baseIdParserNoSpaces .>> Parser.spaces
+ let speciesparser = baseIdParser |>> fun (x) -> (Species.create(x))
+ let speciesExpParser = Expression.parse speciesparser
+ let exp_from_string (s:string) = Parser.from_string speciesExpParser s
+ let exp = exp_from_string rate
+ let reaction = Reaction.create_functional renzymes rreactants exp None rproducts
+ (reaction:: reactions,initials)*)
+ (reactions,initials)
+ | LBSDegReac(reactants,rate) ->
+ let rreactants = createComplexSpeciesList(reactants)
+ let reaction = Reaction.create([], rreactants, !-> (Expression.Key rate), [])
+ (reaction::reactions,initials)
+ | LBSTrans(complex1,complex2,compartment,rate,direction) ->
+ if direction = Ast.In then
+ let reaction = Reaction.create([], [(createComplexSpecies complex1)], !-> (Expression.Key rate), [(createComplexCompSpecies complex2 compartment)])
+ (reaction::reactions,initials)
+ else
+ let reaction = Reaction.create([], [(createComplexCompSpecies complex1 compartment)], !-> (Expression.Key rate), [(createComplexSpecies complex2)])
+ (reaction::reactions,initials)
+ | LBSReacAbstraction((enzymes,reactants,products,rate,massAction),prog1) ->
+ let rreactants = createComplexSpeciesList(reactants) //|> Mset.from_list
+ let renzymes = createComplexSpeciesList(enzymes) //|> Mset.from_list
+ let rproducts = createComplexSpeciesList(products) //|> Mset.from_list
+ let (reactions1,initials1) = createCrnReactions prog1 [] []
+ if massAction then
+ let reaction = Reaction.create(renzymes, rreactants, !-> (Expression.Key rate), rproducts)
+ ((reaction::reactions1)@reactions,initials1@initials)
+ else
+ (reactions1@reactions,initials1@initials)
+
+ | _ -> ([],[]) //This is basically LBSNil,
+
+
+
+
+let create (lbsProg:tLBSProg) =
+ let (reactions,initials) = createCrnReactions lbsProg List.empty List.empty
+ let (crn:Crn) = {Crn.empty with reactions = reactions; initials = initials}
+ let gcrn = Crn.group_reactions crn
+ gcrn
diff --git a/ClassicGEC/ClassicGECDotNet/app.config b/ClassicGEC/ClassicGECDotNet/app.config
new file mode 100644
index 0000000..2bc077c
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/app.config
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+ True
+
+
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/ast.fs b/ClassicGEC/ClassicGECDotNet/ast.fs
new file mode 100644
index 0000000..244c19c
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/ast.fs
@@ -0,0 +1,158 @@
+(*
+Defines the abstract syntax tree data types for GEC.
+Also defines compiler exceptions.
+
+Author: Michael Pedersen.
+Copyright Microsoft Research, 2009.
+*)
+
+[]
+module Microsoft.Research.GEC.Ast
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+// exceptions for compilation errors.
+//type pos = {l1 : int; c1 : int; l2 : int; c2 : int}
+//exception CompilerEx of string
+//exception CompilerExPos of string * pos
+
+// values can be names or variables (collectively identifiers), floats or wild cards;
+// or more recently, algebraic expressions for functional rate expressions in promoter properties.
+type value =
+ | IdVal of string
+ | FloatVal of float
+ | WildCardVal
+ | AlgebraicExp of aexp
+
+// in order to parse actual parameter lists without conflicts, we allow "abstract complexes"
+// to contain any value, including floats, and rely on a type system to filter out bad uses.
+and abstractComplex = value list
+
+// properties:
+and prop = string * abstractComplex list
+
+// arithmetic expressions (very basic for now):
+and aexp = //| ValAExp of value
+ | FloatAExp of float
+ | IdAExp of string
+ | PlusAExp of aexp * aexp
+ | MinusAExp of aexp * aexp
+ | MulAExp of aexp * aexp
+ | DivAExp of aexp * aexp
+ | PowAExp of aexp * aexp
+
+// direction for transport reactions (in or out of compartment):
+type direction = In | Out
+
+// predicate operators for quantitative constraints:
+type op = Gt | Lt | Eq
+
+// programmes:
+type prog =
+ | Nil
+ | Brick of value * string * prop list
+ | Device of string
+ | Reac of abstractComplex list * abstractComplex list * abstractComplex list * value * bool
+ | Trans of abstractComplex * abstractComplex * string * value * bool * direction
+ | TemplateInv of string * abstractComplex list
+ | Seq of prog * prog
+ | Par of prog * prog
+ | Comp of string * prog
+ | New of string * prog
+ | TemplateDef of string * string list * prog * prog
+ | Constraint of aexp * op * aexp
+ | Rate of value * float
+ | InitPop of abstractComplex * float
+ | Copy of int * prog * bool * bool // first bool indicates par/seq, second bool indicates simonly
+
+// directives:
+type gecSimpleSpecies = CompartmentSpecies of string * abstractComplex
+ | SimpleSpecies of abstractComplex
+type gecSpecies = gecSimpleSpecies list
+type gecNumPoints = Default | IntPoints of int | AllPoints
+type kinetics =
+ | Contextual_kinetics
+ | Stochastic_kinetics
+ | Deterministic_kinetics
+let string_of_kinetics = function
+ | Contextual_kinetics -> "contextual"
+ | Stochastic_kinetics -> "stochastic"
+ | Deterministic_kinetics -> "deterministic"
+type directive =
+ | SAMPLE of float * gecNumPoints
+ | TIME of Time
+ | CONCENTRATION of Concentration
+ | ABSTOLERANCE of float
+ | RELTOLERANCE of float
+ | SCALE of float
+ | PLOT of gecSimpleSpecies Key Expression.t list
+ | KINETICS of kinetics
+
+(* ************************************************************************************************************ *)
+
+(* String representation of a species complex. *)
+let complexString xs = Lib.string_of_list Lib.id "::" xs
+
+(* String representation of a species in a compartment. *)
+let compartmentString c x = c + Lib.brack x
+
+(* String representation of an operator. *)
+let stringOfOp = function
+ | Gt -> ">"
+ | Lt -> "<"
+ | Eq -> "="
+
+(* String representation of an expression. *)
+let rec stringOfAExp = function
+ | FloatAExp f -> Lib.display_float f
+ | IdAExp id -> id
+ | PlusAExp (e1,e2) -> (stringOfAExp e1) + "+" + (stringOfAExp e2)
+ | MinusAExp (e1,e2) -> (stringOfAExp e1) + "-" + (stringOfAExp e2)
+ | MulAExp (e1,e2) -> (stringOfAExp e1) + "*" + (stringOfAExp e2)
+ | DivAExp (e1,e2) -> (stringOfAExp e1) + "/" + (stringOfAExp e2)
+ | PowAExp (e1,e2) -> (stringOfAExp e1) + "^" + (stringOfAExp e2)
+
+
+(* String representation of an expression. *)
+let rec lbsStringOfAExp = function
+ | FloatAExp f -> Lib.display_float f
+ | IdAExp id -> id
+ | PlusAExp (e1,e2) -> "(" + (lbsStringOfAExp e1) + "+" + (lbsStringOfAExp e2) + ")"
+ | MinusAExp (e1,e2) -> "(" + (lbsStringOfAExp e1) + "--" + (lbsStringOfAExp e2) + ")"
+ | MulAExp (e1,e2) -> (lbsStringOfAExp e1) + "*" + (lbsStringOfAExp e2)
+ | DivAExp (e1,e2) -> (lbsStringOfAExp e1) + "/" + (lbsStringOfAExp e2)
+ | PowAExp (e1,e2) -> (lbsStringOfAExp e1) + "^" + (lbsStringOfAExp e2)
+
+(* String representation of a value. *)
+let stringOfValue = function
+ | IdVal x -> x
+ | FloatVal f -> Lib.display_float f
+ | WildCardVal -> "_"
+ | AlgebraicExp aexp -> stringOfAExp aexp
+
+(* String representation of an abstract complex. *)
+let abstractComplexString vs = Lib.string_of_list stringOfValue "::" vs
+
+(* Are two complexes equal? *)
+let complexesEqual (xs:string list) (ys:string list) = Lib.is_permutation (=) xs ys
+
+(* Produce a string representation of a "gecSpecies". *)
+let stringOfGecSimpleSpecies (g:gecSimpleSpecies) : string =
+ (* Produce a string representation of a "gecSimpleSpecies". *)
+ let stringOfGecSimpleSpecies (g:gecSimpleSpecies) : string =
+ match g with
+ | SimpleSpecies ac -> abstractComplexString ac
+ | CompartmentSpecies (c,ac) -> compartmentString c (abstractComplexString ac)
+ stringOfGecSimpleSpecies g
+
+(* Produce the source code representation of a directive. *)
+let stringOfDirective (d:directive) : string =
+ match d with
+ | SAMPLE(f,io) -> "directive sample " + (Lib.display_float f) + (match io with Default -> "" | IntPoints i -> " " + (string i) | AllPoints -> " all")
+ | TIME u -> "directive time " + u.to_string
+ | CONCENTRATION u -> "directive concentration " + u.to_string
+ | ABSTOLERANCE f -> "directive abstolerance " + (Lib.display_float f)
+ | RELTOLERANCE f -> "directive reltolerance " + (Lib.display_float f)
+ | SCALE f -> "directive scale " + (Lib.display_float f)
+ | PLOT ps -> "directive plot " + (Lib.string_of_list (Expression.to_string (Key.to_string stringOfGecSimpleSpecies)) "; " ps)
+ | KINETICS k -> "directive kinetics " + string_of_kinetics k
diff --git a/ClassicGEC/ClassicGECDotNet/characterization.fs b/ClassicGEC/ClassicGECDotNet/characterization.fs
new file mode 100644
index 0000000..5cca4c8
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/characterization.fs
@@ -0,0 +1,1455 @@
+module GEC.Characterization
+
+open Microsoft.Research.Filzbach //MCMC inference
+open System.Collections.Generic
+open System
+open System.Text
+open System.Text.RegularExpressions
+
+
+
+type GrowthModels = Gompertz = 0 | Richards = 1 | Logistic = 2
+type GrowthModelType = {
+ mu: float;
+ lag: float;
+ tm: float;
+ K: float;
+ res: int;
+ model: (int * float -> float);
+}
+type NoiseModel = Linear=0| Squared=1
+
+type DataTypes = Data | Gain | Blank | Negative
+type Well = {
+ Row: char;
+ Col: int;
+ Content: string;
+ Colony: string;
+ DataType: DataTypes;
+ Condition: Map;
+
+ Signals: double[][];
+ SignalNames: string[];
+ T: double[];
+
+ GrowthModel: GrowthModelType option;
+ Filter: int -> bool; //given an signal array index, is this part of the selection
+ SteadyStates: Map<(string*string),(double*double)>;
+ Activity: Map<(string*string),double>;
+}
+type Plate = {
+ Name: string;
+ Data: seq;
+ Blanks: Map;
+
+ Conditions: Map;
+ Cname: string;
+ C: double[]; //conditions
+ Properties: double[][][]; //computed or measured properties
+ PropertyNames: string[]; //name of properties
+
+ Gain: Map;
+ log:string;
+}
+
+let EmptyPlate = {Name=""; Data = Seq.empty; Blanks = Map.empty; Conditions = Map.empty; C = [||];Properties=[||]; PropertyNames=[||]; Cname=""; Gain = Map.empty; log=""}
+let EmptyWell = {
+ Row = ' ';
+ Col = -1;
+ Content = "";
+ Colony = "";
+ DataType = DataTypes.Blank;
+ Condition = Map.empty;
+ Signals = Array.empty;
+ SignalNames = Array.empty;
+ T = Array.empty;
+ GrowthModel = None;
+ Filter = (fun x -> true);
+ SteadyStates = Map.empty;
+ Activity = Map.empty;
+}
+type Parameter = {
+ pname: string;
+ value: double;
+ dist: double[];
+ log: bool;
+}
+type ModelTypes =
+ | Constitutive = 0
+ | Linear = 1
+ | Michaelis_Menten_Activation = 2
+ | Michaelis_Menten_Repression = 3
+ | Michaelis_Menten_General = 4
+ | Dimer_Activation = 5
+ | Dimer_Repression = 6
+ | Dimer_General = 7
+ | Hill_Activation = 8
+ | Hill_Repression = 9
+ | Hill_General = 10
+ | Sequential_Binding = 11
+
+type ResponseTypes =
+ | EYFP_ECFP = 0
+ | EYFP_OD = 1
+ | ECFP_OD = 2
+ | mu = 3
+ | K = 4
+ | lag = 5
+ | EYFP_mRFP1 = 6
+ | ECFP_mRFP1 = 7
+ | mRFP1_OD = 8
+
+type Model = {
+ modelType: ModelTypes;
+ AIC: double;
+ BIC: double;
+ CIC: double; //rename this information criterion to the right abbreviation
+ model: int * double -> double;
+ res: int;
+ parameters: Parameter[];
+ X: double[];
+ bayestable: List;
+}
+
+
+let string_of_response response = match response with
+ | ResponseTypes.EYFP_ECFP -> "EYFP/ECFP"
+ | ResponseTypes.EYFP_OD -> "EYFP/OD"
+ | ResponseTypes.ECFP_OD -> "ECFP/OD"
+ | ResponseTypes.mu -> "mu"
+ | ResponseTypes.K -> "K"
+ | ResponseTypes.lag -> "lag"
+ | ResponseTypes.EYFP_mRFP1 -> "EYFP/mRFP1"
+ | ResponseTypes.ECFP_mRFP1 -> "ECFP/mRFP1"
+ | ResponseTypes.mRFP1_OD -> "mRFP1/OD"
+
+
+
+let Interp (X:double[]) (Y:double[]) (Z:double[]) =
+ let InterpVal xt =
+ match Array.tryFindIndex(fun x -> x=xt) X with
+ | Some n -> Y.[n] //exact match -> return the value
+ | None -> //no exact match, interpolate
+ let (P,N) = Array.fold2(fun (P,N) x y ->
+ let dx = x-xt in
+ if dx>0.0 then ((dx,y)::P,N)
+ else (P,(dx,y)::N)) ([],[]) X Y in
+ let (x1,y1) = Seq.maxBy(fun (x,y) -> x) N in //largest negative element (on the left of target)
+ let (x2,y2) = Seq.minBy(fun (x,y) -> x) P in //smallest positive element (on the right of target)
+
+ let (x1,x2) = (x1+xt, x2+xt) in //expresss xt as a linear combination
+ let a = (xt - x2)/(x1-x2) in
+ let y = a*y1 + (1.0-a)*y2 in
+ y
+ in
+ Array.map(fun x -> InterpVal x) Z
+
+
+
+let LoadPlate (data:string) =
+ let ParseLine (str: string list) =
+ let fields = str.Head.Split([|','|]) |> Array.toList
+ (fields, str.Tail)
+
+ let rec Skip n l =
+ match (n, l) with
+ | 0, _ -> l
+ | _, [] -> []
+ | n, _ :: ls -> Skip (n-1) ls
+ in
+
+ //load the time and ids information from the header files; returns (signal name * id * time in min)
+ let ParseHeaders (hdr:string list) =
+ let regex = new Regex(@"\((?.*)\)\s*(?\d+)\s*-\s*(?\d+)\s*h\s*((?\d+)\s*min)?", RegexOptions.IgnoreCase) in
+ Seq.map(fun x-> let mc = regex.Match(x)
+ let signal = mc.Groups.Item("signal").ToString()
+ let id = (int)(mc.Groups.Item("id").ToString())
+ let h = (double)(mc.Groups.Item("h").ToString())
+ let m = let ms = mc.Groups.Item("m").ToString()
+ if (ms <> "") then (double)ms else 0.0
+ signal,id , h * 60.0 + m) (Skip 5 hdr) //The number of skips has to match the meta-data columns of the file
+
+
+ let data = data.Replace('\r',' ') in
+ let lines = data.Split([|'\n'|]) |> Array.toList in
+ let (headers, lines) = ParseLine(lines) in //read in the headers line
+ let headers = ParseHeaders(headers) in //parse the headers and extract time and samples information
+ let lines = Skip 1 lines in //get rid of averages line
+ let lines = Seq.fold(fun acc (x:string) -> if x.Replace(',',' ').Trim()="" then acc else acc@[x]) [] lines in //remove empty lines
+ //parse the wells and data
+ let data = Seq.map(fun (line:string) ->
+ let fields = line.Split(',') |> List.ofArray in //String.split([',']) line in
+ match fields with
+ | content::colony::col::row::cond::data ->
+ let signals = Seq.map2(fun (s,_,t) v -> (s,t,(double)v)) headers data
+ |> Seq.groupBy(fun (s,t,v) -> s)
+ |> Seq.map(fun (k,x) -> (k,Seq.map(fun (s,t,v) -> t,v) x |> Seq.sortBy(fun (t,v) -> t)))
+ |> Seq.map(fun (k,x) -> (k,Seq.map(fun (t,_) -> t) x |> Array.ofSeq , Seq.map(fun (_,y) -> y) x |> Array.ofSeq)) in
+ let (_,T,OD) = Seq.find(fun (s:string,_,_) -> s.ToLower()="od") signals in
+ let signals = Seq.map(fun (s,Tc,S) -> if Tc=T then (s,S)
+ else (s, Interp Tc S T)
+ ) signals in //TODO: THROW A WARNING WHEN INTERPOLATING
+ let condition = Seq.fold(fun acc (x:string) ->
+ if (x.Length>0) then
+ let y = x.Split '=' in
+ (y.[0],Double.Parse(y.[1]))::acc
+ else
+ acc
+ ) [] (cond.Split(';'))
+ |> Map.ofSeq in
+ let dT = if content.ToLower().Contains("gain") then Gain
+ else if content.ToLower().Contains("blank") then Blank
+ else if content.ToLower().Contains("negative") then Negative
+ else Data in
+
+ let names = Seq.map(fun (n,_) ->n) signals |> Array.ofSeq in
+ let signals = Seq.map(fun (_,s) ->s) signals |> Array.ofSeq in
+ let row = row.Trim().[0] in
+ let col = Convert.ToInt32(col) in
+ {
+ EmptyWell with
+ Row = row;
+ Col = col;
+ Content = content;
+ Colony = colony;
+ DataType = dT;
+ Condition = condition;
+ Signals = signals;
+ SignalNames = names;
+ T = T;
+ }
+ //| _ -> failwith "Headers in the wrong format."
+ ) lines in
+ let conditions = Seq.fold (fun ag well -> Seq.append(ag) (well.Condition|>Map.toSeq)) Seq.empty data
+ |> Seq.groupBy fst
+ |> Seq.map(fun (c,vals) -> c, Seq.map snd vals |> Seq.distinct |> Array.ofSeq)
+ |> Map.ofSeq in
+
+ {EmptyPlate with Data=data; Conditions=conditions}
+
+
+let getSignal(well:Well, str:string) =
+ match Array.tryFindIndex(fun x -> x=str) well.SignalNames with
+ |Some n -> (well.T,well.Signals.[n])
+ |None -> (Array.empty, Array.empty)
+let getSignals(well:Well, s1:string, s2:string) =
+ match (getSignal(well,s1), getSignal(well,s2)) with
+ |((X1,Y1), (X2,Y2)) when not (Array.isEmpty(Y1)) && not (Array.isEmpty(Y2)) -> (Y1,Y2)
+ |_ -> (Array.empty, Array.empty)
+
+
+
+let getFluorescence (well:Well) =
+ let namedSignals = Array.map2(fun name signal -> (name,signal)) well.SignalNames well.Signals
+ |> Seq.filter(fun (name,signal) -> not (name="OD")) in //ignore the growth signal
+ (well.T,namedSignals)
+
+
+let getFOd (well:Well) =
+ let namedSignals = Array.map2(fun name signal -> (name,signal)) well.SignalNames well.Signals in
+ let F = Seq.filter(fun (n,_) -> not (n = "OD")) namedSignals in
+ let OD = snd (Seq.find(fun (n,_) -> n="OD") namedSignals) in
+ (OD,F)
+
+let getFF (well:Well, chan:string) =
+ let namedSignals = Array.map2(fun name signal -> (name,signal)) well.SignalNames well.Signals in
+ let F = Seq.filter(fun (n,_) -> not (n = chan || n="OD")) namedSignals in
+ let X = snd (Seq.find(fun (n,_) -> n=chan) namedSignals) in
+ (X,F)
+
+
+
+let MergePlates (plate1:Plate, plate2:Plate) =
+ let name = "Merged " + plate1.Name + " and " + plate2.Name in
+ let data = Seq.append plate1.Data plate2.Data in
+ let conditions = Map.fold (fun s k v ->
+ match Map.tryFind k s with
+ | Some v' -> Map.add k (Array.ofSeq (Seq.distinct (Seq.append (Seq.ofArray v) (Seq.ofArray v')))) s
+ | None -> Map.add k v s) plate1.Conditions plate2.Conditions in
+ { EmptyPlate with Name = name; Data = data; Conditions = conditions }
+
+let Median (vals:seq) =
+ let sorted = Seq.sort vals |> List.ofSeq in
+ let n = Seq.length sorted in
+ if n % 2 =0 then
+ sorted.[n/2]
+ else
+ let mp = Convert.ToDouble(n)/2.0 in
+ let l = Convert.ToInt32(floor(mp/2.0)) in
+ let h = Convert.ToInt32(ceil(mp/2.0)) in
+ (sorted.[l] + sorted.[h]) /2.0
+
+
+
+(* Linear least squares *)
+let LsqLin (Xi:double[]) (Yi:double[]) =
+ let sum X = Array.fold(fun s x -> s + x) 0.0 X
+ let ave X = (sum X)/((float)(Array.length X))
+ let mx = ave Xi
+ let my = ave Yi
+ let S1 = Array.map2(fun x y -> (x-mx)*(y-my)) Xi Yi |> sum
+ let S2 = Array.map(fun x-> Math.Pow((x-mx),2.0)) Xi |> sum
+ let a = if S2 = 0.0 then failwith "Linear regression failed because of divide by zero." else S1/S2
+ let b = my - a * mx
+ (a,b)
+
+
+let CorrectBlanks (plate:Plate) =
+ let ComputeBlanks (plate:Plate) =
+ let blanks = Seq.filter(fun x -> x.DataType = DataTypes.Blank) plate.Data in
+ let signals = Seq.fold(fun acc well -> Array.map2(fun name signal -> (name,signal)) well.SignalNames well.Signals |> Seq.append(acc)) Seq.empty blanks
+ |> Seq.groupBy(fun (s,x) ->s)
+ |> Seq.map(fun (s,x) -> (s, Seq.fold(fun acc (_,v) -> Seq.append(acc) v) Seq.empty x|> Median)) //compute the median of the background
+ //|> Seq.map(fun (s,x) -> (s, Seq.fold(fun acc (_,v) -> Seq.append(acc) v) Seq.empty x|> Seq.average)) //compute the average of the background
+ //|> Seq.filter(fun (s,_) -> not (s = "OD")) //use this to avoid the correction of OD data
+ //|> Seq.filter(fun (s,_) -> (s = "OD")) //use this to only allow the correction of OD data
+ |> Map.ofSeq in
+ {plate with Blanks=signals} //Check this?
+ in
+ let BlankCorrect (blanks:Map) (well:Well) =
+ {well with Signals = Array.map2(fun name signal -> if blanks.ContainsKey(name) then
+ let df = blanks.Item(name) in
+ Array.map(fun x -> x - df) signal
+ else
+ signal
+ ) well.SignalNames well.Signals}
+ in
+ let plate = ComputeBlanks plate in
+ let bc = BlankCorrect plate.Blanks in
+ let newData = Seq.map(fun w -> bc w) plate.Data |> Seq.cache in
+ {plate with Data = newData;}
+
+
+
+// let CorrectBlanksAndGain (plate:Plate) =
+// let ComputeBlanks (plate:Plate) =
+// let blanks = Seq.filter(fun x -> x.DataType = DataTypes.Blank) plate.Data in
+// let signals = Seq.fold(fun acc well -> Array.map2(fun name signal -> (name,signal)) well.SignalNames well.Signals|> Seq.append(acc)) Seq.empty blanks
+// |> Seq.groupBy(fun (s,x) ->s)
+// |> Seq.map(fun (s,x) -> (s, Seq.fold(fun acc (_,v) -> Seq.append(acc) v) Seq.empty x|> Median))
+// //|> Seq.filter(fun (s,_) -> not (s = "OD")) //use this to avoid the correction of OD data
+// |> Map.ofSeq in
+// {plate with Blanks=signals}
+// in
+// let BlankCorrect (blanks:Map) (well:Well) =
+// {well with Signals = Array.map2(fun name signal -> if blanks.ContainsKey(name) then
+// let df = blanks.Item(name) in
+// if name="OD" then
+// Array.map(fun x -> x - df) signal //use the original (subtraction) for OD [no gain]
+// else
+// Array.map(fun x -> x/df-1.0) signal //use the modified procedures for all other (fluorescent) channels
+// else
+// signal) well.SignalNames well.Signals}
+// in
+// let plate = ComputeBlanks plate in
+// let bc = BlankCorrect plate.Blanks in
+// let newData = Seq.map(fun w -> bc w) plate.Data |> Seq.cache in
+// {plate with Data = newData;}
+
+
+
+
+
+let Add (s1:double[]) (s2:double[]) = Array.map2(fun x y -> x+y) s1 s2
+let Div (s:double[]) (n:double) = Array.map(fun x -> x/n) s
+
+let CorrectAutofluorescence (plate:Plate) =
+ let negatives = Seq.filter(fun x -> x.DataType = DataTypes.Negative) plate.Data |> Seq.map(fun w -> w) in
+
+ if Seq.isEmpty negatives then //no autofluorescence information was found, proceed without correcting but raise a message
+ //TO DO: Include a delegate for displaying information to the user
+ {plate with log=plate.log + "\n No autofluorescence callibration was performed!\n";}
+ else
+// let T = (Seq.head negatives).T in
+// let autofl = Seq.fold(fun acc well -> let ns = (Seq.map2(fun name signal -> (name,Interp well.T signal T)) well.SignalNames well.Signals) in Seq.concat([acc; ns])) Seq.empty negatives
+// |> Seq.groupBy(fun (s,x) ->s)
+// |> Seq.map(fun (s,x) -> (s,Seq.map(fun (_,y) -> y) x))
+// |> Seq.map(fun (s,x) ->
+// let n = Convert.ToDouble(Seq.length x) in
+// (s,Seq.fold(fun acc y -> Add acc (Div y n)) (Div (Seq.head x) n) (Seq.skip 1 x)))
+// |> Map.ofSeq
+// in
+// let AutoCorrect (well:Well) =
+// {well with Signals = Array.map2(fun name signal -> if not (name="OD") then
+// let Df = Interp T (autofl.Item(name)) well.T in
+// Array.map2(fun x df -> x - df) signal Df
+// else
+// signal) well.SignalNames well.Signals}
+// in
+// let newData = Seq.map(fun w -> AutoCorrect w) plate.Data |> Seq.cache in
+// {plate with Data = newData}
+//
+ let autofl = Seq.map(fun w -> let od= getSignal(w,"OD") |> snd |> Seq.mapi(fun i x -> (i,x)) |> Seq.filter(fun (i,x) -> w.Filter(i)) |> Seq.map(fun (i,x) -> x) |> Array.ofSeq in
+ Seq.map2(fun name signal -> if not (name="OD") then
+ let signal = signal |> Seq.mapi(fun i x -> (i,x)) |> Seq.filter(fun (i,x) -> w.Filter(i)) |> Seq.map(fun (i,x) -> x) |> Array.ofSeq in
+ (name,od,signal)
+ else
+ ("",[||],[||])
+ ) w.SignalNames w.Signals
+ |> Seq.filter(fun (n,_,_) -> not (n=""))
+ ) negatives
+ |> Seq.fold(fun acc s -> Seq.append(acc) s) Seq.empty
+ |> Seq.groupBy(fun (s,_,_) ->s)
+ |> Seq.map(fun (s,x) -> (s,Seq.fold(fun (OD,F) (_,od,f) -> (Seq.append(OD) od,Seq.append(F) f)) (Seq.empty,Seq.empty) x))
+ |> Seq.map(fun (s,(OD,F)) -> (s,LsqLin (OD |> Array.ofSeq) (F |> Array.ofSeq)))
+ |> Map.ofSeq
+ in
+ let AutoCorrect (well:Well) =
+ {well with Signals = let od = getSignal(well,"OD") |> snd in
+ Array.map2(fun name signal ->
+ if not (name="OD") then
+ let (a,b) = autofl.Item(name) in
+ Array.mapi(fun i x -> x - a*od.[i]+b) signal
+ else
+ signal) well.SignalNames well.Signals}
+ in
+ let newData = Seq.map(fun w -> AutoCorrect w) plate.Data |> Seq.cache in
+ {plate with Data = newData}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ //model parameters, Filzbach parameters, likelihood (param->double)
+//Replace this with the built-in Filzbach scriptable
+type Filzbach(mparam,likefn) =
+ class
+ inherit ModelBase(new System.Random())
+ override this.setup_data() = ()
+ override this.setup_parameters() =
+ Seq.iter(fun (name,lb,ub,v,t) -> this.parameter_create(name,lb,ub,v,t,0,0)) mparam;
+ override this.likelihood() =
+ let cv = Seq.map(fun (name,_,_,_,_) -> this.cv(name)) mparam
+ |> Seq.cache in
+ let log_like = likefn cv in
+ this.set_metr_ltotnew(log_like);
+ this.inc_metr_number_ok(1.0);
+ member this.ltotmax = 0.0;
+ member this.Run(fparam) =
+ this.setup_data();
+ this.setup_parameters();
+ let burnin,eststeps,burnin2,mleexp = fparam in
+ this.runmcmc(burnin,eststeps,burnin2,mleexp, null, null, null,null);
+ this.params_set_to_MLE(); //or set_to_posterior_mean?
+ Seq.map(fun (name,_,_,_,_) -> this.cv(name)) mparam
+ |> Seq.cache
+ member this.GetParamHist() = this.bayestable
+ end
+
+
+
+
+
+
+//growth models, inverse and derivatives
+(*
+Gompertz model is reparametrized as in:
+Zwietering MH, Jongenburger I, Rombouts FM, Van’t Riet K (1990)
+Modelling of the bacterial growth curve.
+Appl Environ Microbiol 56:1875–1881
+*)
+let Gompertz(mu, K, lag) t = K*exp(-exp((lag-t)*(mu*exp(1.0)/K)+1.0)) //Gompertz growth model.
+//let GompInv(mu, K, lag) od = lag-(log(-log(od/K))-1.0)*K/(mu*exp(1.0)) //Inverse Gompertz function
+//let GompDer(mu, K, lag) t = mu*exp(exp(1.0)*mu*(lag-t)/K-exp(exp(1.0)*mu*(lag-t)/K+1.0)+2.0) //Gompertz derivative function
+let Richards(mu,K,lag,v) t =
+ // let A = Math.Pow(mu/K*(1.0+v),(1.0+1.0/v))*(lag-t) in
+ let A = mu/K*Math.Pow((1.0+v),(1.0+1.0/v))*(lag-t) in
+ let B = 1.0+v*exp(1.0+v)*exp(A) in
+ K*Math.Pow(B,-1.0/v)
+let Logistic(mu,K,lag) t =
+ K * exp(-exp(mu*exp(1.0)/K*(lag-t)+1.0))
+
+
+//runs Filzbach using a selected growth model and returns the identified parameters (mu,K,lag)
+
+let FitGrowthModel (modelType) (plate:Plate) =
+ let FitGrowthModelOD(ODi, model) =
+
+
+ //od fit
+ //let od0 = Seq.map(fun (t, od) -> od) ODi |> Seq.min in //use smallest OD measurement to avoid negative value
+// let od0 = snd (Seq.nth 0 ODi) in //use the first OD value
+// let OD = Seq.map(fun (t,od) -> (t, od/od0)) ODi |> Seq.cache in
+
+ //window slope calculation procedure for growth
+// let od0 = ODi |> Seq.map(fun (_,x) -> x) |> Seq.min in
+// let OD = Seq.map(fun (t,od) -> (t,od - od0) ) ODi in
+// let OD = Seq.map(fun (t,od) -> (t, log(od))) OD |> Seq.cache in
+// let mus = new List() in
+// let ws = 50 in //window size
+// for i in ws..((Seq.length OD)-ws) do
+// let a = OD|> Seq.skip(i) |> Seq.take(5) |> Seq.fold(fun (acc1, acc2) (x,y) -> (List.concat([acc1; [x]]), List.concat([acc2;[y]]))) ([],[]) in
+// let (A,B) = (fst a |> Array.ofSeq, snd a |> Array.ofSeq) in
+// mus.Add(fst (LsqLin A B));
+// done;
+// let mx = mus |> Seq.filter(fun x-> not (Double.IsNaN(x) || Double.IsInfinity(x))) |> Seq.max in
+
+ let OD = Seq.map(fun (t,od) -> (t,if od<=0.0 then 1.0e-2 else od)) ODi |> Seq.cache in //negative values are bad when using log fits
+ //let OD = Seq.filter(fun (t,od) -> od>0.0) ODi |> Seq.cache in //negative values are bad when using log fits
+ let od0 = snd (Seq.nth 0 OD) in //use the first OD value
+ let OD = Seq.map(fun (t,od) -> (t, log (od/od0))) OD |> Seq.cache in
+
+ match model with
+ | GrowthModels.Logistic ->
+ let fparam = 2000, 2000, 500, 500 in
+ let mparam = Seq.ofList[("mu", 0.0, 1.0, 0.25, 0);
+ ("K", 0.0, 10.0, 1.0, 0);
+ ("lag",-500.0, 500.0, 100.0, 0);
+ ("s", 1e-8, 1e2, 1e-8, 1)] in
+ let likefn param = let (mu,K,lag,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ Seq.fold (fun sum (x,y) ->
+ let obs = Logistic(mu, K, lag) x in
+ let noise = s in
+ sum + log(ModelBase.normal_density(y,obs,noise))) 0.0 OD in
+ let FilzGrowth = Filzbach(mparam,likefn) in
+ let param = FilzGrowth.Run(fparam) in
+ let mu = Seq.nth 0 param in
+ let K = Seq.nth 1 param in
+ let lag = Seq.nth 2 param in
+ let e = Math.Exp(1.0) in
+ let maturation_offset = 50.0 in
+ let tm = lag + K/(2.0*mu) + maturation_offset in
+ let ParamHist = FilzGrowth.GetParamHist() in
+ let res = ParamHist.Count in
+ let RandLogistic(id, x) =
+ let param = ParamHist.[id] in //random parameter from posterior
+ let (mu,K,lag) = param.[2], param.[3],param.[4] in
+ let y = Logistic(mu,K,lag) x in
+ od0 * Math.Exp(y)
+ //y
+
+ in
+ mu, lag, tm, K,res, RandLogistic, OD
+
+
+ | GrowthModels.Gompertz ->
+ let fparam = 2000, 2000, 500, 500 in
+ let mparam = Seq.ofList[("mu", 0.0, 1.0, 0.25, 0);
+ ("K", 0.0, 10.0, 1.0, 0);
+ ("lag",-500.0, 500.0, 100.0, 0);
+ ("s", 1e-8, 1e3, 1e-8, 1)] in
+ let likefn param = let (mu,K,lag,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ Seq.fold (fun sum (x, y) ->
+ let obs = Gompertz(mu, K, lag) x in
+ let noise = s in
+ sum + log(ModelBase.normal_density(y,obs,noise))) 0.0 OD in
+ let FilzGrowth = Filzbach(mparam,likefn) in
+ let param = FilzGrowth.Run(fparam) in
+ let mu = Seq.nth 0 param in
+ let K = Seq.nth 1 param in
+ let lag = Seq.nth 2 param in
+ let e = Math.Exp(1.0) in
+ let maturation_offset = 50.0 in
+ let tm = (K + e*lag*mu)/(e*mu) + maturation_offset in
+ let ParamHist = FilzGrowth.GetParamHist() in
+ let res = ParamHist.Count in
+ let RandGompertz(id, x) =
+ let param = ParamHist.[id] in //random parameter from posterior
+ let (mu,K,lag) = param.[2], param.[3],param.[4] in
+ let y = Gompertz(mu,K,lag) x in
+ od0*Math.Exp(y)
+ //y
+ in
+ mu, lag, tm, K,res, RandGompertz, OD
+ // mx, lag, tm, K,res, RandGompertz, OD
+
+
+ | GrowthModels.Richards ->
+ //let fparam = 2000, 2000, 500, 500 in
+ let fparam = 2000, 2000, 500, 500 in
+ let mparam = Seq.ofList[("mu", 0.0, 1.0, 0.25, 0);
+ ("K", 0.0, 10.0, 1.0, 0);
+ ("lag",-500.0, 500.0, 100.0, 0);
+ ("v",0.0, 1.0, 0.01, 0);
+ ("s", 1e-8, 1e2, 1e-8, 1)] in
+ let likefn param = let (mu,K,lag,v,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param, Seq.nth 4 param in
+ Seq.fold(fun sum (x, y) ->
+ let obs = Richards(mu, K, lag,v) x in
+ let noise = s in
+ sum + log(ModelBase.normal_density(y,obs,noise))) 0.0 OD in
+ let FilzGrowth = Filzbach(mparam,likefn) in
+ let param = FilzGrowth.Run(fparam) in
+ let mu = Seq.nth 0 param in
+ let K = Seq.nth 1 param in
+ let lag = Seq.nth 2 param in
+ let e = Math.Exp(1.0) in
+ let maturation_offset = 50.0 in
+ let tm = (K + e*lag*mu)/(e*mu) + maturation_offset in
+ //construct a random growth sampling function
+ let ParamHist = FilzGrowth.GetParamHist() in
+ let res = ParamHist.Count in
+ let RandRichards(id, x) =
+ let param = ParamHist.[id] in //random parameter from posterior
+ let (mu,K,lag,v) = param.[2], param.[3],param.[4],param.[5] in
+ let y = Richards(mu,K,lag,v) x in
+ od0 * Math.Exp(y)
+ //y
+ in
+ //return results
+ mu, lag, tm, K,res, RandRichards , OD
+ in
+ let FitGrowthModelWell (modelType) (well:Well) =
+ let (T,OD) = getSignal(well, "OD") in
+ let OD = Seq.map2(fun t od -> (t,od)) T OD in
+ let rec runner OD modelType =
+ let (mu,lag,tm,K,res,md,nOD) = FitGrowthModelOD(OD,modelType) in
+ if (tm < 0.0)
+ then runner OD modelType
+ else (mu,lag,tm,K,res,md,nOD) in
+ let (mu,lag,tm,K,res,md,nOD) = runner OD modelType in
+ let nOD = Seq.map(fun (t,od) -> od) nOD |> Array.ofSeq in
+ let model = {mu=mu;lag=lag;tm=tm;K=K; res=res;model=md} in
+ //let newSignals = Array.mapi(fun i s -> if well.SignalNames.[i]="OD" then nOD else s) well.Signals in
+ //{well with Signals = newSignals; GrowthModel = Some model;}
+ {well with GrowthModel = Some model;}
+ in
+ let newData = Seq.map(fun w -> FitGrowthModelWell modelType w ) plate.Data |> Seq.cache in
+ {plate with Data = newData;}
+
+
+//physical properties of commonly used fluorescent proteins
+//assume all FPs have the same degradation and translation rates - specific values from (Elowitz and Leibler, Nature, 2000) are used.
+//CFP, YFP maturation rates are taken from (J. Brown, 2011) which refers to (Gordon et. al., Nat. Meth 2007)
+type ReporterPropertiesType = {name:string; degradation:double; maturation:double; translation: double; mRNAdeg:double}
+
+//let degradationRate = 0.0693
+let degradationRate = 0.0005
+
+let ReporterProperties (name:string) =
+ let reporter = name.ToLower() in
+ match reporter with
+ | "gfpmut3" -> Some {name="GFPmut3"; degradation=degradationRate; maturation=0.0277; translation=0.1443; mRNAdeg=0.001;}
+ | "mcherry" -> Some {name="mCherry"; degradation=degradationRate; maturation=0.0186; translation=0.1443; mRNAdeg=0.001;}
+ | "ecfp" -> Some {name="ECFP"; degradation=degradationRate; maturation=0.0139; translation=0.1443; mRNAdeg=0.001;}
+ | "eyfp" -> Some {name="EYFP"; degradation=degradationRate; maturation=0.0173; translation=0.1443; mRNAdeg=0.001;}
+ | "mrfp1" -> Some {name="mRFP1"; degradation=degradationRate; maturation=0.0173; translation=0.1443; mRNAdeg=0.001;}
+ | _ -> None
+
+//construct a filter function for each well to capture the exponential phase based on the inferred growth curve.
+let SetFilters plate =
+ let newData = Seq.map(fun w ->
+ let newFilter =
+ match w.GrowthModel with
+ | Some model ->
+ let filter id =
+ let t = w.T.[id] in
+ t > model.lag && t < 2.0*model.tm-model.lag in
+ filter
+ | None -> w.Filter
+ in
+ { w with Filter = newFilter }
+ ) plate.Data |> Seq.cache in
+ {plate with Data = newData;}
+
+
+let FindSteadyStates plate =
+ let filteri filter X =
+ let mapped = Array.mapi (fun i x -> (i,x)) X in
+ let filtered = Array.filter (fun (i,x) -> filter i) mapped in
+ Array.map (fun (i,x) -> x) filtered
+ in
+ let FindSS well =
+ let Filter = filteri well.Filter in
+ let Signals = Array.map(fun s -> Filter s) well.Signals in //filter signals
+ Array.fold2(fun (map:Map<(string*string),(double*double)>) name signal -> //for each pair of signals, compute the cross slope
+ Array.fold2(fun map2 name2 signal2 ->
+ let fit = LsqLin signal2 signal in //signal2 is the X, signal is Y;
+ map2.Add((name,name2),fit)) map well.SignalNames Signals)
+ Map.empty well.SignalNames Signals
+ in
+ let newData = Seq.map(fun w -> {w with SteadyStates = FindSS w;}) plate.Data |> Seq.cache in
+ {plate with Data=newData;}
+
+let FindActivities (plate:Plate) =
+ let copies = 1.0 in //single copy number assumption
+ let FindActivity (well:Well) =
+ Map.toSeq well.SteadyStates
+ |> Seq.fold(fun (map:Map<(string*string),double>) ((s1,s2), (a,_)) ->
+ if not (s1="OD") && s2="OD" then
+ let propOpt = ReporterProperties s1 in
+ match propOpt with
+ | Some prop ->
+ let Pdeg = prop.degradation in
+ let Pmat = prop.maturation in
+ let Ptrans = prop.translation in
+ let mRNAdeg = prop.mRNAdeg in
+ let mu = well.GrowthModel.Value.mu in
+ let factor = mRNAdeg * (Pdeg + mu)*(Pdeg + mu + Pmat)/(Pmat*Ptrans*copies) in
+ map.Add((s1,s2),factor*a)
+ | None -> map
+ else if not (s1="OD") && not (s2="OD") && not(s1=s2) then
+ let prop1 = ReporterProperties s1 in
+ let prop2 = ReporterProperties s2 in
+ match (prop1,prop2) with
+ | (Some p1, Some p2) ->
+ let Pdeg1 = p1.degradation in
+ let Pmat1 = p1.maturation in
+ let Ptrans1 = p1.translation in
+ let mRNAdeg1 = p1.mRNAdeg in
+
+ let Pdeg2 = p2.degradation in
+ let Pmat2 = p2.maturation in
+ let Ptrans2 = p2.translation in
+ let mRNAdeg2 = p2.mRNAdeg in
+
+ let mu = well.GrowthModel.Value.mu in
+
+ let F1 = mRNAdeg1 * (Pdeg1 + mu)*(Pdeg1 + mu + Pmat1)/(Pmat1*Ptrans1) in
+ let F2 = mRNAdeg2 * (Pdeg2 + mu)*(Pdeg2 + mu + Pmat2)/(Pmat2*Ptrans2) in
+
+ map.Add((s1,s2),(F1/F2)*a)
+ | _ -> map
+ else
+ map
+ ) Map.empty
+ in
+ let newData = Seq.map(fun w -> {w with Activity = FindActivity w;}) plate.Data |> Seq.cache in
+ {plate with Data=newData;}
+
+
+let ComputeProperties condition default_values (plate:Plate) =
+ let devices = Seq.groupBy(fun w -> w.Content) plate.Data //group wells by device
+ |> Seq.filter(fun (s:string,w) -> //remove controls
+ let name = s.ToLower() in
+ not (name.Contains("blank") ||
+ name.Contains("negative") ||
+ name.Contains("gain"))) in
+ let device = snd (Seq.head devices) in //select the first devices (TODO: generalize for multiple devices)
+ //let d0 = Seq.head device in //select the first well to explore the available conditions
+
+ //TODO: FIX EMPTY CONDITION
+
+ // Filter the wells for matched conditions and their values
+ let get_condition well key = if well.Condition.ContainsKey key then well.Condition.[key] else 0.0 in
+
+ let device =
+ let filtered_values = Seq.filter (fun (cnd,_) -> not (cnd=condition)) default_values in
+ Seq.filter (fun w -> Seq.fold (fun res (c,v) -> res && (get_condition w c = v)) true filtered_values) device in
+
+ let measurements = Seq.groupBy(fun w -> get_condition w condition) device
+ |> Seq.map(fun (c, wells) -> (c,Seq.map(fun w ->
+ let activities = Map.toSeq w.Activity |> Seq.map(fun ((s1,s2),v) -> (s1 + "/" + s2, v)) in
+ let growth = [("mu", w.GrowthModel.Value.mu); ("lag", w.GrowthModel.Value.lag);("K", w.GrowthModel.Value.K);] |> Seq.ofList in
+ Seq.concat([activities; growth])
+ |> Map.ofSeq) wells))
+ in
+ let propertyNames = Seq.head measurements |> snd |> Seq.head |> Map.toSeq |> Seq.map(fun (s,_) -> s) |> Array.ofSeq in
+ let C = Seq.map(fun (s,_) -> s) measurements |> Array.ofSeq in
+
+ let mMap = measurements |> Map.ofSeq in
+ let properties = Seq.map(fun c -> //for each condition
+ let d = mMap.[c] in
+ Seq.map(fun n -> Seq.map(fun (s:Map) -> s.[n]) d |> Array.ofSeq) propertyNames //for each property
+ |> Array.ofSeq) C |> Array.ofSeq in
+ {plate with C=C; Properties=properties; PropertyNames=propertyNames; Cname=condition;}
+
+let FilterByDevice plate device =
+ let data = Seq.filter (fun w -> w.Content = device) plate.Data in
+ { plate with Data = data }
+
+
+let AdjustGain(plate:Plate) =
+ let ComputeGain(plate:Plate) =
+ let gain = Seq.filter(fun w -> w.DataType=DataTypes.Gain) plate.Data //filter only the "Gain" wells
+ |> Seq.map(fun w -> w.Activity |> Map.toSeq) //take the calculated activity values and represent as sequences
+ |> Seq.fold(fun acc s -> Seq.append(acc) s) Seq.empty //append all replicates
+ |> Seq.groupBy(fun (s,_) -> s) //group by the signal type
+ |> Seq.map(fun (s,x) -> //compute the average gain of each channel
+ let ave = Seq.map(fun (_,X) -> X) x |> Seq.average in
+ (s,ave))
+ |> Seq.filter(fun ((s1,s2),_) -> not (s1="OD" || s2="OD")) //leave only fluorescent channels
+ |> Map.ofSeq in
+ {plate with Gain=gain}
+ in
+ let AdjustSignals(plate:Plate) =
+ let newData = Seq.map(fun w ->
+ if w.DataType = DataTypes.Data then
+ let activity = w.Activity |> Map.toSeq in
+ let newActivity = Seq.map(fun (key,value) ->
+ let newValue = if plate.Gain.ContainsKey(key) then value/(plate.Gain.[key]) else value in
+ (key,newValue)) activity
+ |> Map.ofSeq in
+ {w with Activity=newActivity}
+ else
+ w
+ ) plate.Data in
+ {plate with Data = newData;}
+ in
+ plate
+ |> ComputeGain
+ |> AdjustSignals
+
+
+
+
+let Characterize(plate:Plate, growthModel) =
+ let def_cond = plate.Conditions |> Map.toSeq |> Seq.head |> fst in
+ let def_cond_vals = plate.Conditions |> Map.toSeq |> Seq.map(fun (c,_) -> c, 0.0) in
+ plate
+ |> CorrectBlanks //compute and subtract background signals from blank media
+ |> FitGrowthModel growthModel //fit the parameters of a growth curve to each werll
+ |> SetFilters //use the growth curve to select a range of data
+ |> CorrectAutofluorescence //compute and subtract the background fluorescence of nonfluorescent cells (autofluorescence)
+ |> FindSteadyStates //compute the steady states of each reporter (individually)
+ |> FindActivities //compute the promoter activities from the fluorescence
+ |> AdjustGain //compute the average gain adjustment and modify the signals accordingly
+ |> ComputeProperties def_cond def_cond_vals //collect a represenation of the different properties (activities, growht, etc) as a function of condition
+
+
+
+
+
+
+
+let getKeys map = Seq.map(fun (k,_) -> k) (Map.toSeq map)
+
+let getProperties (plate:Plate, property:string) =
+ let id = Array.findIndex(fun x -> x = property) plate.PropertyNames in
+ Seq.map2(fun x (y:double[][]) -> (x,y.[id])) plate.C plate.Properties
+
+
+
+let DataOutput(plate:Plate) =
+ let result = "" in
+
+ let conditions = Seq.fold(fun acc w -> Seq.append(acc) (w.Condition |> Map.toSeq |> Seq.map(fun (s,_) -> s))) Seq.empty plate.Data |> Set.ofSeq in
+ let result = Seq.fold(fun acc c -> acc + c + ",") result conditions in
+ let signals = (Seq.head plate.Data).SignalNames in
+ let has_rfp = Array.contains "mRFP1" signals in
+ let result = result
+ + "F(EYFP/OD),F(ECFP/OD),"
+ + (if has_rfp then "F(mRFP1/OD)," else "")
+ + "F(EYFP/ECFP),"
+ + (if has_rfp then "F(EYFP/mRFP1),F(ECFP/mRFP1)," else "")
+ + "P(EYFP/OD),P(ECFP/OD),"
+ + (if has_rfp then "P(mRFP1/OD)," else "")
+ + "P(EYFP/ECFP),"
+ + (if has_rfp then "P(EYFP/mRFP1),P(ECFP/mRFP1)," else "")
+ + "mu,K,lag\n" in
+ let result = Seq.fold(fun acc well ->
+ //let acc = acc + well.Row.ToString() + "," + well.Col.ToString() + "," + well.DataType.ToString() + "," in
+ //let acc = acc + well.Condition.Aggregate("", (acc, y) => acc + y.Key + "=" + y.Value + ";") + "," in
+ let acc = Seq.fold(fun acc c -> acc + (if well.Condition.ContainsKey(c) then well.Condition.[c].ToString() else "0.0") + ",") acc conditions in
+ let acc = acc
+ + (fst well.SteadyStates.[("EYFP", "OD")]).ToString() + ","
+ + (fst well.SteadyStates.[("ECFP", "OD")]).ToString() + ","
+ + (if has_rfp then (fst well.SteadyStates.[("mRFP1", "OD")]).ToString() + "," else "")
+ + (fst well.SteadyStates.[("EYFP", "ECFP")]).ToString() + ","
+ + (if has_rfp then (fst well.SteadyStates.[("EYFP", "mRFP1")]).ToString() + ","
+ + (fst well.SteadyStates.[("ECFP", "mRFP1")]).ToString() + "," else "") in
+
+ let acc = acc
+ + well.Activity.[("EYFP", "OD")].ToString() + ","
+ + well.Activity.[("ECFP", "OD")].ToString() + ","
+ + (if has_rfp then well.Activity.[("mRFP1", "OD")].ToString() + "," else "")
+ + well.Activity.[("EYFP", "ECFP")].ToString() + ","
+ + (if has_rfp then well.Activity.[("EYFP", "mRFP1")].ToString() + ","
+ + well.Activity.[("ECFP", "mRFP1")].ToString() + "," else "") in
+
+ let acc = acc + well.GrowthModel.Value.mu.ToString() + "," in
+ let acc = acc + well.GrowthModel.Value.K.ToString() + "," in
+ let acc = acc + well.GrowthModel.Value.lag.ToString() + "\n" in
+ acc
+ ) result (Seq.filter( fun w -> w.DataType=DataTypes.Data) plate.Data) in
+ result
+
+
+//--------------------------------------------------------------------------
+//The following block of code deals with different regulation models
+//
+//This is a VERY preliminary prototype! These procedures should be generalized
+// in order to avoid code duplication
+//--------------------------------------------------------------------------
+
+let Hill(a,b,K,n) x = (a*x**n + b*K**n)/(x**n+K**n)
+
+let Hill_General(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ //let fparam = (500000, 500000, 20000, 20000) in
+ let mparam = Seq.ofList[("a", 0.0, 5000.0, 5.0, 0);
+ ("b", 0.0, 200.0, 0.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("n", 0.0, 5.0, 1.0, 0);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+
+// //use these settings for the growth model fits -> smaller ranges for a,b parameters
+// let mparam = Seq.ofList[("a", 0.0, 0.05, 5.0, 0);
+// ("b", 0.0, 0.05, 0.0, 0);
+// ("K", 1e-15, 1e15, 1e-8, 1);
+// ("n", 0.0, 5.0, 1.0, 0);
+// ("s", 1e-5, 10.0, 1.0, 1)] in
+
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (a,b,K,n,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param,Seq.nth 4 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,b,K,n) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("b",false);("K",true);("n",false); ("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+let Hill_Activation(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("n", 0.0, 5.0, 1.0, 0);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param =
+ let (a,K,n,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,0.0,K,n) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("K",true);("n",false); ("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+let Hill_Repression(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("b", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("n", 0.0, 5.0, 1.0, 0);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param =
+ let (b,K,n,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(0.0,b,K,n) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist |> Array.ofSeq in
+ (n,log,dist)) [("b",false);("K",true);("n",false); ("s",true)]
+ in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+let MM_General(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 5000.0, 5.0, 0);
+ ("b", 0.0, 200.0, 0.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param =
+ let (a,b,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,b,K,1.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("b",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+let MM_Repression(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("b", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (b,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(0.0,b,K,1.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then
+ 0.0
+ else
+ log(v)
+ in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("b",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+let MM_Activation(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (a,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,0.0,K,1.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+
+let Dimer_General(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 200.0, 5.0, 0);
+ ("b", 0.0, 200.0, 0.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (a,b,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,b,K,2.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("b",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+let Dimer_Repression(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("b", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (b,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(0.0,b,K,2.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("b",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+let Dimer_Activation(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 200.0, 5.0, 0);
+ ("K", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (a,K,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = Hill(a,0.0,K,2.0) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("K",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+let Sequential(B)=
+ let fparam = (100000, 100000, 2000, 2000) in
+ let mparam = Seq.ofList[("a", 0.0, 200.0, 5.0, 0);
+ ("b", 0.0, 200.0, 0.0, 0);
+ ("c", 0.0, 200.0, 0.0, 0);
+ ("K1", 1e-15, 1e15, 1e-8, 1);
+ ("K2", 1e-15, 1e15, 1e-8, 1);
+ ("s", 1e-5, 10.0, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let SeqMech(a,b,c,K1,K2) conc = (a * conc ** 2.0 + b * conc * K1 + c * K2 ** 2.0)/(conc**2.0 + conc*K1 + K2**2.0) in
+ let likefn param = let (a,b,c,K1,K2,s) = Seq.nth 0 param,Seq.nth 1 param,Seq.nth 2 param,Seq.nth 3 param,Seq.nth 4 param,Seq.nth 5 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = SeqMech(a,b,c,K1,K2) conc in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",false);("b",false);("c",false);("K1",true);("K2",true); ("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+
+let Linear(B)=
+ let fparam = (50000, 50000, 2000, 2000) in
+ let mparam = Seq.ofList[("a",1e-10,1e5, 0.001, 1);
+ ("b", 1e-5, 1e5, 0.001, 1);
+ ("s", 1e-5, 1e10, 1.0, 1)] in
+ let ltotmax = ref Double.MinValue in
+ let likefn param = let (a,b,s) = Seq.nth 0 param, Seq.nth 1 param, Seq.nth 2 param in
+ let logLk = Seq.fold (fun s1 (conc,vals) ->
+ let obs = a*conc+b in
+ Seq.fold(fun s2 y ->
+ let noise = if (y<0.0) then 0.0 else Math.Sqrt(obs)*s in
+ let v = ModelBase.normal_density(y,obs,noise) in
+ let v = if v<=0.0 || Double.IsInfinity(v) then 0.0 else log(v) in
+ s2 + v) s1 vals) 0.0 B in
+ ltotmax:= if (!ltotmax
+ let dist = Seq.map(fun (y:float[]) -> y.[i+2]) ParamHist
+ |> Array.ofSeq in
+ (n,log,dist)) [("a",true);("b",true);("s",true)] in
+ let parameters = List.mapi(fun i (name,log,dist) -> {pname=name; value= Seq.nth i param; log=log; dist=dist;}) paramDist |> Array.ofList in
+ let (AIC,BIC,CIC) = ICs in
+ let X = Seq.map(fun (x,_) -> x) B |> Array.ofSeq in
+ {
+ modelType = ModelTypes.Linear;
+ AIC = AIC;
+ BIC = BIC;
+ CIC = CIC;
+ model = RandFunc;
+ res = res;
+ parameters = parameters;
+ X = X;
+ bayestable = ParamHist;
+ }
+
+//note: currently, this function supports only a single inducible/repressible promoter with a single regulator
+let CharacterizeModel(data:seq, modelType)=
+ match modelType with
+ | ModelTypes.Hill_General -> Hill_General(data)
+ | ModelTypes.Hill_Activation -> Hill_Activation(data)
+ | ModelTypes.Hill_Repression -> Hill_Repression(data)
+ | ModelTypes.Linear -> Linear(data)
+ | ModelTypes.Michaelis_Menten_General -> MM_General(data)
+ | ModelTypes.Michaelis_Menten_Activation -> MM_Activation(data)
+ | ModelTypes.Michaelis_Menten_Repression -> MM_Repression(data)
+ | ModelTypes.Dimer_General -> Dimer_General(data)
+ | ModelTypes.Dimer_Activation -> Dimer_Activation(data)
+ | ModelTypes.Dimer_Repression -> Dimer_Repression(data)
+ | ModelTypes.Sequential_Binding -> Sequential(data)
+ | ModelTypes.Constitutive ->
+ {
+ modelType = ModelTypes.Constitutive;
+ AIC = 0.0;
+ BIC = 0.0;
+ CIC = 0.0;
+ model = (fun (id,x) -> 0.0);
+ res = 0;
+ parameters = [||];
+ X = Seq.map(fun (x,_) -> x) data |> Array.ofSeq;
+ bayestable = new List();
+ }
diff --git a/ClassicGEC/ClassicGECDotNet/characterization.fsi b/ClassicGEC/ClassicGECDotNet/characterization.fsi
new file mode 100644
index 0000000..5a8bbd6
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/characterization.fsi
@@ -0,0 +1,106 @@
+module GEC.Characterization
+
+open System.Collections.Generic
+
+type GrowthModels = Gompertz =0| Richards =1 | Logistic =2
+type GrowthModelType = {
+ mu: float;
+ lag: float;
+ tm: float;
+ K: float;
+ res: int;
+ model: (int * float -> float);
+}
+type DataTypes = Data | Gain | Blank | Negative
+type Well = {
+ Row: char;
+ Col: int;
+ Content: string;
+ Colony: string;
+ DataType: DataTypes;
+ Condition: Map;
+ Signals: double[][];
+ SignalNames: string[];
+ T: double[];
+ GrowthModel: GrowthModelType option;
+ Filter: int -> bool; //given an signal array index, is this part of the selection
+ SteadyStates: Map<(string*string),(double*double)>;
+ Activity: Map<(string*string),double>;
+}
+
+type Plate = {
+ Name: string;
+ Data: seq;
+ Blanks: Map;
+
+ Conditions: Map;
+ Cname: string;
+ C: double[]; //conditions
+ Properties: double[][][]; //computed or measured properties
+ PropertyNames: string[]; //name of properties
+
+ Gain: Map;
+ log: string;
+}
+
+type ModelTypes =
+ | Constitutive = 0
+ | Linear = 1
+ | Michaelis_Menten_Activation = 2
+ | Michaelis_Menten_Repression = 3
+ | Michaelis_Menten_General = 4
+ | Dimer_Activation = 5
+ | Dimer_Repression =6
+ | Dimer_General = 7
+ | Hill_Activation = 8
+ | Hill_Repression = 9
+ | Hill_General = 10
+ | Sequential_Binding = 11
+
+type ResponseTypes =
+ | EYFP_ECFP = 0
+ | EYFP_OD = 1
+ | ECFP_OD = 2
+ | mu = 3
+ | K = 4
+ | lag = 5
+ | EYFP_mRFP1 = 6
+ | ECFP_mRFP1 = 7
+ | mRFP1_OD = 8
+
+type Parameter = {
+ pname: string;
+ value: double;
+ dist: double[];
+ log: bool;
+}
+
+type Model = {
+ modelType: ModelTypes;
+ AIC: double;
+ BIC: double;
+ CIC: double; //rename this information criterion to the right abbreviation
+ model: int * double -> double;
+ res: int;
+ parameters: Parameter[];
+ X: double[];
+ bayestable: List;
+}
+
+val string_of_response: ResponseTypes -> string
+val LoadPlate: string -> Plate
+val getSignal: Well * string -> double[] * double[] //return signal over time
+val getSignals: Well * string * string -> double[] * double[] //return signal over time
+val getFluorescence: Well -> double[] * seq
+val getFOd: Well -> double[] * seq
+val getFF: Well*string -> double[] * seq
+
+val Characterize: Plate*GrowthModels -> Plate
+val ComputeProperties: string -> seq -> Plate -> Plate
+val FilterByDevice : Plate -> string -> Plate
+val getKeys: Map<'a,'b> -> seq<'a>
+val CharacterizeModel: seq*ModelTypes -> Model
+val getProperties: Plate*string -> seq
+val MergePlates: Plate * Plate -> Plate
+val DataOutput: Plate -> string
+val EmptyPlate: Plate
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/cssubst.fs b/ClassicGEC/ClassicGECDotNet/cssubst.fs
new file mode 100644
index 0000000..168fd41
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/cssubst.fs
@@ -0,0 +1,92 @@
+[]
+module Microsoft.Research.GEC.Cssubst
+
+open Microsoft.Research.GEC
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* ************************************************************************************************************ *)
+
+(* A "context-sensitive" substitution has four parts. *)
+type t = { theta:Subst.t; (* The actual substitution. *)
+ rho: string list; (* The variables on which "theta" must be injective. *)
+ sigma: string list list; (* Species names used in the current context. *)
+ tau: string list list } (* Species names excluded for use. *)
+
+(* The "empty" context-sensitive substitution. *)
+let empty = { theta=Subst.empty; rho=[]; sigma=[]; tau=[] }
+
+(* Make a context-sensitive substitution. *)
+let make (theta:Subst.t) (rho:string list) (sigma:string list list) (tau:string list list) : t =
+ { theta=theta; rho=rho; sigma=sigma; tau=tau }
+
+let printListDisplay (f:'a -> string) (xs:'a list) = "[" + (Lib.string_of_list f "; " xs) + "]"
+(* Produce a string representation of a context-sensitive substitution. *)
+let display (cs:t) =
+ "{ theta = " + (Subst.display cs.theta) + ";" + Lib.newline +
+ " rho = " + (printListDisplay Lib.id cs.rho) + ";" + Lib.newline +
+ " sigma = " + (printListDisplay Ast.complexString cs.sigma) + ";" + Lib.newline +
+ " tau = " + (printListDisplay Ast.complexString cs.tau) + " }"
+
+(* Check that a given element of the "csSubst" type satisfies the 2 criteria for a context-sensitive substitution. *)
+let isOK (cs:t) =
+ let check_ii () =
+ // Assume that cs.rho contains no duplicates...
+ match Lib.find_duplicate Subst.targetEq (List.map (fun x -> Subst.find x cs.theta) cs.rho) with
+ | None -> true
+ | Some _ -> false
+ in
+ let check_iii () = Lib.disjoint Ast.complexesEqual cs.sigma cs.tau in
+ (check_ii ()) && (check_iii ())
+
+(* Get the "normal" substitution out of a context-sensitive one. *)
+let getSubst (cs:t) : Subst.t = cs.theta
+
+(* ************************************************************************************************************ *)
+
+(* "Merge" two context-sensitive substitutions together, and test to see if the result is
+ also a context-sensitive substitution. *)
+let merge (cs1:t) (cs2:t) : t option =
+ match (Subst.union cs1.theta cs2.theta) with
+ | None -> None
+ | Some theta ->
+ let cs12 = { theta = theta;
+ rho = Lib.remove_duplicates (=) (cs1.rho @ cs2.rho);
+ sigma = Lib.remove_duplicates Ast.complexesEqual (cs1.sigma @ cs2.sigma);
+ tau = Lib.remove_duplicates Ast.complexesEqual (cs1.tau @ cs2.tau) }
+ in
+ if isOK cs12 then Some cs12 else None
+
+(* Compose two lists of context-sensitive substitutions by only retaining those elements of the
+ "cartesian product" which satisfy the criteria. *)
+let compose (css1:t list) (css2:t list) : t list =
+ (* NB: we don't form the entire cartesian product - it could get quite big.
+ Instead, have two nested loops with an accumulator running through them.
+ TO DO: this could be put into CPS to make it tail-recursive... *)
+ let rec loop (acc:t list) (css1:t list) =
+ match css1 with
+ | [] -> acc
+ | (cs1::css1) ->
+ let rec loop2 (acc:t list) (css2:t list) =
+ match css2 with
+ | [] -> acc
+ | (cs2::css2) ->
+ match merge cs1 cs2 with
+ | None -> loop2 acc css2
+ | Some cs12 -> loop2 (acc@[cs12]) css2
+ in
+ let acc = loop2 acc css2 in
+ loop acc css1
+ in
+ loop [] css1
+
+(* Erase the "context" data in a context-sensitive substitution. *)
+let eraseContext (cs:t) : t = { theta=cs.theta; rho=[]; sigma=[]; tau=[] }
+
+(* Check whether a context-sensitive substitution satisfies a list of arithmetic constraints. *)
+let satisfiesConstraints (cs:t) (ks:(Ast.aexp*Ast.op*Ast.aexp) list) : bool =
+ Lib.forall (Subst.satisfiesConstraint cs.theta) ks
+
+(* Produce a "varAss" (variable assignments) from a context-sensitive substitution. *)
+let mkVarAss (cs:t) = Subst.mkVarAss cs.theta
diff --git a/ClassicGEC/ClassicGECDotNet/cssubst.fsi b/ClassicGEC/ClassicGECDotNet/cssubst.fsi
new file mode 100644
index 0000000..9457700
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/cssubst.fsi
@@ -0,0 +1,45 @@
+module Microsoft.Research.GEC.Cssubst
+
+open Microsoft.Research.GEC
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* ************************************************************************************************************ *)
+
+(* Type for "context-sensitive" substitutions. *)
+type t
+
+(* The "empty" context-sensitive substitution. *)
+val empty : t
+
+(* Make a context-sensitive substitution. *)
+val make : Subst.t -> string list -> string list list -> string list list -> t
+
+(* Produce a string representation of a context-sensitive substitution. *)
+val display : t -> string
+
+(* Check that a given element of the "csSubst" type satisfies the 2 criteria for a context-sensitive substitution. *)
+val isOK : t -> bool
+
+(* Get the "normal" substitution out of a context-sensitive one. *)
+val getSubst : t -> Subst.t
+
+(* ************************************************************************************************************ *)
+
+(* "Merge" two context-sensitive substitutions together, and test to see if the result is
+ also a context-sensitive substitution. *)
+val merge : t -> t -> t option
+
+(* Compose two lists of context-sensitive substitutions by only retaining those elements of the
+ "cartesian product" which satisfy the criteria. *)
+val compose : t list -> t list -> t list
+
+(* Erase the "context" data in a context-sensitive substitution. *)
+val eraseContext : t -> t
+
+(* Check whether a context-sensitive substitution satisfies a list of arithmetic constraints. *)
+val satisfiesConstraints : t -> (Ast.aexp * Ast.op * Ast.aexp) list -> bool
+
+(* Produce a "varAss" (variable assignments) from a context-sensitive substitution. *)
+val mkVarAss : t -> (string * string) list * (string * string) list * (string * string) list
diff --git a/ClassicGEC/ClassicGECDotNet/database.fs b/ClassicGEC/ClassicGECDotNet/database.fs
new file mode 100644
index 0000000..5946139
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/database.fs
@@ -0,0 +1,571 @@
+[]
+module Microsoft.Research.GEC.Database
+
+open Microsoft.Research.GEC
+open Microsoft.Research.FSBOLWrapper
+open FSBOL
+open FSBOL.Annotation
+open FSBOL.ComponentDefinition
+open FSBOL.ModuleDefinition
+open FSBOL.FunctionalComponent
+open FSBOL.Participation
+open FSBOL.Interaction
+open FSBOL.SBOLDocument
+open FSBOL.TopLevel
+open Parser
+open System.Diagnostics
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* ************************************************************************************************* *)
+
+(* The different kinds of property that part types can have. *)
+
+type device = string * string list
+
+
+type pcrProperty = CODES of string list * float
+type promProperty = POS of string list * float * float * float
+ | NEG of string list * float * float * float
+ | CON of float
+ | FRATE of Ast.aexp
+type rbsProperty = RATE of float
+
+(* An encoding of part types, along with their properties. *)
+type partType = PCR of pcrProperty
+ | PROM of promProperty list
+ | RBS of rbsProperty
+ | TER
+
+let fold_string_list (strList:string list) (folder:string) =
+ match strList.Length with
+ | 0 -> ""
+ | 1 -> strList.Head
+ | _ -> strList.Tail |> List.fold (fun f s -> (f + folder + s)) strList.Head
+
+let device_to_string (d:device) =
+ let (devname,deviceComps) = d
+ devname + "[" + (fold_string_list deviceComps ";") + "]"
+
+(* Produce a string representation of a part type. *)
+let string_of_partType (pt:partType) =
+ let string_of_promProperty = function
+ | POS(zs,q1,q2,q3) -> "pos(" + (Ast.complexString zs) + ", " + (Lib.display_float q1) + ", " + (Lib.display_float q2) + ", " + (Lib.display_float q3) + ")"
+ | NEG(zs,q1,q2,q3) -> "neg(" + (Ast.complexString zs) + ", " + (Lib.display_float q1) + ", " + (Lib.display_float q2) + ", " + (Lib.display_float q3) + ")"
+ | CON(q) -> "con(" + (Lib.display_float q) + ")"
+ | FRATE(a) -> "frate(" + (Ast.stringOfAExp a) + ")"
+ in
+ match pt with
+ | PCR(CODES(zs,q)) -> "pcr"
+ | PROM(pps) -> "prom<" + (Lib.string_of_list string_of_promProperty ", " pps) + ">"
+ | RBS(RATE(q)) -> "rbs"
+ | TER -> "ter"
+
+(* Compute FS(Q+t). *)
+let speciesInPartType (qt:partType) : string list list =
+ let getPromPropertySpeciesNames = function POS(xs,_,_,_) | NEG(xs,_,_,_) -> [xs] | _ -> [] in
+ let snames = match qt with
+ | PCR(CODES(xs,_)) -> [xs]
+ | PROM(pps) -> Lib.collect_union Ast.complexesEqual getPromPropertySpeciesNames pps
+ | RBS _ | TER -> []
+ in
+ Lib.remove_duplicates (=) snames
+
+
+
+(* ************************************************************************************************* *)
+
+(* A "database" consists of a "parts database" and a "reaction database".
+ A "parts database" is just a mapping of part identifiers (i.e. strings) to their part types.
+ A "reaction database" is just a list of reactions. *)
+type 'a entry = { value:'a; enabled:bool; comments:string }
+type t = { parts:partType entry Stringmap.t; devices: device list; reactions:Gecreaction.t entry list }
+
+let partTypeToSBOL (name:string) (p:partType entry)=
+
+ let role = match p.value with
+ | PROM _ -> Role.Promoter
+ | RBS _ -> Role.RBS
+ | PCR _ -> Role.CDS
+ | TER -> Role.Terminator
+
+ let renamedName = name.Replace("::","_")
+ let gecSO = "www.microsoft.com/gec#"
+ (*let RB = gecSO + "RB"
+ let RUB = gecSO + "RUB"
+ let RTB = gecSO + "RTB"
+ let RT = gecSO + "RT"
+ let R = gecSO + "R"
+ let RD = gecSO + "RD"
+ let P = gecSO + "P"*)
+
+ let RB = "RB"
+ let RUB = "RUB"
+ let RTB = "RTB"
+ let RT = "RT"
+ let R = "R"
+ let RD = "RD"
+ let P = "P"
+
+
+ let annotations:Annotation list =
+ match p.value with
+ | PROM(a) ->
+ let propAnnotations =
+ a |> List.map(fun promprop ->
+ match promprop with
+ | POS(p,rb,rub,rtb) ->
+ let compositeName = p |> List.reduce(fun a b -> a + "::" + b)
+ [Helper.create_string_annotation (Name(P)) compositeName ;
+ Helper.create_double_annotation (Name(RB)) rb;
+ Helper.create_double_annotation (Name(RUB)) rub;
+ Helper.create_double_annotation (Name(RTB)) rtb]
+ | NEG(p,rb,rub,rtb) ->
+ let compositeName = p |> List.reduce(fun a b -> a + "::" + b)
+ [Helper.create_string_annotation (Name(P)) compositeName;
+ Helper.create_double_annotation (Name(RB)) rb;
+ Helper.create_double_annotation (Name(RUB)) rub;
+ Helper.create_double_annotation (Name(RTB)) rtb]
+ | CON(rt) ->
+ [Helper.create_double_annotation (Name(RT)) rt]
+ | _ -> [])
+ [0..(propAnnotations.Length-1)]
+ |> List.map (fun i ->
+ let na = NestedAnnotation(Name("PromoterProperty" + i.ToString() + "Annotations"),gecSO + "PromoterProperties",propAnnotations.Item(i))
+ Annotation(Name("PromoterProperty" + i.ToString()),AnnotationValue.NestedAnnotation(na)))
+ | RBS(RATE(r)) -> [Helper.create_double_annotation (Name(R)) r]
+ | PCR(CODES(codes,rd)) ->
+ let compositeName = codes |> List.reduce(fun a b -> a + "::" + b)
+ [Helper.create_string_annotation (Name(P)) compositeName;
+ Helper.create_double_annotation (Name(RD)) rd]
+ | TER -> []
+
+ let version = "1"
+ let persistentId = "http://www.microsoft.com/gec/db/" + renamedName + "/"
+ let uri = persistentId + renamedName + "/" + version + "/"
+ let c = new ComponentDefinition(uri,Some(renamedName),Some(renamedName),Some(version),Some(persistentId),[],[ComponentDefinitionType.DNA],[role],[],[],[],[])
+ c.annotations <- annotations
+ c
+
+
+let createProteinCDs (tableList:((string*(partType entry))list)) =
+ let partTypes = tableList
+ |> List.map (fun (x,y) -> y.value)
+ let promProts = partTypes
+ |> List.choose ( fun x ->
+ match x with
+ | PROM(props) -> Some props
+ | _ -> None)
+ |> List.map (fun props ->
+ props |> List.map(fun prop ->
+ match prop with
+ | POS(p,rb,rub,rtb) -> Some(p |> List.reduce(fun a b -> a + "::" + b))
+ | NEG(p,rb,rub,rtb) -> Some(p |> List.reduce(fun a b -> a + "::" + b))
+ | _ -> None
+ )
+ ) |> List.concat
+ |> List.filter (fun x->
+ match x with
+ | Some(_) -> true
+ | None -> false
+ ) |> List.map (fun x -> x.Value)
+
+ let cdsProts = partTypes
+ |> List.choose (fun x ->
+ match x with
+ | PCR(CODES(prots,r)) -> Some (prots,r)
+ | _ -> None
+ ) |> List.map (fun (prots,r) ->
+ prots |> List.reduce(fun a b -> a + "::" + b)
+ )
+
+ let prots = (promProts@cdsProts) |> Set.ofList |> List.ofSeq
+ prots |> List.map(fun protName ->
+ let renamedProt = protName.Replace("::","_")
+ let version = "1"
+ let persistentId = "http://www.microsoft.com/gec/db/" + renamedProt + "/"
+ let uri = persistentId + renamedProt + "/" + version + "/"
+ new ComponentDefinition(uri,Some(renamedProt),Some(renamedProt),Some(version),Some(persistentId),[],[ComponentDefinitionType.Protein],[],[],[],[],[]))
+
+
+let createModuleDefinitions (cds:ComponentDefinition list) (tableList:((string*(partType entry))list))=
+ let urlPrefix = "http://www.microsoft.com/gec/db/"
+ let version = "1"
+
+
+ let findCDwithURI (uri:string) =
+ match cds |> List.tryFind (fun cd -> cd.uri = uri) with
+ | Some (x) -> x
+ | None -> failwith "Error. This CD should have been created in an earlier step"
+ let findCDwithDisplayID (display:string) =
+ let displayIdsMatch (cdDisplayId:string option) (display:string) =
+ match cdDisplayId with
+ | Some(d) -> (d=display)
+ | None -> failwith "Error. This CD should have a displayId created in an earlier step"
+ match cds |> List.tryFind (fun cd -> displayIdsMatch (cd.displayId) display) with
+ | Some(x) -> x
+ | None -> failwith "Error. This CD should have been created in an earlier step"
+ let pcrs = tableList
+ |> List.choose (fun (name,x) ->
+ match x.value with
+ | PCR(CODES(prots,r)) -> Some(name,prots,r)
+ | _ -> None
+ )
+
+ let proms = tableList
+ |> List.choose (fun (name,x) ->
+ match x.value with
+ | PROM(props) -> Some(name,props)
+ | _ -> None
+ )
+
+ let mds =
+ pcrs |> List.map (fun (pcrName,prots,r) ->
+ let compositeName = prots |> List.reduce(fun a b -> a + "_" + b)
+ let mdsinProms =
+ proms |>
+ List.map(fun (promName,props) ->
+ let mdsInProps =
+ props |> List.map(fun prop ->
+ match prop with
+ | POS(regList,_,_,_) ->
+ let compositeReg = regList |> List.reduce(fun a b -> a + "_" + b)
+ if compositeReg = compositeName then
+ let pcr_cd = findCDwithDisplayID pcrName
+ let prot_cd = findCDwithDisplayID compositeReg
+ let prom_cd = findCDwithDisplayID promName
+
+ let compoundNameProd = pcrName + "_" + compositeName
+ let mdProd_name = compoundNameProd + "_production_md"
+ let mdProd_perId = urlPrefix + "/" + mdProd_name + "/"
+ let mdProd_uri = mdProd_perId + version + "/"
+
+ let fc_pcr_name = pcrName + "_FC"
+ let fc_pcr_perId = urlPrefix + fc_pcr_name + "/"
+ let fc_pcr_uri = fc_pcr_perId + version + "/"
+
+ let fc_prot_name = compositeName + "_protein_FC"
+ let fc_prot_perId = urlPrefix + fc_prot_name + "/"
+ let fc_prot_uri = fc_pcr_perId + version + "/"
+
+ let fc_pcr = new FunctionalComponent(fc_pcr_uri,Some(fc_pcr_name),Some(fc_pcr_name),Some(version),Some(fc_pcr_perId),pcr_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+ let fc_prot = new FunctionalComponent(fc_prot_uri,Some(fc_prot_name),Some(fc_prot_name),Some(version),Some(fc_prot_perId),prot_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+
+ let part_pcr_name = pcrName+"_participation"
+ let part_pcr_perId = urlPrefix + part_pcr_name + "/"
+ let part_pcr_uri = part_pcr_perId + version + "/"
+
+ let part_prot_name = compositeName+"prot_participation"
+ let part_prot_perId = urlPrefix + part_prot_name + "/"
+ let part_prot_uri = part_prot_perId + version + "/"
+
+ let part_pcr = new Participation(part_pcr_uri,Some(part_pcr_name),Some(part_pcr_name),Some(version),Some(part_pcr_perId),[ParticipationRole.Template],fc_pcr)
+ let part_prot = new Participation(part_prot_uri, Some(part_prot_name),Some(part_prot_name),Some(version),Some(part_prot_perId),[ParticipationRole.Product],fc_prot)
+
+ let interactionProd_name = compoundNameProd + "_production_interaction"
+ let interactionProd_perId = mdProd_perId + "/" + interactionProd_name + "/"
+ let interactionProd_uri = interactionProd_perId + version + "/"
+
+ let interactionProd = new Interaction(interactionProd_uri,Some(interactionProd_name),Some(interactionProd_name),Some(version),Some(interactionProd_perId),[InteractionType.GeneticProduction],[part_pcr;part_prot])
+
+
+ let mdProd = new ModuleDefinition(mdProd_uri,Some(mdProd_name),Some(mdProd_name),Some(version),Some(mdProd_perId),[],[],[],[interactionProd],[fc_pcr;fc_prot],[])
+
+ let compoundNameStim = compositeName + "_" + promName
+ let mdStim_name = compoundNameStim + "_stimulation_md"
+ let mdStim_perId = urlPrefix + "/" + mdStim_name + "/"
+ let mdStim_uri = mdStim_perId + "/" + version + "/"
+
+ let fc_complex_name = compositeName + "_complex_FC"
+ let fc_complex_perId = urlPrefix + fc_complex_name + "/"
+ let fc_complex_uri = fc_pcr_perId + version + "/"
+
+ let fc_prom_name = promName + "_FC"
+ let fc_prom_perId = urlPrefix + fc_prom_name + "/"
+ let fc_prom_uri = fc_prom_perId + version + "/"
+
+ let fc_complex = new FunctionalComponent(fc_complex_uri,Some(fc_complex_name),Some(fc_complex_name),Some(version),Some(fc_complex_perId),prot_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+ let fc_prom = new FunctionalComponent(fc_prom_uri,Some(fc_prom_name),Some(fc_prom_name),Some(version),Some(fc_prom_perId),prom_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+
+ let part_complex_name = compositeName+"complex_participation"
+ let part_complex_perId = urlPrefix + part_complex_name + "/"
+ let part_complex_uri = part_complex_perId + version + "/"
+
+ let part_prom_name = pcrName+"_participation"
+ let part_prom_perId = urlPrefix + part_prom_name + "/"
+ let part_prom_uri = part_prom_perId + version + "/"
+
+ let part_complex = new Participation(part_complex_uri,Some(part_complex_name),Some(part_complex_name),Some(version),Some(part_complex_perId),[ParticipationRole.Stimulator],fc_complex)
+ let part_prom = new Participation(part_prom_uri,Some(part_prom_name),Some(part_prom_name),Some(version),Some(part_prom_perId),[ParticipationRole.Stimulated],fc_prom)
+
+ let interactionStim_name = compoundNameStim + "_stimulation_interaction"
+ let interactionStim_perId = mdStim_perId + "/" + interactionStim_name + "/"
+ let interactionStim_uri = interactionStim_perId + "/" + version + "/"
+
+ let interactionStim = new Interaction(interactionStim_uri,Some(interactionStim_name),Some(interactionStim_name),Some(version),Some(interactionStim_perId),[InteractionType.Stimulation],[part_complex;part_prom])
+
+ let mdStim = new ModuleDefinition(mdStim_uri,Some(mdStim_name),Some(mdStim_name),Some(version),Some(mdStim_perId),[],[],[],[interactionStim],[fc_complex;fc_prom],[])
+
+ Some([mdProd;mdStim])
+ else
+ None
+ | NEG(regList,_,_,_) ->
+ let compositeReg = regList |> List.reduce(fun a b -> a + "::" + b)
+ if compositeReg = compositeName then
+ let pcr_cd = findCDwithDisplayID pcrName
+ let prot_cd = findCDwithDisplayID compositeReg
+ let prom_cd = findCDwithDisplayID promName
+
+ let compoundNameProd = pcrName + "_" + compositeName
+ let mdProd_name = compoundNameProd + "_production_md"
+ let mdProd_perId = urlPrefix + "/" + mdProd_name + "/"
+ let mdProd_uri = mdProd_perId + version + "/"
+
+ let fc_pcr_name = pcrName + "_FC"
+ let fc_pcr_perId = urlPrefix + fc_pcr_name + "/"
+ let fc_pcr_uri = fc_pcr_perId + version + "/"
+
+ let fc_prot_name = compositeName + "_protein_FC"
+ let fc_prot_perId = urlPrefix + fc_prot_name + "/"
+ let fc_prot_uri = fc_pcr_perId + version + "/"
+
+ let fc_pcr = new FunctionalComponent(fc_pcr_uri,Some(fc_pcr_name),Some(fc_pcr_name),Some(version),Some(fc_pcr_perId),pcr_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+ let fc_prot = new FunctionalComponent(fc_prot_uri,Some(fc_prot_name),Some(fc_prot_name),Some(version),Some(fc_prot_perId),prot_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+
+ let part_pcr_name = pcrName+"_participation"
+ let part_pcr_perId = urlPrefix + part_pcr_name + "/"
+ let part_pcr_uri = part_pcr_perId + version + "/"
+
+ let part_prot_name = compositeName+"prot_participation"
+ let part_prot_perId = urlPrefix + part_prot_name + "/"
+ let part_prot_uri = part_prot_perId + version + "/"
+
+ let part_pcr = new Participation(part_pcr_uri,Some(part_pcr_name),Some(part_pcr_name),Some(version),Some(part_pcr_perId),[ParticipationRole.Template],fc_pcr)
+ let part_prot = new Participation(part_prot_uri, Some(part_prot_name),Some(part_prot_name),Some(version),Some(part_prot_perId),[ParticipationRole.Product],fc_prot)
+
+ let interactionProd_name = compoundNameProd + "_production_interaction"
+ let interactionProd_perId = mdProd_perId + "/" + interactionProd_name + "/"
+ let interactionProd_uri = interactionProd_perId + version + "/"
+
+ let interactionProd = new Interaction(interactionProd_uri,Some(interactionProd_name),Some(interactionProd_name),Some(version),Some(interactionProd_perId),[InteractionType.GeneticProduction],[part_pcr;part_prot])
+
+
+ let mdProd = new ModuleDefinition(mdProd_uri,Some(mdProd_name),Some(mdProd_name),Some(version),Some(mdProd_perId),[],[],[],[interactionProd],[fc_pcr;fc_prot],[])
+
+
+ let compoundNameInh = compositeName + "_" + promName
+ let mdInh_name = compoundNameInh + "_inhibition_md"
+ let mdInh_perId = urlPrefix + "/" + mdInh_name + "/"
+ let mdInh_uri = mdInh_perId + "/" + version + "/"
+
+ let fc_complex_name = compositeName + "_complex_FC"
+ let fc_complex_perId = urlPrefix + fc_complex_name + "/"
+ let fc_complex_uri = fc_pcr_perId + version + "/"
+
+ let fc_prom_name = promName + "_FC"
+ let fc_prom_perId = urlPrefix + fc_prom_name + "/"
+ let fc_prom_uri = fc_prom_perId + version + "/"
+
+ let fc_complex = new FunctionalComponent(fc_complex_uri,Some(fc_complex_name),Some(fc_complex_name),Some(version),Some(fc_complex_perId),prot_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+ let fc_prom = new FunctionalComponent(fc_prom_uri,Some(fc_prom_name),Some(fc_prom_name),Some(version),Some(fc_prom_perId),prom_cd.uri,ComponentInstance.Access.Private,[],Direction.InOut)
+
+ let part_complex_name = compositeName+"complex_participation"
+ let part_complex_perId = urlPrefix + part_complex_name + "/"
+ let part_complex_uri = part_complex_perId + version + "/"
+
+ let part_prom_name = pcrName+"_participation"
+ let part_prom_perId = urlPrefix + part_prom_name + "/"
+ let part_prom_uri = part_prom_perId + version + "/"
+
+ let part_complex = new Participation(part_complex_uri,Some(part_complex_name),Some(part_complex_name),Some(version),Some(part_complex_perId),[ParticipationRole.Inhibitor],fc_complex)
+ let part_prom = new Participation(part_prom_uri,Some(part_prom_name),Some(part_prom_name),Some(version),Some(part_prom_perId),[ParticipationRole.Inhibited],fc_prom)
+
+ let interactionInh_name = compoundNameInh + "_inhibition_interaction"
+ let interactionInh_perId = mdInh_perId + "/" + interactionInh_name + "/"
+ let interactionInh_uri = interactionInh_perId + "/" + version + "/"
+
+ let interactionInh = new Interaction(interactionInh_uri,Some(interactionInh_name),Some(interactionInh_name),Some(version),Some(interactionInh_perId),[InteractionType.Inhibition],[part_complex;part_prom])
+
+ let mdInh = new ModuleDefinition(mdInh_uri,Some(mdInh_name),Some(mdInh_name),Some(version),Some(mdInh_perId),[],[],[],[interactionInh],[fc_complex;fc_prom],[])
+
+ Some([mdProd;mdInh])
+ else
+ None
+ | _ -> None)
+ |> List.filter (fun optionX ->
+ match optionX with
+ | Some (_) -> true
+ | None -> false)
+ |> List.map( fun x -> x.Value)
+ if mdsInProps.IsEmpty then
+ []
+ else
+ mdsInProps |> List.reduce (fun a b -> a@b)
+ )
+ if mdsinProms.IsEmpty then
+ []
+ else
+ mdsinProms |>List.reduce (fun a b -> a@b)
+ )
+ if mds.IsEmpty then
+ []
+ else
+ mds |>List.reduce (fun a b -> a@b)
+
+let convertTableToSBOLDocument (table:t) =
+ let cds = table.parts |> List.ofSeq |> List.map (fun (x) -> (x.Key,x.Value)) |> List.map (fun (name,part) -> partTypeToSBOL name part)
+
+ let protCds = createProteinCDs (table.parts |> List.ofSeq |> List.map (fun x -> (x.Key,x.Value)))
+ let allCds = (cds@protCds)
+ let mds = createModuleDefinitions allCds (table.parts |> List.ofSeq |> List.map (fun x -> (x.Key,x.Value)))
+ let collections =
+ (allCds |> List.map (fun x -> x :> TopLevel))
+ @ (mds|> List.map (fun x -> x :> TopLevel))
+ SBOLDocument(collections)
+
+(* The "empty" database. *)
+let empty = { parts=Stringmap.empty; devices = []; reactions=[] }
+
+(* Produce a string representation of a database entry. *)
+let string_of_entry (display:'a -> string) (entry:'a entry) : string =
+ let enabledStr = if entry.enabled then "[*] " else "[ ] " in
+ let valueStr = display entry.value in
+ let commentsStr = if entry.comments = "" then "" else " (Comments: \"" + entry.comments + "\")" in
+ enabledStr + valueStr + commentsStr
+
+(* Produce a string representation of a database. *)
+let display (db:t) : string =
+ let partsString = Stringmap.fold (fun str x entry -> str + Lib.newline + x + " : " + (string_of_entry string_of_partType entry)) "" db.parts in
+ let reactionsString = Lib.fold_left (fun str entry -> str + Lib.newline + (string_of_entry Gecreaction.display entry)) "" db.reactions in
+ "PARTS:" + partsString + Lib.newline + Lib.newline +
+ "REACTIONS:" + reactionsString + Lib.newline
+
+(* Find out the part type for an identifer (if it exists). *)
+let findPart (db:t) (id:string) : partType option =
+ match Stringmap.tryFind id db.parts with
+ | Some entry -> Some entry.value
+ | None -> None
+
+(* ************************************************************************************************* *)
+(* Functions for adding entries to the database. *)
+
+(* Convert an abstractComplex into a string list, assuming it is "simple" (i.e. just strings...) *)
+let convertSimpleComplex (vs:Ast.abstractComplex) : string list =
+ let convertSimpleValue (v:Ast.value) : string =
+ match v with
+ | Ast.IdVal x -> x
+ | _ -> failwith ("Only strings are allowed in species names in the database " + Lib.paren("found " + Ast.stringOfValue v))
+ in
+ List.map convertSimpleValue vs
+
+(* Get a float from an Ast.value. *)
+let getValueFloat (v:Ast.value) =
+ match v with
+ | Ast.FloatVal f -> f
+ | _ -> failwith ("Only float rates are allowed in the database " + Lib.paren("found " + Ast.stringOfValue v))
+
+
+type parser = Parser.t
+type partParser = Parser.t
+
+
+
+let createEntry (id:string, part:partType) =
+ let entry:partType entry = {value = part;enabled = true;comments = ""}
+ (id,entry)
+
+
+let createTable (partMapList:(string*partType)list) (devicelist:device list)=
+ let tableMap = partMapList |> List.map createEntry
+ {parts = Stringmap.of_list(tableMap); reactions=[]; devices = devicelist}
+
+
+
+
+let TAB = Parser.kw "\t"
+let COMMA = Parser.kw ","
+let SEMICOLON = Parser.kw ";"
+
+let delimiter = COMMA //Primary delimiter
+let sDelimiter = SEMICOLON //Secondary Delimiter used to separate elements or values within a cell
+
+let NEWLINE = Parser.newline
+
+let lookaheadLinebreak = Parser.pTry (Parser.linebreak >>. Parser.failParser "" <|> Parser.satisfy Parser.isWhiteSpace >>. preturn ())
+let spacesnlb :t = fun st ->
+ match many (commentLine <|> commentMultiline () <|> lookaheadLinebreak) <| st with
+ | OkEmpty (_, st') -> OkEmpty ("", st')
+ | OkConsumed (_, st') -> OkEmpty ("", st')
+ | FailEmpty _ -> OkEmpty ("", st)
+ | FailConsumed (e, p) -> FailConsumed (e, p)
+let kwnlb s = pstring s .>> spacesnlb
+let bracketnlb l r = Parser.between (Parser.kw l) (Parser.spaces >>. kwnlb r)
+
+let bracketNoSpace l r = Parser.between (Parser.pstring l) (Parser.spaces >>. Parser.pstring r)
+let sqbracketNoSpace a = bracketnlb "[" "]" a
+let parenNoSpace a = bracketnlb "(" ")" a
+//let nameGEC = (Parser.many1Satisfy Parser.isLetter .>>. Parser.manySatisfy (fun c -> Parser.isLetter c || Parser.isDigit c || c = '_'|| c = '-' || c = '\'') |>> fun (a,b) -> a + b) > "an identifier"
+
+let parsePos = Parser.kw "pos" >>. parenNoSpace(GecSpecies.parse_species .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat) |>> fun(((regBy,rb),rub),rtb) -> POS(regBy,rb,rub,rtb)
+let parseNeg = Parser.kw "neg" >>. parenNoSpace(GecSpecies.parse_species .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat) |>> fun(((regBy,rb),rub),rtb) -> NEG(regBy,rb,rub,rtb)
+let parseCon = Parser.kw "con" >>. parenNoSpace (Parser.pfloat) |>> fun (rt:float) -> CON(rt)
+
+let parsePromProperties = Parser.choice[
+ parsePos
+ parseNeg
+ parseCon
+ ]
+
+let parseCodes = Parser.kw "codes" >>. parenNoSpace (GecSpecies.parse_species .>> sDelimiter .>>. Parser.pfloat) |>> fun ((codes:string list), rd:float) -> CODES(codes,rd)
+(*let parseConstitutiveProm = parseCon |>> fun (con:promProperty) -> PROM([con])
+let parseRegulatedProm = (Parser.kw "pos" <|> Parser.kw "neg") .>>. parenNoSpace (nameGEC .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat .>> sDelimiter .>>. Parser.pfloat) .>> sDelimiter .>>. parseCon |>> fun ((regType:string,((((regBy:string list),rb:float),rub:float),rtb:float)),conProp:promProperty) ->
+ match regType with
+ | "pos" -> PROM([POS(regBy,rb,rub,rtb);conProp])
+ | "neg" -> PROM([NEG(regBy,rb,rub,rtb);conProp])
+ | _ -> failwith ""*)
+
+let parseRate = Parser.kw "rate" >>. parenNoSpace (Parser.pfloat) |>> fun(r:float) -> RATE(r)
+
+
+let pdevicedelim = Parser.kw "|" <|> Parser.kw ";"
+let (parse_device:t) = Parser.name .>> Parser.spaces .>> Parser.kw "=" .>>. Parser.sqBrackets( Parser.sepBy (Parser.name .>> Parser.spaces) pdevicedelim)
+let deviceParser = Parser.kw "devices" >>.
+ (Parser.sqBrackets (Parser.many parse_device)) .>> Parser.spaces
+
+
+
+type dnacomponent =
+ | Part of string * partType
+ | Device of device
+
+let parse_deviceComponents = Parser.kw "components" >>. sqbracketNoSpace (Parser.sepBy (Parser.name .>> Parser.spaces) pdevicedelim)
+
+
+let partParser =
+ Parser.name .>> delimiter >>= fun n ->
+ Parser.choice [
+ Parser.kw "prom" >>. delimiter >>. (Parser.sepBy parsePromProperties sDelimiter) |>> fun(props) -> Part(n,PROM(props))
+ Parser.kw "rbs" >>. delimiter >>. parseRate |>> fun(rate) -> Part(n,RBS(rate))
+ Parser.kw "pcr" >>. delimiter >>. parseCodes |>> fun(codes) -> Part(n,PCR(codes))
+ pstring "ter" |>> fun (_) -> Part(n, TER)
+ Parser.kw "device" >>. delimiter >>. parse_deviceComponents |>> fun (components) -> Device(n,components)
+ ]
+
+
+let fileParser = (Parser.sepBy partParser NEWLINE)
+
+
+let parse = fileParser .>> Parser.eof |>> fun(components) ->
+ let partComponents = components |> List.choose
+ (fun x ->
+ match x with
+ | Part(x,y) -> Some(x,y)
+ | _ -> None)
+ let deviceList = components |> List.choose
+ (fun x ->
+ match x with
+ | Device(x) -> Some(x)
+ | _ -> None)
+
+ createTable partComponents deviceList
diff --git a/ClassicGEC/ClassicGECDotNet/database.fsi b/ClassicGEC/ClassicGECDotNet/database.fsi
new file mode 100644
index 0000000..cc4d6cc
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/database.fsi
@@ -0,0 +1,67 @@
+module Microsoft.Research.GEC.Database
+
+open Microsoft.Research.GEC
+open FSBOL.ComponentDefinition
+open FSBOL.ModuleDefinition
+open FSBOL.SBOLDocument
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+open Parser
+
+
+(* ************************************************************************************************* *)
+
+(* Devices. *)
+type device = string * string list
+
+(* The different kinds of property that part types can have. *)
+type pcrProperty = CODES of string list * float
+type promProperty = POS of string list * float * float * float
+ | NEG of string list * float * float * float
+ | CON of float
+ | FRATE of Ast.aexp
+type rbsProperty = RATE of float
+
+
+(* An encoding of part types, along with their properties. *)
+type partType = PCR of pcrProperty
+ | PROM of promProperty list
+ | RBS of rbsProperty
+ | TER
+
+(* Compute FS(Q^t). *)
+val speciesInPartType : partType -> string list list
+
+(* ************************************************************************************************* *)
+
+(* A "database" consists of a "parts database" and a "reaction database".
+ A "parts database" is just a mapping of part identifiers (i.e. strings) to their part types.
+ A "reaction database" is just a list of reactions. *)
+type 'a entry = { value:'a; enabled:bool; comments:string }
+type t = { parts:partType entry Stringmap.t; devices: device list; reactions:Gecreaction.t entry list }
+
+val partTypeToSBOL: string -> (partType entry) -> ComponentDefinition
+val createModuleDefinitions: (ComponentDefinition list) -> ((string*(partType entry))list) -> (ModuleDefinition list)
+val convertTableToSBOLDocument: t -> SBOLDocument
+val createProteinCDs: (string * (partType entry)) list -> ComponentDefinition list
+(* The "empty" database. *)
+val empty : t
+
+(* Produce a string representation of a database. *)
+val display : t -> string
+
+(* Add a part to the database (part id must be unique). *)
+//val addPart : t -> bool -> string -> string -> string -> string -> t
+
+(* Add a reaction to the database. *)
+//val addReaction : t -> bool -> string -> string -> t
+
+type parser = Parser.t
+val parse : parser
+
+type dnacomponent =
+ | Part of string * partType
+ | Device of device
+
+val partParser: Parser.t
+
diff --git a/ClassicGEC/ClassicGECDotNet/directivesParser.fs b/ClassicGEC/ClassicGECDotNet/directivesParser.fs
new file mode 100644
index 0000000..6fe8ca7
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/directivesParser.fs
@@ -0,0 +1,580 @@
+[]
+module Microsoft.Research.GEC.DirectivesParser
+
+open Microsoft.Research.CRNEngine
+open Parser
+
+(**********************************************************************)
+(**********************************************************************)
+(************* Legacy CRN parser **************************************)
+(**********************************************************************)
+(**********************************************************************)
+(* The code to parse directives in this section is duplicated from
+ SLConversion in Classic DSD. The original Lex grammar for the
+ Silver Light version of CRN and DSD were also duplicated
+ (ModellingEngineDotNet had its own parser.mly file, which was copied
+ and modified over in SLDNADotNet). The grammar for CRN directives
+ and species should be the same, but since there might
+ be subtle differences in the two copies of the mly files,
+ the conversion tool is also duplicated here. *)
+(**********************************************************************)
+
+// utilities
+let spaces = Parser.spaces
+let choice = Parser.choice
+let kw = Parser.kw
+let preturn = Parser.preturn
+let spFloat = Parser.pfloat .>> spaces
+let spInt = Parser.pint32 .>> spaces
+let spBool = choice [ kw "true" >>. preturn true
+ ; kw "false" >>. preturn false] .>> spaces
+let spName = Parser.name .>> spaces
+let paren = Parser.paren
+let braces = Parser.braces
+let sqBrackets = Parser.sqBrackets
+let sepBy = Parser.sepBy
+let sepBy1 = Parser.sepBy1
+
+let fpMsg = "Floating point conversion not supported"
+
+type crnModuleDefinition = (string * string list)
+type crnInstructions = ((crnModuleDefinition * Instruction list) list) * Instruction list
+
+type settings = {settings:Crn_settings; crn: crnInstructions option; overrideCrn: bool}
+
+type oldSimMode = JIT
+ | SSA
+ | OSLO of bool (* is stiff? *)
+ | SPACIAL_PERIODIC of int32
+ | SUNDIALS of bool (* is stiff? *)
+ | CME_OSLO_OR_SUNDIALS of bool (* is stiff? *) (* the parser is ambiguous on "cme" *)
+ | LNA_OSLO of bool (* is stiff? *)
+
+type SpParam = Burnin of int32
+ | SpSamples of int32
+ | Thin of int32
+ | SeparateNoise of bool
+ | NoiseModel of int
+ | Prune of bool
+
+type CoreElem = CoreW of float
+ | CoreI of float
+ | CoreO of float
+
+type PointElem = PointX of float
+ | PointY of float
+ | PointW of float
+ | PointV of float
+
+type ParSpace = ParReal | ParLog
+type ParVar = ParFixed | ParRandomized | ParInitVal
+type ParItem = ParAssign of string * float * float * float
+ | ParItem of string * float * float * float * ParSpace * ParVar
+
+type SweepVar = SweepVar of string list * Value list list
+
+type SweepItem = NamedSweep of string * SweepVar list
+ | UnnamedSweep of SweepVar
+
+type KMode = KContextual | KStochastic | KDeterministic
+
+type VerMode = Encoding of int32
+ | Abstraction of int32
+ | Enumeration of int32
+ | PopBound of int32
+ | DummyRxn of bool
+ | EnfInitial of bool
+
+type oldDirective = Samples of float option * float option * int32 option // start, end, points
+ | DurationPoints of float option * float option * int32 option // start, end, points
+ | Scale of float
+ | Plot of Expression.t list
+ | Simulation of oldSimMode
+ | RelTolerance of float
+ | Tolerance of float // maps to abstolerance in deterministic
+ | Seed of int32
+ // | SpecMax of Species.t * int32
+ | OldTime of Time
+ | Concentration of Concentration
+ | Dt of float
+ | XMax of float
+ | Nx of int32
+ | Theta of float
+ | Params of ParItem list
+ | Sweeps of SweepItem list
+ | FitRun of SpParam list
+ | Kinectics of KMode
+ | Crn of crnInstructions * bool
+// | Verification of VerMode
+// | StabilityCorrection of float
+// | CoaxialDAngle of float
+// | DoubleCoaxialDAngle of float
+// | Temperature of float
+// | TerminalDAngle of float
+
+// Tokens
+let SAMPLE = kw "sample"
+let ALL = kw "all"
+let PLOT = kw "plot"
+let POINTS = kw "points"
+let DURATION = kw "duration"
+let SCALE = kw "scale"
+let SEED = kw "seed"
+let SIMULATION = kw "simulation"
+let DETERMINISTICSTIFF = kw "deterministicstiff"
+let RELTOLERANCE = kw "reltolerance"
+let TOLERANCE = kw "tolerance" <|> kw "abstolerance"
+let EVENT = kw "event"
+let SPECMAX = kw "specmax"
+let TIME = kw "time"
+let CONCENTRATION = kw "concentration"
+let DT = kw "dt"
+let XMAX = kw "xmax"
+let NX = kw "nx"
+let THETA = kw "theta"
+let COAXIALDANGLE = kw "coaxialDangle"
+let DOUBLECOAXIALDANGLE = kw "doubleCoaxialDangle"
+let COAXIALCORRECTION = kw "coaxialCorrection"
+let TEMPERATURE = kw "temperature"
+let TERMINALDANGLE = kw "terminalDangle"
+let SPATIALIC = kw "spatialic"
+let SPATIALBC = kw "spatialbc"
+let SPATIALPLOT = kw "spatialplot"
+//let COMPILATION = kw "compilation"
+let DECLARE = kw "declare"
+let DEFAULTDIFFUSION = kw "defaultdiffusion"
+let DIFFUSION = kw "diffusion"
+let LEAKS = kw "leaks"
+let PINLEAK = kw "pinleak"
+let PINLEAKS = kw "pinleaks"
+let LENGTHS = kw "lengths"
+let MIGRATE = kw "migrate"
+let LOCALCONCENTRATIONS = kw "localconcentrations"
+let POLYMERS = kw "polymers"
+let SEQUENCERATES = kw "sequenceRates"
+let STABILITYCORRECTION = kw "stabilityCorrection"
+let TAU = kw "tau"
+let TOEHOLDS = kw "toeholds"
+let UNPRODUCTIVE = kw "unproductive"
+let VERIFICATION = kw "verification"
+let FIT = kw "fit"
+let FITRUN = kw "fit_run"
+let KINETICS = kw "kinetics"
+let PARAMETERS = kw "parameters"
+let PLOTWINDOW = kw "plotwindow"
+let PREDICATES = kw "predicates"
+let SWEEP = kw "sweep"
+let CRN = kw "crn"
+let OVERRIDE = kw "override"
+
+let COMMA = kw ","
+let SEMI = kw ";"
+let AT = kw "@"
+let UNDERSCORE = kw "_"
+let SUM = kw "sum"
+let SUB = kw "sub"
+let DIFF = kw "diff"
+let PROD = kw "prod"
+let DIV = kw "div"
+let EQUAL = kw "="
+let DLBRACKET = kw "[["
+let DRBRACKET = kw "]]"
+let BAR = kw "|"
+
+(* each function below parses a specific "directive" string *)
+// samples directive
+let dirSamples =
+ SAMPLE >>. Expression.parse spFloat >>= fun x ->
+ choice [ COMMA >>. Expression.parse spFloat >>= fun y ->
+ choice [ ALL >>. preturn (Some (Expression.eval id x), Some (Expression.eval id y), Some 0)
+ ; spInt >>= fun z -> preturn (Some (Expression.eval id x), Some (Expression.eval id y), Some z)
+ ; preturn (Some (Expression.eval id x), Some (Expression.eval id y), None) ]
+ ; ALL >>. preturn (None, Some (Expression.eval id x), Some 0)
+ ; spInt >>= fun y -> preturn (None, Some (Expression.eval id x), Some y)
+ ; preturn (None, Some (Expression.eval id x), None) ]
+ >>= (Samples >> preturn) // wraps the result inside Samples
+
+// duration directive
+let dirDuration =
+ DURATION >>. spFloat >>= fun x ->
+ choice [ COMMA >>. spFloat >>= fun y ->
+ choice [ POINTS >>.
+ choice [ ALL >>. preturn (Some x, Some y, Some 0)
+ ; spInt >>= fun z -> preturn (Some x, Some y, Some z) ]
+ ; preturn (Some x, Some y, None) ]
+ ; POINTS >>. choice [ ALL >>. preturn (None, Some x, Some 0)
+ ; spInt >>= fun y -> preturn (None, Some x, Some y) ]
+ ; preturn (None, Some x, None) ]
+ >>= (DurationPoints >> preturn )
+
+// seed directive
+let dirSeed = SEED >>. spInt >>= (Seed >> preturn)
+
+// old molecule parser
+ // TODO: double check that "--(cogs)" | "--(+ cogs)" | "--(cogs+)" is not used anymore
+
+// plots
+// TODO check empty plot "()" is parsed correctly with many or sepBy, double check that many1 or sepBy1 is not misused
+let pPlot pSpecies = Expression.parse pSpecies
+
+
+// plots directive
+let pPlots pSpecies sp = Parser.sepBy1 (pPlot pSpecies) SEMI sp
+let dirPlot pSpecies = PLOT >>. pPlots pSpecies >>= (Plot >> preturn)
+
+
+let curry f (a, b) = f a b
+
+//let dirSpecMax = SPECMAX >>. DSDParser.speciesParser .>>. spInt >>= (SpecMax >> preturn)
+let dirTime =
+ let s = Time.Seconds 1.0
+ let m = Time.Seconds 6.0
+ let h = Time.Seconds 3.6
+ let d = Time.Seconds 8.64
+ let ret = OldTime >> preturn
+ TIME >>. choice [ kw "seconds" >>. ret s
+ ; kw "s" >>. ret s
+ ; kw "minutes" >>. ret m
+ ; kw "m" >>. ret m
+ ; kw "hours" >>. ret h
+ ; kw "h" >>. ret h
+ ; kw "days" >>. ret d
+ ; kw "d" >>. ret d ]
+
+let dirConcentration =
+ let m = Concentration.Molar 0
+ let mM = Concentration.Molar -3
+ let uM = Concentration.Molar -6
+ let nM = Concentration.Molar -9
+ let pM = Concentration.Molar -12
+ let fM = Concentration.Molar -15
+ let aM = Concentration.Molar -18
+ let zM = Concentration.Molar -21
+ let yM = Concentration.Molar -24
+ let ret = Concentration >> preturn
+ CONCENTRATION >>. choice [ kw "molar" >>. ret m
+ ; kw "M" >>. ret m
+ ; kw "milimolar" >>. ret mM
+ ; kw "mM" >>. ret mM
+ ; kw "millimolar" >>. ret mM
+ ; kw "micromolar" >>. ret uM
+ ; kw "uM" >>. ret uM
+ ; kw "nanomolar" >>. ret nM
+ ; kw "nM" >>. ret nM
+ ; kw "picomolar" >>. ret pM
+ ; kw "pM" >>. ret pM
+ ; kw "femtomolar" >>. ret fM
+ ; kw "fM" >>. ret fM
+ ; kw "attomolar" >>. ret aM
+ ; kw "aM" >>. ret aM
+ ; kw "zeptomolar" >>. ret zM
+ ; kw "zM" >>. ret zM
+ ; kw "yoctomolar" >>. ret yM
+ ; kw "yM" >>. ret yM ]
+let dirRelativeTolerance = RELTOLERANCE >>. spFloat >>= (RelTolerance >> preturn)
+let dirTolerance = TOLERANCE >>. spFloat >>= (Tolerance >> preturn)
+let dirScale = SCALE >>. spFloat >>= (Scale >> preturn)
+
+// simulation
+let dirSimulation =
+ SIMULATION >>. choice [ kw "jit" >>. preturn (Simulation JIT)
+ ; kw "stochastic" >>. preturn (Simulation SSA)
+ ; kw "deterministicstiff" >>. preturn (Simulation (OSLO true))
+ ; kw "deterministic" >>. preturn (Simulation (OSLO false))
+ ; kw "spatial1d" >>. preturn (Simulation (SPACIAL_PERIODIC 1))
+ ; kw "spatial2d" >>. preturn (Simulation (SPACIAL_PERIODIC 2))
+ ; kw "sundials" >>. preturn (Simulation (SUNDIALS false))
+ ; kw "sundialsstiff" >>. preturn (Simulation (SUNDIALS true))
+ ; kw "cme" >>. preturn (Simulation (CME_OSLO_OR_SUNDIALS false))
+ ; kw "cmestiff" >>. preturn (Simulation (CME_OSLO_OR_SUNDIALS true))
+ ; kw "lna" >>. preturn (Simulation (LNA_OSLO false))
+ ; kw "lnastiff" >>. preturn (Simulation (LNA_OSLO true)) ]
+
+let dirDT = DT >>. spFloat >>= (Dt >> preturn)
+let dirXMax = XMAX >>. spFloat >>= (XMax >> preturn)
+let dirNX = NX >>. spInt >>= (Nx >> preturn)
+let dirTheta = THETA >>. spFloat >>= (Theta >> preturn)
+
+// spatial directives
+// TODO: Add spatial directives
+let spatialErrorMsg _ = failwith "spatial directives not supported"
+let dirSpatialic = SPATIALIC >>= spatialErrorMsg
+
+
+
+let dirSpatialbc = SPATIALBC >>= spatialErrorMsg
+let dirSpatialPlot = SPATIALPLOT >>= spatialErrorMsg
+
+let dirDiffusion = DIFFUSION >>= spatialErrorMsg
+let dirDefaultDiffusion = DEFAULTDIFFUSION >>= spatialErrorMsg
+
+// parameters
+let paramP =
+ let f n x y z pType = choice
+ [ kw "fixedvar" >>. preturn (ParItem (n, x, y, z, pType, ParFixed))
+ ; kw "fixed" >>. preturn (ParItem (n, x, y, z, pType, ParFixed))
+ ; kw "randomized" >>. preturn (ParItem (n, x, y, z, pType, ParRandomized))
+ ; kw "random" >>. preturn (ParItem (n, x, y, z, pType, ParRandomized))
+ ; kw "init" >>. preturn (ParItem (n, x, y, z, pType, ParInitVal))
+ ; kw "initval" >>. preturn (ParItem (n, x, y, z, pType, ParInitVal)) ]
+ spName >>= fun n ->
+ choice [ EQUAL >>. spFloat >>= fun f -> preturn (ParAssign (n, f, f, f))
+ ; COMMA >>. Parser.paren (spFloat .>> COMMA .>>. spFloat) .>> COMMA .>>. spFloat .>> COMMA
+ >>= fun ((x,y), z) ->
+ choice [ kw "realspace" >>. COMMA >>. f n x y z ParReal
+ ; kw "real" >>. COMMA >>. f n x y z ParReal
+ ; kw "log" >>. COMMA >>. f n x y z ParLog
+ ; kw "logspace" >>. COMMA >>. f n x y z ParLog ] ]
+
+let dirParameters = PARAMETERS >>. Parser.sqBrackets (sepBy1 paramP SEMI) >>= (Params >> preturn)
+
+// sweeps
+let namesList = Parser.sepBy1 spName COMMA
+
+let valList = Parser.sepBy1 (Expression.parse spName) COMMA
+let valListP = Parser.paren valList
+let valTuples = Parser.sepBy1 valListP COMMA
+
+let varSweep = choice [ Parser.paren namesList .>> EQUAL .>>. Parser.sqBrackets valTuples
+ >>= (SweepVar >> preturn)
+ ; spName .>> EQUAL .>>. Parser.sqBrackets valList >>= fun (n, xs) ->
+ preturn (SweepVar ([n], List.map (fun x -> [x]) xs)) ]
+let combSweep = Parser.sepBy1 varSweep COMMA
+
+let dirSweep =
+ SWEEP >>.
+ choice [ paren namesList .>> EQUAL .>>. sqBrackets valTuples >>=
+ (SweepVar >> UnnamedSweep >> (fun x -> [x]) >> Sweeps >> preturn)
+ ; spName .>> EQUAL >>= fun n ->
+ choice [ braces combSweep >>= (fun x -> preturn (Sweeps [NamedSweep (n, x)]))
+ ; sqBrackets valList >>= (fun x -> preturn (Sweeps [UnnamedSweep (SweepVar ([n], [x]))])) ] ]
+
+
+let dirCrn =
+ CRN >>. Parser.choice[
+ OVERRIDE >>. Parser.braces (Instruction.parse Species.parse Crn_settings.defaults) |>> fun x -> Crn(x,true)
+ Parser.braces (Instruction.parse Species.parse Crn_settings.defaults) |>> fun x -> Crn(x,false)
+ ]
+
+// fit
+let dirFit = FIT >>= fun _ -> failwith "fit not supported"
+
+// fit run
+let fitElem =
+ choice [ kw "burnin" >>. EQUAL >>. spInt >>= (Burnin >> preturn)
+ ; kw "samples" >>. EQUAL >>. spInt >>= (SpSamples >> preturn)
+ ; kw "thin" >>. EQUAL >>. spInt >>= (Thin >> preturn) // TODO: default = findintdef "thin" 10 t
+ ; kw "separatenoise" >>. EQUAL >>. spBool >>= (SeparateNoise >> preturn) // TODO: default = findbooldef true t
+ ; kw "noisemodel" >>. EQUAL >>. spInt >>= (NoiseModel >> preturn) // TODO: Constant t
+ ; kw "prune" >>. EQUAL >>. spBool >>= (Prune >> preturn) // TODO: default true t }
+ ]
+let fitRecord = braces (sepBy1 fitElem SEMI)
+let dirFitRun sp = (FITRUN >>. fitRecord >>= (FitRun >> preturn)) sp
+
+// plot window, kinectics
+let dirPlotWindow = PLOTWINDOW >>= fun _ -> failwith "plot window not supported"
+let dirKinectics = KINETICS >>. choice [ kw "contextual" >>. preturn (Kinectics KContextual)
+ ; kw "stochastic" >>. preturn (Kinectics KStochastic)
+ ; kw "deterministic" >>. preturn (Kinectics KDeterministic) ]
+
+// verification
+let dirVerification = VERIFICATION >>= fun _ -> failwith "verification not supported"
+
+
+let pOldDirectives pSpecies = [ dirConcentration
+ ; dirDT
+ ; dirDefaultDiffusion
+ ; dirDiffusion
+ ; dirDuration
+ ; dirFit
+ ; dirFitRun
+ ; dirKinectics
+ ; dirNX
+ ; dirParameters
+ ; dirPlot pSpecies
+ ; dirPlotWindow
+ ; dirRelativeTolerance
+ ; dirSamples
+ ; dirScale
+ ; dirSeed
+ ; dirSimulation
+ ; dirSpatialbc
+ ; dirSpatialic
+ ; dirSpatialPlot
+ ; dirSweep
+ ; dirTheta
+ ; dirTime
+ ; dirTolerance
+ ; dirVerification
+ ; dirXMax
+ ; dirCrn]
+let oldDirective pSpecies = choice (pOldDirectives pSpecies)
+
+let oldToCrnParam param =
+ match param with
+ | ParAssign (n, f1, f2, f3) ->
+ let par : Parameter =
+ { name = n
+ ; value = f3
+ ; prior = Some { interval = Interval.Real
+ ; variation = Variation.Fixed
+ ; distribution = Distribution.Uniform {min = f1; max = f2} } }
+ par
+ | ParItem (n, f1, f2, f3, parSpace, parVar) ->
+ let pr : Prior = { interval = match parSpace with
+ | ParReal -> Interval.Real
+ | ParLog -> Interval.Log
+ ; variation = match parVar with
+ | ParFixed -> Variation.Fixed
+ | ParRandomized -> Variation.Random
+ | ParInitVal -> Variation.Initial2
+ ; distribution = Distribution.Uniform {min = f1; max = f2}}
+ let par : Parameter = { name = n
+ ; value = f3
+ ; prior = Some pr }
+ par
+
+
+let oldToCrnSweepVar (SweepVar (names, values)) : Assignment =
+ { variables = names
+ ; values = values }
+
+
+let sweep_id = ref 0
+let new_sweep_name () =
+ let id = !sweep_id + 1 in
+ sweep_id := id
+ "sweep_" + id.ToString() // the hard-coded "sweep_" is from the old DNA solution
+
+let oldToCrnSweep (sweep:SweepItem) =
+ match sweep with
+ | UnnamedSweep sweep -> let newName = new_sweep_name()
+ Sweep.create(newName,[oldToCrnSweepVar sweep])
+ | NamedSweep (n, sweeps) -> let asns = List.map oldToCrnSweepVar sweeps
+ Sweep.create(n,asns)
+
+
+let fromOpt m x = match m with
+ | None -> x
+ | Some y -> y
+
+let updateSettings (cs : settings ) oldDir =
+ match oldDir with
+ | Samples (startOpt, endOpt, pointsOpt)
+ | DurationPoints (startOpt, endOpt, pointsOpt) ->
+ {cs with settings = {cs.settings with simulation = {cs.settings.simulation with points = fromOpt pointsOpt cs.settings.simulation.points
+ ; initial = fromOpt startOpt cs.settings.simulation.initial
+ ; final = fromOpt endOpt cs.settings.simulation.final}}}
+ | Scale f -> { cs with settings = {cs.settings with stochastic = { cs.settings.stochastic with scale = f }}}
+ | Plot ps -> { cs with settings = {cs.settings with simulation = { cs.settings.simulation with plots = List.map (Expression.map Key.Species) ps @ cs.settings.simulation.plots}}}
+ | Simulation smode ->
+ {cs with settings = {cs.settings with simulator =
+ match smode with
+ | JIT -> Simulator.SSA
+ | SSA -> Simulator.SSA
+ | OSLO _ -> Simulator.Oslo
+ | SPACIAL_PERIODIC _ -> Simulator.PDE
+ | SUNDIALS _ -> Simulator.Sundials
+ | CME_OSLO_OR_SUNDIALS _ -> Simulator.CME
+ | LNA_OSLO _ -> Simulator.LNA
+ ; deterministic = {
+ cs.settings.deterministic with
+ stiff = match smode with
+ | OSLO isStiff -> isStiff
+ | LNA_OSLO isStiff -> isStiff
+ | SUNDIALS isStiff -> isStiff
+ | CME_OSLO_OR_SUNDIALS isStiff -> isStiff
+ | SPACIAL_PERIODIC _ -> false
+ | SSA -> false
+ | JIT -> false
+ }
+ ; simulation = cs.settings.simulation
+ }} // TODO: add dimensions to spatial settings
+ | RelTolerance f -> { cs with settings = {cs.settings with deterministic = { cs.settings.deterministic with reltolerance = f }}}
+ | Tolerance f -> { cs with settings = {cs.settings with deterministic = { cs.settings.deterministic with abstolerance = f }}}
+ | Seed i -> { cs with settings = {cs.settings with simulation = { cs.settings.simulation with seed = Some i}}}
+ | OldTime _ -> cs
+ | Concentration _ -> cs
+ | Dt f -> { cs with settings = {cs.settings with spatial = { cs.settings.spatial with dt = f }}}
+ | XMax f -> { cs with settings = {cs.settings with spatial = { cs.settings.spatial with xmax = f }}}
+ | Nx i -> { cs with settings = {cs.settings with spatial = { cs.settings.spatial with nx = i }}}
+ | Theta _ -> failwith "theta directive not supported in the spatial simulator"
+ | Params ps -> { cs with settings = {cs.settings with parameters = List.map oldToCrnParam ps }}
+ | Sweeps ss -> { cs with settings = {cs.settings with sweeps = List.map oldToCrnSweep ss }}
+ | FitRun ps ->
+ let updateSpSet (inf:Inference_settings) spParam =
+ match spParam with
+ | Burnin i -> { inf with burnin = i}
+ | SpSamples i -> { inf with samples = i}
+ | Thin i -> { inf with thin = i }
+ | SeparateNoise b -> { inf with noise_parameter = if b
+ then Noise_parameter.Multiple
+ else Noise_parameter.Random}
+ | NoiseModel i -> { inf with noise_model = match i with
+ | 0 -> Noise_model.Constant
+ | 1 -> Noise_model.Proportional
+ | _ -> failwith "Unrecognised noise model. Use linear or proportional." }
+ | Prune b -> { inf with prune = b}
+ { cs with settings = {cs.settings with inference = List.fold updateSpSet cs.settings.inference ps }}
+ | Kinectics kmode ->
+ { cs with settings =
+ {cs.settings with
+ simulation =
+ {cs.settings.simulation with
+ kinetics =
+ match kmode with
+ | KContextual -> Kinetics.Contextual
+ | KStochastic -> Kinetics.Stochastic
+ | KDeterministic -> Kinetics.Deterministic } }}
+ | Crn (instructions,ovveride) -> {cs with crn = Some(instructions); overrideCrn = ovveride}
+
+let parseOldDirectives pSpecies : Parser.t =
+ Parser.many (Parser.kw "directive" >>. oldDirective pSpecies)
+ .>> spaces
+ >>= (fun oldSettings -> let def : settings = {settings=Crn_settings.defaults;crn=None;overrideCrn=false}
+ let settings = List.fold updateSettings def oldSettings
+ preturn settings)
+
+(* legacy CRN parser, parses the body of a CRN written in the Silver Light tool's syntax.
+ The parser is parametric to the species, to allow species names such as '""'
+ for testing purposes in Classic DSD. *)
+(*type instruction =
+ | Reaction of Reaction
+ | Initial of Initial
+
+let convert_instructions (instructions:instruction list) =
+ let f (reactions,initials) command =
+ match command with
+ | Reaction reaction -> reaction::reactions, initials
+ | Initial initial -> reactions, initial::initials
+ let reactions, initials = List.fold f ([],[]) instructions
+ List.rev reactions, List.rev initials
+
+let create_from_instructions (settings:Crn_settings) (instructions:instruction list) =
+ let reactions,initials = convert_instructions instructions
+ Crn.create "" settings reactions initials Stringmap.empty
+
+let parse_legacy_SL pSpecies =
+ let zeroVal (init : float) = Expression.Float init
+ let zero = Expression.Float 0.0
+ let unitVal = Expression.Float 1.0
+
+ // base parsers
+ let pValue = Expression.parse (Parser.name .>> Parser.spaces)
+ let pExpr = Expression.parse (Key.parse pSpecies)
+
+ // crn parsers
+ let pInitial iv = Initial.parse pSpecies pValue zero (zeroVal iv) |>> Initial
+ let pConstant iv = Parser.kw "constant" >>. pSpecies .>>. pValue >>= fun (sp, v) ->
+ Parser.preturn (Initial.create(true, v, sp, (zeroVal iv), None) |> Initial)
+ let pEvent = Parser.kw "event" >>. pSpecies .>>. pValue .>> Parser.kw "@" .>>. pValue
+ >>= fun ((sp, amount), time) -> Parser.preturn (Initial.create(false, amount, sp, time, None) |> Initial)
+ let pReaction = Reaction.parse pSpecies pValue pExpr unitVal |>> Reaction
+ let pLine iv = (pConstant iv <|> pEvent <|> pInitial iv) <|> pReaction
+ let pBar = Parser.kw "|"
+
+ // full CRN parser
+ parseOldDirectives pSpecies >>= fun settings ->
+ Parser.spaces >>. Parser.opt pBar
+ >>. Parser.sepBy (pLine settings.settings.simulation.initial) pBar
+ |>> create_from_instructions settings.settings*)
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/gec.fs b/ClassicGEC/ClassicGECDotNet/gec.fs
new file mode 100644
index 0000000..fb4a633
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/gec.fs
@@ -0,0 +1,783 @@
+[]
+module Microsoft.Research.GEC.GECEngine
+
+open System
+open Microsoft.Research.GEC
+open Microsoft.Research.CRNEngine
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+open FSBOL
+open FSBOL.JsonSerializer
+open FSBOL.SBOLDocument
+open FSBOL.TopLevel
+open FSBOL.ComponentDefinition
+open Microsoft.Research.CRNEngine.InferenceSiteGraph
+open Microsoft.Research.GEC.Trans
+open Microsoft.Research.GEC.Settings
+open Microsoft.Research.GEC.Program
+open Microsoft.Research.FSBOLWrapper
+
+(* Main GUI datatype. *)
+type t = {
+ options:Options.t;
+ database:Database.t;
+ solution:(Ast.directive list * Main.tSolution * Trans.gecConstraint list * Trans.tArithmeticConstraints * string list) option
+ }
+let empty = {options = Options.default_options; database = Database.empty; solution = None}
+
+(******************************************************************************)
+(* *** Get/set GUI options. *)
+
+(* Get or set the "options" part of the GUI data structure. *)
+let getOptions (gec:t) = gec.options
+let setOptions (opts:Options.t) (gec:t) = {gec with options = opts}
+
+(* Get, set or erase the "solution" part of the GUI data structure. *)
+let setSolution (ds:Ast.directive list) (sol:Main.tSolution) (prologConstraints:Trans.gecConstraint list) (arithmeticConstraints:Trans.tArithmeticConstraints)
+ (log:string list) (gec:t) = {gec with solution = Some (ds, sol,prologConstraints,arithmeticConstraints,log)}
+let getSolution (gec:t) = gec.solution
+let eraseSolution (gec:t) = {gec with solution = None}
+
+(* Access the parts and reactions database. *)
+let getDatabase (gec:t) = gec.database
+let setDatabase (db:Database.t) (gec:t) = {gec with database = db}
+
+(* Produce a string representation of the results of the translation process, for debugging purposes... *)
+let getDebuggingOutput (g:t) =
+ match (getSolution g) with
+ | None -> ""
+ | Some (ds, sol,prologConstraints,arithmeticConstraints,log) ->
+ let bbTemplatesDebug = Lib.string_of_list (fun xs -> "[" + (Lib.string_of_list Lib.id "; " xs) + "]") Lib.newline sol.bbDevices in
+ let prologConstraintsDebug = Lib.string_of_list Trans.printConstraint Lib.newline prologConstraints in
+ let arithmeticConstraintsDebug = Lib.string_of_list Trans.stringOfArithmeticConstraint Lib.newline arithmeticConstraints in
+ let lbsProgDebug = Trans.lbsProgToStr sol.lbsProgram [] in // is empty list OK here for varDefs?
+ let rateDecsDebug = Lib.string_of_list (fun (r,f) -> r + " |==> " + (Lib.display_float f)) Lib.newline sol.rateDecs in
+ let varAssDebug = sol.getVarAssString() in
+ let databaseDebug = Database.display (getDatabase g) in
+ let logDebug = Lib.string_of_list Lib.id Lib.newline log in
+ let directivesDebug = match ds with [] -> "" | ds -> Lib.string_of_list Ast.stringOfDirective Lib.newline ds in
+ "bbTemplates:" + Lib.newline +
+ "============" + Lib.newline +
+ bbTemplatesDebug + Lib.newline + Lib.newline +
+ "rateDecs:" + Lib.newline +
+ "=========" + Lib.newline +
+ rateDecsDebug + Lib.newline + Lib.newline +
+ "varAss:" + Lib.newline +
+ "=======" + Lib.newline +
+ varAssDebug + Lib.newline + Lib.newline +
+ "Arithmetic constraints:" + Lib.newline +
+ "=======================" + Lib.newline +
+ arithmeticConstraintsDebug + Lib.newline + Lib.newline +
+ "Database:" + Lib.newline +
+ "=========" + Lib.newline +
+ databaseDebug + Lib.newline + Lib.newline +
+ "lbsProg:" + Lib.newline +
+ "========" +
+ lbsProgDebug + Lib.newline + Lib.newline +
+ "directives:" + Lib.newline +
+ directivesDebug + Lib.newline + Lib.newline +
+ "PROLOG Constraints:" + Lib.newline +
+ "============" + Lib.newline +
+ prologConstraintsDebug + Lib.newline + Lib.newline +
+ "log:" + Lib.newline +
+ "====" + Lib.newline +
+ logDebug + Lib.newline
+
+(* LBS program text. *)
+let getGECProgramText (g:t) = Options.getGECProgramText (getOptions g)
+let setGECProgramText (s:string) (g:t) = setOptions (Options.setGECProgramText s (getOptions g)) g
+
+(* Option to enable simulation-only reactions. *)
+let getSimulationOnlyReactionsOption (g:t) = Options.getSimulationOnlyReactions (getOptions g)
+let setSimulationOnlyReactionsOption (b:bool) (g:t) = setOptions (Options.setSimulationOnlyReactions b (getOptions g)) g
+
+(******************************************************************************)
+(* *** Access other information from the datatypes. *)
+
+(* Have the options changed enough to warrant recompilation? *)
+let identicalOptions (gold:t) (gnew:t) =
+ ((getGECProgramText gold) = (getGECProgramText gnew)) &&
+ ((getSimulationOnlyReactionsOption gold) = (getSimulationOnlyReactionsOption gnew)) &&
+ ((getDatabase gold) = (getDatabase gnew))
+
+(* Maybe prefix some directives onto an LBS program. *)
+let prefixDirectives (ds:Ast.directive list) (body:string) =
+ match ds with
+ | [] -> body
+ | ds -> (Lib.string_of_list Ast.stringOfDirective Lib.newline ds) + Lib.newline + Lib.newline + body
+
+(* Get the "default" LBS program, i.e. with general reactions (no substitution applied). *)
+let getDefaultLBSProgram (g:t) =
+ match (getSolution g) with
+ | Some(ds,sol,_,_,_) -> Some(prefixDirectives ds (sol.getProgramDefault()))
+ | None -> None
+
+(* Get a particular LBS program instance, corresponding to a particular set of variable instantiations. *)
+let getLBSProgramInstance (num:int) (g:t) =
+ match (getSolution g) with
+ | Some(ds,sol,_,_,_) ->
+ let ds = List.map (Subst.applyToDirective (List.item num sol.substs)) ds in
+ Some(prefixDirectives ds (sol.getProgramInstance(num)))
+ | None -> None
+
+(* Get a particular species instance. *)
+let getSpeciesAssignment (num:int) (g:t) =
+ match (getSolution g) with
+ | Some(_,sol,_,_,_) -> sol.getSpecAss(num)
+ | None -> ""
+
+(* Get a particular devices instance. *)
+let getDevicesInstance (num:int) (g:t) =
+ match (getSolution g) with
+ | Some(_,sol,_,_,_) -> sol.getDevicesInstance(num)
+ | None -> ""
+
+(* Get a particular devices instance as a string list list *)
+let getDevicesInstanceStructured (num:int) (g:t) =
+ match (getSolution g) with
+ | Some(_,sol,_,_,_) -> sol.getDevicesInstanceStructured(num)
+ | None -> List.toArray([])
+
+(* Get the number of solutions. *)
+let getNumSolutions (g:t) =
+ match (getSolution g) with
+ | Some(_,sol,_,_,_) -> sol.numSolutions
+ | None -> 0
+
+(* Get the directives text (if any). *)
+let getDirectives (g:t) =
+ match (getSolution g) with
+ | Some(ds,_,_,_,_) -> Some ds
+ | None -> None
+
+(******************************************************************************)
+(* Process a GEC program. *)
+
+let reduce_gecprog (prog:Ast.prog) =
+ let rec reduce (p:Ast.prog)=
+ match p with
+ | Ast.Par(p1,p2) ->
+ let rp1 = reduce p1
+ let rp2 = reduce p2
+ match rp1 with
+ | Ast.Nil ->
+ match rp2 with
+ | Ast.Nil -> Ast.Nil
+ | _ -> rp2
+ | _ ->
+ match rp2 with
+ | Ast.Nil -> rp1
+ | _ -> Ast.Par(rp1,rp2)
+ | Ast.Seq(p1,p2) ->
+ let rp1 = reduce p1
+ let rp2 = reduce p2
+ match rp1 with
+ | Ast.Nil ->
+ match rp2 with
+ | Ast.Nil -> Ast.Nil
+ | _ -> rp2
+ | _ ->
+ match rp2 with
+ | Ast.Nil -> rp1
+ | _ -> Ast.Seq(rp1,rp2)
+ | Ast.Comp(c,p1) -> Ast.Comp(c,reduce p1)
+ | Ast.New(n,p1) -> Ast.New(n,reduce p1)
+ | Ast.TemplateDef(tname,targs,p1,p2) -> Ast.TemplateDef(tname,targs,reduce p1, reduce p2)
+ | Ast.Copy(i,p1,b1,b2) -> Ast.Copy(i,reduce p1,b1,b2)
+ | _ -> p
+ reduce prog
+
+
+let unroll_gecprog (gecprog:ClassicProgram) =
+ let template_prog = gecprog.templates
+ let rec unroll_templates (prog:Ast.prog) =
+ match prog with
+ | Ast.TemplateDef(tempname,tempargs,body,next) ->
+ match next with
+ | Ast.TemplateDef(_) -> [(tempname,tempargs,body)]@(unroll_templates next)
+ | Ast.Nil -> [(tempname,tempargs,body)]
+ | _ -> failwith "Top Templates should not have anything other than TemplateDef and Nil in the recursive structure."
+ | Ast.Nil -> []
+ | _ -> failwith "Top Templates should not have anything other than TemplateDef and Nil in the recursive structure."
+
+ let templates = unroll_templates template_prog
+
+ let find_key (map) key=
+ map |> List.tryFind(fun (x,y:Ast.abstractComplex) -> x = key)
+
+ let rec sub_exp (e:Ast.aexp) (map) =
+ match e with
+ | Ast.FloatAExp _ -> e
+ | Ast.IdAExp(s) ->
+ match (find_key (map) s) with
+ | Some(mkey,mval_list) ->
+ match mval_list with
+ | [mval] ->
+ match mval with
+ | Ast.IdVal(id) -> Ast.IdAExp(id)
+ | Ast.FloatVal(f) -> Ast.FloatAExp(f)
+ | Ast.AlgebraicExp(exp) -> exp
+ | _ -> failwith "Shouldn't really see a wild card in template invocation?"
+ | _ -> failwith "Improper Template Invocation"
+ | None -> e
+ | Ast.PlusAExp(p1,p2) -> Ast.PlusAExp(sub_exp p1 map,sub_exp p2 map)
+ | Ast.MinusAExp(p1,p2) -> Ast.MinusAExp(sub_exp p1 map,sub_exp p2 map)
+ | Ast.MulAExp(p1,p2) -> Ast.MulAExp(sub_exp p1 map,sub_exp p2 map)
+ | Ast.DivAExp(p1,p2) -> Ast.DivAExp(sub_exp p1 map,sub_exp p2 map)
+ | Ast.PowAExp(p1,p2) -> Ast.PowAExp(sub_exp p1 map,sub_exp p2 map)
+
+ let sub_value (v:Ast.value) (map) =
+ match v with
+ | Ast.IdVal (x) ->
+ match (find_key map x) with
+ | Some(mkey,mval_list) ->
+ match mval_list with
+ | [mval] -> mval
+ | _ -> failwith "Improper Template Invocation"
+ | None -> v
+ | Ast.FloatVal f -> v
+ | Ast.WildCardVal -> v
+ | Ast.AlgebraicExp exp -> Ast.AlgebraicExp(sub_exp exp map)
+
+ let sub_abstractcomplex (ac:Ast.abstractComplex) (map) =
+ match ac with
+ | [Ast.IdVal(id)] ->
+ match (find_key map id) with
+ | Some(mkey,mval) -> mval
+ | None -> ac
+ | _ -> ac
+
+ let sub_string (s:string) (map) =
+ match (find_key map s) with
+ | Some(mkey,mval) ->
+ match mval with
+ | [Ast.IdVal(id)] -> id
+ | _ -> failwith "Improper Template Invocation - Compartment name"
+ | None -> s
+
+ let rec sub_prog (prog:Ast.prog) (map) =
+ match prog with
+ | Ast.Brick(v,btype,props) ->
+ let sv = sub_value v map
+ let sprops =
+ props |> List.map (fun (x,y) ->
+ let sy = y |> List.map (fun z ->
+ match z with
+ | [Ast.IdVal(id)] ->
+ match (find_key (map) id) with
+ | Some(mkey,mval) -> mval
+ | None -> z
+ | _ -> z)
+ (x,sy))
+ Ast.Brick(sv,btype,sprops)
+ | Ast.Reac(enz,reac,prod,rate,sim) ->
+ let senz = enz |> List.map (fun x -> sub_abstractcomplex x map)
+ let sreac = reac |> List.map (fun x -> sub_abstractcomplex x map)
+ let sprod = prod |> List.map (fun x -> sub_abstractcomplex x map)
+ Ast.Reac(senz,sreac,sprod,sub_value rate map,sim)
+ | Ast.Trans(reac,prod,comp,rate,sim,dir) -> Ast.Trans(sub_abstractcomplex reac map,sub_abstractcomplex prod map,sub_string comp map,sub_value rate map,sim,dir)
+ | Ast.TemplateInv(tname,targs) -> //This maybe a corner case
+ let sargs = targs |> List.map (fun x -> sub_abstractcomplex x map)
+ Ast.TemplateInv(tname,sargs)
+ | Ast.Seq(s1,s2) -> Ast.Seq(sub_prog s1 map,sub_prog s2 map)
+ | Ast.Par(s1,s2) -> Ast.Par(sub_prog s1 map,sub_prog s2 map)
+ | Ast.Comp(s,cprog) -> Ast.Comp(sub_string s map,sub_prog cprog map)
+ | Ast.New(n,nprog) -> Ast.New(sub_string n map,sub_prog nprog map)
+ | Ast.Constraint(c1,op,c2) -> Ast.Constraint(sub_exp c1 map,op,sub_exp c2 map)
+ | Ast.Rate(v,rate) -> Ast.Rate(sub_value v map,rate)
+ | Ast.Copy(i,cprog,b1,b2) -> Ast.Copy(i,sub_prog cprog map,b1,b2)
+ | _ -> prog
+
+ let rec unroll_prog (prog:Ast.prog) (templates)=
+ match prog with
+ | Ast.TemplateInv(tempname,args) ->
+ match (templates |> List.tryFind (fun(x,y,z) -> x = tempname)) with
+ | Some(tname,targs,tprog) ->
+ let subs = List.zip targs args
+ let sprog = sub_prog tprog subs
+ unroll_prog sprog templates
+ | None ->
+ failwith ("Template " + tempname + " not defined")
+ | Ast.TemplateDef(name,args,body,next) ->
+ let unroll_body = unroll_prog body templates //This maybe optional?
+ unroll_prog next ((name,args,unroll_body)::templates)
+ | Ast.Seq(s1,s2) ->
+ let u_s1 = unroll_prog s1 templates
+ let u_s2 = unroll_prog s2 templates
+ Ast.Seq(u_s1,u_s2)
+ | Ast.Par(p1,p2) ->
+ let u_p1 = unroll_prog p1 templates
+ let u_p2 = unroll_prog p2 templates
+ Ast.Par(u_p1,u_p2)
+ | Ast.Comp (name,prog) ->
+ let u_prog = unroll_prog prog templates
+ Ast.Comp(name,u_prog)
+ | Ast.New(n,prog) ->
+ let u_prog = unroll_prog prog templates
+ Ast.New(n,u_prog)
+ | Ast.Copy(i,prog,b1,b2) ->
+ let u_prog = unroll_prog prog templates
+ Ast.Copy(i,u_prog,b1,b2)
+ | _ -> prog
+
+ let unrolled_top = reduce_gecprog (unroll_prog gecprog.prog templates)
+ let unrolled_systems = gecprog.systems |> List.map(fun x -> {x with prog = reduce_gecprog (unroll_prog x.prog templates)})
+ {gecprog with prog = unrolled_top; systems = unrolled_systems}
+
+
+let translate_systems_to_prog (gecprog:ClassicProgram) =
+ let systems = gecprog.systems |> List.map (fun x -> Ast.Comp(x.name,x.prog))
+ let parsystems = Program.fold_parallel systems
+ let top_prog = gecprog.prog
+
+ match parsystems with
+ | Ast.Nil -> top_prog
+ | _ ->
+ match top_prog with
+ | Ast.Nil -> parsystems
+ | _ -> Ast.Par(top_prog,parsystems)
+
+
+
+exception CompileException of string * exn
+
+let modify_crn (crn:Crn) (settings:Gec_settings) crnSettings=
+ let instructions = settings.crn
+ let overrideCrn = settings.overrideCrn
+ if overrideCrn then
+ (None,instructions)
+ //Crn.create_from_instructions crnSettings instructions
+ else
+ Some(crn),instructions
+ (*let basecrn = {crn with settings=crnSettings}.saturate_initials()
+ let instCrn = Crn.create_from_instructions crnSettings instructions
+ let reactions' = basecrn.reactions@instCrn.reactions
+ //let attributes = instCrn.attributes
+ let attributes' = instCrn.attributes
+ |> Map.toList
+ |> List.fold (fun (acc:Stringmap.t) (x,y) -> acc.Add(x,y)) basecrn.attributes
+ let initials' = basecrn.initials@instCrn.initials
+ {basecrn with reactions=reactions';attributes=attributes';initials=initials'}*)
+
+type solve_result = { solution : t
+ ; graph : InferenceSiteGraph.IGraph
+ ; sbol : SBOLDocument
+ ; crnString: string}
+
+let getLBSSystems (gecprog:ClassicProgram) (lbs:tLBSProg) =
+ let systems = gecprog.systems
+ let system_names = systems |> List.map (fun x -> x.name)
+
+ let rec lbsSystem lbs =
+ match lbs with
+ | LBSComp(comp,prog) ->
+ if (system_names |> List.contains comp) then
+ [lbs]
+ else
+ []
+ | LBSPar(p1,p2) ->
+ (lbsSystem p1)@(lbsSystem p2)
+ | LBSReacAbstraction(_,prog) -> lbsSystem prog
+ | LBSCompDec(comp,prog) -> lbsSystem prog
+ | LBSCopy(i,prog) -> lbsSystem prog
+ | _ -> []
+
+ let rec lbsTop lbs =
+ match lbs with
+ | LBSComp(comp,prog) ->
+ if (system_names |> List.contains comp) then
+ Trans.LBSNil
+ else
+ lbs
+ | LBSPar(p1,p2) ->
+ LBSPar(lbsTop p1,lbsTop p2)
+ | LBSReacAbstraction(x,prog) -> LBSReacAbstraction(x,lbsTop prog)
+ | LBSCompDec(comp,prog) -> LBSCompDec(comp,lbsTop prog)
+ | LBSCopy(i,prog) -> LBSCopy(i,lbsTop prog)
+ | _ -> lbs
+
+ (lbsTop lbs,lbsSystem lbs)
+
+let create_inference_graph (crnSettings:Crn_settings) (gecprog:ClassicProgram) (top_crn:(Crn option * crnInstructions)) (system_crn_map) (db)=
+ let dir_str = Program.crnSettings_to_string crnSettings
+ let modules_str = Program.modules_to_string crnSettings.simulation.initial gecprog.modules
+ let devices_str = Lib.string_of_list (fun x -> Program.deviceDefinition_to_string x) "\n" gecprog.devices
+ let top_prog_str = Program.crn_contents_to_string crnSettings.simulation.initial top_crn
+
+ let system_strings = gecprog.systems
+ |> List.map (fun sys ->
+ match (system_crn_map |> List.tryFind(fun (x,crn) -> x = sys.name)) with
+ | Some(_,crn) -> Program.system_to_string crn gecprog.modules gecprog.devices sys db
+ | None -> failwith ("Unexpected error. System name not found in to_string method for: " + sys.name)
+ )
+ let system_str = Lib.string_of_list (fun x -> x) "\n" system_strings
+
+ let ig_str =
+ match gecprog.graph with
+ | [] ->
+ match system_crn_map with
+ | [] -> "" //"node node0 { }"
+ | _ ->
+ let system_names = system_crn_map |> List.map (fun (x,y) -> x)
+ "node node0 { systems = [" + (Lib.string_of_list (fun x -> x) ";" system_names) + "] }"
+ | _ -> Lib.string_of_list (fun x -> Program.igElement_to_string x) "\n" gecprog.graph
+
+
+ dir_str + modules_str + devices_str + top_prog_str + system_str + ig_str
+
+
+let getSBOLAssignment (bbTemplates:Trans.tBbDevices) (table:Database.t) (substs:Subst.t list) (index:int)=
+ let assignment = substs.Item(index)
+
+ let findPart (id:string) =
+ match Stringmap.tryFind id table.parts with
+ | Some entry -> Some entry.value
+ | None -> None
+
+ let IdExists (id:string) =
+ match findPart id with
+ | Some(_) -> true
+ | None -> false
+
+ let createTUAssignment (tu:string list) =
+ let createCDAssignment (p:string) =
+ let partName =
+ match (IdExists p) with
+ | true ->
+ p
+ | false ->
+ match assignment.Item(p) with
+ | Subst.PART(partVal) -> partVal
+ | _ -> failwith "Can't find the part in the substitution. Some error occurred."
+ let part =
+ match Stringmap.tryFind partName table.parts with
+ | Some entry -> entry
+ | None -> failwith "Can't find the part in the database. Some error occurred."
+
+ let cd = Database.partTypeToSBOL partName part
+ (cd,(partName,part))
+ let cdList = tu |> List.map (fun x -> (createCDAssignment x))
+ cdList
+ let urlPrefix = "http://www.microsoft.com/gec/db"
+ let tuList = [0..(bbTemplates.Length-1)] |>
+ List.map (fun indx ->
+ let a = (createTUAssignment (bbTemplates.Item(indx)))
+ let cdList = a |> List.map (fun (x,y) -> x)
+ let partEntryList = a |> List.map (fun(x,y) -> y)
+ let tu =
+ let tuName = ("tu" + indx.ToString())
+ let perId = urlPrefix + "/" + tuName
+ let version = "1"
+ GECHelper.createHigherFunction tuName perId version cdList
+ (cdList,tu,partEntryList)
+ )
+ let partCDList = tuList |> List.map(fun (x,y,z) -> x)
+ let partCDs = match partCDList.Length with
+ | 0 -> []
+ | 1 -> partCDList.Head
+ | _ -> partCDList |> List.reduce (fun a b -> a@b)
+
+ let tuCDs = tuList |> List.map(fun (x,y,z) -> y)
+
+ let partsUsedList =
+ let a = tuList |> List.map (fun (x,y,z) -> z)
+ match a.Length with
+ | 0 -> []
+ | 1 -> a.Head
+ | _ -> a |> List.reduce (fun b c -> b@c)
+
+
+ let partIdList = partsUsedList |> List.map(fun (x,y) -> x) |> Seq.ofList |> List.ofSeq
+ let partEntryList =
+ partIdList |> List.map(fun (x) ->
+ partsUsedList |> List.find (fun (a,b) -> a=x)
+ )
+
+ (*let protList = partEntryList
+ |> List.map (fun (x,y) -> y)
+ |> List.map (fun entry -> entry.value)
+ |> List.filter (fun partEntry ->
+ match partEntry with
+ | Database.PCR(_) -> true
+ | _ -> false
+ )
+ |> List.map (fun (Database.PCR(x))-> x)*)
+
+ let protCDs = Database.createProteinCDs partEntryList
+
+ let mdList = Database.createModuleDefinitions (partCDs@protCDs) partEntryList //|> List.map (fun x -> TopLevel.ModuleDefinition(x))
+
+ let device =
+ let name = "device"
+ let perid = urlPrefix + "/" + name
+ let version = "1"
+ //GECHelper.createHigherFunction name perid version tuCDs
+ GECHelper.createHigherFunction name perid version partCDs
+
+ //let allCDs = List.rev(device::( List.rev(tuCDs) @ List.rev(partCDs@protCDs)))
+ let allCDs = List.rev(device::( (*List.rev(tuCDs) @*) List.rev(partCDs@protCDs)))
+
+ let s = SBOLDocument(
+ (allCDs |> List.map (fun x -> x :> TopLevel))
+ //@ (mdList |> List.map (fun x -> x :> TopLevel))
+ )
+ s
+
+
+let solveGEC (cancel_flag:bool ref) (program:string) (dbParts:string) (dbReactions:string) : solve_result =
+ let db_from_string (s:string) = Parser.from_string Database.parse s
+ let partstable =
+ try
+ db_from_string dbParts
+ with e ->
+ raise (CompileException ("parts", e))
+
+ let reactionListParser = Parser.sepBy Gecreaction.parseReaction Parser.newline
+ let reactiondb_from_string (s:string) = Parser.from_string reactionListParser s
+
+ let createReactionEntry reaction =
+ let (reactionEntry:Gecreaction.t Database.entry) ={value=reaction;enabled=true;comments=""}
+ reactionEntry
+
+ let reactiondb =
+ try
+ reactiondb_from_string dbReactions |> List.map (fun(x) -> createReactionEntry(x))
+ with e ->
+ raise (CompileException ("reactions", e))
+
+ try
+ let table = {partstable with reactions = reactiondb}
+ let options = Options.setGECProgramText program Options.default_options
+ let guioptions = setOptions options empty
+ let gui = setDatabase table guioptions
+ match Main.parse (getGECProgramText gui) with
+ | LogicGec _ -> failwith "Logic GEC program not supported yet."
+ | ClassicGec gecprog ->
+ let ugecprog = unroll_gecprog gecprog
+ let prog = translate_systems_to_prog ugecprog
+ let ds = ugecprog.settings.directives |> Settings.convert_crn_to_gec_directives
+ let (bbTemplates, prologConstraints, lbsProg, rateDecs, substitutions, arithmeticConstraints, log) =
+ Trans.translate0 prog (getSimulationOnlyReactionsOption gui) (getDatabase gui)
+
+ let varAss = List.map Cssubst.mkVarAss substitutions
+ let substs = List.map Cssubst.getSubst substitutions
+ (* Put the results into a Main.tSolution data structure. *)
+ let sol = { Main.bbDevices = bbTemplates;
+ Main.lbsProgram = lbsProg;
+ Main.rateDecs = rateDecs;
+ Main.varAss = varAss;
+ Main.substs = substs;
+ Main.error = None;
+ Main.numSolutions = List.length varAss }
+
+ let solution = setSolution ds sol prologConstraints arithmeticConstraints log gui
+
+
+ let (toplbs,lbsSystems) = getLBSSystems ugecprog lbsProg
+
+ let crnSettings = Crn_settings.defaults.from_default_directive_list ugecprog.settings.directives
+
+ let top_crn = TransCrn.create toplbs |> (fun x -> modify_crn x ugecprog.settings crnSettings)
+ let system_crn_map = lbsSystems
+ |> List.map (fun x ->
+ let systems = ugecprog.systems
+ match x with
+ | Trans.LBSComp(compname,prog) ->
+ let crn = TransCrn.create x
+ match (systems |> List.tryFind (fun y -> y.name = compname)) with
+ | Some(res) -> (compname,modify_crn crn res.settings crnSettings)
+ | None -> failwith ("Unexpected error. System " + compname + " not found.")
+ | _ -> failwith "Unexpected LBS Comparment encountered")
+
+ let crnString = create_inference_graph crnSettings ugecprog top_crn system_crn_map table
+ let igraph = Parser.from_string InferenceSiteGraph.parse crnString
+
+ let (varAss',subst') =
+ match sol.numSolutions with
+ | 0 ->
+ match igraph.nodes.Count with
+ | 0 -> failwith "This should never happen"
+ | 1 ->
+ let model = igraph.nodes |> Map.toSeq |> Seq.head |> snd
+ match (model.top.initials.IsEmpty) && (model.systems.IsEmpty) with
+ | true -> ([],[])
+ | false -> ([[],[],[]],[Map.empty])
+ | _ -> ([[],[],[]],[Map.empty])
+ | _ -> (sol.varAss,sol.substs)
+
+ let solution' =
+ match solution.solution with
+ | Some(a,sol,b,c,d) ->
+ let sol' = {sol with Main.varAss = varAss'; Main.numSolutions = varAss'.Length; Main.substs = subst'}
+ Some(a,sol',b,c,d)
+ | None -> None
+
+
+ let sbol =
+ match solution' with
+ | Some(dir,sol,gecConst,arthConst,_) -> getSBOLAssignment sol.bbDevices table sol.substs 0
+ | None -> Database.convertTableToSBOLDocument table
+ { solution = {solution with solution = solution'}
+ ; graph = igraph
+ ; sbol = sbol
+ ; crnString = crnString}
+
+
+ with e ->
+ raise (CompileException ("code", e))
+
+(******************************************************************************)
+
+let rec evaluateExpression (exp:Expression.t<_>) (smap:Subst.t) =
+ match exp with
+ | Expression.Key(key) ->
+ if key = "RMRNADeg" then
+ 0.001
+ else
+ if not (smap.ContainsKey(key)) then
+ try
+ float key
+ with e ->
+ failwith "Key not found in substitution"
+ raise(CompileException ("code", e))
+ else
+ match smap.Item(key) with
+ | Subst.NUMBER(fl) -> fl
+ | _ -> failwith "Unexpected format in the map"
+ | Expression.Float(fl) -> fl
+ | Expression.Times(times) ->
+ times |> List.fold (fun acc x -> acc*(evaluateExpression x smap)) 1.0
+ | Expression.Divide(divide) ->
+ let d1 = evaluateExpression divide.div1 smap
+ let d2 = evaluateExpression divide.div2 smap
+ if d2 = 0.0 then
+ failwith "Divide by 0 error."
+ (d1)/(d2)
+ | Expression.Power(pow) ->
+ let b = evaluateExpression pow.base_ smap
+ let pow = evaluateExpression pow.exponent smap
+ Math.Pow(b,pow)
+ | Expression.Plus(plus) ->
+ plus |> List.fold (fun acc x -> acc+(evaluateExpression x smap)) 0.0
+ | Expression.Minus(minus) ->
+ let sub1 = evaluateExpression minus.sub1 smap
+ let sub2 = evaluateExpression minus.sub2 smap
+ sub1 - sub2
+ | Expression.Absolute(abs) ->
+ let vabs = evaluateExpression abs smap
+ if vabs < 0.0 then
+ (vabs * (-1.0))
+ else
+ vabs
+ | Expression.Log(log) ->
+ let l = evaluateExpression log smap
+ Math.Log(l)
+ | Expression.Modulo(modulo) ->
+ let div = evaluateExpression modulo.div smap
+ let modul = evaluateExpression modulo.modulo smap
+ div%modul
+ | Expression.If(bexp1,bexp2,bexp3) ->
+ failwith "unexpected expression type"
+
+
+let assignReverseRate (rxn:Reaction) (smap:Subst.t) =
+
+ match rxn.reverse with
+ | Some(Rate.MassAction(exp:Expression.t)) ->
+ match exp with
+ | Expression.Key(rate) ->
+ if rate = "RMRNADeg" then
+ {rxn with reverse = Some(Rate.MassAction(Expression.Float(0.001)))}
+ else
+ if not (smap.ContainsKey(rate)) then
+ let mfloat = ref 0.0f
+ match Single.TryParse(rate, mfloat) with
+ | true -> {rxn with reverse = Some(Rate.MassAction (Expression.Float(float !mfloat)))}
+ | false -> rxn
+ (*try
+ let mfloat = float rate
+ {rxn with reverse = Some(Rate.MassAction (Expression.Float(mfloat)))}
+ with e ->
+ failwith "Key not found in substitution"
+ raise(CompileException ("code", e))*)
+ else
+ match smap.Item(rate) with
+ | Subst.NUMBER(fl) ->
+ {rxn with reverse = Some(Rate.MassAction(Expression.Float(fl)))}
+ | _ -> failwith "Unexpected format in the map"
+
+ | _ ->
+ try
+ let value = evaluateExpression exp smap
+ {rxn with reverse = Some(Rate.MassAction(Expression.Float(value)))}
+ with e ->
+ raise(CompileException ("code", e))
+ | Some(Rate.Function(e)) -> rxn //This case is encountered when userdefined CRNs are substituted.
+ | None -> rxn
+
+
+let assignReaction (rxn:Reaction) (smap:Subst.t) =
+ match rxn.rate with
+ | Rate.MassAction(exp:Expression.t) ->
+ match exp with
+ | Expression.Key(rate) ->
+ if rate = "RMRNADeg" then
+ let newRxn = {rxn with rate = (Rate.MassAction (Expression.Float(0.001)))}
+ assignReverseRate newRxn smap
+ else
+ if not (smap.ContainsKey(rate)) then
+ let mfloat = ref 0.0f
+ match Single.TryParse(rate, mfloat) with
+ | true ->
+ let newRxn = {rxn with reverse = Some(Rate.MassAction (Expression.Float(float !mfloat)))}
+ assignReverseRate newRxn smap
+ | false -> rxn
+
+ (*try
+ let mfloat = float rate
+ let newRxn = {rxn with rate = (Rate.MassAction (Expression.Float(mfloat)))}
+ assignReverseRate newRxn smap
+ with e ->
+ failwith "Key not found in substitution"
+ raise(CompileException ("code", e))*)
+ else
+ let newRate = match smap.Item(rate) with
+ | Subst.NUMBER(fl) -> fl
+ | _ -> failwith "Unexpected format in the map"
+
+ let newRxn = {rxn with rate = (Rate.MassAction (Expression.Float(newRate)))}
+ assignReverseRate newRxn smap
+ | _ ->
+ try
+ let value = evaluateExpression exp smap
+ let newRxn = {rxn with rate = (Rate.MassAction(Expression.Float(value)))}
+ assignReverseRate newRxn smap
+ with e ->
+ raise(CompileException ("code", e))
+ | Rate.Function(e) -> rxn //This case is encountered when userdefined CRNs are substituted.
+
+
+type solution_result = { model : InferenceSiteGraph.IGraph
+ ; sbol : SBOLDocument }
+
+let getCrnAssignment (igraph:InferenceSiteGraph.IGraph) (gecSol:t) (index:int) : solution_result =
+ if gecSol.solution.IsNone then
+ failwith "No solution found"
+
+ let (dirlist,sol,constraints,aritconstraints,d) = gecSol.solution.Value
+ let substitution = sol.substs.Item(index)
+
+ //SBOL
+ let sbol = getSBOLAssignment sol.bbDevices gecSol.database sol.substs index
+
+ //CRN
+ let assign_crn (crn:Crn) =
+ let assignedReactions = crn.reactions |> List.map(fun x -> assignReaction x substitution)
+ {crn with reactions = assignedReactions}
+
+ let nodes' = igraph.nodes |> Map.map (fun k node ->
+ {node with top = (assign_crn node.top); systems = (node.systems |> List.map (fun x -> assign_crn x))})
+
+
+ { model = {igraph with nodes = nodes'} ; sbol = sbol }
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/gecreaction.fs b/ClassicGEC/ClassicGECDotNet/gecreaction.fs
new file mode 100644
index 0000000..5b6af00
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/gecreaction.fs
@@ -0,0 +1,124 @@
+[]
+module Microsoft.Research.GEC.Gecreaction
+
+open Microsoft.Research.GEC
+open Parser
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+open System.Diagnostics
+
+(* A type for "database reactions", which records some of the structure of complexes. *)
+type normalReacData = { catalysts: string list list;
+ reactants: string list list;
+ products: string list list;
+ rate: float }
+type transportReacData = { reactant: string list;
+ product: string list;
+ rate: float;
+ compartment: string;
+ direction: Ast.direction }
+type t = Normal of normalReacData
+ | Transport of transportReacData
+
+(* Functions to create GEC reaction datatypes. *)
+let makeNormal (catalysts:string list list) (reactants:string list list) (products:string list list) (rate:float) =
+ Normal {catalysts=catalysts; reactants=reactants; products=products; rate=rate}
+let makeTransport (reactant:string list) (product:string list) (rate:float) (compartment:string) (direction:Ast.direction) =
+ Transport {reactant=reactant; product=product; rate=rate; compartment=compartment; direction=direction}
+
+(* Decide whether a reaction is a normal or a transport reaction... *)
+let isNormal (r:t) = match r with Normal r -> Some (r.catalysts, r.reactants, r.products, r.rate) | _ -> None
+let isTransport (r:t) = match r with Transport r -> Some (r.reactant, r.product, r.rate, r.compartment, r.direction) | _ -> None
+
+(* Produce a string representation of a GEC reaction. *)
+let display (r:t) : string =
+ let mkStr xss = Lib.string_of_list Ast.complexString " + " xss in
+ match r with
+ | Normal r -> let prefix = match r.catalysts with [] -> "" | _ -> (mkStr r.catalysts) + " ~ " in
+ prefix + (mkStr r.reactants) + " ->{" + (Lib.display_float r.rate) + "} " + (mkStr r.products)
+ | Transport r -> let reactantStr,productStr =
+ match r.direction with
+ | Ast.In -> Ast.complexString r.reactant, Ast.compartmentString r.compartment (Ast.complexString r.product)
+ | Ast.Out -> Ast.compartmentString r.compartment (Ast.complexString r.reactant), Ast.complexString r.product
+ in
+ reactantStr + " ->{" + (Lib.display_float r.rate) + "} " + productStr
+
+(* Are two reactions equal? Must consider reordering of reactions/products/catalysts and the ordering of species within complexes themselves... *)
+let equal (r1:t) (r2:t) =
+ match r1,r2 with
+ | Normal r1, Normal r2 -> (Lib.is_permutation Ast.complexesEqual r1.catalysts r2.catalysts) &&
+ (Lib.is_permutation Ast.complexesEqual r1.reactants r2.reactants) &&
+ (Lib.is_permutation Ast.complexesEqual r1.products r2.products) &&
+ (r1.rate = r2.rate)
+ | Transport r1, Transport r2 -> (Ast.complexesEqual r1.reactant r2.reactant) &&
+ (Ast.complexesEqual r1.product r2.product) &&
+ (r1.rate = r2.rate) &&
+ (r1.compartment = r2.compartment) &&
+ (r1.direction = r2.direction)
+ | _,_ -> false
+
+(* Get all species names from a GEC reaction. *)
+let species (r:t) : string list list =
+ let allRawSpecies =
+ match r with
+ | Normal r -> r.catalysts @ r.reactants @ r.products
+ | Transport r -> [r.reactant; r.product]
+ in
+ Lib.remove_duplicates Ast.complexesEqual allRawSpecies
+
+(* Apply a substitution to a GEC reaction. *)
+let applySubst (theta:Subst.t) (r:t) : t =
+ match r with
+ | Normal r -> Normal { r with catalysts = List.map (Subst.applyToComplex theta) r.catalysts;
+ reactants = List.map (Subst.applyToComplex theta) r.reactants;
+ products = List.map (Subst.applyToComplex theta) r.products }
+ | Transport r -> Transport { r with reactant = Subst.applyToComplex theta r.reactant;
+ product = Subst.applyToComplex theta r.product }
+
+
+let lookaheadLinebreak = Parser.pTry (Parser.linebreak >>. Parser.failParser "" <|> Parser.satisfy Parser.isWhiteSpace >>. preturn ())
+let lookaheadDashSeparator = Parser.pTry(Parser.pstring "->" >>. failParser "" <|> Parser.pstring "-")
+ // Parser.satisfy (fun c -> Parser.isWhiteSpace c && c <> '\n')
+//let whiteSpacenlb : t = skipChar isWhiteSpace > "a white space"
+
+let spacesnlb :t = fun st ->
+ match many (commentLine <|> commentMultiline () <|> lookaheadLinebreak) <| st with
+ | OkEmpty (_, st') -> OkEmpty ("", st')
+ | OkConsumed (_, st') -> OkEmpty ("", st')
+ | FailEmpty _ -> OkEmpty ("", st)
+ | FailConsumed (e, p) -> FailConsumed (e, p)
+
+let kwnlb s = pstring s .>> spacesnlb
+
+let gecName = (Parser.sepBy Parser.name (Parser.pstring "::")) .>> spacesnlb
+let bracketnlb l r = Parser.between (Parser.pstring l) (Parser.spaces >>. kwnlb r)
+let parennlb a = bracketnlb "(" ")" a
+let sqBracketnlb a = bracketnlb "[" "]" a
+let bracesnlb a = bracketnlb "{" "}" a
+let compartmentParser = (sqBracketnlb gecName)
+let rateParser = bracesnlb Parser.pfloat
+let chainNames = Parser.sepBy gecName (Parser.kw "+")
+
+let parseReaction = chainNames >>= fun n ->
+ Parser.choice[
+ compartmentParser .>> Parser.kw "->" .>>. rateParser .>>. gecName |>> fun(((reactant:string list),rate:float),(product:string list)) -> Transport {reactant = reactant; product=product;rate = rate;compartment = n.Head.Head; direction = Ast.direction.Out}
+ Parser.skw "~" >>.
+ Parser.choice[
+ Parser.kw "->" >>. rateParser .>>. chainNames |>> fun((rate:float),(products:string list list)) -> Normal {catalysts=n;reactants = [];rate=rate;products=products}
+ chainNames .>> Parser.kw "->" .>>. rateParser .>>. chainNames |>> fun(((reactants:string list list),rate:float),(products:string list list)) -> Normal {catalysts=n;reactants = reactants;rate=rate;products=products}
+ ]
+ Parser.kw "->" >>. rateParser .>>. chainNames >>= fun (r,x) ->
+ Parser.choice[
+ compartmentParser |>> fun(product) -> Transport {reactant = n.Head;product=product;rate=r;compartment=x.Head.Head;direction=Ast.direction.In}
+ Parser.preturn (Normal {catalysts=[];reactants = n;products=x;rate=r})
+ ]
+ ]
+
+
+
+//let parseTransportOut = compartmentParser .>> Parser.kw "->" .>>. rateParser .>>. gecName |>> fun ( ((compartment:string, (reactant:string list)), rate:float), (product: string list)) -> Transport {reactant=reactant; product=product; rate=rate; compartment=compartment; direction=Ast.direction.Out}
+//let parseTransportIn = gecName .>> Parser.kw "->" .>>. rateParser .>>. compartmentParser |>> fun(((reactant:string list),rate:float),(compartment:string,(product:string list))) -> Transport {reactant=reactant; product=product; rate=rate; compartment=compartment; direction=Ast.direction.In}
+
+
diff --git a/ClassicGEC/ClassicGECDotNet/gecreaction.fsi b/ClassicGEC/ClassicGECDotNet/gecreaction.fsi
new file mode 100644
index 0000000..27024e0
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/gecreaction.fsi
@@ -0,0 +1,28 @@
+module Microsoft.Research.GEC.Gecreaction
+
+open Microsoft.Research.GEC
+
+(* Opaque reaction datatype. *)
+type t
+
+(* Functions to create GEC reaction datatypes. *)
+val makeNormal : string list list -> string list list -> string list list -> float -> t
+val makeTransport : string list -> string list -> float -> string -> Ast.direction -> t
+
+(* Decide whether a reaction is a normal or a transport reaction... *)
+val isNormal : t -> (string list list * string list list * string list list * float) option
+val isTransport : t -> (string list * string list * float * string * Ast.direction) option
+
+(* Produce a string representation of a GEC reaction. *)
+val display : t -> string
+
+(* Are two reactions equal? *)
+val equal : t -> t -> bool
+
+(* Get all species names from a GEC reaction. *)
+val species : t -> string list list
+
+(* Apply a substitution to a GEC reaction. *)
+val applySubst : Subst.t -> t -> t
+
+val parseReaction : Parser.t
diff --git a/ClassicGEC/ClassicGECDotNet/gecspecies.fs b/ClassicGEC/ClassicGECDotNet/gecspecies.fs
new file mode 100644
index 0000000..fa95f3f
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/gecspecies.fs
@@ -0,0 +1,61 @@
+[]
+module Microsoft.Research.GEC.GecSpecies
+
+open Parser
+open Microsoft.Research.CRNEngine
+
+type species = string list
+
+let species_to_gecAbstractComplex (sp:species) =
+ sp |> List.map (fun x ->
+ match x with
+ | "_" -> Ast.WildCardVal
+ | _ -> Ast.IdVal(x))
+
+type t = {
+ compartment: string option
+ species:species
+}
+with
+ static member empty_Species =
+ {species = []; compartment=None}
+ member s.to_string() =
+ match s.compartment with
+ | Some(comp) -> comp + "[" + (Lib.string_of_list (fun x -> x) "::" s.species) + "]"
+ | None -> (Lib.string_of_list (fun x -> x) "::" s.species)
+ member s.to_crn_string() =
+ match s.compartment with
+ | Some(comp) -> comp + "_" + (Lib.string_of_list (fun x -> x) "_" s.species)
+ | None -> (Lib.string_of_list (fun x -> x) "_" s.species)
+ member s.to_crn_species() = Species.create(s.to_crn_string())
+ member s.to_ast_gecSpecies() =
+ match s.compartment with
+ | Some(x) -> Ast.CompartmentSpecies(x,species_to_gecAbstractComplex s.species)
+ | None -> Ast.SimpleSpecies(species_to_gecAbstractComplex s.species)
+
+let SPECIES_SEP = Parser.pstring "::"
+
+let pName = Parser.name_kw Keywords.kwList
+
+let parse_species_ns = Parser.sepBy (pName) SPECIES_SEP
+let parse_species = parse_species_ns .>> Parser.spaces
+
+let parse_kw (keywords:string list) =
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.pTry((Parser.name_kw keywords) .>> Parser.pstring "[" >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>=
+ fun (hasCompartment) ->
+ if hasCompartment then
+ pName .>> Parser.pstring "[" .>>. parse_species_ns .>> Parser.pstring "]" .>> Parser.spaces |>> fun(x,y) -> {species=y;compartment=Some(x)}
+ else
+ parse_species |>> fun y -> {species=y;compartment=None}
+
+let parse = parse_kw Keywords.kwList
+
+
+let parse_crn_species = parse |>> fun x -> x.to_crn_string() |> Species.create
+let parse_gec_to_crn_species = parse_species |>> fun x -> Lib.string_of_list (fun x -> x) "_" x |> Species.create
+
diff --git a/ClassicGEC/ClassicGECDotNet/hypothesis.fs b/ClassicGEC/ClassicGECDotNet/hypothesis.fs
new file mode 100644
index 0000000..6182380
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/hypothesis.fs
@@ -0,0 +1,360 @@
+module Microsoft.Research.GEC.Hypothesis
+
+open Parser
+open Microsoft.Research.CRNEngine
+
+
+type parser<'a> = Parser.t<'a>
+
+
+type HypothesisDirective =
+ | Devices of (string list)
+
+
+
+type HypothesisSettings =
+ {
+ devices : string list
+ }
+ static member defaults = {
+ devices = []
+ }
+ member setting.from_directive (directive:HypothesisDirective) =
+ match directive with
+ | Devices(x) -> {setting with devices=x}
+ member setting.from_directiveList (directives:HypothesisDirective list) =
+ directives |> List.fold (fun (s:HypothesisSettings) (d:HypothesisDirective) -> setting.from_directive d) setting
+
+
+
+type arguments = (string list)
+type crndirective = string
+type crnmodule = string * arguments * string
+//type device = string * arguments * string
+
+type crnModules = ((string * string list) * Instruction list) list * Instruction list
+
+type igPriorType =
+ | Fixed
+ | Normal
+ | TruncatedNormal
+
+type igPriorOption =
+ | HasPrior of igPriorType
+ | NoPrior
+
+type igPrior = string * igPriorOption
+
+type igName = string list
+
+type igedge = igName * (igPrior list) * igName
+type ignode = string * (string list) * (Inference_settings option)
+
+
+
+type igraphElement =
+ | Node of ignode
+ | Edge of igedge
+
+type moduleDefinition = string * (arguments)
+
+type deviceDefinition = moduleDefinition * (moduleDefinition list)
+
+type systemReference =
+ | System of string
+ | NoSystem
+
+type crnSystem = string * systemReference * Crn_settings * HypothesisSettings * crnModules
+
+type hypothesis = Crn_settings * (crnModules) * (deviceDefinition list) * (crnSystem list) * (igraphElement list)
+
+
+let kwList = ["module";"system";"inference";"directive";"device"]
+
+//Parsers Start here:
+
+let parse_species = Parser.(|>>) (Parser.name_kw kwList) Species.create
+
+let pcomma = Parser.kw ","
+let pPipe = Parser.kw "|"
+let pDot = Parser.kw "."
+
+let argumentsParser = Parser.paren (Parser.sepBy Parser.name pcomma)
+
+let parse_crnDirective = Directive.parse Functional2.parse Functional2.parse_plot
+
+
+let parse_hypothesisDirective = Parser.kw "device" >>. Parser.list_of Parser.name .>> Parser.opt (Parser.kw ";") |>> Devices
+
+let parse_crnSettings = Crn_settings.parse Functional2.parse Functional2.parse_plot
+
+
+let parse_moduleInvocation = Parser.name .>> Parser.spaces .>>. argumentsParser
+
+let parse_device = Parser.kw "device" >>. parse_moduleInvocation .>> Parser.kw "="
+ .>>. Parser.braces (Parser.sepBy parse_moduleInvocation pPipe)
+
+
+
+let parse_instructions pspecies settings =
+ let zero = Expression.zero
+ let unitVal = Expression.one
+
+ let pname = Parser.name_kw kwList .>> Parser.spaces
+ let pvalue = Expression.parse pname
+ let pexpr = Expression.parse (Key.parse pspecies)
+ let pcomma = Parser.kw ","
+
+ // crn parsers
+ let pinitial = Initial.parse pspecies pvalue zero |>> Instruction.Initial2
+ let preaction = Reaction.parse pspecies pvalue pexpr unitVal |>> Instruction.Reaction
+ let pinvoke = Parser.pTry( pname .>> Parser.kw "(")
+ .>>. Parser.sepBy pvalue pcomma
+ .>> Parser.kw ")"
+ |>> Module
+ let pline = pinvoke <|> preaction <|> pinitial
+ let pbar = Parser.kw "|"
+
+ // module definitions parser
+ let pmodule =
+ Parser.kw "module"
+ >>. Parser.name .>>. Parser.paren (Parser.sepBy Parser.name pcomma) // module_name(comma-separated args)
+ .>> Parser.kw "="
+ .>>. Parser.braces (Parser.opt pbar >>. Parser.sepBy pline pbar)
+
+ // full CRN parser
+ Parser.spaces
+ >>. Parser.many pmodule
+ .>> Parser.opt pbar
+ .>>. Parser.sepBy pline pbar
+
+let parse_crnModules crnSettings = parse_instructions parse_species crnSettings
+
+let crnDirectiveChoice = parse_crnDirective |>> Choice1Of2
+let hypothesisDirectiveChoice = parse_hypothesisDirective |>> Choice2Of2
+
+
+let pfixed = Parser.kw "Fixed" |>> fun _ -> Fixed
+let pnormal = Parser.kw "Normal" |>> fun _ -> Normal
+let ptruncatedNormal = Parser.kw "TruncatedNormal" |>> fun _ -> TruncatedNormal
+
+let parse_priorType = pfixed <|> pnormal <|> ptruncatedNormal
+
+let parse_priorOption:Parser.t = (Parser.plookAheadWith (
+ Parser.choice[
+ Parser.pTry (Parser.kw "=" >>. parse_priorType >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasPriorType ->
+ if hasPriorType
+ then Parser.kw "=" >>. parse_priorType |>> fun (x:igPriorType) -> HasPrior(x)
+ else Parser.preturn(NoPrior)
+ )
+
+let parse_prior:t = Parser.name .>> Parser.spaces .>>. parse_priorOption
+
+
+let parse_igInferenceSettings = Parser.kw ";" >>. Parser.kw "inference" >>. Parser.kw "=" >>. (Inference_settings.parse)
+
+let parse_igName = Parser.sepBy (Parser.name .>> Parser.spaces) pDot
+
+let parse_edge = Parser.kw "edge" >>. parse_igName .>> Parser.kw "->" .>>.
+ Parser.list_of parse_prior .>>. parse_igName |>> fun ((x,y),z) -> Edge(x,y,z)
+
+let parse_node = Parser.kw "node" >>. (Parser.name .>> Parser.spaces) .>>
+ Parser.kw "{" .>>. (Parser.kw "systems" >>. Parser.kw "=" >>.
+ Parser.list_of (Parser.name .>> Parser.spaces)) >>= fun (x,y) ->
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.pTry(Parser.kw ";" >>. Parser.kw "inference" >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasInference ->
+ if hasInference
+ then
+ parse_igInferenceSettings .>> Parser.kw "}" |>> fun (z) -> Node(x,y,Some(z))
+ else
+ Parser.kw "}" |>> fun _ -> Node(x,y,None)
+
+
+
+let parse_igraphElement = parse_edge <|> parse_node
+
+
+let parse_withSystem = (Parser.plookAheadWith (
+ Parser.choice [
+ Parser.pTry(Parser.name .>> Parser.spaces .>> Parser.kw "with" >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasWith ->
+ if hasWith
+ then Parser.name .>> Parser.spaces .>> Parser.kw "with" |>> fun x -> System(x)
+ else Parser.preturn(NoSystem))
+
+
+
+
+let parse_hybridDirective = Parser.many (Parser.kw "directive" >>. (crnDirectiveChoice <|> hypothesisDirectiveChoice)) |>>
+ (fun hybridList ->
+ let crnList = hybridList |>
+ List.filter (fun x ->
+ match x with
+ | Choice1Of2 t -> true
+ | _ -> false) |>
+ List.map (fun x ->
+ match x with
+ | Choice1Of2 t -> t
+ | _ -> failwith "Unexpected choice2 in parse_hybridDirective")
+ let hypList = hybridList |>
+ List.filter (fun x ->
+ match x with
+ | Choice2Of2 t -> true
+ | _ -> false) |>
+ List.map (fun x ->
+ match x with
+ | Choice2Of2 t -> t
+ | _ -> failwith "Unexpected choice1 in parse_hybridDirective")
+ let crn_settings = Crn_settings.defaults.from_directive_list crnList
+ let hypothesis_settings = HypothesisSettings.defaults.from_directiveList hypList
+ (crn_settings,hypothesis_settings)
+ )
+
+let (parse_crn_system:t) = Parser.kw "system" >>. Parser.name .>> Parser.spaces .>> Parser.kw "="
+ .>> Parser.kw "{" .>>. parse_withSystem .>>. parse_hybridDirective >>= fun((systemName,withSystem),(crnSettings,hypothesisSettings)) ->
+ parse_crnModules crnSettings .>> (Parser.kw "}") >>= fun y -> Parser.preturn(systemName,withSystem,crnSettings,hypothesisSettings,y)
+
+
+
+
+let (parse_hypothesis_content:t) =
+ parse_crnSettings >>= fun (crnSettings) ->
+ (parse_crnModules crnSettings)
+ .>>. (Parser.many parse_device)
+ .>>. (Parser.many parse_crn_system)
+ .>>. (Parser.many parse_igraphElement)
+ |>> fun (((modulelist:crnModules,deviceDefinitions: deviceDefinition list),systemlist:crnSystem list),igraph) -> (crnSettings,modulelist,deviceDefinitions,systemlist,igraph)
+
+
+//To String Methods
+let fold_string_list (strList:string list) (folder:string) =
+ match strList.Length with
+ | 0 -> ""
+ | 1 -> strList.Head
+ | _ -> strList.Tail |> List.fold (fun f s -> (f + folder + s)) strList.Head
+
+let crnDirectives_to_string (crnSettings:Crn_settings) = crnSettings.to_string Functional2.to_string Functional2.to_string_plot
+
+let args_to_string (args: arguments) = fold_string_list args ","
+
+let modules_to_string initial_time (modules:crnModules) =
+ let moduleList,externalInstructions = modules
+ let instructionList_to_string (instructions:Instruction list) =
+ let instructionStringList = instructions |> List.map (fun x -> ("| " + (Instruction.to_string initial_time x)))
+ fold_string_list instructionStringList "\n"
+ let module_to_string (((moduleName:string),(moduleArgs:string list)),(instructions:Instruction list)) =
+ let str = "module " + moduleName + "(" + (args_to_string moduleArgs) + ") = {\n" +
+ (instructionList_to_string instructions) + "\n}\n"
+ str
+ let str =
+ let moduleListString = moduleList |> List.map (fun x -> (module_to_string x))
+ let moduleStr = fold_string_list moduleListString ""
+ moduleStr + (instructionList_to_string externalInstructions)
+ str
+
+let moduleDefinition_to_string (moduleDef:moduleDefinition) =
+ let (moduleName,moduleArgs) = moduleDef
+ moduleName + "(" + (args_to_string moduleArgs) + ")"
+
+let deviceDefinition_to_string (device:deviceDefinition) =
+ let ((deviceDef),deviceBody) = device
+ let deviceBodyString = "{" + (fold_string_list (deviceBody |> List.map (fun x -> moduleDefinition_to_string x)) " | ") + "}"
+ let str = "module " + (moduleDefinition_to_string deviceDef) + " = " + deviceBodyString
+ str
+
+
+let igNode_to_string (node:ignode) =
+ let (nodeName,nodeSystems,iSettings) = node
+ let str = "node " + nodeName + " { systems = [" + (fold_string_list nodeSystems ";") + "]"
+ match iSettings with
+ | Some(x) -> str + ";" + "inference " + "=" + (Inference_settings.to_string(x)) + "}"
+ | None -> str + "}"
+
+
+
+let igEdge_to_string (edge:igedge) =
+ let edgeNameString edgelist = fold_string_list edgelist "."
+ let priorType_to_string (ptype:igPriorType) =
+ match ptype with
+ | Fixed -> "Fixed"
+ | Normal -> "Truncated"
+ | TruncatedNormal -> "TruncatedNormal"
+ let prior_to_string ((p,ptype):igPrior) =
+ match ptype with
+ | HasPrior(x) -> p + "=" + (priorType_to_string x)
+ | NoPrior -> p
+ let (fromNode,priorlist,toNode) = edge
+ let str = "edge " + (edgeNameString fromNode) + " -> " + "["+
+ (fold_string_list (priorlist |> List.map (fun x-> prior_to_string x)) ";") +
+ "]" + (edgeNameString toNode)
+ str
+
+let igElement_to_string (elem:igraphElement) =
+ match elem with
+ | Node(x) -> igNode_to_string x
+ | Edge(x) -> igEdge_to_string x
+
+let hypothesisSettings_to_string (hypSettings:HypothesisSettings) (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list) =
+ let deviceList = hypSettings.devices
+ let rec device_unroll (dev:string) (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list) =
+ let deviceDefOpt = deviceDefs |> List.tryFind (fun (x,y) -> x=dev)
+ match deviceDefOpt with
+ | Some(a) -> [a]
+ | None ->
+ let modOpt = (moduleDefs |> List.tryFind (fun (x,y) -> x=dev))
+ match modOpt with
+ | Some(a) -> [a]
+ | None ->
+ let devOpt = (devices |> List.tryFind (fun (x,y) -> x=dev ))
+ match devOpt with
+ | Some (devName,devComps) ->
+ let deflist = devComps |> List.map (fun x -> device_unroll x devices deviceDefs moduleDefs)
+ match deflist.Length with
+ | 0 -> []
+ | _ -> deflist |> List.reduce (fun x y -> x@y)
+ | None ->
+ raise (System.ArgumentException("Device in System Directive must be defined."))
+ let mdeflistlist = deviceList |> List.map (fun x -> device_unroll x devices deviceDefs moduleDefs)
+ let mdeflist =
+ match mdeflistlist.Length with
+ | 0 -> []
+ | _ -> mdeflistlist |> List.reduce (fun x y -> x@y)
+ fold_string_list (mdeflist |> List.map (fun x -> "| " + (moduleDefinition_to_string x))) "\n"
+
+
+
+let system_to_string (sys:crnSystem) (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list)=
+ let (sysName,sysRef,crnSettings,hypSettings,crnMods) = sys
+ let sysRef_to_string (sysRef:systemReference) =
+ match sysRef with
+ | System(x) -> x + " with "
+ | NoSystem -> ""
+
+ let str = "system " + sysName + " = { " + (sysRef_to_string sysRef) + "\n" +
+ (crnDirectives_to_string crnSettings) + "\n" +
+ hypothesisSettings_to_string hypSettings devices deviceDefs moduleDefs +
+ (modules_to_string crnSettings.simulation.initial crnMods) + "\n" + "}\n"
+
+ str
+
+let hypothesis_to_crn_program (h:hypothesis) (devicelib:Database.device list)=
+ let (crnSettings,moduleDefs,deviceDefs,systemDefs,igraph) = h
+ let (modules,_) = moduleDefs
+ let moduleDefinitions = modules |> List.map fst
+ let deviceDefinitions = deviceDefs |> List.map fst
+ let str = crnDirectives_to_string crnSettings + "\n" +
+ (modules_to_string crnSettings.simulation.initial moduleDefs) + "\n" +
+ (fold_string_list (deviceDefs |> List.map deviceDefinition_to_string) "\n") + "\n" +
+ (fold_string_list (systemDefs |> List.map (fun x -> system_to_string x devicelib deviceDefinitions moduleDefinitions)) "\n") + "\n" +
+ (fold_string_list (igraph |> List.map igElement_to_string) "\n")
+
+ str
diff --git a/ClassicGEC/ClassicGECDotNet/jsapi.fs b/ClassicGEC/ClassicGECDotNet/jsapi.fs
new file mode 100644
index 0000000..efc873d
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/jsapi.fs
@@ -0,0 +1,68 @@
+[]
+module Microsoft.Research.GEC.JSAPI
+
+open Microsoft.Research.GEC.GECEngine
+
+#if JavaScript
+open WebSharper
+#endif
+
+open Microsoft.Research.CRNEngine
+open Microsoft.Research.CRNEngine.JSAPI
+open FSBOL
+open FSBOL.Component
+open FSBOL.ComponentDefinition
+open FSBOL.Sequence
+open FSBOL.Range
+open FSBOL.Location
+open FSBOL.SequenceAnnotation
+open FSBOL.FunctionalComponent
+open FSBOL.Interaction
+open FSBOL.ModuleDefinition
+open FSBOL.Participation
+open FSBOL.TopLevel
+open FSBOL.SBOLDocument
+open FSBOL.JsonSerializer
+
+
+type ClassicResult = { solution : t
+ ; solutionCount: int
+ ; model : GuiIG
+ ; jsbol : rSBOLDocument
+ ; sbol : SBOLDocument }
+
+type LogicResult = { solution : t
+ ; solutionCount: int
+ ; model : GuiIG
+ ; jsbol : rSBOLDocument
+ ; sbol : SBOLDocument }
+
+type solve_result = ClassicGEC of ClassicResult | LogicGEC of LogicResult
+
+let compile (program:string) (dbParts:string) (dbReactions:string) : solve_result =
+ let output = GECEngine.solveGEC (ref false) program dbParts dbReactions
+ let graph = GuiIG.from_ig output.graph
+ let jsbol = JsonSerializer.sbolToJson output.sbol
+ let scount =
+ match output.solution.solution with
+ | Some(_,sol,_,_,_) -> sol.numSolutions
+ | None -> failwith "Output of solution is null"
+ ClassicGEC { model = graph; solution = output.solution; solutionCount= scount; jsbol = jsbol; sbol = output.sbol }
+
+type solution_result = { model : GuiIG
+ ; jsbol : rSBOLDocument
+ ; sbol : SBOLDocument
+ ; crnstring : string}
+
+let get_solution (so:solve_result) (i:int) : solution_result =
+ match so with
+ | ClassicGEC o ->
+ let model = o.model.to_ig()
+
+ //let model = o.model.nodes |> Map.toSeq |> Seq.head |> snd
+ //let gmodel = model.to_model()
+ let result = GECEngine.getCrnAssignment model o.solution (i-1)
+ let model = GuiIG.from_ig result.model
+ let jsbol = JsonSerializer.sbolToJson result.sbol
+ { model = model ; jsbol = jsbol ; sbol = result.sbol ; crnstring = result.model.to_string()}
+ | LogicGEC o -> failwith "Logic GEC solution selection not implemented yet."
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/keywords.fs b/ClassicGEC/ClassicGECDotNet/keywords.fs
new file mode 100644
index 0000000..85fd2cf
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/keywords.fs
@@ -0,0 +1,18 @@
+[]
+module Microsoft.Research.GEC.Keywords
+
+let kwList = [
+ "module";
+ "prom";
+ "rbs";
+ "pcr";
+ "ter";
+ "pos";
+ "con";
+ "initPop";
+ "directive";
+ "rate";
+ "codes";
+ "new";
+ "system";
+ "template"]
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/logicGEC.fs b/ClassicGEC/ClassicGECDotNet/logicGEC.fs
new file mode 100644
index 0000000..c1d0c0d
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/logicGEC.fs
@@ -0,0 +1,911 @@
+[]
+module Microsoft.Research.GEC.LogicGEC
+
+open RulesDSD.Syntax
+open RulesDSD.Substitution
+open RulesDSD.Resolution
+open Microsoft.Research.CRNEngine
+open Parser
+
+// variable, wildcard or identifier parser
+let pname = (name .>> spaces) <|> kw "_"
+let noTypePart = "%NoTypePart"
+
+
+type Element = Part of Part // e.g. r0040::prom
+ | Var of Var // X
+ with static member wildcard = Var (-1, "_")
+ static member doParse domainKeywords postParsingDisambigation idProvider : Parser.t =
+ Parser.plookAheadWith (pname >>= fun str ->
+ if domainKeywords |> List.contains str
+ then preturn None
+ else choice [ kw "(" >>. preturn None
+ kw "[" >>. preturn None
+ kw "[[" >>. preturn None
+ kw "::" >>. preturn (Some true)
+ preturn (if str = "_" || System.Char.IsUpper (str.Chars 0) then Some false else Some true) ])
+ >>= fun isPart ->
+ match isPart with
+ | None -> failParser ""
+ | Some isConcrete -> if isConcrete
+ then Part.doParse idProvider domainKeywords postParsingDisambigation |>> Element.Part
+ else pname |>> fun x -> Element.Var (idProvider x)
+ static member parse domainKeywords idProvider = Element.doParse idProvider false domainKeywords
+ static member ToString e =
+ match e with
+ | Element.Var v -> printVar v
+ | Element.Part p -> Part.ToString p
+and Part = { name : Term // either a variable or a string. CS: I set Element as parametric value just to make unification and resolution more uniform
+ ; type_ : Term } // either a variable or a string
+ with static member Create (name : Term, type_ : Term) = { name = name; type_ = type_ }
+ static member CreateByName (name:string) = Part.Create(Term.Const name, Term.wildcard)
+ static member CreateByType (type_:string) = Part.Create(Term.wildcard, Term.Const type_)
+ static member doParse idProvider domainKeywords postParsingDisambiguation : Parser.t =
+ Parser.plookAheadWith (pname >>= fun str ->
+ if domainKeywords |> List.contains str
+ then preturn None
+ else choice [ kw "(" >>. preturn None
+ kw "[" >>. preturn None
+ kw "[[" >>. preturn None
+ kw "::" >>. preturn (Some true)
+ preturn (Some false)])
+ >>= fun isPart ->
+ match isPart with
+ | None -> failParser ""
+ | Some isConcrete ->
+ let toTerm (s) : Term =
+ if s = "_" then Term.wildcard
+ elif System.Char.IsUpper (s.Chars 0)
+ then idProvider s |> Term.Var
+ else Term.Const s
+ // let pterm = RulesDSD.Parser.pterm (Element.parse domainKeywords idProvider) idProvider domainKeywords
+
+ pname >>= fun partName ->
+ let nameTerm = toTerm partName
+ if isConcrete
+ then kw "::" >>. pname >>= fun partType ->
+ let typeTerm = toTerm partType
+ preturn (Part.Create(nameTerm, typeTerm) )
+ else preturn (Part.Create(nameTerm, if postParsingDisambiguation then Term.Const noTypePart
+ else Term.wildcard))
+ static member parse idProvider domainKeywords : Parser.t = Part.doParse idProvider domainKeywords false
+ static member ToString p = // TODO: add cle
+ let stringTerm t =
+ match t with
+ | Term.Const x -> x
+ | _ -> Term.ToString t
+ stringTerm p.name + "::" + stringTerm p.type_
+type Engine = RulesDSD.Syntax.CLE
+type Semantics = RulesDSD.Syntax.RulesProgram
+
+// find all concrete parts mentioned in the semantics (concrete meaning no open Prolog variable, each term is ground)
+let getParts (s:Semantics) : Part list =
+ s.Values
+ |> Seq.collect(Set.toList >> List.collect Clause.Species >> List.distinct)
+ |> Seq.distinct
+ |> Seq.choose (fun e ->
+ match e with
+ | Element.Part p -> match p.name, p.type_ with
+ | Term.Var _, _
+ | _, Term.Var _ -> None
+ | _ -> Some p
+ | Element.Var _ -> None)
+ |> Seq.toList
+
+
+let PREDEFINED_PART_TYPE_NAMES = ["ter"; "prom"; "rbs"; "pcr"; "cds"]
+let PREDEFINED_PART_TYPES : Term list = PREDEFINED_PART_TYPE_NAMES |> List.map Term.Const
+
+type Rate = Term
+type Complex = Element Mset
+let toComplex x : Complex = [1, x]
+let mapComplex (f:Element -> Element) (c:Complex) : Complex =
+ // let g = Process.Map f
+ let g = Term.Map f
+ c |> List.map (fun (i, t) -> i, t |> Term.Map f) // |> Term.Map g)
+
+
+let termToDevice cle t : Element list =
+ let err x = failwithf "Unexpected term %s is not a device (a list of parts )." (Term.ToStringWith cle x)
+ match t with
+ | Term.Proc p -> match Process.ToList p with
+ | [x] -> x
+ | _ -> err t
+ | _ -> err t
+
+
+type Instruction = Device of Element list
+ | Constraint of Literal
+ | Reaction of Complex option * Complex * Complex * Rate * Rate option // cata, react, prod, rate, bw rate
+ | Initial of Term * Complex // concentration, molecule
+ with
+ static member Map (f:Element -> Element) i =
+ match i with
+ | Device d -> d |> List.map f |> Device
+ | Constraint c -> c |> Literal.Map (Term.Map f) |> Constraint
+ | Reaction (a,b,c,d,e) -> let g = mapComplex f
+ let h = Rate.Map f
+ Reaction (a |> Option.map g, g b, g c, h d, Option.map h e)
+ | Initial (pop, t) -> Initial ((pop |> Term.Map f), mapComplex f t)
+ static member Species i : Element list =
+ let f = List.collect (snd >> Term.Species)
+ match i with
+ | Device d -> d
+ | Constraint c -> Literal.Species c
+ | Reaction (a,b,c,d,e) -> let s1 = a |> Option.toList |> List.collect f
+ let s2 = f b
+ let s3 = f c
+
+ let s4 = d |> Term.Species
+ let s5 = e |> Option.toList |> List.collect Term.Species
+ s1 @ s2 @ s3 @ s4 @ s5 |> List.distinct
+
+ | Initial (pop, t) -> (Term.Species pop @ f t) |> List.distinct
+ static member Apply (cle:CLE) (Sub s:Substitution) i =
+ match i with
+ | Device d -> Device (d |> List.map (fun x -> cle.applySub s x))
+ | Constraint c -> Constraint (c |> applyL cle (Sub s))
+ | Reaction (a,b,c,d,e) -> failwith "Reactions not supported yet"
+ | Initial (pop, t) -> let pop' = Substitution.Apply(Sub s, pop, cle)
+ let t' = t |> List.map (fun (i,x) -> i, Substitution.Apply(Sub s, x, cle))
+ Initial (pop', t')
+ static member ToString (cle:CLE) i : string =
+ let printDevice d = d |> List.map Element.ToString |> String.concat " " |> sprintf "<%s>"
+ match i with
+ | Instruction.Device d -> printDevice d
+ | Instruction.Constraint c -> Literal.ToStringWith cle c
+ | Reaction (a,b,c,d,e) -> failwith "Reactions not supported yet"
+ | Initial (pop, t) -> sprintf "%s %s" (Term.ToStringWith cle pop) (Term.ToStringWith cle (TMSet t))
+
+ static member GetParts (i:Instruction) =
+ let f e = match e with
+ | Element.Part p -> match p.name, p.type_ with
+ | Term.Var _, _
+ | _, Term.Var _ -> None
+ | _ -> Some p
+ | Element.Var _ -> None
+
+ match i with
+ | Device d -> d |> List.choose f
+ | Constraint c -> c |> Literal.Species |> List.choose f
+ | Initial (c, i) -> let x = c |> Term.Species |> List.choose f
+ let y = i |> List.collect (snd >> Term.Species >> List.choose f)
+ x @ y
+ | Reaction _ -> failwith "Reactions are not supported yet"
+ |> List.distinct
+
+// Disambiguation step:
+// if X is both a term var and an element var, turn Term.Var X into Term.Pattern [Pattern.Inner [Element.Var X, Locatiom.wildcard]]
+// create var to assignments map
+let rec updateMap (m:Map option * bool * bool>) // what has v been used for so far? As a term, a part, a part name (store the part type if so, so that var and part type can reconstruvct the full type), a part type, a location?
+ (v:Var)
+ (arg:Choice, unit, unit>) = // what is v being used for?
+ if m.ContainsKey v
+ then m.Add (v, (match m.[v] with
+ (a,b,c,d,e) ->
+ match arg with
+ | Choice1Of5 _ -> (true,b,c,d,e)
+ | Choice2Of5 _ -> (a,true,c,d,e)
+ | Choice3Of5 t ->
+ // TODO: check if c or t are Term.wildcard
+ (a,b,Some t,d,e)
+ | Choice4Of5 _ -> (a,b,c,true,e)
+ | Choice5Of5 _ -> (a,b,c,d,true) ))
+ else m.Add (v, match arg with
+ | Choice1Of5 _ -> (true,false,None,false,false)
+ | Choice2Of5 _ -> (false,true,None,false,false)
+ | Choice3Of5 t -> (false,false,Some t,false,false)
+ | Choice4Of5 _ -> (false,false,None,true,false)
+ | Choice5Of5 _ -> (false,false,None,false,true)
+ )
+//
+and getMapElement m (e:Element) =
+ match e with
+ | Element.Var v -> updateMap m v (Choice2Of5 ())
+ | Element.Part p ->
+ let m' = match p.name with
+ | Term.Var (i,v) -> updateMap m (i, v) (Choice3Of5 p.type_)
+ | _ -> getMapTerm m p.name
+ match p.type_ with
+ | Term.Var (i,v) -> updateMap m' (i, v) (Choice4Of5 ())
+ | _ -> getMapTerm m' p.name
+
+and getMapLocation m l =
+ match l with
+ | Location.Var (x, y) -> let v = (x,y) in updateMap m v (Choice5Of5 ())
+ | Location.Loc _ -> m
+
+and getMapHole m (s:Element, l:Location) = getMapLocation (getMapElement m s) l
+
+and getMapPattern m =
+ function
+ | Pattern.Inner hs -> hs |> List.fold getMapHole m
+ | Pattern.Nihil -> m
+ | Pattern.FivePrime hs -> hs |> List.fold getMapHole m
+ | Pattern.ThreePrime hs -> hs |> List.fold getMapHole m
+ | Pattern.Nicking(hs1, hs2) -> let m' = hs1 |> List.fold getMapHole m
+ hs2 |> List.fold getMapHole m'
+ | Pattern.Strand hs -> hs |> List.fold getMapHole m
+
+and getMapProcess m =
+ function
+ | Process.Proc strandsMap -> strandsMap
+ |> Map.toList
+ |> List.map snd
+ |> List.fold (fun acc s -> s |> List.fold getMapElement acc) m
+and getMapComplex m (c:Complex) =
+ c |> List.fold (fun acc x -> getMapTerm acc (snd x)) m
+and getMapTerm m =
+ function
+ | Term.Var (x, y) -> updateMap m (x, y) (Choice1Of5 ())
+ | Term.Const _
+ | Term.Float _ -> m
+ | Func (_, ts)
+ | TList ts -> ts |> List.fold getMapTerm m
+ | TCons (t1, t2) -> let m' = getMapTerm m t1
+ getMapTerm m' t2
+ | Proc p -> getMapProcess m p
+ | Pat p -> getMapPattern m p
+ | Term.TMSet ts -> ts |> List.fold (fun acc (_,v) -> getMapTerm acc v) m
+ | Term.TCRN ts -> ts |> List.fold getMapTerm m
+
+and getMapPredicate m = function
+ | Predicate.Pred(_, args) -> args |> List.fold getMapTerm m
+
+and getMapLit m = function
+ | Pos p -> getMapPredicate m p
+ | Neg p -> getMapPredicate m p
+
+(*
+let zzz (cle:Engine) m xmap xapply =
+ m
+ |>
+ Map.fold (fun x varName assignments ->
+ // disambiguate each variable
+ if varName = (-1, "_")
+ then x // skip wildcards
+ else
+ match assignments with
+ // skip unambiguous variables
+ | false, false, None, false, false
+ | true, false, None, false, false
+ | false, true, None, false, false
+ | false, false, Some _, false, false
+ | false, false, None, true, false
+ | false, false, None, false, true -> x
+ | _(*hasTVar*), hasEVar, nameVar, hasTypeVar, hasLocVar ->
+ let hasNameVar = Option.isSome nameVar
+ let p' = match nameVar with
+ | Some ty -> { name = Term.Var varName; type_ = ty }
+ | None -> { name = Term.wildcard; type_ = Term.Var varName }
+ if hasLocVar
+ then
+ if hasEVar || hasNameVar || hasTypeVar
+ then failwith <| sprintf "Cannot unify location variable \"%s\" with a %s variable" (snd varName)
+ (if hasTypeVar then "part type"
+ elif hasNameVar then "part name"
+ else "part")
+ else // must be TVar too
+ let pattern = Term.Pat <| Pattern.Inner [Element.Var (-1,"_"), Location.Var varName]
+ let sub = Substitution.Create(varName, pattern).Add(varName, Choice2Of4 <| Location.Var varName, cle)
+ xapply x sub
+ // disambiguate variable
+ elif hasNameVar || hasTypeVar
+ then
+ if hasEVar
+ then
+ // Consider this example: P = C[X], P = [X::Y]
+ // Disambiguation interprets X in the first term a part with name X and type Y
+ x
+ |> xmap (fun t ->
+ t
+ |> Term.Map (fun e ->
+ match e with
+ | Element.Var (x,y) -> if (x,y) = varName then Part p' else e
+ | Element.Part p'' -> Part <| if hasNameVar && p''.name = p'.name then p' else p''
+ ))
+ else x // if it's a TVar, nothing to do
+ else // not a LocVar, NameVar or TypeVar: must be a TVar and EVar
+ let rec f (term:Term) =
+ match term with
+ | Term.Var (x,y) -> if (x,y) = varName
+ then Term.Pat <| Pattern.Inner [Part p', Location.wildcard]
+ else term
+ | Term.Const _
+ | Term.Float _
+ | Term.Pat _
+ | Term.Proc _ -> term
+ | Term.Func (n, ts) -> Term.Func (n, ts |> List.map f)
+ | Term.TCons (t1, t2) -> Term.TCons (f t1, f t2)
+ | Term.TList ts -> Term.TList (ts |> List.map f)
+ | Term.TCRN ts -> Term.TCRN (ts |> List.map f)
+ | Term.TMSet ts -> Term.TMSet (ts |> List.map (fun (i, x) -> i, f x))
+ x |> xmap f
+ )
+*)
+
+///////////////////////////////////
+// Logic GEC Custom Logic Engine //
+///////////////////////////////////
+and fvPart (p:Part) =
+ [p.name; p.type_]
+ |> List.map (fvt cle)
+ |> Set.unionMany
+
+and fvElement (e:Element) =
+ let rec fv t =
+ match t with
+ | Term.Var (-1, "_") -> Set.empty
+ | Term.Var (x,y) -> Set.singleton (TVar (x,y))
+ | Term.Const _ -> Set.empty
+ | Term.Float _ -> Set.empty
+ | Term.Func (_, ts) -> ts |> unionFold fv
+ | Term.TList ts -> ts |> unionFold fv
+ | Term.TCons (t,t') -> [t;t'] |> unionFold fv
+ | Term.Pat _ -> Set.empty // p |> fvPattern cle
+ | Term.Proc _ -> Set.empty // TODO
+ | Term.TCRN ts -> ts |> unionFold fv
+ | Term.TMSet ts -> ts |> List.map snd |> unionFold fv
+ match e with
+ | Part p -> fvPart p
+ | Var x -> if x = (-1, "_") then Set.empty else Set.singleton (SVar (x, e))
+
+and elemToString (x : Element) : string =
+ let toString t = match t with
+ | Term.Const x -> x
+ | _ -> Term.ToStringWith cle t
+ match x with
+ | Part p -> let typ = match p.type_ with
+ | Term.Var (-1, "_") -> ""
+ | _ -> " : " + toString p.type_
+ toString p.name // + typ
+ | Var (_, y) -> y
+
+and elemCompare (x:Element) (y:Element) =
+ match x, y with
+ | Part _, Var _ -> RulesDSD.Syntax.LT
+ | Var _, Part _ -> RulesDSD.Syntax.GT
+ | Part p1, Part p2 -> Term.Compare cle p1.name p2.name
+ | Var (v1, _), Var (v2, _) -> compare v1 v2
+
+and elemCanonicalForm (x:Element) = x
+
+and elemUnderscore () = Var (-1, "_")
+
+and elemRefresh (idProvider : string -> int) e =
+ match e with
+ | Part p ->
+ let refresher = Term.refresh cle idProvider
+ let n = refresher p.name
+ let t = refresher p.type_
+
+ Part (Part.Create(n, t))
+ | Var (_, y) -> Var (idProvider y, y)
+
+and unimplemented _ = failwith ""
+
+and deviceComposition p q = Process.ToList p @ Process.ToList q |> Process.OfList
+
+and elemResolveGoal (p, args) _ =
+ match (p, args) with
+ | _ -> None
+
+
+and elemDisambiguateVarsWith m (c:Clause) : Clause =
+ // TODO: is this still necessary?
+
+ // remove "noTypePart" types from parts (in patterns and processes)
+ let g(e:Element) =
+ match e with
+ | Element.Var _ -> e
+ | Element.Part p -> if p.type_ = Term.Const noTypePart
+ then { p with type_ = Term.wildcard }
+ else p
+ |> Element.Part
+
+ // turn all other "noTypePart" parts into (Term.Const part.name)
+ let rec f (e:Term) =
+ match e with
+ | Term.Pat (Pattern.Inner [Element.Part ({ name = n; type_ = Term.Const "%NoTypePart"}), Location.Var (-1, "_")]) -> n
+ | Term.Float _
+ | Term.Const _
+ | Term.Var _ -> e
+ | Term.Pat p -> p |> Pattern.Map (fun (x, y) -> g x, y) |> Term.Pat
+ | Term.Proc p -> p |> RulesDSD.Syntax.Process.Map g
+ |> Term.Proc
+ | Term.TList ts -> ts |> List.map f |> Term.TList
+ | Term.TCons (t1, t2) -> Term.TCons (f t1, f t2)
+ | Term.TCRN ts -> ts |> List.map f |> Term.TCRN
+ | Term.TMSet ts -> ts |> List.map (fun (i, t) -> i, f t) |> Term.TMSet
+ | Term.Func (n, ts) -> Term.Func (n, ts |> List.map f)
+
+ let c' = c |> Clause.Map f
+ match c'.head with
+ | Pred (_, lits) ->
+ // collect how each variable is used
+ c'.body
+ |> List.fold getMapLit (lits |> List.fold getMapTerm Map.empty)
+ // m
+ |> Map.fold (fun (clause:Clause) varName assignments ->
+ // disambiguate each variable
+ if varName = (-1, "_")
+ then clause // skip wildcards
+ else
+ match assignments with
+ // skip unambiguous variables
+ | false, false, None, false, false
+ | true, false, None, false, false
+ | false, true, None, false, false
+ | false, false, Some _, false, false
+ | false, false, None, true, false
+ | false, false, None, false, true -> clause
+ | _(*hasTVar*), hasEVar, nameVar, hasTypeVar, hasLocVar ->
+ let hasNameVar = Option.isSome nameVar
+ let p' = match nameVar with
+ | Some ty -> { name = Term.Var varName; type_ = ty }
+ | None -> { name = Term.wildcard; type_ = Term.Var varName }
+ if hasLocVar
+ then
+ if hasEVar || hasNameVar || hasTypeVar
+ then failwith <| sprintf "Cannot unify location variable \"%s\" with a %s variable" (snd varName)
+ (if hasTypeVar then "part type"
+ elif hasNameVar then "part name"
+ else "part")
+ else // must be TVar too
+ let pattern = Term.Pat <| Pattern.Inner [Element.Var (-1,"_"), Location.Var varName]
+ let sub = Substitution.Create(varName, pattern).Add(varName, Choice2Of4 <| Location.Var varName, cle)
+ sub.Apply(clause,cle)
+ // disambiguate variable
+ elif hasNameVar || hasTypeVar
+ then
+ if hasEVar
+ then
+ // Consider this example: P = C[X], P = [X::Y]
+ // Disambiguation interprets X in the first term a part with name X and type Y
+ clause
+ |> Clause.Map (fun t ->
+ t
+ |> Term.Map (fun e ->
+ match e with
+ | Element.Var (x,y) -> if (x,y) = varName then Part p' else e
+ | Element.Part p'' -> Part <| if hasNameVar && p''.name = p'.name then p' else p''
+ ))
+ else clause // if it's a TVar, nothing to do
+ else // not a LocVar, NameVar or TypeVar: must be a TVar and EVar
+ let rec f (term:Term) =
+ match term with
+ | Term.Var (x,y) -> if (x,y) = varName
+ then Term.Pat <| Pattern.Inner [Part p', Location.wildcard]
+ else term
+ | Term.Const _
+ | Term.Float _
+ | Term.Pat _
+ | Term.Proc _ -> term
+ | Term.Func (n, ts) -> Term.Func (n, ts |> List.map f)
+ | Term.TCons (t1, t2) -> Term.TCons (f t1, f t2)
+ | Term.TList ts -> Term.TList (ts |> List.map f)
+ | Term.TCRN ts -> Term.TCRN (ts |> List.map f)
+ | Term.TMSet ts -> Term.TMSet (ts |> List.map (fun (i, x) -> i, f x))
+ clause |> Clause.Map f
+ ) c'
+ //) c
+
+and elemDisambiguateVars (c:Clause) : Clause =
+ let m = match c.head with Pred (_, lits) -> c.body |> List.fold getMapLit (lits |> List.fold getMapTerm Map.empty)
+ elemDisambiguateVarsWith m c
+
+and elemApplySub (theta:Sub) (e:Element) : Element =
+ match e with
+ | Var (-1, "_") -> e
+ | Var v -> if theta.ContainsKey v
+ then match theta.[v] with
+ | Choice1Of4 _ -> failwith ""
+ | Choice2Of4 _ -> failwith ""
+ | Choice3Of4 x -> x
+ | Choice4Of4 _ -> failwith ""
+ else e
+ | Part p -> let applier (x:Term) = Substitution.Apply(Sub theta, x, cle)
+ let n = applier p.name
+ let t = applier p.type_
+ Part (Part.Create(n, t))
+
+and elemApplyAll (theta:Sub) (x:Choice) =
+ match x with
+ | Choice1Of2 e -> elemApplySub theta e
+ | Choice2Of2 () -> failwith ""
+
+and elemUnify (x:Element, y:Element) : Sub list =
+ match x, y with
+ | Part p, Var x
+ | Var x, Part p -> [Map.ofList [x, Choice3Of4 <| Part p]]
+ | Var x, Var y -> [Map.ofList [y, Choice3Of4 <| Var x]]
+ | Part p1, Part p2 ->
+ let eq1 = RulesDSD.Unification.TEq (p1.name, p2.name)
+ let eq2 = RulesDSD.Unification.TEq (p1.type_, p2.type_)
+ let eqs = [eq1; eq2]
+ RulesDSD.Unification.unify cle eqs
+
+ |> List.map (fun (Sub x) -> x)
+
+and cle : Engine =
+ { toString = elemToString // print 's
+ toStringTempVar = unimplemented // print 'a
+ compare = elemCompare // compare two 's, used for sorting; the actual ordering is unimportant, as long as it is a partial order
+ cast = unimplemented // cast a 'a into a 's (e.g. a bond X can be cast into a site _!X); used in substitutions
+ toCanonicalForm = elemCanonicalForm // find the canonical form of 's
+ toCanonicalFormProcess = id // find the canonical form of a process. Since species 's might reference each other (e.g. as in bonds), it is necessary to have a Process level canonical form function
+ unify = elemUnify // species unification. The core algorithm that finds a 's and 'a variable substitution such that two species are equivalent after applying it
+ underscore = elemUnderscore // wildcard "_" for 's
+ applyAll = elemApplyAll // apply a substitution to a species or subspecies
+ applySub = elemApplySub // apply a species substitution
+ applySubVar = unimplemented // apply a substitution to a subspecies
+ fvs = fvElement // free variables in 's
+ refresh = elemRefresh // provide a copy of 's where variables have been renamed by an ID provider. Used in resolution
+ disambiguateVars = elemDisambiguateVars // post-parsing step applied to each parsed clause. In Logic DSD this is used to disambiguate the use of domain variables (e.g. in P = C[D][D!i], D can be cast down to an unbound domain rather than a generic site)
+ ComposeProcesses = deviceComposition // compose two processes together (possibly forming a complex in Logic DSD)
+ resolveGoal = elemResolveGoal // species-specific predicates resolution. The core resolution algorithm that executes custom predicates for species (e.g. "compl(D, E)" is a custom predicate in Logic DSD to find the complement E of a domain D)
+ domainKeywords = [] }
+
+
+// free variables
+let fvi (i:Instruction) =
+ let rec fvElement (e:Element) =
+ match e with
+ | Element.Part p ->
+ let f x = fvt cle x
+ Set.union (f p.name) (f p.type_)
+ | Element.Var v -> Set.singleton (Variable.SVar (v, e))
+
+ let rec fvComplex (c:Complex) =
+ c |> List.fold (fun acc (_, tp) ->
+ let t = tp |> Term.Species // |> List.collect (Process.ToList >> List.concat) |> List.distinct
+ Set.union acc (Set.unionMany (t |> List.map fvElement))) Set.empty
+
+ match i with
+ | Device d -> d |> List.map fvElement |> List.fold (Set.union) Set.empty
+ | Constraint c -> fvl cle c
+ | Initial (n,c) -> Set.union (fvt cle n) (fvComplex c)
+ | Reaction(a,b,c,d,e) ->
+ let av = a |> Option.toList |> List.map fvComplex
+ let ev = e |> Option.toList |> List.map (fvt cle)
+ let fvs = av @ ([b;c] |> List.map fvComplex) @ [fvt cle d] @ ev
+ Set.unionMany fvs
+
+type Program = Instruction list
+
+let enumerateDeviceSubstitutions (cle:Engine) (db:Semantics) (prog:Program) =
+ let freevars =
+ prog
+ |> List.map fvi
+ |> Set.unionMany
+ let maxVar =
+ freevars
+ |> Set.map (fun x ->
+ match x with
+ | Variable.SVar ((n,_), _)
+ | Variable.IVar ((n,_), _)
+ | Variable.LVar (n,_)
+ | Variable.TVar (n,_) -> n)
+ |> fun s -> if s.IsEmpty then 0 else Set.maxElement s
+ let counter = ref (maxVar + 1)
+
+ let deviceEnumeration d sols =
+ d |> List.fold (fun acc elem ->
+ match acc with
+ | None -> None
+ | Some solutions ->
+ solutions
+ |> List.collect (fun (s:RulesDSD.Substitution.Substitution) ->
+ match elem with
+ | Part part ->
+ // prepare device query
+ let pName = s.Apply(part.name , cle)
+ let pType = s.Apply(part.type_, cle)
+ let qPart = Part { name = pName; type_ = pType }
+ let query = [ Pos (Pred ("part", [Term.Pat (Pattern.Inner [qPart, Location.wildcard]) ])) ]
+
+ // interrogate DB
+ let goal = RulesDSD.Resolution.Goal.Create(query, cle)
+ match RulesDSD.Resolution.resolveInner [goal] cle counter db [] RulesDSD.Resolution.Mode.AllAnswers with
+ | None -> []
+ | Some newSols -> if solutions = [Substitution.id]
+ then newSols
+ else newSols |> List.map (fun s' -> RulesDSD.Substitution.Substitution.Compose s s' cle)
+ | Var v ->
+ // look for any part in the DB
+ let query = [ Pos (Pred ("part", [Term.Pat (Pattern.Inner [Var v, Location.wildcard]) ])) ]
+ let goal = RulesDSD.Resolution.Goal.Create(query, cle)
+ match RulesDSD.Resolution.resolveInner [goal] cle counter db [] RulesDSD.Resolution.Mode.AllAnswers with
+ | None -> []
+ | Some newSols -> if solutions = [Substitution.id]
+ then newSols
+ else newSols |> List.map (fun s' -> RulesDSD.Substitution.Substitution.Compose s s' cle) )
+ |> fun x -> if x.IsEmpty then None else Some (x |> List.distinct)
+ ) (Some sols)
+
+ prog |> List.fold (fun (solutionsSet:RulesDSD.Substitution.Substitution list option) i ->
+ match solutionsSet with
+ | None -> None // some constraint is unsatisfiable; abort enumeration
+ | Some sols ->
+ match i with
+ | Initial (_, [1, Term.Proc p]) -> match p |> Process.ToList with
+ | [d] -> deviceEnumeration d sols
+ | _ -> failwithf "Unexpected multiple devices in initial %s." (Instruction.ToString cle i)
+ | Device d -> deviceEnumeration d sols
+
+ | Constraint c -> let sols' =
+ sols
+ |> List.collect (fun (s:RulesDSD.Substitution.Substitution) ->
+ let c' = s.Apply(c, cle)
+ let g = RulesDSD.Resolution.Goal.Create([c'], cle)
+ match RulesDSD.Resolution.resolveInner [g] cle counter db [] RulesDSD.Resolution.Mode.AllAnswers with
+ | None -> []
+ | Some newSols -> if sols.IsEmpty
+ then newSols
+ else newSols |> List.map (fun s' -> RulesDSD.Substitution.Substitution.Compose s s' cle) )
+ match sols' with
+ | [] -> None
+ | _ -> Some sols'
+
+ | Reaction _ -> solutionsSet // TODO: check that the interaction is in the DB?
+ | Initial _ -> solutionsSet
+ ) (Some [Substitution.id])
+
+let enumerateDevices (cle:Engine) (db:Semantics) (prog:Program) : Program list =
+ let maxVar =
+ prog
+ |> List.map fvi
+ |> Set.unionMany
+ |> Set.map (fun x ->
+ match x with
+ | Variable.SVar ((n,_), _)
+ | Variable.IVar ((n,_), _)
+ | Variable.LVar (n,_)
+ | Variable.TVar (n,_) -> n)
+ |> fun s -> if s.IsEmpty then 0 else Set.maxElement s
+ |> ref
+
+ let fullProgram =
+ prog
+ |> List.map (Instruction.Map (fun e ->
+ match e with
+ | Element.Var _ -> e
+ | Element.Part p -> if p.name = Term.wildcard
+ then
+ let x = !maxVar
+ maxVar := !maxVar + 1
+ let freshVar = Term.Var(x, sprintf "X_%i" x)
+ Element.Part { p with name = freshVar}
+ else e))
+
+
+ let devs =
+ fullProgram
+ |> List.filter (fun i -> match i with
+ | Instruction.Device _ -> true
+ | Instruction.Initial _ -> true
+ | _ -> false)
+
+ match enumerateDeviceSubstitutions cle db fullProgram with
+ | None -> []
+ | Some sols ->
+ sols
+ |> List.map (fun (RulesDSD.Substitution.Substitution.Sub s) ->
+ devs
+ |> List.map (Instruction.Map (cle.applySub s)))
+ |> List.distinct
+
+
+
+(* GEC calculus*)
+let makeGecCalculus (db:Semantics) : Calculus> =
+ // prepare the set of "reaction" predicates to run in the calculus
+
+ // collect all "reactions" signatures
+ // find all reactions predicate
+ let reactionsSigs = seq { for kv in db.Keys do
+ if fst kv = "reactions" then yield kv else () }
+ |> Seq.sortWith (fun (_, x) (_, y) -> compare x y)
+ |> Seq.toList
+ |> Seq.map (fun x -> x, db.Item x)
+
+ { react = fun (oldElements:Term list) (newElement:Term) ->
+ // find all query combos: reactions(CRN), reactions(newElement, CRN), reactions (newElement, oldElem, CRN), reactions (newElement, oldElem1, oldElem2, ..., CRN) ...
+ // run all queries
+ // create new reactions
+ let newProc = newElement |> Term.Canonical cle
+ let oldProcs = oldElements |> List.map (Term.Canonical cle)
+ let rec combo n i : Term list list =
+ if n <= 0
+ then []
+ else let ccombo = if n = i
+ then [[newProc]]
+ else combo (n-1) i
+ if ccombo.IsEmpty
+ then [oldProcs]
+ else
+ oldProcs
+ |> List.collect (fun p ->
+ ccombo
+ |> List.map (fun ps -> p :: ps))
+
+ let queries =
+ reactionsSigs
+ |> Seq.filter (fun ((_, numberOfArguments), _) -> numberOfArguments >= 2 ) // take reactions(E1, ...., En, CRN) predicates
+ |> Seq.collect (fun ((queryName, numberOfArguments), preds) ->
+ match numberOfArguments with
+ | 2 -> preds |> Set.map (fun p -> match p.head.Args with [_; x] -> Pos (Pred(queryName, [newProc; x])) | _ -> failwith "") |> Set.toSeq
+ | n -> let allElementArgs = [1..n-1] |> List.collect (fun i -> combo (n-1) i)
+ preds
+ |> Set.map (fun (p:Clause) -> allElementArgs
+ |> List.map (fun args -> Pos (Pred(queryName, args @ [p.head.Args |> List.last] ))))
+ |> Set.toSeq
+ |> Seq.concat)
+ |> Seq.distinct
+
+ // query the Prolog engine and create CRN reactions if any "reactions()" predicate matched
+ queries
+ |> Seq.choose (fun query ->
+ match RulesDSD.Resolution.resolveAll query db cle with
+ | None -> None
+ | Some sols ->
+ sols
+ |> List.collect (fun theta ->
+ match theta.Apply(query, cle) with
+ | Pos p ->
+ // reactants are already in canonical form by construction
+ match p.Args |> List.last with
+ | Term.TCRN ts -> ts
+ |> List.map (Term.Canonical cle)
+ |> List.collect Term.ToReactions
+ | _ -> let str = query |> Literal.ToStringWith cle
+ failwithf "Error: enumeration predicate %s generated a non-CRN term." str
+ | _ -> failwith "" )
+ |> Some
+ )
+ |> List.concat
+ |> List.distinct
+ |> List.filter (fun r -> r.reactants <> r.products)
+ }
+
+
+///////////////////////////
+///////////////////////////
+//// Parser
+///////////////////////////
+///////////////////////////
+
+let pInstruction (idProvider : string -> RulesDSD.Syntax.Var) =
+ let pElement = Element.doParse cle.domainKeywords true idProvider
+ let pDevice = Parser.between (kw "<") (kw ">") (Parser.many1 pElement)
+ let pDeviceAst = pDevice |>> Instruction.Device
+ let pConstraintAst = RulesDSD.Parser.pliteral cle pElement idProvider cle.domainKeywords |>> Instruction.Constraint
+ let pInitialAst = RulesDSD.Parser.pterm pElement cle idProvider cle.domainKeywords .>>.
+ choice [ pDevice |>> Choice1Of2
+ RulesDSD.Parser.pterm pElement cle idProvider cle.domainKeywords |>> Choice2Of2 ]
+ >>= fun (i, x) ->
+ match x with
+ | Choice1Of2 x -> preturn (Instruction.Initial (i, x |> List.singleton |> Process.OfList |> Term.Proc |> toComplex))
+ | Choice2Of2 x -> preturn (Instruction.Initial (i, x |> toComplex))
+
+
+ Parser.plookAheadWith
+ (choice [
+ // device
+ kw "<" >>. preturn (Choice1Of4 ())
+ // constraint
+ kw "not" >>. pname >>. kw "(" >>. preturn (Choice2Of4 ())
+ pname >>. kw "(" >>. preturn (Choice2Of4 ())
+ // reaction
+ // choice [ pdevice >>. choice [kw "+"; kw "->"; preturn Choice1Of4 ()] // last case is actually a device
+ // kw "->" ] // no reactants reaction
+
+ // initial
+ Expression.parse pname >>. preturn (Choice4Of4 ())
+ ]) >>=
+ fun next ->
+ match next with
+ | Choice1Of4 _ -> pDeviceAst
+ | Choice2Of4 _ -> pConstraintAst
+ | Choice3Of4 _ -> failParser "Reactions not supported yet"
+ | Choice4Of4 _ -> pInitialAst
+
+
+let generateCRN (cle:Engine) (db:Semantics) (prog:Program) =
+ // collect devices, initials and reactions // TODO: merge devices and initials into a single field initials of type (Term * Process)
+ let ps, is, rs =
+ prog |> List.fold (fun (ps, is, rs) instruction ->
+ match instruction with
+ | Constraint _ -> (ps, is, rs) // skip constraints
+ | Reaction (a,b,c,d,e) -> (ps, is, (a,b,c,d,e) :: rs)
+ | Device d -> (Process.OfList [d] :: ps, is, rs)
+ | Initial (a,b) -> if a <> Term.Float 0.0
+ then (ps, (a,b)::is, rs)
+ else (ps, is, rs)) ([], [], [])
+
+ // species namer
+ let default_namer () : (Term -> string) =
+ let cache = new System.Collections.Generic.Dictionary, string>()
+ let names = new System.Collections.Generic.HashSet()
+ let namer species : string =
+ let sp = species |> Term.Canonical cle
+ if cache.ContainsKey sp then
+ cache.Item sp
+ else
+ let mutable unique_name = ""
+ let mutable c = names.Count + 1
+ while unique_name = "" do
+ if not (names.Contains ("sp" + string c)) then
+ unique_name <- "sp" + string c
+ else c <- c + 1
+ let name = unique_name
+
+ cache.Add(sp, name)
+ ignore(names.Add(name))
+ name
+ namer
+ let namer = default_namer ()
+
+
+ // prepare initials and reactions for CRN enumeration
+ // TODO: get the initial concentration from the core GEC program after merging process and initials
+ let inits = (is |> List.map (fun (n, i) -> let t = match i with
+ | [1, x] -> x
+ | _ -> Term.TMSet i
+ let c : Value =
+ match n with
+ | Term.Float x -> Expression.Float x
+ | Term.Const x -> Expression.Key x
+ | Term.Var (_, x) -> Expression.Key x
+ | _ -> failwithf "Initial condition %s must be a float, const or a variable." (Term.ToStringWith cle n)
+ c, t))
+ @ (ps |> List.map (fun p -> Expression.Float 1.0, p |> Term.Proc))
+ |> List.map Initial.create
+
+ let toMSet (x:Complex) : Microsoft.Research.CRNEngine.Mset.t> =
+ x |> List.map (fun (i, sp) -> { Microsoft.Research.CRNEngine.Mset.element = sp
+ ; Microsoft.Research.CRNEngine.Mset.multiplicity = i})
+ let reacts = rs |> List.choose ( fun (catalysts,reactants,products,fwRate,bwRate) ->
+ let r = reactants |> toMSet
+ let p = products |> toMSet
+ match Term.ToRate fwRate with
+ | None -> None
+ | Some fr ->
+ let br = match bwRate with
+ | None -> None
+ | Some b -> Term.ToRate b
+ match catalysts with
+ | None -> Reaction.create([], r, br, fr, p) |> Some
+ | Some c -> Reaction.create(c |> toMSet, r, br, fr, p) |> Some )
+
+ // expand the GEC program into a CRN using the GEC calculus
+ let equalsSpecies p q = Term.Compare cle (p |> Term.Canonical cle) (q|> Term.Canonical cle) = EQ
+ let plotMatcher p q = Term.Compare cle p q = EQ
+ let gecCalculus = makeGecCalculus db
+
+ let gecRenderer (s:Term) : Attributes =
+ { name = namer s
+ ; structure = Term.ToStringWith cle s
+ ; svg = "" }
+
+
+
+ let crn = Crn.from_calculus_translated
+ (fun p -> namer p |> Species.create)
+ gecRenderer
+ equalsSpecies
+ plotMatcher
+ (fun sp -> (fvt cle sp).IsEmpty)
+ ""
+ Microsoft.Research.CRNEngine.Crn_settings.defaults
+ gecCalculus
+ inits
+ reacts
+ false
+ true
+ true
+ |> Crn.group_reactions
+
+ crn
+
+let pGecProgram : Parser.t = RulesDSD.Parser.pprogram cle (Element.doParse cle.domainKeywords true)
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/main.fs b/ClassicGEC/ClassicGECDotNet/main.fs
new file mode 100644
index 0000000..79c9262
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/main.fs
@@ -0,0 +1,140 @@
+(*
+Provides top-level access to LSB translation. Functions in this module
+will invoke the LSB compiler, invoke the Prolog engine and parse the results
+in to an appropriate .NET data structure.
+
+Author: Michael Pedersen.
+Copyright Microsoft Research, 2008-2009.
+*)
+
+[]
+module Microsoft.Research.GEC.Main
+
+open Microsoft.Research.GEC.Ast
+open Microsoft.Research.GEC.Trans
+open Microsoft.Research.CRNEngine
+open Microsoft.Research.GEC.DirectivesParser
+
+open Parser
+//open Microsoft.FSharp.Compatibility.OCaml
+//open Microsoft.Research.ModellingEngine
+open System.IO
+open Printf
+
+
+
+// make LBS rate definition strings
+let mkSingleLBSRateDef (r,f) = "rate " + r + " = " + (Lib.display_float f) + ";"
+let mkLBSRateDefs rateDecs =
+ (Lib.string_of_list mkSingleLBSRateDef Lib.newline (expandRateDecs rateDecs)) + Lib.newline
+
+// produce a string representation of an assignment...
+let stringOfAss (xs:(string * string) list) =
+ Lib.brack (Lib.string_of_list (fun (x,y) -> Lib.paren(Lib.quote x + ", " + Lib.quote y)) "; " xs)
+
+/// Input position range, this will likely be replaced by something from FParsec
+type pos = {l1 : int; c1 : int; l2 : int; c2 : int}
+
+// a solution type for passing back to a C# client:
+type tSolution =
+ {
+ bbDevices : tBbDevices;
+ lbsProgram : tLBSProg;
+ rateDecs : tRateDecs;
+
+ // variable assignments represent solutions to constraints:
+ varAss : ((string * string) list * (string * string) list * (string * string) list) list;
+ substs : Subst.t list;
+
+ // an error option for reporting errors:
+ error : (string * pos option) option;
+
+ // the number of solutions to constraints:
+ numSolutions : int;
+ }
+
+ // get a specific instance of the device of a solution:
+ member v.getDevicesInstance(num) =
+ let devices = v.bbDevices
+ let (subst,_,_) = List.item num v.varAss
+ //let devices' = devices |> List.map (fun device -> device |> List.map (fun var -> if (List.mem_assoc var subst) then List.assoc var subst else var))
+ let devices' = devices |> List.map (fun device -> device |> List.map (fun var -> match Lib.try_assoc var subst with | Some x -> x | None -> var))
+ Lib.brack (Lib.string_of_list (fun xs -> Lib.brack(Lib.string_of_list Lib.id "; " xs)) ";\r " devices')
+
+ // get a specific instance of the device of a solution as a string list list:
+ member v.getDevicesInstanceStructured(num) =
+ let devices = v.bbDevices
+ let (subst,_,_) = List.item num v.varAss
+ let devices' = devices |> List.map (fun device -> device |> List.map (fun var -> match Lib.try_assoc var subst with | Some x -> x | None -> var))
+ let devicesArray = List.toArray(List.map (fun lst -> List.toArray(lst)) devices' )
+ devicesArray
+
+ // get a specific instance of the program of a solution:
+ member v.getProgramInstance(num) =
+ let prog = v.lbsProgram
+ let (_,substSpec,substRates) = List.item num v.varAss
+ let lbsProgStr = lbsProgToStr prog (substSpec@substRates)
+ (mkLBSRateDefs v.rateDecs) + lbsProgStr
+ // add a default declaration for mrna degradation:
+ //let mrnaDegRate = "rate RMRNADeg = " + (Lib.display_float default_RMRNADeg) + ";\n"
+ //mrnaDegRate + lbsProgStr
+
+ // get the program instance with declared rates assigned:
+ member v.getProgramDefault() =
+ //let lbsProgStr = lbsProgToStr v.lbsProgram v.rateDecs
+ //lbsProgStr
+ let lbsProgStr = lbsProgToStr v.lbsProgram []
+ (mkLBSRateDefs v.rateDecs) + lbsProgStr
+
+ // get a specific instance of a species assignment:
+ member v.getSpecAss(num) =
+ let (l1, specVarAss, l3) = List.item num v.varAss
+ stringOfAss specVarAss
+
+ // get a specific instance of a species assignment:
+ member v.getRateAss(num) =
+ let (_, _, rateVars) = List.item num v.varAss
+ stringOfAss rateVars
+
+ member v.getVarAssString() =
+ Lib.brack (Lib.string_of_list (fun (xs,ys,zs) -> Lib.paren (stringOfAss xs + ", " + stringOfAss ys + "; " + stringOfAss zs )) ",\r " v.varAss)
+
+// define an empty solution:
+let emptySolution = { bbDevices = [];
+ lbsProgram = LBSNil
+ rateDecs = [];
+ varAss = [];
+ substs = [];
+ error = None;
+ numSolutions = 0; }
+
+(*
+#if JavaScript
+let Lexing_from_string = Microsoft.FSharp.Text.Lexing.LexBuffer<_>.FromString
+#else
+let Lexing_from_string = Lexing.from_string
+#endif
+
+(* Parse the LSB program from the given string. *)
+let parse (text:string) =
+ let prog =
+ // Create the lexer, presenting the bytes to the lexer as ASCII regardless of the original
+ // encoding of the string (the lexer specification is designed to consume ASCII)
+ let lexbuf = Lexing_from_string text
+
+ // Call the parser
+ try
+ let prog = GEC.Pars.start Lex.token lexbuf
+ prog
+
+ with e ->
+ let bufPos1 = lexbuf.StartPos
+ let bufPos2 = lexbuf.EndPos
+ let pos = (bufPos1, bufPos2)
+ let err = "Parse error near line " + bufPos1.Line.ToString() + ", character " + bufPos2.Column.ToString() + "\n\n"
+ raise (LBS.Error.CompilerExPos(err, Some pos))
+ prog
+ *)
+
+
+let parse (text:string) = Parser.from_string Program.parse text
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/options.fs b/ClassicGEC/ClassicGECDotNet/options.fs
new file mode 100644
index 0000000..8e53035
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/options.fs
@@ -0,0 +1,15 @@
+[]
+module Microsoft.Research.GEC.Options
+
+type t = { gecProgram:string
+ ; simulationOnlyReactions:bool }
+
+let default_options = { gecProgram=""
+ ; simulationOnlyReactions=false }
+
+let keep_ui_options (opts:t) = opts
+
+let getGECProgramText (opts:t) = opts.gecProgram
+let setGECProgramText (s:string) (opts:t) = {opts with gecProgram=s}
+let getSimulationOnlyReactions (opts:t) = opts.simulationOnlyReactions
+let setSimulationOnlyReactions (b:bool) (opts:t) = {opts with simulationOnlyReactions=b}
diff --git a/ClassicGEC/ClassicGECDotNet/options.fsi b/ClassicGEC/ClassicGECDotNet/options.fsi
new file mode 100644
index 0000000..f83bc46
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/options.fsi
@@ -0,0 +1,11 @@
+module Microsoft.Research.GEC.Options
+
+type t
+val default_options : t
+
+val keep_ui_options : t -> t
+
+val getGECProgramText : t -> string
+val setGECProgramText : string -> t -> t
+val getSimulationOnlyReactions : t -> bool
+val setSimulationOnlyReactions : bool -> t -> t
diff --git a/ClassicGEC/ClassicGECDotNet/paket.references b/ClassicGEC/ClassicGECDotNet/paket.references
new file mode 100644
index 0000000..2b6fb0e
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/paket.references
@@ -0,0 +1,3 @@
+group NETSTANDARD
+
+FSharp.Core
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/program.fs b/ClassicGEC/ClassicGECDotNet/program.fs
new file mode 100644
index 0000000..bdc0b18
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/program.fs
@@ -0,0 +1,1069 @@
+[]
+module Microsoft.Research.GEC.Program
+
+open Parser
+open Microsoft.Research.GEC.Ast
+open Microsoft.Research.GEC.Trans
+open Microsoft.Research.GEC.LogicGEC
+open Microsoft.Research.CRNEngine
+open Microsoft.Research.GEC.DirectivesParser
+open RulesDSD.Syntax
+//open FsCheck
+
+//open Microsoft.Research.CRNEngine.InferenceSiteGraph
+
+
+type moduleDefinition = string * (string list)
+type moduleInvocation = string * (value list)
+
+type deviceDefinition = moduleDefinition * (moduleInvocation list)
+
+type crnModules = ((string * string list) * Microsoft.Research.CRNEngine.Instruction list) list // * Instruction list
+
+type igPriorType =
+ | Fixed
+ | Normal
+ | TruncatedNormal
+
+type igPriorOption =
+ | HasPrior of igPriorType
+ | NoPrior
+
+type igPrior = string * igPriorOption
+
+type igName = string list
+
+type igedge = igName * (igPrior list) * igName
+type ignode = string * (string list) * (Inference_settings option)
+
+
+
+type igraphElement =
+ | Node of ignode
+ | Edge of igedge
+
+
+type systemReference =
+ | System of string
+ | NoSystem
+
+type system = {
+ name:string;
+ withSystem:systemReference;
+ settings:Settings.Gec_settings;
+ modules:crnModules;
+ devices:deviceDefinition list;
+ prog:Ast.prog}
+
+type ClassicProgram = {
+ settings:Settings.Gec_settings;
+ modules:crnModules;
+ templates:prog;
+ devices:deviceDefinition list;
+ systems:system list;
+ prog:Ast.prog;
+ graph:igraphElement list
+ }
+
+type LogicProgram = {
+ settings : Settings.Gec_settings;
+ rules : Semantics;
+ program : LogicGEC.Instruction list;
+}
+
+type t = ClassicGec of ClassicProgram
+ | LogicGec of LogicProgram
+
+let isLogicGecProgram (prog:t) = match prog with LogicGec _ -> true | _ -> false
+
+let MODULE = Parser.kw "module"
+let PROM = Parser.kw "prom"
+let RBS = Parser.kw "rbs"
+let PCR = Parser.kw "pcr"
+let TER = Parser.kw "ter"
+let POS = Parser.kw "pos"
+let NEG = Parser.kw "neg"
+let CON = Parser.kw "con"
+let INITPOP = Parser.kw "initPop"
+let NEW = Parser.kw "new"
+let DIRECTIVE = Parser.kw "directive"
+let MODEL = Parser.kw "model"
+let DEVICE = Parser.kw "device"
+let TEMPLATE = Parser.kw "template"
+let SYSTEM = Parser.kw "system"
+let PIPE = Parser.kw "|"
+let COMMA = Parser.kw ","
+let DOT = Parser.kw "."
+
+let pPipeLookAhead = Parser.pTry(Parser.pstring "||" >>. Parser.failParser "single expected" <|> Parser.pstring "|")
+let PARALLEL = Parser.choice [
+ pPipeLookAhead
+ Parser.pstring "||"
+ ] .>> Parser.spaces
+
+
+//let speciesnameparser = Parser.pTry(Parser.kw "_" >>. Parser.failParser "Reserved as wildcard keyword" <|> (Parser.many1Satisfy Parser.isLetter .>>. Parser.manySatisfy (fun c -> Parser.isLetter c || Parser.isDigit c || c = '_'|| c = '['|| c = ']'|| c = '-' || c = '\'') |>> fun (a,b) -> a + b) > "an identifier")
+
+
+
+let oldDirectiveLineParser = (DIRECTIVE >>. (DirectivesParser.oldDirective GecSpecies.parse_crn_species))
+//let directiveParser = oldDirectiveLineParser |>> convertOldDirectiveToGECDirective
+let directiveParser = oldDirectiveLineParser
+
+let parse_id_ns = (Parser.name_kw Microsoft.Research.GEC.Keywords.kwList)
+let parse_id = parse_id_ns .>> Parser.spaces
+
+let pSepLookAhead = Parser.pTry(Parser.pstring "::" >>. Parser.failParser "Unexpected Species separator found" <|> Parser.kw ":")
+let parse_brickid = parse_id .>> pSepLookAhead
+
+let parse_species_id = GecSpecies.parse_species |>> fun(splist) -> {GecSpecies.t.empty_Species with species = splist}.to_string()
+
+
+
+
+
+let rec convertExpToAst (exp:Expression.t)=
+ match exp with
+ | Expression.Float(float) -> Ast.FloatAExp(float)
+ | Expression.Key(key) -> Ast.IdAExp(key)
+ | Expression.Plus(plus) ->
+ match plus with first::second::remaining ->
+ let plusfirst = Ast.PlusAExp(convertExpToAst(first),convertExpToAst(second))
+ remaining |> List.fold (fun x y -> Ast.PlusAExp(x,convertExpToAst(y))) plusfirst
+ | _ -> failwith ""
+ | Expression.Minus(minus) -> Ast.MinusAExp(convertExpToAst(minus.sub1),convertExpToAst(minus.sub2))
+ | Expression.Times(times) ->
+ match times with first::second::remaining ->
+ let multfirst = Ast.MulAExp(convertExpToAst(first),convertExpToAst(second))
+ remaining |> List.fold (fun x y -> Ast.PlusAExp(x,convertExpToAst(y))) multfirst
+ | _ -> failwith ""
+ | Expression.Divide(divide) -> Ast.DivAExp(convertExpToAst(divide.div1),convertExpToAst(divide.div2))
+ | Expression.Power(power) -> Ast.PowAExp(convertExpToAst(power.base_),convertExpToAst(power.exponent))
+ | _ -> failwith ""
+
+
+let expressionParser = Microsoft.Research.CRNEngine.Expression.parse parse_species_id |>> convertExpToAst
+
+
+let parse_value = Parser.choice[
+ Parser.kw "_" |>> fun(_) -> Ast.WildCardVal //Wildcard check against IDParser
+ expressionParser |>> fun(x) ->
+ match x with
+ | Ast.IdAExp(y) -> Ast.IdVal(y)
+ | Ast.FloatAExp(y) -> Ast.FloatVal(y)
+ | _ -> Ast.AlgebraicExp(x)
+ ]
+
+
+let parse_initpop = INITPOP >>. GecSpecies.parse_species .>>. Parser.pfloat
+ |>> fun(complexSpecies,fl:float) ->
+ Ast.InitPop(GecSpecies.species_to_gecAbstractComplex complexSpecies,fl)
+
+let LT = (Parser.pTry((Parser.kw "<-" >>. Parser.failParser "Unexpected - symbol found") <|> (Parser.kw "<")) ) |>> fun _ -> Ast.Lt
+//let LT = Parser.kw "<"
+let GT = Parser.kw ">" |>> fun _ -> Ast.Gt
+let EQ = Parser.kw "=" |>> fun _ -> Ast.Eq
+
+
+let COMPAREOP = LT <|> GT <|> EQ
+
+
+let lookaheadLinebreak = Parser.pTry (Parser.linebreak >>. Parser.failParser "" <|> Parser.satisfy Parser.isWhiteSpace >>. preturn ())
+let lookaheadDashSeparator = Parser.pTry(Parser.pstring "->" >>. failParser "" <|> Parser.pstring "-")
+ // Parser.satisfy (fun c -> Parser.isWhiteSpace c && c <> '\n')
+//let whiteSpacenlb : t = skipChar isWhiteSpace > "a white space"
+
+//#region BrickParser
+let propParser = Parser.sepBy parse_value (Parser.kw ",")
+
+type prom = Regprom of string * Option * Ast.value list list //regType * By * Properties
+ | Conprom of Option
+
+//let value_from_string (s:string) = Parser.from_string valueParser s
+
+let convPromToAstProp (a:prom) =
+ match a with
+ |Regprom(regtype,regBy,otherprops) ->
+ if regBy.IsNone then
+ (regtype,[])
+ else
+ let firstreg = match regBy.Value with
+ | IdVal(str) -> (Parser.from_string GecSpecies.parse_species str) |> List.map (fun(x) -> Ast.IdVal(x))
+ | _ -> [regBy.Value]
+ let proplist = firstreg::otherprops
+ (regtype,proplist)
+
+ |Conprom(conprop) ->
+ if conprop.IsNone then
+ "con",[]
+ else
+ "con",[[conprop.Value]]
+
+let regProm (t:string) (props:value list) =
+ match props with
+ [] -> Regprom(t,None,[])
+ | regBy::properties ->
+ let proplist = properties |> List.map (fun(x) -> [x])
+ Regprom(t,Some(regBy),proplist)
+
+let conProm (props:value list) =
+ match props with
+ [] -> Conprom(None)
+ | conval::error ->
+ if error.IsEmpty then
+ Conprom(Some(conval))
+ else
+ //Parser.failParser "Too many consititutive options" //Can I do this?
+ Conprom(Some(conval))
+
+let promSinglePropertyParser = Parser.choice[
+ (POS <|> NEG) .>>. Parser.paren propParser |>> fun(reg,props) -> regProm reg props
+ CON >>. Parser.paren propParser |>> fun(props) -> conProm props
+ ]
+
+let promProperties = Parser.sepBy promSinglePropertyParser (Parser.kw ",")
+
+let rbsProperty = Parser.kw "rate" >>. Parser.paren propParser |>> fun(proplist) -> proplist |> List.map (fun(x)-> ("rate",[[x]]))
+
+let codesProperty = Parser.kw "codes" >>. Parser.paren propParser |>> fun(proplist) ->
+ let absComplexlist = proplist |> List.map(fun(x) -> [x])
+ ("codes",absComplexlist)
+
+let brickPartParser =
+ Parser.choice[
+ PROM >>. Parser.choice [
+ Parser.kw "<"
+ >>. promProperties
+ .>> Parser.kw ">" |>> fun(proplist) ->
+ let convertedproplist = proplist |> List.map convPromToAstProp
+ ("prom",convertedproplist)
+ Parser.preturn("prom",[])
+ ]
+ RBS >>. Parser.choice[
+ Parser.kw "<" >>. rbsProperty .>> Parser.kw ">" |>> fun(proplist) -> ("rbs",proplist)
+ Parser.preturn("rbs",[])
+ ]
+ PCR >>. Parser.choice[
+ Parser.kw "<" >>. codesProperty .>> Parser.kw ">" |>> fun(proplist) -> ("pcr",[proplist])
+ Parser.preturn("pcr",[])
+ ]
+ TER |>> fun(_) -> ("ter",[])
+ ]
+
+
+let parse_brick =
+ let brickid_to_value (str:string) =
+ match str with
+ | "_" -> Ast.WildCardVal
+ | _ -> Ast.IdVal(str)
+ Parser.choice[
+ parse_brickid >>= fun(brickid) ->
+ Parser.choice[
+ brickPartParser |>> fun(bricktype,propLst) -> Ast.Brick(brickid_to_value brickid,bricktype,propLst)
+ DEVICE |>> fun _ -> Ast.Device(brickid)
+ ]
+ brickPartParser |>> fun(bricktype,propLst) -> Ast.Brick(Ast.WildCardVal,bricktype,propLst)
+ ]
+//#endregion
+
+
+
+type nextParser =
+ | Brick
+ | Seq
+ | Reaction
+ | ModuleInvocation
+ | Constraint
+ | Nil
+ | GecSpecies
+ | Compartment
+
+
+let parse_constraints = expressionParser .>>. COMPAREOP .>>. expressionParser
+let parse_ast_constraints = parse_constraints |>> fun ((lhs,op),rhs) -> Ast.Constraint(lhs,op,rhs)
+
+let parse_sequence = Parser.sepBy parse_brick (Parser.kw ";")
+let parse_ast_sequence =
+ parse_sequence |>> fun(seq) ->
+ match seq with
+ | [] -> Ast.Nil
+ | [brick] -> brick
+ | f::s::rem ->
+ let fs = Ast.Seq(f,s)
+ match rem.Length with
+ | 0 -> fs
+ | _ -> rem |> List.fold (fun acc x -> Ast.Seq(acc,x)) fs
+
+let parse_template_args = parse_id .>>. Parser.paren (Parser.sepBy parse_value COMMA)
+
+let parse_template_inv_args = parse_id >>. Parser.paren (Parser.sepBy GecSpecies.parse_species COMMA)
+let parse_ast_template_inv = parse_template_args
+ |>> fun(modname,args) ->
+ let complexargs = args |> List.map (fun x ->
+ match x with
+ | IdVal(id) ->
+ let strlist = (Parser.from_string GecSpecies.parse_species id)
+ strlist |> List.map(fun x -> Ast.IdVal(x))
+ | _ -> [x]
+ )
+ Ast.TemplateInv(modname,complexargs)
+ // check with edge cases. should complexes be separated?
+
+let parse_reaction_species = Parser.sepBy GecSpecies.parse (Parser.kw "+")
+let parse_reactants =
+ Parser.sepBy GecSpecies.parse_species (Parser.kw "+")
+ |>> fun (reactants) ->
+ match reactants with
+ | [[]] -> []
+ | _ -> reactants
+let parse_reaction_rate =
+ Parser.opt (Parser.braces parse_value)
+
+let parse_reaction_rates = parse_reaction_rate .>>. parse_reaction_rate
+
+type reactionDirection = | Forward | Reversible
+let parse_reaction_direction =
+ Parser.choice [
+ Parser.kw "->" |>> fun _ -> Forward
+ Parser.kw "<->" |>> fun _ -> Reversible
+ ]
+
+let parse_enzyme_option = Parser.opt (Parser.kw "~")
+let parse_simulation_option =
+ Parser.opt (Parser.kw "*")
+ |>> fun (x) ->
+ match x with
+ | Some(_) -> true
+ | None -> false
+
+let create_transport_reaction (lhs:GecSpecies.t) (rhs:GecSpecies.t) (dir:reactionDirection) ((r1,r2):value option*value option) (sim:bool) =
+
+ let get_direction (lhs:GecSpecies.t) = match lhs.compartment with | None -> Ast.In | Some(_) -> Ast.Out
+ let get_compartment (lhs:GecSpecies.t) (rhs:GecSpecies.t) =
+ match lhs.compartment with
+ | Some(comp) -> comp
+ | None ->
+ match rhs.compartment with
+ | Some(comp) -> comp
+ | None -> failwith "Malformed Transport Reaction"
+ let create_forward_transport_reaction (lhs:GecSpecies.t) (rhs:GecSpecies.t) (rate:value) (sim:bool) =
+ let reactants = GecSpecies.species_to_gecAbstractComplex lhs.species
+ let products = GecSpecies.species_to_gecAbstractComplex rhs.species
+ let compartment = get_compartment lhs rhs
+ let dir = get_direction lhs
+ Ast.Trans(reactants,products,compartment,rate,sim,dir)
+ match dir with
+ | Forward -> match r2 with None -> () | _ -> failwith "Extra rate found in Forward reaction"
+ | Reversible -> ()
+
+ match dir with
+ | Forward ->
+ let rate = match r1 with | Some(r) -> r | None -> Ast.WildCardVal
+ create_forward_transport_reaction lhs rhs rate sim
+ | Reversible ->
+ let frate = match r1 with | Some(r) -> r | None -> Ast.WildCardVal
+ let rrate = match r2 with | Some(r) -> r | None -> Ast.WildCardVal
+ let forreac = create_forward_transport_reaction lhs rhs frate sim
+ let revreac = create_forward_transport_reaction rhs lhs rrate sim
+ Ast.Par(forreac,revreac)
+
+let create_normal_reaction (enzymes:string list list) (reactants:string list list) (products:string list list) (dir:reactionDirection) ((r1,r2):value option*value option) (sim:bool) =
+ let reactant_to_ast_val (slist:string list list) =
+ slist |> List.map (fun x -> GecSpecies.species_to_gecAbstractComplex x)
+
+ let create_forward_reaction (enzymes:abstractComplex list) (reactants:abstractComplex list) (products:abstractComplex list) (rate_option:value option) (sim:bool) =
+ let rate =
+ match rate_option with
+ | Some (x) -> x
+ | None -> Ast.WildCardVal
+ Ast.Reac(enzymes,reactants,products,rate,sim)
+
+ match dir with
+ | Forward ->
+ match r2 with | None -> () | Some(_) -> failwith "Forward reaction can't have two rates."
+ create_forward_reaction (reactant_to_ast_val enzymes) (reactant_to_ast_val reactants) (reactant_to_ast_val products) r1 sim
+ | Reversible ->
+ match enzymes with | [] -> () | _ -> failwith "Reversible reactions should not have any enzymes."
+
+ let freac = create_forward_reaction [] (reactant_to_ast_val reactants) (reactant_to_ast_val products) r1 sim
+ let rreac = create_forward_reaction [] (reactant_to_ast_val products) (reactant_to_ast_val reactants) r2 sim
+ Ast.Par(freac,rreac)
+
+let parse_reaction =
+ let compartment_checker (splist:GecSpecies.t list) =
+ splist |> List.iter (fun sp ->
+ match sp.compartment with
+ | Some (comp) -> failwith "Improper format for Transport Reaction"
+ | None -> ())
+ parse_reaction_species >>= fun(species) ->
+ match species with
+ | [reactant] ->
+ match reactant.compartment with
+ | Some(comp) ->
+ //Start Transport Reaction
+ parse_simulation_option
+ .>>. parse_reaction_direction
+ .>>. (parse_reaction_rates)
+ .>>. GecSpecies.parse_species
+ |>> fun (((simulationonly,reactiondir),rates),products) -> create_transport_reaction reactant {GecSpecies.t.empty_Species with species = products} reactiondir rates simulationonly
+ | None ->
+ parse_enzyme_option
+ .>>. parse_reactants
+ .>>. parse_simulation_option
+ .>>. parse_reaction_direction
+ .>>. (parse_reaction_rates)
+ .>>. parse_reaction_species
+ |>> fun (((((enzyme_option,reactants),simulationonly),reactiondir),rates),product_species)->
+ match enzyme_option with
+ | Some(_) ->
+ let enzymes =
+ match species with
+ | [] -> []
+ | _ -> species |> List.map (fun x -> x.species)
+ compartment_checker product_species
+ let products = product_species |> List.map (fun x -> x.species)
+ create_normal_reaction enzymes reactants products reactiondir rates simulationonly
+ | None ->
+ match product_species with
+ | [product] ->
+ match product.compartment with
+ | Some(comp) ->
+ create_transport_reaction reactant product reactiondir rates simulationonly
+ | None ->
+ let r =
+ match species with
+ | [] -> []
+ | _ -> species |> List.map (fun x -> x.species)
+ compartment_checker product_species
+ let products = product_species |> List.map (fun x -> x.species)
+ create_normal_reaction [] r products reactiondir rates simulationonly
+ | _ ->
+ let r =
+ match species with
+ | [] -> []
+ | _ -> species |> List.map (fun x -> x.species)
+ compartment_checker product_species
+ let products = product_species |> List.map (fun x -> x.species)
+ create_normal_reaction [] r products reactiondir rates simulationonly
+
+ | _ ->
+ compartment_checker species //Checks to see if there are any compartments in normal reactions.
+ parse_enzyme_option
+ .>>. parse_reactants
+ .>>. parse_simulation_option
+ .>>. parse_reaction_direction
+ .>>. (parse_reaction_rates)
+ .>>. parse_reaction_species
+ |>> fun (((((enzyme_option,reactants),simulationonly),reactiondir),rates),product_species)->
+ compartment_checker product_species
+ let enzymes =
+ match species with
+ | [] -> []
+ | _ -> species |> List.map (fun x -> x.species)
+ let products = product_species |> List.map (fun x -> x.species)
+ match enzyme_option with
+ | Some(_) -> create_normal_reaction enzymes reactants products reactiondir rates simulationonly
+ | None ->
+ let r =
+ match species with
+ | [] -> []
+ | _ -> species |> List.map (fun x -> x.species)
+ create_normal_reaction [] r products reactiondir rates simulationonly
+
+
+
+let reactionOrConstraint =
+ Parser.choice[
+ Parser.kw "~" |>> fun _ -> Reaction
+ Parser.kw "*" >>. Parser.choice[
+ Parser.kw "-" |>> fun _ -> Reaction
+ Parser.kw "<" |>> fun _ -> Reaction
+ Parser.preturn Constraint
+ ]
+ Parser.pstring "-" >>. Parser.choice[
+ Parser.pstring ">" |>> fun _ -> Reaction
+ Parser.preturn Constraint
+ ]
+ Parser.pstring "<" >>. Parser.choice[
+ Parser.pstring "-" |>> fun _ -> Reaction
+ Parser.preturn Constraint
+ ]
+ Parser.pstring ">" |>> fun _ -> Constraint
+ ]
+
+let pInnerParallelContent =
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.pTry(Parser.pfloat |>> fun _ -> true)
+ Parser.preturn(false)
+ ])
+ >>=
+ fun(startsWithFloat) ->
+ if startsWithFloat then
+ //Parser an expression and this should be a constraint, right?
+ parse_ast_constraints
+ else
+ //This is where the real plookahead fun begins...
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.pTry(parse_sequence |>> fun _ -> Seq)
+ GecSpecies.parse |>> fun _ -> GecSpecies
+ ]
+ )
+ >>=
+ fun (progType) ->
+ match progType with
+ | Seq -> parse_ast_sequence
+ | GecSpecies ->
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.sepBy GecSpecies.parse (Parser.kw "+")
+ >>= fun(pseq) ->
+ match pseq.Length with
+ | 1 -> Parser.choice[
+ Parser.kw "(" |>> fun _ -> ModuleInvocation
+ reactionOrConstraint
+ ]
+ | _ -> reactionOrConstraint
+ ]
+ )
+ >>= fun (progType2) ->
+ match progType2 with
+ | Constraint -> parse_ast_constraints
+ | ModuleInvocation -> parse_ast_template_inv
+ | Reaction -> parse_reaction
+ | _ -> failParser "At this stage, only Constraint, ModuleInvocation, and Reactions were expected"
+ | _ -> failParser "At this stage, only Seq or GecSpecies was expected as the Next Parser"
+
+
+let fold_parallel (proglist: Ast.prog list) =
+ match (List.rev proglist) with
+ | [] -> Ast.Nil
+ | [prog] -> prog
+ | first::second::remaining ->
+ let parfst = Ast.Par(second,first)
+ if remaining.IsEmpty then
+ parfst
+ else
+ List.foldBack (fun x y -> Ast.Par(x,y)) (List.rev remaining) parfst
+
+let parse_parallel_inner = Parser.sepBy (Parser.choice [
+ parse_initpop
+ pInnerParallelContent
+ ]) PARALLEL
+ |>> fold_parallel
+
+let parse_new = NEW >>. parse_species_id .>> Parser.kw "."
+
+let rec parse_new_inner st =
+ Parser.choice[
+ parse_new .>>. parse_new_inner |>> fun(newstr,prog) -> Ast.New(newstr,prog)
+ parse_parallel_inner
+ ] st
+
+
+let parse_compartment = Parser.plookAheadWith(Parser.choice[
+ Parser.pTry(parse_id .>> Parser.kw "[" .>> GecSpecies.parse_species .>> Parser.kw "]" |>> fun _ -> Reaction)
+ Parser.pTry(parse_id .>> Parser.kw "[" |>> fun _ -> Compartment)
+ ])
+ >>= fun(progType) ->
+ match progType with
+ | Reaction -> parse_reaction
+ | Compartment -> parse_id .>>. Parser.sqBrackets parse_new_inner |>> fun(compName,prog) -> Ast.Comp(compName,prog)
+ | _ -> failwith "At this point, the program type should only either be a Reaction or a Compartment."
+
+let parse_parallel_outer = Parser.sepBy (Parser.choice [
+ parse_initpop
+ parse_compartment
+ pInnerParallelContent
+ ]) PARALLEL
+ |>> fold_parallel
+
+let rec parse_new_outer st =
+ Parser.choice[
+ parse_new .>>. parse_new_outer |>> fun(newstr,prog) -> Ast.New(newstr,prog)
+ parse_parallel_outer
+ ] st
+
+let rec parse_system_template st =
+ Parser.choice[
+ TEMPLATE >>. parse_template_args
+ .>>. (Parser.braces parse_new_outer) .>> Parser.kw ";"
+ .>>. parse_system_template |>>
+ fun (((temName,temArgs),progBody),progout) ->
+ let args = temArgs |> List.map(fun x -> match x with | IdVal(y) -> y | _ -> failwith "unexpected format for template arguments")
+ Ast.TemplateDef(temName,args,progBody,progout)
+ parse_new_outer
+ ] st
+
+
+let parse_template =
+ let rec parse_system_template st =
+ Parser.choice[
+ TEMPLATE >>. parse_template_args
+ .>>. (Parser.braces parse_new_outer) .>> Parser.kw ";"
+ .>>. parse_system_template |>>
+ fun (((temName,temArgs),progBody),progout) ->
+ let args = temArgs |> List.map(fun x -> match x with | IdVal(y) -> y | _ -> failwith "unexpected format for template arguments")
+ Ast.TemplateDef(temName,args,progBody,progout)
+ Parser.preturn Ast.Nil
+ ] st
+ parse_system_template .>>. parse_new_outer
+
+
+
+let parse_arguments = Parser.paren (Parser.sepBy parse_id COMMA)
+let parse_val_arguments = Parser.paren (Parser.sepBy parse_value COMMA)
+let parse_moduleDefinition = parse_id .>> Parser.spaces .>>. parse_arguments
+let parse_moduleInvocation = parse_id .>> Parser.spaces .>>. parse_val_arguments
+
+let parse_device = Parser.kw "device" >>. parse_moduleDefinition .>> Parser.kw "="
+ .>>. Parser.braces (Parser.sepBy parse_moduleInvocation PIPE)
+
+let parse_instructions pspecies settings =
+ let zero = Expression.zero
+ let unitVal = Expression.one
+
+ let pvalue = Expression.parse parse_id
+ let pexpr = Expression.parse (Key.parse pspecies)
+ let pcomma = Parser.kw ","
+
+ // crn parsers
+ let pinitial = Microsoft.Research.CRNEngine.Initial.parse pspecies pvalue zero |>> Instruction.Initial2
+ let preaction = Reaction.parse pspecies pvalue pexpr unitVal |>> Instruction.Reaction
+ let pinvoke = Parser.pTry( parse_id .>> Parser.kw "(")
+ .>>. Parser.sepBy pvalue pcomma
+ .>> Parser.kw ")"
+ |>> Module
+ let pline = pinvoke <|> preaction <|> pinitial
+ let pbar = Parser.kw "|"
+
+ // module definitions parser
+ let pmodule =
+ Parser.kw "module"
+ >>. Parser.name .>>. Parser.paren (Parser.sepBy Parser.name pcomma) // module_name(comma-separated args)
+ .>> Parser.kw "="
+ .>>. Parser.braces (Parser.opt pbar >>. Parser.sepBy pline pbar)
+
+ // full CRN parser
+ Parser.spaces
+ >>. Parser.many pmodule
+ //.>> Parser.opt pbar
+ //.>>. Parser.sepBy pline pbar
+
+let parse_crnModules crnSettings =
+ parse_instructions GecSpecies.parse_gec_to_crn_species crnSettings
+
+
+let pfixed = Parser.kw "Fixed" |>> fun _ -> Fixed
+let pnormal = Parser.kw "Normal" |>> fun _ -> Normal
+let ptruncatedNormal = Parser.kw "TruncatedNormal" |>> fun _ -> TruncatedNormal
+
+let parse_priorType = pfixed <|> pnormal <|> ptruncatedNormal
+
+let parse_priorOption:Parser.t =
+ Parser.plookAheadWith (
+ Parser.choice[
+ Parser.pTry (Parser.kw "=" >>. parse_priorType >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasPriorType ->
+ if hasPriorType
+ then Parser.kw "=" >>. parse_priorType |>> fun (x:igPriorType) -> HasPrior(x)
+ else Parser.preturn(NoPrior)
+
+
+let parse_prior:t = Parser.name .>> Parser.spaces .>>. parse_priorOption
+
+
+let parse_igInferenceSettings = Parser.kw ";" >>. Parser.kw "inference" >>. Parser.kw "=" >>. (Inference_settings.parse)
+
+let parse_igName = Parser.sepBy (Parser.name .>> Parser.spaces) DOT
+
+let parse_edge = Parser.kw "edge" >>. parse_igName .>> Parser.kw "->"
+ .>>. Parser.list_of parse_prior .>>. parse_igName |>> fun ((x,y),z) -> Edge(x,y,z)
+
+let parse_node =
+ Parser.kw "node" >>. (Parser.name .>> Parser.spaces)
+ .>> Parser.kw "{" .>>. (Parser.kw "systems" >>. Parser.kw "="
+ >>. Parser.list_of (Parser.name .>> Parser.spaces)) >>= fun (x,y) ->
+ Parser.plookAheadWith(
+ Parser.choice[
+ Parser.pTry(Parser.kw ";" >>. Parser.kw "inference" >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasInference ->
+ if hasInference
+ then
+ parse_igInferenceSettings .>> Parser.kw "}" |>> fun (z) -> Node(x,y,Some(z))
+ else
+ Parser.kw "}" |>> fun _ -> Node(x,y,None)
+
+
+
+let parse_igraphElement = parse_edge <|> parse_node
+
+let parse_withSystem =
+ Parser.plookAheadWith (
+ Parser.choice [
+ Parser.pTry(Parser.name .>> Parser.spaces .>> Parser.kw "with" >>= fun _ -> Parser.preturn true)
+ Parser.preturn false
+ ])
+ >>= fun hasWith ->
+ if hasWith
+ then Parser.name .>> Parser.spaces .>> Parser.kw "with" |>> fun x -> System(x)
+ else Parser.preturn(NoSystem)
+
+let rename_settings_species (settings:Settings.Gec_settings) =
+ let rename_species (sp:Species) =
+ let spName = sp.name
+ if spName.Contains("[") && spName.Contains("]") then
+ let spNameParser = Parser.name .>>. Parser.sqBrackets Parser.name |>> fun(x,y) -> (x + "_" + y)
+ let newName (str:string) = Parser.from_string spNameParser str
+ Species.create(newName spName)
+ else
+ sp
+ let crn = Crn_settings.defaults.from_default_directive_list settings.directives
+ let renamed_crn_settings = crn.map (Expression.map (Key.map (fun sp -> rename_species sp)))
+ renamed_crn_settings
+
+
+let parse_program (crnsettings:Crn_settings)=
+ Settings.parse_defaults crnsettings >>= fun(top_settings) ->
+ let top_crn_settings = crnsettings.from_default_directive_list top_settings.directives
+ parse_crnModules top_crn_settings
+ .>>. (Parser.many parse_device)
+ .>>. parse_system_template
+ |>> fun((crn_modules,device_definitions),gecprog) ->
+ (top_settings,crn_modules,device_definitions,gecprog)
+
+
+let parse_system (settings:Crn_settings) =
+ SYSTEM >>. parse_id .>> (Parser.kw "=") .>>. Parser.braces (parse_withSystem .>>. parse_program settings)
+ |>> fun(systemName,(sysRef,(settings,modules,devices,prog))) ->
+ {name=systemName;
+ withSystem=sysRef;
+ settings=settings;
+ modules = modules;
+ devices = devices;
+ prog = prog}
+
+let parseClassic (top_settings:Settings.Gec_settings) =
+ let top_crn_settings = Crn_settings.defaults.from_default_directive_list top_settings.directives
+ parse_crnModules top_crn_settings
+ .>>. (Parser.many parse_device)
+ .>>. parse_template
+ .>>. (Parser.many (parse_system top_crn_settings))
+ .>>. (Parser.many parse_igraphElement)
+ |>> fun((((modules,devices),(templates,topProg)),systems),igraph) ->
+ {settings=top_settings;
+ modules = modules;
+ devices = devices;
+ systems = systems;
+ templates = templates;
+ prog = topProg;
+ graph = igraph}
+
+let getMapInstruction m (i:LogicGEC.Instruction) =
+ let getMapComplex sp m =
+ sp |> List.fold (fun acc (_, x) -> getMapTerm acc x) m
+ match i with
+ | LogicGEC.Constraint c -> LogicGEC.getMapLit m c
+ | LogicGEC.Device d -> d |> List.fold (LogicGEC.getMapElement) m
+ | LogicGEC.Initial(c,sp) -> c
+ |> LogicGEC.getMapTerm m
+ |> getMapComplex sp
+ | LogicGEC.Reaction(a,b,c,d,e) ->
+ let cs = if a.IsSome then [a.Value; b; c]
+ else [b;c]
+ let rs = if e.IsSome then [e.Value; d]
+ else [d]
+ let m' = cs |> List.fold (fun acc x -> getMapComplex x acc) m
+ rs |> List.fold getMapTerm m'
+
+let parseLogic(settings:Settings.Gec_settings) =
+ let idProvider = RulesDSD.Syntax.makeProvider () // initialise an ID provider for logical variables, so that the same variable in different predicates/devices is given the same ID
+ Parser.opt (kw "|")
+ >>. Parser.sepBy1 (pInstruction idProvider) (kw "|")
+ >>= fun prog ->
+
+ // find the parts declared in the database
+ let declaredParts =
+ match settings.rules with
+ | None -> failwith "Missing Logic GEC rules in instructions parsing."
+ | Some rules -> LogicGEC.getParts rules
+ let declaredNames =
+ declaredParts
+ |> List.choose (fun p -> match p.name with Term.Const n -> Some n | _ -> None)
+ |> Set.ofList
+
+ // part name and types disambiguation step
+ let parts =
+ prog
+ |> List.collect (Instruction.Species)
+ |> List.fold (fun acc x -> match x with Element.Var _ -> acc | Element.Part p -> p::acc) []
+
+ let partNames, partTypes =
+ parts
+ |> List.fold (fun (acc1, acc2) p ->
+ let names =
+ match p.name with
+ | RulesDSD.Syntax.Term.Const x ->
+ if not (acc1 |> Set.contains x) && p.type_ <> Term.Const LogicGEC.noTypePart
+ then Set.add x acc1
+ else acc1
+ | _ -> acc1
+ let types =
+ match p.type_ with
+ | RulesDSD.Syntax.Term.Const x ->
+ if not (acc2 |> Set.contains x) && p.type_ <> Term.Const LogicGEC.noTypePart
+ then Set.add x acc2
+ else acc2
+ | _ -> acc2
+ names, types
+ ) (Set.empty, LogicGEC.PREDEFINED_PART_TYPE_NAMES |> Set.ofList)
+ let ambiguousNames = Set.intersect partNames partTypes
+ if not (ambiguousNames.IsEmpty)
+ then ambiguousNames |> Set.toList |> List.head |> failwithf "Ambiguous part declaration: \"%s\" is used as a part name and a part type at the same time."
+ else
+ // guess #1: turn undeclared parts back into strings
+ let prog1 =
+ let rec f (x:Term) : Term =
+ match x with
+ | Term.Pat (Pattern.Inner [y, _]) ->
+ match y with
+ | Element.Part {name = Term.Const n
+ type_ = _ } -> if declaredNames.Contains n || partNames.Contains n
+ then x
+ else Term.Const n
+ | _ -> x
+ | Term.Pat _
+ | Term.Proc _
+ | Term.Var _
+ | Term.Const _
+ | Term.Float _ -> x
+ | Term.TCRN ts -> Term.TCRN (ts |> List.map f)
+ | Term.Func (n, ts) -> Term.Func (n, ts |> List.map f)
+ | Term.TList ts -> Term.TList (ts |> List.map f)
+ | Term.TCons (t1, t2) -> Term.TCons (f t1, f t2)
+ | Term.TMSet s -> Term.TMSet (s |> List.map (fun (i, x) -> i, f x))
+ prog
+ |> List.map (fun i ->
+ match i with
+ | LogicGEC.Device _ -> i
+ | LogicGEC.Constraint c -> LogicGEC.Constraint (c |> Literal.Map f)
+ | LogicGEC.Initial (n,c) -> LogicGEC.Initial (f n, c |> List.map (fun (x,y) -> x, f y))
+ | LogicGEC.Reaction (a,b,c,d,e) -> LogicGEC.Reaction (a,b,c,f d, Option.map f e)
+ )
+
+ // guess #2: turn a part name into a part type (e.g. "ter" might be parsed as a part called ter and no type, when it's actually a terminator part type )
+ let guessPartTypes e =
+ match e with
+ | Element.Part {name = Term.Const n; type_ = Term.Const t} ->
+ if t = noTypePart
+ then if Set.contains n partTypes
+ then Element.Part { name = Term.wildcard; type_ = Term.Const n}
+ else Element.Part { name = Term.Const n; type_ = Term.wildcard}
+ else e
+ | _ -> e
+
+ let prog2 = prog1 |> List.map (Instruction.Map guessPartTypes)
+
+ // guess #3: add part types to parts that were only written as part names (e.g. r0011 in "" )
+ let declaredDict = declaredParts
+ |> List.map (fun p -> p.name, p)
+ |> fun decs -> // W# doesn't process "dict"
+ let x = new System.Collections.Generic.Dictionary, Part>()
+ for k,v in decs do
+ x.Add(k,v)
+ x
+ let prog3 =
+ prog2
+ |> List.map (Instruction.Map (fun e ->
+ match e with
+ | Element.Var _ -> e
+ | Element.Part p -> if p.type_ = Term.wildcard && declaredDict.ContainsKey p.name
+ then Element.Part (declaredDict.Item p.name)
+ else e
+ ))
+
+ // disambiguate variables in prog
+
+
+ preturn { settings = settings
+ ; rules = settings.rules.Value // TODO: refactor settings
+ ; program = prog3 }
+
+let parse : Parser.t =
+ Parser.spaces >>.
+ Settings.parse >>= fun(top_settings) ->
+ if top_settings.rules.IsNone
+ then parseClassic top_settings |>> ClassicGec
+ else parseLogic top_settings |>> LogicGec
+/// TO STRING METHODS.
+
+let crnSettings_to_string (crnSettings:Crn_settings) = crnSettings.to_string Functional2.to_string Functional2.to_string_plot
+
+
+let argsval_to_string (args: value list) = Lib.string_of_list (fun x -> Ast.stringOfValue x) "," (args)
+let args_to_string (args: string list) = Lib.string_of_list (fun x -> x) "," (args)
+
+
+let modules_to_string initial_time (modules:crnModules) =
+ let moduleList = modules
+ let instructionList_to_string (instructions:Instruction list) =
+ let instructionStringList = instructions |> List.map (fun x -> ("| " + (Instruction.to_string initial_time x)))
+ Lib.string_of_list (fun x -> x) "\n" instructionStringList
+ let module_to_string (((moduleName:string),(moduleArgs:string list)),(instructions:Instruction list)) =
+ let str = "module " + moduleName + "(" + (args_to_string moduleArgs) + ") = {\n" +
+ (instructionList_to_string instructions) + "\n}\n"
+ str
+ let str =
+ let moduleListString = moduleList |> List.map (fun x -> (module_to_string x))
+ let moduleStr = Lib.string_of_list (fun x -> x) "" moduleListString
+ moduleStr //+ (instructionList_to_string externalInstructions)
+
+ match modules with
+ | [] -> ""
+ | _ -> str
+
+let crn_contents_to_string (initial_time) (crnExtended:Crn option * crnInstructions) =
+
+ let (crnOpt,crnInstructions) = crnExtended
+ let (modules,instructions) = crnInstructions
+ let instructions_tp_string instructions = Lib.string_of_list (fun x -> ("|" + Instruction.to_string initial_time x)) "\n" instructions
+ let module_to_string (m) =
+ let ((mname,margs),instructions) = m
+ mname + "(" + (Lib.string_of_list (fun x -> x) "," margs) + ") = {\n" +
+ instructions_tp_string instructions +
+ "}\n"
+
+ let modules_to_string (modules:crnModules) = Lib.string_of_list (fun m -> module_to_string m) "\n" modules
+
+ let inst_string = (modules_to_string modules) + (instructions_tp_string instructions)
+
+ match crnOpt with
+ | Some(crn) ->
+ let initials = crn.initials
+ let reactions = crn.reactions
+ let not_initial i = Expression.simplify i <> Expression.Float initial_time
+ let initial_to_string = Initial.to_string Species.to_string (Expression.to_string id) not_initial
+ let reaction_to_string = Reaction.to_string Species.to_string (Expression.to_string id) Functional2.to_string
+ let initStr = Lib.string_of_list (fun x -> ("| " + (initial_to_string x))) "\n" initials
+ let reacStr = Lib.string_of_list (fun x -> ("| " + (reaction_to_string x))) "\n" reactions
+ inst_string + initStr + reacStr
+ | None -> inst_string
+
+let moduleDefinition_to_string (moduleDef:moduleDefinition) =
+ let (moduleName,moduleArgs) = moduleDef
+ moduleName + "(" + (args_to_string moduleArgs) + ")"
+
+let moduleInvocation_to_string (moduleInv:moduleInvocation) =
+ let (moduleName,moduleArgs) = moduleInv
+ moduleName + "(" + (argsval_to_string moduleArgs) + ")"
+
+let deviceDefinition_to_string (device:deviceDefinition) =
+ let ((deviceDef),deviceBody) = device
+ let deviceBodyString = "{" + (Lib.string_of_list (fun x -> x) " | " (deviceBody |> List.map (fun x -> moduleInvocation_to_string x))) + "}"
+ let str = "module " + (moduleDefinition_to_string deviceDef) + " = " + deviceBodyString
+ str
+
+let system_to_string (crn) (modules) (deviceDefs) (system:system) (db:Database.t)=
+ let moduleDefinitions = modules |> List.map fst
+ let deviceDefinitions = deviceDefs |> List.map fst
+
+ let device_list =
+ let rec get_devices (prog:Ast.prog) =
+ match prog with
+ | Ast.Device(d) -> [d]
+ | Ast.Seq(s1,s2) -> (get_devices s1)@(get_devices s2)
+ | Ast.Par(p1,p2) -> (get_devices p1)@(get_devices p2)
+ | Ast.Comp(c,p) -> get_devices p
+ | Ast.New(n,p) -> get_devices p
+ | Ast.TemplateDef(_,_,p1,p2) -> (get_devices p2)
+ | Ast.Copy(_,p,_,_) -> get_devices p
+ | _ -> []
+ get_devices system.prog
+
+ let hypothesisSettings_to_string (deviceList:string list) (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list) =
+ let rec device_unroll (dev:string) (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list) =
+ let deviceDefOpt = deviceDefs |> List.tryFind (fun (x,y) -> x=dev)
+ match deviceDefOpt with
+ | Some(a) -> [a]
+ | None ->
+ let modOpt = (moduleDefs |> List.tryFind (fun (x,y) -> x=dev))
+ match modOpt with
+ | Some(a) -> [a]
+ | None ->
+ let devOpt = (devices |> List.tryFind (fun (x,y) -> x=dev ))
+ match devOpt with
+ | Some (devName,devComps) ->
+ let deflist = devComps |> List.map (fun x -> device_unroll x devices deviceDefs moduleDefs)
+ match deflist.Length with
+ | 0 -> []
+ | _ -> deflist |> List.reduce (fun x y -> x@y)
+ | None ->
+ raise (System.ArgumentException("Device in System Directive must be defined."))
+ let mdeflistlist = deviceList |> List.map (fun x -> device_unroll x devices deviceDefs moduleDefs)
+ let mdeflist =
+ match mdeflistlist.Length with
+ | 0 -> []
+ | _ -> mdeflistlist |> List.reduce (fun x y -> x@y)
+ let l = (mdeflist |> List.map (fun x -> "| " + (moduleDefinition_to_string x)))
+ match l with
+ | [] -> ""
+ | _ -> Lib.string_of_list (fun x -> x) "\n" l
+
+ let system_to_string (devices:Database.device list) (deviceDefs:moduleDefinition list) (moduleDefs:moduleDefinition list)=
+ let sysRef_to_string (sysRef:systemReference) =
+ match sysRef with
+ | System(x) -> x + " with "
+ | NoSystem -> ""
+ let nl_str (str:string) =
+ match (str.Trim()) with
+ | "" -> ""
+ | _ -> str + "\n"
+ let str =
+ "system " + system.name + " = { " + (sysRef_to_string system.withSystem) + "\n" +
+ let crnSettings = Crn_settings.defaults.from_default_directive_list system.settings.directives
+ nl_str (crnSettings_to_string crnSettings) +
+ nl_str (modules_to_string crnSettings.simulation.initial system.modules) +
+ nl_str (crn_contents_to_string crnSettings.simulation.initial crn) + //Crn to String (Only initials and reactions)
+ hypothesisSettings_to_string (device_list) devices deviceDefs moduleDefs + "\n}\n"
+
+ str
+
+ system_to_string db.devices deviceDefinitions moduleDefinitions
+
+let igNode_to_string (node:ignode) =
+ let (nodeName,nodeSystems,iSettings) = node
+ let str = "node " + nodeName + " { systems = [" + (Lib.string_of_list (fun x -> x) "; " nodeSystems) + "]"
+ match iSettings with
+ | Some(x) -> str + "; " + "inference " + "= " + (Inference_settings.to_string(x)) + "}"
+ | None -> str + "}"
+
+
+
+let igEdge_to_string (edge:igedge) =
+ let edgeNameString edgelist = Lib.string_of_list (fun x -> x) "." edgelist
+ let priorType_to_string (ptype:igPriorType) =
+ match ptype with
+ | Fixed -> "Fixed"
+ | Normal -> "Truncated"
+ | TruncatedNormal -> "TruncatedNormal"
+ let prior_to_string ((p,ptype):igPrior) =
+ match ptype with
+ | HasPrior(x) -> p + "=" + (priorType_to_string x)
+ | NoPrior -> p
+ let (fromNode,priorlist,toNode) = edge
+ let str = "edge " + (edgeNameString fromNode) + " -> " + "["+
+ (Lib.string_of_list (fun x -> x) "; " (priorlist |> List.map (fun x-> prior_to_string x)) ) +
+ "] " + (edgeNameString toNode)
+ str
+
+let igElement_to_string (elem:igraphElement) =
+ match elem with
+ | Node(x) -> igNode_to_string x
+ | Edge(x) -> igEdge_to_string x
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/settings.fs b/ClassicGEC/ClassicGECDotNet/settings.fs
new file mode 100644
index 0000000..fa13bce
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/settings.fs
@@ -0,0 +1,145 @@
+[]
+module Microsoft.Research.GEC.Settings
+open Microsoft.Research.CRNEngine
+open Microsoft.Research.GEC.Ast
+open Parser
+//open FsCheck
+
+type crnModuleDefinition = (string * string list)
+type crnInstructions = ((crnModuleDefinition * Instruction list) list) * Instruction list
+
+
+let pSpecies = GecSpecies.parse_crn_species
+
+type Directive =
+ | Crn of crnInstructions
+ | Override of crnInstructions
+ | RmrnaDeg of float
+ | Rules of LogicGEC.Semantics
+ static member parse_defaults (settings:Crn_settings<'e>) =
+ //let parse_species = pSpecies - Clashes with key words...
+ let parse_species = (GecSpecies.parse_kw Microsoft.Research.CRNEngine.Keywords.kwList) |>> fun x -> x.to_string() |> Species.create
+ let CRN = Parser.kw "crn"
+ let OVERRIDE = Parser.kw "override"
+ let RMRNADEG = Parser.kw "RMRNADeg"
+ let RULES = Parser.kw "rules"
+ let parse_crn = CRN
+ Parser.choice[
+ CRN >>. Parser.braces (Instruction.parse parse_species settings) |>> fun x -> Crn x
+ OVERRIDE >>. Parser.braces (Instruction.parse parse_species settings) |>> fun x -> Override x
+ RMRNADEG >>. Parser.pfloat .>> Parser.spaces |>> fun x -> RmrnaDeg x
+ RULES >>. Parser.braces (LogicGEC.pGecProgram) |>> Rules
+ ]
+ static member parse =
+ Directive.parse_defaults Crn_settings.defaults
+
+type Gec_settings = {directives:Directive list; crn:crnInstructions; overrideCrn:bool; rmrnadeg:float; rules:LogicGEC.Semantics option}
+with
+ static member default_settings = {directives=[]; crn=([],[]); overrideCrn=false;rmrnadeg=0.001;rules=None}
+ member default_settings.from_directive (gecDirective:Directive)=
+ match gecDirective with
+ | Crn (x) -> {default_settings with crn = x; overrideCrn = false}
+ | Override(x) -> {default_settings with crn = x; overrideCrn = true}
+ | RmrnaDeg(x) -> {default_settings with rmrnadeg = x}
+ | Rules x -> {default_settings with rules = Some x}
+ member default_settings.from_directive_list (ds:Directive list) =
+ ds |> List.fold (fun (acc:Gec_settings) s -> (acc.from_directive s)) default_settings
+
+
+let parse_species:Parser.t = Expression.parse (Key.parse pSpecies)
+ ///Special case: a single name x is interpreted as a species instead of a parameter
+ ///e.g. "plots = [x]"
+let parse__species_plot:Parser.t =
+ let species_from_string = Parser.from_string pSpecies
+ Expression.parse (Key.parse pSpecies)
+ |>> fun exp ->
+ match exp with
+ | Expression.Key (Key.Parameter s) -> Expression.Key (Key.Species (species_from_string s))
+ | _ -> exp
+
+type directiveType =
+ | CRNDir of Microsoft.Research.CRNEngine.Directive
+ | GECDir of Directive
+
+let parseCrnDir = Directive.parse parse_species parse__species_plot |>> CRNDir
+
+let parseGecDir_defaults (settings:Crn_settings) = Directive.parse_defaults settings |>> GECDir
+let parseGecDir = parseGecDir_defaults Crn_settings.defaults
+
+let parse_defaults (default_crn_settings:Crn_settings) =
+ Parser.many (Parser.kw "directive" >>. ( (parseGecDir_defaults default_crn_settings) <|> parseCrnDir))
+ |>> fun(dirlist) ->
+ let crnlist = dirlist |> List.choose(fun elem ->
+ match elem with
+ | CRNDir(x) -> Some(x)
+ | _ -> None)
+ let geclist = dirlist |> List.choose(fun elem ->
+ match elem with
+ | GECDir(x) -> Some(x)
+ | _ -> None)
+ //let crnSettings = default_crn_settings.from_default_directive_list crnlist
+ let settings = { Gec_settings.default_settings with directives = crnlist}
+ settings.from_directive_list geclist
+
+
+let parse = parse_defaults Crn_settings.defaults
+
+
+let convertExprToAst (exp:Functional) =
+
+
+ let gecExp = Parser.from_string (GecSpecies.parse)
+ let f s = gecExp (Species.to_string s) |> fun x -> x.to_ast_gecSpecies()
+ Expression.map (Key.map f) exp
+ (*match exp with
+ | Expression (Key.Species s) ->
+ let gecExp = Parser.from_string (GecSpecies.parse)
+ let gecSpecies = gecExp (Species.to_string s) |> fun x -> x.to_ast_gecSpecies()
+ Expression.Key(gecSpecies)
+
+ | _ -> failwith "Unexpected expression encountered in directive functional"*)
+
+
+
+let convertCRNdirToGECdir (directive:Directive) =
+ match directive with
+ | Simulation x ->
+ let plotSpecies = x.plots |> List.map convertExprToAst
+ let plots = Ast.PLOT(plotSpecies)
+ let kinetics =
+ match x.kinetics with
+ | Kinetics.Contextual -> Ast.KINETICS(Ast.Contextual_kinetics)
+ | Kinetics.Stochastic -> Ast.KINETICS(Ast.Stochastic_kinetics)
+ | Kinetics.Deterministic -> Ast.KINETICS(Ast.Deterministic_kinetics)
+ [Ast.SAMPLE(x.final,Ast.IntPoints(x.points));kinetics;plots]
+ | Units x -> [Ast.TIME(x.time);Ast.CONCENTRATION(x.concentration)]
+ | Microsoft.Research.CRNEngine.Directive.Deterministic x -> [Ast.ABSTOLERANCE(x.abstolerance);Ast.RELTOLERANCE(x.reltolerance)]
+ | Microsoft.Research.CRNEngine.Directive.Stochastic x -> [Ast.SCALE(x.scale)]
+ | _ -> []
+ (*| Samples(startVal,endVal,inc) ->
+ if(inc.IsSome) then
+ if(inc.Value = 0) then
+ Ast.SAMPLE(endVal.Value,Ast.AllPoints)
+ else
+ Ast.SAMPLE(endVal.Value,Ast.IntPoints(inc.Value))
+ else
+ Ast.SAMPLE(endVal.Value,Ast.Default)
+ | OldTime(sec) -> Ast.TIME(sec)
+ | Concentration(conc) -> Ast.CONCENTRATION(conc)
+ | Tolerance(value) -> Ast.ABSTOLERANCE(value)
+ | RelTolerance(value) -> Ast.RELTOLERANCE(value)
+ | Scale(value) -> Ast.SCALE(value)
+ | Kinectics(mode) ->
+ match mode with
+ | KContextual -> Ast.KINETICS(Ast.Contextual_kinetics)
+ | KStochastic -> Ast.KINETICS(Ast.Stochastic_kinetics)
+ | KDeterministic -> Ast.KINETICS(Ast.Deterministic_kinetics)
+ | Plot(expList) ->
+ let gecExpList = expList |> List.map convertExprToAst
+ Ast.PLOT(gecExpList)
+ | _ -> failwith "Unknown Directive encountered"*)
+
+
+let convert_crn_to_gec_directives (directives :Directive list) =
+ let list = directives |> List.map convertCRNdirToGECdir
+ list |> List.fold (fun acc x -> acc@x) []
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/solver.fs b/ClassicGEC/ClassicGECDotNet/solver.fs
new file mode 100644
index 0000000..eb96b40
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/solver.fs
@@ -0,0 +1,288 @@
+[]
+module Microsoft.Research.GEC.Solver
+
+open Microsoft.Research.GEC
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* ************************************************************************************************************ *)
+
+(* Some helper functions. *)
+
+(* NB: copied from trans.fs... NB: altered to handle complexes! *)
+//let getComplexNamesFromStrings (prop:string * (string list list)) : string list = match prop with
+// | (pname, x::xs) when pname = "pos" || pname = "neg" || pname = "pcr" || pname = "codes" -> [Ast.complexString x]
+// | _ -> []
+
+(* Get the COMPLEXES which exist in a list of part properties. *)
+let getComplexesFromStrings (prop:string * (string list list)) : string list list =
+ match prop with
+ | (pname, x::xs) when pname = "pos" || pname = "neg" || pname = "pcr" || pname = "codes" -> [x]
+ | _ -> []
+
+(* Compare a string and a partType to see if they match... *)
+let typesAgree (t:string) (partTy:Database.partType) =
+ match t,partTy with
+ | "pcr", Database.PCR _ | "prom", Database.PROM _ | "rbs", Database.RBS _ | "ter", Database.TER _ -> true
+ | _,_ -> false
+
+(* Find all substitutions that can unify two complexes, in any order... *)
+let unifyComplexes ((*variables*)xs:string list) ((*species*)zs:string list) : Subst.t list =
+ let zs = List.map (fun z -> Subst.SPECIES [z]) zs in
+ if not(List.length xs = List.length zs) then [] else
+ let assocLsts = List.map (fun perm -> List.zip xs perm) (Lib.permutations zs) in
+ Lib.maybemap Subst.multiple assocLsts
+
+(* Unify two (possibly empty) lists of complexes. *)
+let unifyComplexLists ((*variables*)xss:string list list) ((*species*)zss:string list list) : Subst.t list =
+ match xss,zss with
+ | [],[] -> [Subst.empty]
+ | _::_,_::_ ->
+ if not(List.length xss = List.length zss) then [] else
+ let rec loop (thetas:Subst.t list) ((*variables*)qss:string list list) ((*species*)wss:string list list) =
+ match qss,wss with
+ | [],[] -> thetas
+ | (qs::qss, ws::wss) ->
+ let thetas' = Lib.collect (fun theta -> let qs' = Subst.applyToComplex theta qs in
+ let ws' = Subst.applyToComplex theta ws in
+ let thetas' = unifyComplexes qs' ws' in
+ let thetas' = Lib.maybemap (Subst.union theta) thetas' in
+ let str =
+ "Trying to unify " + (Ast.complexString qs) + " with " + (Ast.complexString ws) +
+ " when theta = " + (Subst.display theta) + " *** "+
+ " got thetas' = " + (Lib.string_of_list Subst.display " ~~ " thetas')
+ in
+ thetas') thetas
+ in
+ //let newLog = [] in
+ loop thetas' qss wss
+ | _,_ -> failwith "unifyComplexLists: outer lists must be the same length"
+ in
+ Lib.collect (fun zss -> loop [Subst.empty] xss zss) (Lib.permutations zss)
+ | _,_ -> []
+
+(* ************************************************************************************************************ *)
+
+(* Scan the database for matching parts. *)
+
+(* Try to find substitutions which make a string-based promoter property match a ground one from the database. *)
+let tryFindPromoterSubsts (theta_original:Subst.t) (bp:string * (string list list)) (pp:Database.promProperty) : Subst.t list =
+ let bp = Subst.applyToPartTypeStrings theta_original bp in
+ let unifyPP (xs,q1,q2,q3) (zs,r1,r2,r3) =
+ match Subst.multiple [(q1,Subst.NUMBER r1);(q2,Subst.NUMBER r2);(q3,Subst.NUMBER r3)] with
+ | None -> []
+ | Some theta' ->
+ match Subst.union theta_original theta' with
+ | None -> []
+ | Some theta''' -> Lib.maybemap (fun theta'' -> Subst.union theta'' theta''') (unifyComplexes xs zs)
+ in
+ match bp, pp with
+ | ("frate", [[q]]), Database.FRATE(a) ->
+ begin match (Subst.unify q (Subst.ALGEBRAIC_EXPRESSION a)) with
+ | None -> []
+ | Some theta ->
+ begin match Subst.union theta_original theta with
+ | None -> []
+ | Some theta' -> [theta']
+ end
+ end
+ | ("pos", [xs;[q1];[q2];[q3]]), Database.POS(zs,r1,r2,r3) //
+ | ("neg", [xs;[q1];[q2];[q3]]), Database.NEG(zs,r1,r2,r3) -> unifyPP (xs,q1,q2,q3) (zs,r1,r2,r3)
+ | ("con", [[q]]), Database.CON(r) ->
+ begin match (Subst.unify q (Subst.NUMBER r)) with
+ | None -> []
+ | Some theta ->
+ begin match Subst.union theta_original theta with
+ | None -> []
+ | Some theta' -> [theta']
+ end
+ end
+ | _,_ -> []
+
+(* Try to find substitutions which make a string-based PCR property match a ground one from the database. *)
+let tryFindPCRSubsts (theta_original:Subst.t) (bp:string * (string list list)) (pp:Database.pcrProperty) : Subst.t list =
+ let bp = Subst.applyToPartTypeStrings theta_original bp in
+ match bp, pp with
+ | ("codes", [xs;[q]]), Database.CODES(zs,r) ->
+ begin match (Subst.unify q (Subst.NUMBER r)) with
+ | None -> []
+ | Some theta ->
+ begin match Subst.union theta_original theta with
+ | None -> []
+ | Some theta' -> Lib.maybemap (fun theta'' -> Subst.union theta'' theta') (unifyComplexes xs zs)
+ end
+ end
+ | _,_ -> []
+
+(* Try to find substitutions which make a string-based RBS property match a ground one from the database. *)
+let tryFindRBSSubsts (theta_original:Subst.t) (bp:string * (string list list)) (rp:Database.rbsProperty) : Subst.t list =
+ let bp = Subst.applyToPartTypeStrings theta_original bp in
+ match bp, rp with
+ | ("rate", [[q]]), Database.RATE(r) ->
+ begin match (Subst.unify q (Subst.NUMBER r)) with
+ | None -> []
+ | Some theta ->
+ begin match Subst.union theta_original theta with
+ | None -> []
+ | Some theta' -> [theta']
+ end
+ end
+ | _,_ -> []
+
+(* Try to find substitutions which make a string-based RBS property match a ground one from the database.
+ NB: this always returns an empty list because terminators don't have properties associated with them
+ (at least the one in the default database doesn't...) *)
+let tryFindTerSubsts (theta_original:Subst.t) (bp:string * (string list list)) : Subst.t list = []
+
+(* Compute a set of context-sensitive substitutions for a brick, relative to a database. *)
+let matchParts (db:Database.t) (brick:string) (t:string) (props:(string * (string list list)) list) : Cssubst.t list * string list =
+
+ (* Recursive function for searching the parts database. *)
+ let find ((res,log):Cssubst.t list * string list) (partId:string) (entry:Database.partType Database.entry) : Cssubst.t list * string list =
+ let partTy = entry.value in
+ if not entry.enabled then (res,log) else
+ // NB: If we limited the input, could we make this simpler???
+ // NB: Should we avoid converting everything to strings in trans.fs???
+ // NB: Should we convert the "database" to use a string-based system so it's more flexible for the future?
+ let init = if not(typesAgree t partTy) then [] else
+ match (Subst.unify brick (Subst.PART partId)) with Some init -> [init] | None -> []
+ in
+ let rec expand ((thetas,log):Subst.t list * string list) (bps:(string * (string list list)) list) : Subst.t list * string list =
+ match bps with
+ | [] -> (thetas,log)
+ | (bp::bps) ->
+ let rec substLoop (new_thetas:Subst.t list) (thetas:Subst.t list) =
+ match thetas with
+ | [] -> new_thetas
+ | (theta::thetas) ->
+ let extra_thetas =
+ begin match partTy with
+ | Database.PROM(props) -> Lib.collect (fun pp -> tryFindPromoterSubsts theta bp pp) props
+ | Database.PCR(prop) -> tryFindPCRSubsts theta bp prop
+ | Database.RBS(prop) -> tryFindRBSSubsts theta bp prop
+ | Database.TER -> tryFindTerSubsts theta bp (* NB: no property to put here as terminators don't have any... *)
+ end
+ in
+ substLoop (new_thetas@extra_thetas) thetas
+ in
+ let new_thetas = substLoop [] thetas in
+ let extra_log = ["Thetas are:\n" + (Lib.string_of_list Subst.display"\n" thetas);
+ "New_thetas are:\n" + (Lib.string_of_list Subst.display"\n" new_thetas)] in
+ let new_log = log@extra_log in
+ expand (new_thetas,new_log) bps
+ in
+ let initString = "Initial subst: " + (match init with [init] -> Subst.display init | _ -> "*NO MATCH*") in
+ let propsString =
+ let inner (zs:string list) = "[" + (Lib.string_of_list Lib.id ";" zs) + "]" in
+ "Properties: " + (Lib.string_of_list (fun (x,zss) -> x + "(" + (Lib.string_of_list inner "," zss) + ")") "; " props)
+ in
+ let thetas,expand_log = expand (init,[]) props in
+ // Eliminate any duplicate results from the list of substitutions
+ let thetas = Lib.remove_duplicates Subst.eq thetas in
+ let mkCSSubst (theta:Subst.t) : (Cssubst.t * string) option =
+ let rho = Subst.speciesDomain theta in
+ let ground_props = List.map (Subst.applyToPartTypeStrings theta) props in
+ let sigma = Lib.collect_union Ast.complexesEqual getComplexesFromStrings ground_props in
+ let tau = Lib.difference Ast.complexesEqual (Database.speciesInPartType partTy) sigma in
+ let cs = Cssubst.make theta rho sigma tau in
+ let log = "Producing a CSSubst: " + Lib.newline +
+ Cssubst.display cs + Lib.newline +
+ "...where FS(Q_i) = " + Lib.string_of_list Ast.complexString ", " (Database.speciesInPartType partTy) + Lib.newline +
+ "...where ground_props = " + Lib.string_of_list (fun (x,ps) -> x+"("+(Lib.string_of_list Ast.complexString ", " ps)+")") ", " ground_props in
+ if Cssubst.isOK cs then Some (cs,log) else None
+ in
+ let new_csSubstsLogs = Lib.maybemap mkCSSubst thetas in
+ let new_csSubsts, new_CsLogs = Lib.unzip new_csSubstsLogs in
+ let new_log = propsString::new_CsLogs in
+ ((res@new_csSubsts),(log@new_log))
+ in
+ Stringmap.fold find ([],[]) db.parts
+
+(* Compute a set of context-sensitive substitutions for a normal reaction, relative to a database. *)
+let matchNormalReactions (db:Database.t) (catalysts:string list list) (reactants:string list list)
+ (products:string list list) (rate:string) : Cssubst.t list * string list =
+
+ (* Recursive function for searching the reactions database. *)
+ let find ((res,log):Cssubst.t list * string list) (entry:Gecreaction.t Database.entry) : Cssubst.t list * string list =
+ if not entry.enabled then (res,log) else
+ let reac = entry.value in
+ match Gecreaction.isNormal reac with
+ | None -> (res,log)
+ | Some(r_catalysts,r_reactants,r_products,r_rate) ->
+ let log = log@["Trying reaction " + Lib.quote (Gecreaction.display reac)] in
+ // All substitutions that unify the catalysts
+ let thetasE = unifyComplexLists catalysts r_catalysts in
+ let log = log@["thetasE = " + Lib.string_of_list Subst.display " ~~ " thetasE] in
+ // Each substitution in thetasE may be expanded to multiple substitutions that also unify the reactants
+ let thetasER = Lib.collect (fun theta -> let reactants = List.map (Subst.applyToComplex theta) reactants in
+ let thetas' = unifyComplexLists reactants r_reactants in
+ Lib.maybemap (Subst.union theta) thetas') thetasE
+ in
+ let log = log@["thetasER = " + Lib.string_of_list Subst.display " ~~ " thetasER] in
+ // Each substitution in thetasER may be expanded to multiple substitutions that also unify the products
+ let thetasERP = Lib.collect (fun theta -> let products = List.map (Subst.applyToComplex theta) products in
+ let thetas' = unifyComplexLists products r_products in
+ Lib.maybemap (Subst.union theta) thetas') thetasER
+ in
+ let log=log@["thetasERP = " + Lib.string_of_list Subst.display " ~~ " thetasERP] in
+ // Each substution in thetasERP may be extended to also unify the rates
+ let thetasERPr = Lib.maybemap (fun theta -> match Subst.unify rate (Subst.NUMBER r_rate) with
+ | None -> None
+ | Some theta' -> Subst.union theta theta') thetasERP
+ in
+ // Eliminate any duplicate results from the list of substitutions
+ let thetasERPr = Lib.remove_duplicates Subst.eq thetasERPr in
+ let log = log@["thetasERPr = " + Lib.string_of_list Subst.display " ~~ " thetasERPr] in
+ let mkCSSubst (theta:Subst.t) : Cssubst.t option =
+ let ground_reaction = Gecreaction.applySubst theta reac in
+ let rho = Subst.speciesDomain theta in
+ let sigma = Gecreaction.species ground_reaction in
+ let cs = Cssubst.make theta rho sigma [] in
+ if Cssubst.isOK cs then Some cs else None
+ in
+ let new_csSubsts = Lib.maybemap mkCSSubst thetasERPr in
+ ((res@new_csSubsts),log)
+ in
+ Lib.fold_left find ([],[]) db.reactions
+
+(* Compute a set of context-sensitive substitutions for a transport reaction, relative to a database. *)
+let matchTransportReactions (db:Database.t) (reactant:string list) (product:string list) (rate:string)
+ (compartment:string) (direction:Ast.direction) : Cssubst.t list * string list =
+
+ (* Recursive function for searching the reactions database. *)
+ let find ((res,log):Cssubst.t list * string list) (entry:Gecreaction.t Database.entry) : Cssubst.t list * string list =
+ if not entry.enabled then (res,log) else
+ let reac = entry.value in
+ match Gecreaction.isTransport reac with
+ | None -> (res,log)
+ | Some (r_reactant,r_product,r_rate,r_compartment,r_direction) ->
+ let log = log@["Trying reaction " + Lib.quote (Gecreaction.display reac)] in
+ if not(r_direction = direction) then (res,log@["...Directions don't match!"]) else
+ // All substitutions that unify the reactant
+ let thetasR = unifyComplexes reactant r_reactant in
+ let log = log@["thetasR = " + Lib.string_of_list Subst.display " ~~ " thetasR] in
+ // Each substitution in thetasR may be expanded to multiple substitutions that also unify the product
+ let thetasRP = Lib.collect (fun theta -> let product = Subst.applyToComplex theta product in
+ let thetas' = unifyComplexes product r_product in
+ Lib.maybemap (Subst.union theta) thetas') thetasR
+ in
+ let log = log@["thetasRP = " + Lib.string_of_list Subst.display " ~~ " thetasRP] in
+ // Each substution in thetasRP may be extended to also unify the rates
+ let thetasRPr = Lib.maybemap (fun theta -> match Subst.unify rate (Subst.NUMBER r_rate) with
+ | None -> None
+ | Some theta' -> Subst.union theta theta') thetasRP
+ in
+ // Eliminate any duplicate results from the list of substitutions
+ let thetasRPr = Lib.remove_duplicates Subst.eq thetasRPr in
+ let log = log@["thetasRPr = " + Lib.string_of_list Subst.display" ~~ " thetasRPr] in
+ let mkCSSubst (theta:Subst.t) : Cssubst.t option =
+ let ground_reaction = Gecreaction.applySubst theta reac in
+ let rho = Subst.speciesDomain theta in
+ let sigma = Gecreaction.species ground_reaction in
+ let cs = Cssubst.make theta rho sigma [] in
+ if Cssubst.isOK cs then Some cs else None
+ in
+ let new_csSubsts = Lib.maybemap mkCSSubst thetasRPr in
+ ((res@new_csSubsts),log)
+ in
+ Lib.fold_left find ([],[]) db.reactions
diff --git a/ClassicGEC/ClassicGECDotNet/solver.fsi b/ClassicGEC/ClassicGECDotNet/solver.fsi
new file mode 100644
index 0000000..0204064
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/solver.fsi
@@ -0,0 +1,16 @@
+module Microsoft.Research.GEC.Solver
+
+open Microsoft.Research.GEC
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* Compute a set of context-sensitive substitutions for a brick, relative to a database. *)
+val matchParts : Database.t -> string -> string -> (string * (string list list)) list -> Cssubst.t list * string list
+
+(* Compute a set of context-sensitive substitutions for a normal reaction, relative to a database. *)
+val matchNormalReactions : Database.t -> string list list -> string list list -> string list list -> string -> Cssubst.t list * string list
+
+(* Compute a set of context-sensitive substitutions for a transport reaction, relative to a database. *)
+val matchTransportReactions : Database.t -> reactant:string list -> product:string list -> string -> string ->
+ Ast.direction -> Cssubst.t list * string list
diff --git a/ClassicGEC/ClassicGECDotNet/subst.fs b/ClassicGEC/ClassicGECDotNet/subst.fs
new file mode 100644
index 0000000..6b363d3
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/subst.fs
@@ -0,0 +1,232 @@
+[]
+module Microsoft.Research.GEC.Subst
+open Microsoft.Research.GEC
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+module Expressions = Microsoft.Research.CRNEngine.Expression
+(* ************************************************************************************************************ *)
+
+(* A "normal" substitution can either produce a species name, a part id or a real number. *)
+type target = SPECIES of string list
+ | PART of string
+ | NUMBER of float
+ | ALGEBRAIC_EXPRESSION of Ast.aexp
+type t = target Stringmap.t
+
+(* The empty substitution and singleton substitution. *)
+let empty : t = Stringmap.empty
+let singleton (x:string) (t:target) : t = empty |> Stringmap.add x t
+
+(* Produce a string representation of a substitution. *)
+let displayTarget = function
+ | SPECIES ys -> Ast.complexString ys
+ | PART y -> y
+ | NUMBER n -> Lib.display_float n
+ | ALGEBRAIC_EXPRESSION(_) -> "(algebraic_expression)"
+let display (theta:t) =
+ let body = Stringmap.fold (fun acc x tgt -> acc + "(" + Lib.quote x + ", " + Lib.quote (displayTarget tgt) + ")" + "; ") "" theta in
+ "[" + body + "]"
+
+(* Find the result of looking up a variable (NB raises an exception if not found...) *)
+let find (x:string) (theta:t) = Stringmap.find x theta
+
+(* Try to find the result of lookup up a variable (returns an option type). *)
+let tryFind (x:string) (theta:t) = Stringmap.tryFind x theta
+
+(* An equality function on substitution targets, which accounts for complexes. *)
+let targetEq (tgt1:target) (tgt2:target) : bool =
+ match tgt1, tgt2 with
+ | SPECIES xs1, SPECIES xs2 -> Ast.complexesEqual xs1 xs2
+ | PART p1, PART p2 -> p1=p2
+ | NUMBER f1, NUMBER f2 -> f1=f2
+ | _,_ -> false
+
+(* An equality function on substitutions themselves. *)
+let eq (theta1:t) (theta2:t) =
+ let dom1 = Stringmap.getKeys theta1 in
+ let dom2 = Stringmap.getKeys theta2 in
+ if (dom1=dom2) then
+ Lib.forall (fun x -> targetEq (find x theta1) (find x theta2)) dom1
+ else false
+
+(* Compute the union of two substitutions, if possible. *)
+let union (theta1:t) (theta2:t) : t option =
+ Stringmap.fold (fun acc x t ->
+ match acc with
+ | None -> None
+ | Some smap ->
+ match Stringmap.tryFind x smap with
+ | None -> Some(Stringmap.add x t smap)
+ | Some t' -> if t=t' then Some smap else None)
+ (Some theta1) theta2
+
+(* Compute Dom_S(theta). *)
+let speciesDomain (theta:t) =
+ let f snames x tgt : string list =
+ match tgt with
+ | SPECIES _ -> Lib.maybeappend (=) snames x
+ | _ -> snames
+ in
+ Stringmap.fold f [] theta
+
+(* ************************************************************************************************************ *)
+
+(* Does a string correspond to a meta-variable? (i.e. does it begin with a capital? *)
+let isMetaVariable (x:string) : bool =
+ System.Char.IsUpper (x.[0])
+
+(* Does a string correspond to a floating-point value? *)
+let getFloat (x:string) : float option =
+ let ret = ref 0.0
+ if System.Double.TryParse(x, ret) then Some !ret else None
+
+(* Implement a rudimentary "occurs check". Assumes that x is a metavariable. *)
+let occursCheckPassed (x:string) (tgt:target) : bool =
+ match tgt with
+ | PART z -> not(x=z)
+ | SPECIES zs -> not(Lib.contains x zs)
+ | _ -> true
+
+(* "Unify" a string from the program with a "substTarget" from the database. *)
+let unify (x:string) (tgt:target) : t option =
+ if isMetaVariable x then
+ (if occursCheckPassed x tgt then Some(singleton x tgt) else None)
+ else
+ match tgt with
+ | PART z -> if x=z then Some empty else None
+ | SPECIES zs -> (if zs=[x] then Some empty else None)
+ | NUMBER f -> (match getFloat x with None -> None | Some f' -> if f=f' then Some empty else None)
+ | ALGEBRAIC_EXPRESSION a -> None // check this
+
+(* Turn an association list into a substitution, if possible... *)
+let multiple (prs:(string * target) list) : t option =
+ let rec loop (theta:t) (prs:(string * target) list) =
+ match prs with
+ | [] -> Some theta
+ | ((x,t)::prs) ->
+ begin match unify x t with
+ | None -> None
+ | Some theta' ->
+ begin match union theta theta' with
+ | None -> None
+ | Some theta -> loop theta prs
+ end
+ end
+ in
+ loop empty prs
+
+(* Apply a substitution to a complex, represented as strings. *)
+let applyToComplex (theta:t) (xs:string list) : string list =
+ Lib.collect (fun x -> match tryFind x theta with Some(SPECIES zs) -> zs | _ -> [x]) xs
+
+(* Apply a substitution to a "part type" presented as in trans.fs, using strings... *)
+let applyToPartTypeStrings (theta:t) (pt:string * (string list list)) : string * (string list list) =
+ let (brickType, brickProps) = pt in
+ let applySubst x = match tryFind x theta with None -> x | Some tgt -> displayTarget tgt in
+ (brickType, List.map (List.map applySubst) brickProps)
+
+(* Apply a substitution to a "gecSpecies" (for generic plotting). *)
+let applyToGecSpecies (theta:t) (i:Ast.gecSimpleSpecies) : Ast.gecSimpleSpecies =
+ (* Apply a substitution to a value. *)
+ let applyToValue (theta:t) (v:Ast.value) : Ast.value list =
+ match v with
+ | Ast.IdVal x -> begin match tryFind x theta with
+ | Some (SPECIES(xs)) -> List.map (fun x -> Ast.IdVal(x)) xs
+ | _ -> [v]
+ end
+ | _ -> [v]
+ in
+ (* Apply a substitution to a "simple" GEC species. *)
+ let applyToSimpleGecSpecies (theta:t) (i:Ast.gecSimpleSpecies) : Ast.gecSimpleSpecies =
+ match i with
+ | Ast.SimpleSpecies ac -> Ast.SimpleSpecies(Lib.collect (applyToValue theta) ac)
+ | Ast.CompartmentSpecies(c,ac) -> Ast.CompartmentSpecies(c, Lib.collect (applyToValue theta) ac)
+ in
+ (applyToSimpleGecSpecies theta) i
+
+(* Apply a substitution to a directive data structure (for generic plotting). *)
+let applyToDirective (theta:t) (d:Ast.directive) : Ast.directive =
+ (* Apply a substitution to a "plottable". *)
+ let applyToPlottable (theta:t) (p:Ast.gecSimpleSpecies Key Expression.t) = Expressions.map (Key.map (applyToGecSpecies theta)) p in
+ (*
+ let rec applyToPlottable (theta:t) (p:Ast.gecSpecies Plottable.t) : Ast.gecSpecies Plottable.t = match p with
+ | Expressions.PopulationAExp g -> Expressions.PopulationAExp (applyToGecSpecies theta g)
+ //| Plottable.PLOT_STRING s -> Plottable.PLOT_STRING s
+ | Expressions.SumAExp ps -> Expressions.SumAExp (List.map (applyToPlottable theta) ps)
+ in *)
+ match d with
+ | Ast.PLOT ps -> Ast.PLOT (List.map (applyToPlottable theta) ps)
+ | _ -> d
+
+(* Apply a substitution to an arithmetic expression. *)
+let rec applyToArithmeticExpression (theta:t) (a:Ast.aexp) : Ast.aexp =
+ match a with
+ | Ast.FloatAExp f -> Ast.FloatAExp f
+ | Ast.IdAExp x -> begin
+ match tryFind x theta with
+ | None -> Ast.IdAExp x
+ | Some (NUMBER f) -> Ast.FloatAExp f
+ | Some t -> failwith ("applyToArithmeticExpression: illegal substitution because " + x + " maps to " + (displayTarget t))
+ end
+ | Ast.PlusAExp (a1,a2) -> Ast.PlusAExp((applyToArithmeticExpression theta a1),(applyToArithmeticExpression theta a2))
+ | Ast.MinusAExp (a1,a2) -> Ast.MinusAExp((applyToArithmeticExpression theta a1),(applyToArithmeticExpression theta a2))
+ | Ast.MulAExp (a1,a2) -> Ast.MulAExp((applyToArithmeticExpression theta a1),(applyToArithmeticExpression theta a2))
+ | Ast.DivAExp (a1,a2) -> Ast.DivAExp((applyToArithmeticExpression theta a1),(applyToArithmeticExpression theta a2))
+ | Ast.PowAExp (a1,a2) -> Ast.PowAExp((applyToArithmeticExpression theta a1),(applyToArithmeticExpression theta a2))
+
+(* ************************************************************************************************************ *)
+
+(* Does a ground constraint hold between floating point values? *)
+let groundConstraintHolds ((f1,op,f2):float*Ast.op*float) : bool =
+ match op with
+ | Ast.Lt -> f1 f1>f2
+ | Ast.Eq -> f1=f2
+
+(* Try to evaluate an algebraic expression to a float, using a given substitution. *)
+let rec tryProduceFloat (theta:t) (a:Ast.aexp) : float option =
+ match a with
+ | Ast.FloatAExp f -> Some f
+ | Ast.IdAExp id -> if isMetaVariable id then begin match tryFind id theta with Some(NUMBER f) -> Some f | _ -> None end
+ else failwith ("Subst.satisfiesConstraint: " + id + " is not a metavariable.")
+ | Ast.PlusAExp (a1,a2) -> (match (tryProduceFloat theta a1, tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> Some(f1 + f2)
+ | _,_ -> None)
+ | Ast.MinusAExp (a1,a2) -> (match (tryProduceFloat theta a1, tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> Some(f1 - f2)
+ | _,_ -> None)
+ | Ast.MulAExp (a1,a2) -> (match (tryProduceFloat theta a1, tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> Some(f1 * f2)
+ | _,_ -> None)
+ | Ast.DivAExp (a1,a2) -> (match (tryProduceFloat theta a1, tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> Some(f1 / f2)
+ | _,_ -> None)
+ | Ast.PowAExp (a1,a2) -> (match (tryProduceFloat theta a1, tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> Some(f1 * f2)
+ | _,_ -> None)
+
+(* Check whether a substitution satisfies an arithmetic constraint. *)
+let satisfiesConstraint (theta:t) ((a1,op,a2):Ast.aexp*Ast.op*Ast.aexp) : bool =
+ (* Turn a string into a float, using a given substitution, if possible... *)
+ match (tryProduceFloat theta a1),(tryProduceFloat theta a2) with
+ | Some f1, Some f2 -> groundConstraintHolds (f1,op,f2)
+ | _,_ -> true (* Constraints involving uninstantiated variables can always be satisfied. *)
+
+(* Produce a "varAss" (variable assignments) from a substitution. *)
+let mkVarAss (theta:t) : (string * string) list * (string * string) list * (string * string) list =
+ Stringmap.fold
+ (fun (parts,species,rates) x tgt ->
+ match tgt with
+ | SPECIES ys ->
+ (parts,(species@[x,(Ast.complexString ys)]),rates)
+ | PART y ->
+ ((parts@[x,y]),species,rates)
+ | NUMBER n ->
+ (parts,species,(rates@[x,(Lib.display_float n)]))
+ | ALGEBRAIC_EXPRESSION a ->
+ (parts,species,(rates@[x,(Ast.lbsStringOfAExp a)]))
+ )
+ ([],[],[])
+ theta
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNet/subst.fsi b/ClassicGEC/ClassicGECDotNet/subst.fsi
new file mode 100644
index 0000000..a91e0d1
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/subst.fsi
@@ -0,0 +1,71 @@
+module Microsoft.Research.GEC.Subst
+
+open Microsoft.Research.GEC
+
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+(* ************************************************************************************************************ *)
+
+(* The target of a "normal" substitution can either produce a species name, a part id or a real number. *)
+type target = SPECIES of string list
+ | PART of string
+ | NUMBER of float
+ | ALGEBRAIC_EXPRESSION of Ast.aexp
+type t = target Stringmap.t
+
+(* The empty substitution. *)
+val empty : t
+
+(* An equality function on substitution targets, which accounts for complexes. *)
+val targetEq : target -> target -> bool
+
+(* An equality function on substitutions themselves. *)
+val eq : t -> t -> bool
+
+(* Produce a string representation of a substitution. *)
+val displayTarget : target -> string
+val display : t -> string
+
+(* Compute the union of two substitutions, if possible. *)
+val union : t -> t -> t option
+
+(* Compute Dom_S(theta). *)
+val speciesDomain : t -> string list
+
+(* Find the result of looking up a variable (NB raises an exception if not found...) *)
+val find : string -> t -> target
+
+(* Try to find the result of lookup up a variable (returns an option type). *)
+val tryFind : string -> t -> target option
+
+(* Does a string correspond to a floating-point value? *)
+val getFloat : string -> float option
+
+(* ************************************************************************************************************ *)
+
+(* "Unify" a string from the program with a "target" from the database. *)
+val unify : string -> target -> t option
+
+(* Turn an association list into a substitution, if possible... *)
+val multiple : (string * target) list -> t option
+
+(* Apply a substitution to a complex. *)
+val applyToComplex : t -> string list -> string list
+
+(* Apply a substitution to a "part type" presented as in trans.fs, using strings... *)
+val applyToPartTypeStrings : t -> string * (string list list) -> string * (string list list)
+
+(* Apply a substitution to a directive data structure (for generic plotting). *)
+val applyToDirective : t -> Ast.directive -> Ast.directive
+
+(* Apply a substitution to an arithmetic expression. *)
+val applyToArithmeticExpression : t -> Ast.aexp -> Ast.aexp
+
+(* ************************************************************************************************************ *)
+
+(* Check whether a substitution satisfies an arithmetic constraint. *)
+val satisfiesConstraint : t -> (Ast.aexp * Ast.op * Ast.aexp) -> bool
+
+(* Produce a "varAss" (variable assignments) from a substitution. *)
+val mkVarAss : t -> (string * string) list * (string * string) list * (string * string) list
diff --git a/ClassicGEC/ClassicGECDotNet/trans.fs b/ClassicGEC/ClassicGECDotNet/trans.fs
new file mode 100644
index 0000000..8d8c9d1
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNet/trans.fs
@@ -0,0 +1,1389 @@
+(*
+Defines the main translation function for LSB programs.
+
+Author: Michael Pedersen.
+Copyright Microsoft Research, 2008-2009.
+*)
+
+#light
+
+
+[]
+module Microsoft.Research.GEC.Trans
+
+open System
+open Microsoft.Research.GEC.Ast
+open System.Text.RegularExpressions
+//open Microsoft.Research.ModellingEngine
+open Microsoft.Research.CRNEngine
+
+
+// define the type of lbs programs that we translate to:
+type tLBSProg =
+ | LBSReacAbstraction of tLBSReac * tLBSProg // needed for promoters which are possibly characterised by hill functions, but this is only known after a substitution is applied.
+ | LBSReac of tLBSReac
+ | LBSDegReac of string list list * string // needed in order to put degradation reactions in all compartments.
+ | LBSTrans of (string list) * (string list) * string * string * direction
+ | LBSComp of string * tLBSProg
+ | LBSPar of tLBSProg * tLBSProg
+ | LBSInitPop of string list * float
+ | LBSCompDec of string * tLBSProg
+ | LBSCopy of int * tLBSProg
+ | LBSNil
+ | LBSDevice of string
+
+// a reactions consists of enzymes; reactants; products; a rate; and a boolean indicating if the rate is mass-action:
+and tLBSReac = string list list * string list list * string list list * string * bool
+
+
+// lets now define the type of return objects.
+// first there are "translation functions" -- these are used to
+// produce reactions representing the genetic translation process.
+// the first function is parameterised on both mrna and the target protein (complex).
+// the following two functions are parameterised on only one of these.
+type tTranslFunc = (string -> string list -> tLBSProg) list
+type tTranslFunc1 = (string -> tLBSProg) list
+type tTranslFunc2 = (string list -> tLBSProg) list
+
+// for the translation to reactions we also need to keep track of the "current"
+// mrna and target protein -- these will be passed to the above functions when appropriate.
+// they are lists in order to cope with parallel composition, but only
+// singleton/empty lists are supported by the sequential composition operation for now.
+type tCurrentMRNA = string list
+type tCurrentProt = string list list
+
+// rate declarations:
+type tRateDecs = (string * float) list
+
+// now to the targets of the genetic translation.
+// first we have a 2d list of brick ids/vars:
+type tBbDevices = string list list
+
+
+
+// Workaround for issues with TextBox in Silverlight
+let newline = "\n"
+
+// the following family converts translated structures to prolog representations:
+let lstToProlog absComp =
+ "[" + (Lib.string_of_list Lib.id "," absComp) + "]"
+
+let lst2dToProlog absCompLst =
+ let absCompLst' = absCompLst |> List.map (fun absComp -> lstToProlog absComp)
+ "[" + (Lib.string_of_list Lib.id "," absCompLst') + "]"
+
+let propToProlog p =
+ match p with
+ | Some (pname, absCompLst) ->
+ // note that we can't use lst2dToProlog for the body of the properties, since
+ // the outer brackets of the 2d list shouldn't be included in this case.
+ let lstStr = absCompLst |> List.map (fun absComp -> lstToProlog absComp)
+ pname + "(" + (Lib.string_of_list Lib.id "," lstStr) + ")"
+ | None -> "_"
+
+(* These are the only kinds of constraint that are produced by the translation... *)
+type gecConstraint = IS_EMPTY_LIST of string
+ | PROM of string * (string * (string list list)) option
+ | RBS of string * (string * (string list list)) option
+ | PCR of string * (string * (string list list)) option
+ | TER of string * (string * (string list list)) option
+ | UNION of string * string * string // These always involve VARIABLES
+ | EXCLUSIVE_NAMES of string * string * string list list * string // These always go VARIABLE-VARIABLE-LITERAL-VARIABLE
+ | NAMES_DISJOINT of string list list * string * string list list * string // These always go LITERAL-VARIABLE-LITERAL-VARIABLE
+ | NO_DUPLICATES of string list // These always involve LIST LITERALS
+ | ARITHMETIC of aexp * Ast.op * aexp
+ | REACTION of string list list * string list list * string list list * string
+ | TRANSPORT of string list * string list * Ast.direction * string
+
+(* Produce a string representation of a constraint. *)
+let printConstraint (c:gecConstraint) =
+ let printClause (r:string) (xs:string list) =
+ r + "(" + (Lib.string_of_list Lib.id "," xs) + ")"
+ in
+ match c with
+ | IS_EMPTY_LIST(x) -> x + "=[]"
+ | PROM(x,y) -> printClause "prom" [x;(propToProlog y)]
+ | RBS(x,y) -> printClause "rbs" [x;(propToProlog y)]
+ | PCR(x,y) -> printClause "pcr" [x;(propToProlog y)]
+ | TER(x,y) -> printClause "ter" [x;(propToProlog y)]
+ | UNION(x,y,z) -> printClause "union" [x;y;z]
+ | EXCLUSIVE_NAMES(w,x,y,z) -> printClause "exclusiveNames" [w;x;(lst2dToProlog y);z]
+ | NAMES_DISJOINT(w,x,y,z) -> printClause "namesDisjoint" [(lst2dToProlog w);x;(lst2dToProlog y);z]
+ | NO_DUPLICATES(x) -> printClause "noDuplicates" [lstToProlog x]
+ | ARITHMETIC(x,op,y) -> (Ast.stringOfAExp x) + (match op with Ast.Lt -> "<" | Ast.Eq -> "=" | Ast.Gt -> ">") + (Ast.stringOfAExp y)
+ | REACTION(es,rs,ps,r) -> printClause "reac" [(lst2dToProlog es);(lst2dToProlog rs);(lst2dToProlog ps);(lstToProlog [r])]
+ | TRANSPORT(x,y,Ast.In,r) -> printClause "transport" [(lstToProlog x); (printClause "compartment" [lstToProlog y]); (lstToProlog [r])]
+ | TRANSPORT(x,y,Ast.Out,r) -> printClause "transport" [(printClause "compartment" [lstToProlog x]); (lstToProlog y); (lstToProlog [r])]
+
+(* Given a brick type, return a constructor for the gecConstraint type. *)
+let getConstraintConstructor (t:string) =
+ match t with
+ | "prom" -> PROM
+ | "rbs" -> RBS
+ | "pcr" -> PCR
+ | "ter" -> TER
+ | _ -> failwith ("\nType error: unexpected brick type: " + t + "\n")
+
+// a variable which in Plolog will unify with a list of exclusive species:
+type tExcSpecVar = string
+
+// a list of species names occurring in a given program:
+type tSpecNames = string list list
+
+// a list of constraints for PROLOG: (NB - delete these soon??)
+type tPrologConstraints = gecConstraint list
+//type tPrologConstraints = string list
+
+// a type for arithmetic constraints collected for solving at the end
+type tArithmeticConstraints = (aexp * op * aexp) list
+let stringOfArithmeticConstraint ((a1,op,a2):aexp*op*aexp) =
+ (Ast.stringOfAExp a1) + " " + (stringOfOp op) + " " + (Ast.stringOfAExp a2)
+
+// and a set of context-sensitive substitutions.
+type tSubstitutions = Cssubst.t list
+
+// all of the above are collected into a semantic object record:
+type tSemObj = {
+ translFunc : tTranslFunc;
+ translFunc1 : tTranslFunc1;
+ translFunc2 : tTranslFunc2;
+ currentMRNA : tCurrentMRNA;
+ currentProt : tCurrentProt;
+ bbDevices : tBbDevices;
+ prologConstraints : tPrologConstraints;
+ arithmeticConstraints : tArithmeticConstraints;
+ substitutions : tSubstitutions;
+ exclusiveSpecVar : tExcSpecVar;
+ specNames : tSpecNames;
+ lbsProg : tLBSProg;
+ rateDefs : tRateDecs;
+ log : string list
+ }
+
+// now to the definition of environment types (a parameter to the translation function).
+// first define the type of substitutions (formal/actual pars) and module environments:
+type tsubst = Map
+type tenvm = Map tSemObj>
+
+// collect the latter two into an environment record for convenience --
+// also add simulation-only flag:
+type tenv = {envm : tenvm; subst : tsubst; simOnlyReacs : bool}
+
+// a closure for generating unique numbers (from Expert F# p. 75):
+let private newStr = // ref (fun () -> "Fixme")
+ let count = ref 0
+ (fun () -> count := !count + 1; string !count)
+
+// Reset the "newStr" counter, so we start numbering from scratch each time we compile
+//let resetCounter () =
+// let count = ref 0
+// newStr := (fun () -> count := !count + 1; Int32.to_string !count)
+
+
+
+// use the above for generating new variables:
+let rec newVar(existing: string list) =
+ let a = "X_" + newStr()
+ if List.contains(a) existing then
+ newVar(existing)
+ else
+ a
+
+
+// define an empty semantic object:
+
+
+
+// Note that mRNA degradation rates do not associate naturally with any part.
+// So for now, we use a globally defined variable with the following default value.
+let RMRNADeg_string = "RMRNADeg"
+let default_RMRNADeg = 0.001
+
+// Expand a set of rateDecs to include the default RMRNADeg string, if necessary
+let expandRateDecs (rateDecs:tRateDecs) : tRateDecs = if (List.exists (fun (x,_) -> x=RMRNADeg_string) rateDecs) then rateDecs
+ else (RMRNADeg_string, default_RMRNADeg)::rateDecs
+
+// Turn a set of rateDecs into a substitution
+let substOfRateDecs (rateDecs:tRateDecs) : Subst.t = Lib.fold_left (fun theta (r,f) -> Stringmap.add r (Subst.NUMBER f) theta) Subst.empty rateDecs
+
+// Apply a set of rateDecs to an arithmetic constraint
+let applyRateDecs2ArithmeticConstraints (rateDecs:tRateDecs) (acs:tArithmeticConstraints) : tArithmeticConstraints =
+ let theta = substOfRateDecs rateDecs in
+ List.map (fun (a1,op,a2) -> ((Subst.applyToArithmeticExpression theta a1),op,(Subst.applyToArithmeticExpression theta a2))) acs
+
+// flag for ignoring consistency constraints:
+let ignoreConsistencyConstraints = ref false
+
+// flag specifying whether constants or variables should be used when introducing
+// e.g. new facts in constraints; the former is for translation of human-readable
+// databases to prolog databases:
+let useConstants = ref false
+
+let rec findExpVars (exp:aexp) =
+ match exp with
+ | FloatAExp(_) -> []
+ | IdAExp(str) -> [str]
+ | PlusAExp(e1,e2) ->
+ (findExpVars e1)@(findExpVars e2)
+ | MinusAExp(e1,e2) ->
+ (findExpVars e1)@(findExpVars e2)
+ | MulAExp(e1,e2) ->
+ (findExpVars e1)@(findExpVars e2)
+ | DivAExp(e1,e2) ->
+ (findExpVars e1)@(findExpVars e2)
+ | PowAExp(e1,e2) ->
+ (findExpVars e1)@(findExpVars e2)
+
+
+let findValueExp (v:Ast.value) =
+ match v with
+ | IdVal(str) -> [str]
+ | AlgebraicExp(exp) -> findExpVars exp
+ | _ -> []
+
+let findAbstractComplexExp (a:Ast.abstractComplex) =
+ let alist = a |> List.map(fun (value) -> findValueExp value)
+
+ match alist.Length with
+ | 0 -> []
+ | 1 -> alist.Head
+ | _ -> alist |> List.reduce (fun a b -> (a@b))
+
+
+let findAbstractComplexListExp (a: Ast.abstractComplex list) =
+ let alist = a|> List.map(fun x -> findAbstractComplexExp x)
+ match alist.Length with
+ | 0 -> []
+ | 1 -> alist.Head
+ | _ -> alist |> List.reduce (fun a b -> (a@b))
+
+let findPropExp (p:Ast.prop) =
+ let (str,acomplex) = p
+ let alist = acomplex |> List.map(fun x -> findAbstractComplexExp x)
+ match alist.Length with
+ | 0 -> []
+ | 1 -> alist.Head
+ | _ -> alist |> List.reduce (fun a b -> (a@b))
+
+let findPropListExp (propList:Ast.prop list) =
+ let alist = propList |> List.map(fun x-> findPropExp x)
+ match alist.Length with
+ | 0 -> []
+ | 1 -> alist.Head
+ | _ -> alist |> List.reduce (fun a b -> (a@b))
+
+let rec findExistingVariables (program:prog) =
+ match program with
+ | Nil -> []
+ | Brick(brickId,_,propList) ->
+ (findValueExp brickId)@(findPropListExp propList)
+ | Reac(enz,react,prod,v,_) ->
+ (findAbstractComplexListExp enz) @
+ (findAbstractComplexListExp react) @
+ (findAbstractComplexListExp prod) @
+ (findValueExp v)
+ | Trans (react,prod,str,v,_,_) ->
+ str ::
+ (findAbstractComplexExp react) @
+ (findAbstractComplexExp prod) @
+ (findValueExp v)
+ | TemplateInv (str,args) ->
+ str ::
+ (findAbstractComplexListExp args)
+ | Seq(s1,s2) ->
+ (findExistingVariables s1)@(findExistingVariables s2)
+ | Par(p1,p2) ->
+ (findExistingVariables p1)@(findExistingVariables p2)
+ | Comp(comp,p) ->
+ comp::(findExistingVariables p)
+ | New(var,p) ->
+ var::(findExistingVariables p)
+ | TemplateDef(modName,args,p1,p2) ->
+ modName::args@(findExistingVariables p1)@(findExistingVariables p2)
+ | Constraint (exp1,_,exp2) ->
+ (findExpVars exp1)@(findExpVars exp2)
+ | Ast.Rate(value,_) -> findValueExp value
+ | InitPop(var,_) -> findAbstractComplexExp var
+ | Copy (_,p,_,_) -> findExistingVariables p
+ | Device (d) -> [d]
+
+// top-level translation function.
+// parameterised on a programme, and a boolean flag indicating simulation only reactions.
+//let translate_base (p:prog) (simOnlyReacs:bool) (db:Database.t) (mrnadeg:float) =
+let rec translate0 (p:prog) (simOnlyReacs:bool) (db:Database.t) =
+ // create empty environments:
+ let subst = Map.empty : tsubst
+ let envm = Map.empty : tenvm
+ let env = { subst = subst; envm = envm; simOnlyReacs = simOnlyReacs }
+ let existing = (findExistingVariables p) |> Set.ofList |> List.ofSeq
+ //Check in Database and GECReaction as well?
+ let excNv = newVar(existing)
+
+ let emptySemObj =
+ {
+ translFunc = [];
+ translFunc1 = [];
+ translFunc2 = [];
+ currentMRNA = [];
+ currentProt = [];
+ bbDevices = [];
+ prologConstraints = [IS_EMPTY_LIST(excNv)];
+ arithmeticConstraints = [];
+ substitutions = [];
+ exclusiveSpecVar = excNv;
+ specNames = [];
+ lbsProg = LBSNil;
+ rateDefs = [];
+ log = []
+ }
+
+ // invoke main translation function:
+ let sobj = translate db p env emptySemObj existing
+
+ // filter out those substitutions which don't satisfy the arithmetic constraints we have accumulated
+ let sobj = {sobj with substitutions = List.filter (fun cs -> Cssubst.satisfiesConstraints cs (applyRateDecs2ArithmeticConstraints sobj.rateDefs sobj.arithmeticConstraints)) sobj.substitutions}
+
+ // append the final set of context-sensitive substitutions to the log
+ let sobj = {sobj with log = sobj.log@["FINAL SET OF CONTEXT-SENSITIVE SUBSTITUTIONS:" + Lib.newline + Lib.string_of_list Cssubst.display Lib.newline sobj.substitutions]}
+
+ // return relevant fields of semantic object:
+ (sobj.bbDevices, sobj.prologConstraints, sobj.lbsProg, sobj.rateDefs, sobj.substitutions, sobj.arithmeticConstraints, sobj.log)
+
+ // main translation function.
+ // parameterised on a program and environment.
+ and translate (db:Database.t) (p:prog) (env:tenv) (emptySemObj:tSemObj) (existing:string list)=
+ match p with
+ | Nil ->
+ emptySemObj
+
+ | Device(d) ->
+ {emptySemObj with lbsProg=LBSDevice(d)}
+
+ | Brick(v, t, propLst) ->
+ // preprocess property list, replacing derived properties (non-quantitative) with their defined counterparts:
+ let prepProp (prop:prop) =
+
+ match (t, prop) with
+ | ("prom", ("pos", [tf])) ->
+ let (r1, r2, r3) =
+ if !useConstants then
+ ("0", "0", "0")
+ else
+ (newVar(existing), newVar(existing), newVar(existing))
+ ("pos", [tf; [IdVal(r1)]; [IdVal(r2)]; [IdVal(r3)]])
+
+ | ("prom", ("neg", [tf])) ->
+ let (r1, r2, r3) =
+ if !useConstants then
+ ("0", "0", "0")
+ else
+ (newVar(existing), newVar(existing), newVar(existing))
+
+ ("neg", [tf; [IdVal(r1)]; [IdVal(r2)]; [IdVal(r3)]])
+
+ | ("pcr", ("codes", [prot])) ->
+ let r = if !useConstants then "0" else newVar(existing)
+ ("codes", [prot; [IdVal(r)]])
+
+ | _ -> prop
+
+ // invoke:
+ let propLst''' = List.map prepProp propLst
+
+ // if promoter does not have a constitutive property, then add one:
+ let conRate = if !useConstants then "0" else newVar(existing)
+ let propLst'' = if (t <> "prom" || List.exists (fun (pname, lst) -> pname = "con") propLst''') then
+ propLst'''
+ else
+ ("con", [[IdVal(conRate)]])::propLst'''
+
+ // if promoter does not have a functional rate property, then add one:
+ (*let funRate = if !useConstants then "0" else newVar()
+ let propLst'' = if (t <> "prom" || List.exists (fun (pname, lst) -> pname = "frate") propLst'') then
+ propLst''
+ else
+ ("frate", [[IdVal(funRate)]])::propLst''*)
+
+ // if ribosome binding site does not have a rate property, then add one:
+ let transcRate = if !useConstants then "1" else newVar(existing)
+ let propLst' = if (t <> "rbs" || List.exists (fun (pname, lst) -> pname = "rate") propLst'') then
+ propLst''
+ else
+ ("rate", [[IdVal(transcRate)]])::propLst''
+
+ // check that brick type is recognised:
+ if not (t = "prom" || t = "pcr" || t = "rbs" || t = "ter") then
+ failwith ("\nType error: unexpected brick type: " + t + "\n")
+
+
+ // process brick value:
+ let brick = match transVal v env existing with
+ | [b] -> b
+ | _ -> failwith("\nType error: non-atomic value used for brick identifier.\n")
+
+ // translate properties:
+ let propLst2 = (transPropLst propLst' env existing)
+
+ // get a constraint for each property:
+ let prologConstraints' = List.map (fun prop -> (getConstraintConstructor t) (brick, (Some prop))) propLst2
+
+ // in case there are no properties, or if we are translating in order to generate
+ // prolog database, add a constraint for the existence of an arbitrary biobrick:
+ let prologConstraints = if prologConstraints'.Length = 0 || !useConstants
+ then ((getConstraintConstructor t) (brick, None))::prologConstraints'
+ else prologConstraints'
+
+ // get species names and build constraints for exclusive names.
+ // first define a function which finds the species names of properties:
+ let getSpecNames (prop : string * string list list) =
+ match prop with
+ | (pname, x::xs) when pname = "pos" || pname = "neg" || pname = "pcr" || pname = "codes" -> [x]
+ | _ -> []
+
+ // and invoke:
+ let specNames = propLst2 |> Seq.collect getSpecNames |> Set.ofSeq |> Set.toList
+
+ // old version of above, where we take all elements of property, including numbers (rates).
+ // this works and is more general than the above, where we must know the properties, but it clutteres
+ // the prolog output for presentation and is probably less effifient.
+ //let specNames = propLst2 |> List.map (fun (pname, absCompLst) -> specNames absCompLst) |> List.flatten
+
+ let nv = newVar(existing)
+ let exclusiveNamesConstraint' = [EXCLUSIVE_NAMES(t,brick,specNames,nv)]
+ let exclusiveNamesConstraint = if !ignoreConsistencyConstraints then [] else exclusiveNamesConstraint'
+
+ // update semantic object with information gathered so far, i.e. concerning the translation to biobricks:
+ let newPrologConstraints = prologConstraints@exclusiveNamesConstraint
+
+ // Compute a list of substitutions for this brick
+ // NB: default database hard-coded in here...
+ let substitutions,logEntries = Solver.matchParts db brick t propLst2
+
+ // Produce some log output for debugging...
+ let newLog = ("Searched for " + brick + " in the database:")::logEntries in
+
+
+ let sobj = {emptySemObj with prologConstraints = emptySemObj.prologConstraints@newPrologConstraints;
+ substitutions = substitutions;
+ bbDevices = [[brick]];
+ specNames = specNames;
+ exclusiveSpecVar = nv;
+ log = emptySemObj.log @ newLog }
+
+ // now update the semantic object with information needed for translation to reactions:
+ let sobj' =
+ match t with
+ | "prom" ->
+ // create new names for gene and mrna:
+ let gene = "g" + newStr()
+ let mrna = "mrna" + newStr()
+
+ // create a degradation reaction for mrna
+ let mrnaDegReac = LBSReac([],[[mrna]],[[]], RMRNADeg_string, true)
+
+ // create initial population statement for gene:
+ let initPop = LBSInitPop([gene], 1.0)
+
+ // function for processing properties; ignores frate properties
+ let rec reacsFromProps prop =
+ match prop with
+ // a constitutive expression:
+ | ("con", [[rate]]) ->
+ let r1 = LBSReac([],[[gene]],[[gene]; [mrna]], rate, true)
+ [r1]
+
+ // a "quantitative" expression (either pos or neg):
+ | (_, [tf; [rBind]; [rUnbind]; [rTranscr]]) ->
+
+ let r1 = LBSReac( [],[[gene]; tf],[gene::tf], rBind, true)
+ let r2 = LBSReac( [],[gene::tf], [[gene]; tf], rUnbind, true)
+ let r3 = LBSReac( [],[gene::tf], [gene::tf; [mrna]], rTranscr, true)
+ [r1;r2;r3]
+
+ // if pos/neg property with no rates, just create fresh variables for rates:
+ | (pname, [tf]) when (pname="pos" || pname="neg") ->
+ reacsFromProps (pname, [tf; [newVar(existing)]; [newVar(existing)]; [newVar(existing)]])
+
+ | _ -> []
+
+ // apply the above function to get reactions:
+ let reactions' =
+ propLst2 |> List.collect reacsFromProps
+
+ // get the frate property and create a functional rate reaction from this:
+ let fRateProp =
+ List.tryFind
+ (fun prop ->
+ match prop with
+ | ("frate", [[rateStr]]) -> true
+ | _ -> false
+ )
+ propLst2
+ in
+ let fRateReac =
+ match fRateProp with
+ | Some("frate", [[rateStr]]) when (rateStr <> "0.0" && rateStr <> "0") ->
+ ( [],[[gene]], [[gene];[mrna]], rateStr, false)
+ | _ ->
+ ( [],[[gene]], [[gene];[mrna]], "0.0", false)
+
+
+ // put reactions in parallel:
+
+ let lbsProg'' = match reactions' with
+ | [] -> LBSNil
+ | [r] -> r
+ | r1::[r2] -> LBSPar(r1,r2)
+ | first::second::remaining ->
+ let firstPar = LBSPar(first,second)
+ List.fold (fun p1 p2 -> LBSPar(p1,p2)) firstPar remaining
+
+ //let lbsProg'' = Lib.fold_left (fun p1 p2 -> LBSPar(p1, p2)) LBSNil reactions'
+
+ // create abstraction construct with full reactions and the single functional rate reaction:
+ let lbsProg' = LBSReacAbstraction(fRateReac, lbsProg'')
+
+ // add mRNA degradation and init population:
+ let lbsProg = LBSPar(lbsProg', LBSPar(mrnaDegReac, initPop))
+
+ {sobj with lbsProg = lbsProg; currentMRNA = [mrna]}
+
+ | "rbs" ->
+ // declare a function which, given mrna and protein, returns a reaction:
+ let f mrna prot =
+ // find the rate in the first "rate" property encountered,
+ // or a fresh variable (or constant) if no such property is given.
+ let translRate = if !useConstants then "1" else newVar(existing)
+ let rec getRate propLst2 =
+ match propLst2 with
+ | [] -> translRate
+ | ("rate", [[r]])::rest -> r
+ | _::rest -> getRate rest
+
+ let rate = getRate propLst2
+ let r1 = LBSReac([],[[mrna]],[[mrna]; prot], rate, true)
+ r1
+
+ {sobj with translFunc = [f]}
+
+ | "pcr" ->
+ // function for finding the protein coded by this pcr:
+ let rec protFromProps (props : (string * string list list) list) =
+ match props with
+ | [] ->
+ None
+ | ("codes", [prot; [degRate]])::rest ->
+ Some(prot, degRate)
+ | _::rest ->
+ protFromProps []
+
+ // invoke the above function and record the protein in return record:
+ match (protFromProps propLst2) with
+ | None -> sobj
+ | Some(prot, rate) ->
+ let protDegReac = LBSDegReac([prot], rate)
+ {sobj with currentProt = [prot]; lbsProg = protDegReac }
+
+ | _ ->
+ sobj
+
+ sobj'
+
+ | Reac(absCompLst1, absCompLst2, absCompLst3, rate, simOnly) ->
+ // translate abstract complex lists:
+ let absCompLst1' = transAbstractComplexLst absCompLst1 env existing
+ let absCompLst2' = transAbstractComplexLst absCompLst2 env existing
+ let absCompLst3' = transAbstractComplexLst absCompLst3 env existing
+
+ // translate rate:
+ let rate' = match transVal rate env existing with
+ | [r] -> if (!useConstants && isVar r) then "1" else r
+ | _ -> failwith ("Type error: complex value used as rate.\n")
+
+ // create reaction and constraints:
+ let lbsReac = LBSReac(absCompLst1', absCompLst2', absCompLst3', rate', true)
+ let prologConstraint = REACTION(absCompLst1', absCompLst2', absCompLst3', rate')
+
+ // get species names:
+ let specNames1 = specNames absCompLst1'
+ let specNames2 = specNames absCompLst2'
+ let specNames3 = specNames absCompLst3'
+
+ // gather constraints and species names, but not if simulation-only flag is true:
+ let prologConstraints = if (simOnly || env.simOnlyReacs) then [] else [prologConstraint]
+ let specNames = if (simOnly || env.simOnlyReacs) then [] else specNames1@specNames2@specNames3
+
+ // get all substitutions which unify the reaction with one from the database (unless it's a sim-only reaction...)
+ let substitutions,logEntries =
+ if (simOnly || env.simOnlyReacs) then [Cssubst.empty],[]
+ else
+ Solver.matchNormalReactions db absCompLst1' absCompLst2' absCompLst3' rate'
+ let logEntries =
+ let tempReac = Gecreaction.makeNormal absCompLst1' absCompLst2' absCompLst3' -1.0
+ let reacStr = (tempReac |> Gecreaction.display |> Lib.quote) + " at rate " + rate'
+ if (simOnly || env.simOnlyReacs) then ["Reaction " + reacStr + " is simulation only..."] else
+ ("Looking for a normal reaction of the form " + reacStr)::logEntries
+
+ {emptySemObj with prologConstraints = prologConstraints@emptySemObj.prologConstraints;
+ substitutions = substitutions;
+ lbsProg = lbsReac;
+ specNames = specNames;
+ log = logEntries
+ }
+
+ | Trans(absComp1, absComp2, compartment, rate, simOnly, direction) ->
+ // translate compartment value (may be under scope of new or formal par)
+ let compartment = match transVal (IdVal(compartment)) env existing with
+ | [c] -> c
+ | _ -> failwith ("\nType error: non-atomic value used for compartment identifier.\n")
+
+ let absComp1' = transAbstractComplex absComp1 env existing
+ let absComp2' = transAbstractComplex absComp2 env existing
+
+ // translate rate:
+ let rate' = match transVal rate env existing with
+ | [r] -> if (!useConstants && isVar r) then "1" else r
+ | _ -> failwith("Type error: complex value used as rate.\n")
+
+ // get species names:
+ let specNames1 = specNames [absComp1']
+ let specNames2 = specNames [absComp2']
+
+ // create reaction and new constraint:
+ let lbsTrans = LBSTrans(absComp1', absComp2', compartment, rate', direction)
+ let prologConstraint = TRANSPORT(absComp1',absComp2',direction,rate')
+
+ // check if simulation-only:
+ let prologConstraints = if (simOnly || env.simOnlyReacs) then emptySemObj.prologConstraints
+ else prologConstraint::emptySemObj.prologConstraints
+
+ // get all substitutions which unify the reaction with one from the database (unless it's a sim-only reaction...)
+ let substitutions,logEntries =
+ if (simOnly || env.simOnlyReacs) then [Cssubst.empty],[]
+ else
+ Solver.matchTransportReactions db absComp1' absComp2' rate' compartment direction
+ let logEntries =
+ let tempReac = Gecreaction.makeTransport absComp1' absComp2' -1.0 compartment direction
+ let reacStr = (tempReac |> Gecreaction.display |> Lib.quote) + " at rate " + rate'
+ if (simOnly || env.simOnlyReacs) then ["Reaction " + reacStr + " is simulation only..."] else
+ ("Looking for a transport reaction of the form " + reacStr)::logEntries
+
+ {emptySemObj with prologConstraints = prologConstraints;
+ substitutions = substitutions;
+ lbsProg = lbsTrans;
+ specNames = specNames1@specNames2;
+ log = logEntries
+ }
+
+ | TemplateDef(mid, fParLst, body, p') ->
+ // define the semantic function for the body of this module:
+ let f aParLst =
+
+ // check that length of formals and actuals match:
+ if not (List.length aParLst = List.length fParLst) then
+
+ let error = "Length of formal and actual parameter lists do not match (" + mid + "/" + (List.length fParLst).ToString() + " <> " + (List.length aParLst).ToString() + ").\n"
+ failwith error
+
+ // update substitution:
+ let subst' = Lib.fold_left (fun (map : tsubst) (fPar, aPar) -> map.Add(fPar, aPar) ) env.subst (List.zip fParLst aParLst)
+
+ // translate body of module in updated environment:
+ translate db body { env with subst = subst' } emptySemObj existing
+
+ // update the module environment and translate the program following module declaration:
+ let envm' = env.envm.Add(mid, f)
+ translate db p' { env with envm = envm' } emptySemObj existing
+
+ | TemplateInv(mid, aParLst) ->
+ // check that module has been declared:
+ if not (env.envm.ContainsKey(mid)) then
+ failwith ("Template " + mid + " has not been defined.\n")
+
+ // translate actual parameter list:
+ let aParLst' = transAbstractComplexLst aParLst env existing
+
+ // look up the semantic function recorded for this module and invoke it with the evaluated formal parameters:
+ let f = env.envm.[mid]
+ f aParLst'
+
+
+ | Par(p1, p2) ->
+ // translate recursively:
+ let sobj1 = translate db p1 env emptySemObj existing
+ let sobj2 = translate db p2 env emptySemObj existing
+
+ // find the a list of names and variables from both components, but with no duplicates:
+ let namesVarsFlat = (List.concat sobj1.specNames)@(List.concat sobj2.specNames)
+ let namesVarsFlatNoDups = namesVarsFlat |> Set.ofList |> Set.toList
+
+ // constraint saying that names for instantiating variables must be fresh, i.e.
+ // the namesVarsNoDups list must remain a set when the variables are instantiated:
+ let freshSubstPrologConstraint = NO_DUPLICATES(namesVarsFlatNoDups)
+
+ // constraint saying that names of programs are disjoint from the respective exclusive names:
+ let specNames1' = sobj1.specNames |> Set.ofList |> Set.toList
+ let specNames2' = sobj2.specNames |> Set.ofList |> Set.toList
+ let disjointPrologConstraint = NAMES_DISJOINT(specNames1', sobj1.exclusiveSpecVar, specNames2', sobj2.exclusiveSpecVar)
+
+ // find the new exclusive names as the union of exclusive names from each component:
+ let exNamesVar = newVar(existing)
+ let exNamesUnionPrologConstraint = UNION(sobj1.exclusiveSpecVar, sobj2.exclusiveSpecVar, exNamesVar)
+
+ // collect new constraints:
+ let prologConstraints = if !ignoreConsistencyConstraints then [] else [freshSubstPrologConstraint; disjointPrologConstraint; exNamesUnionPrologConstraint]
+
+ // combine the two sets of context-sensitive substitutions
+ let substitutions = Cssubst.compose sobj1.substitutions sobj2.substitutions
+
+ // produce a log entry to record the substitution composition
+ let newLog = ["ABOUT TO DO A PARALLEL COMPOSITION OF SUBSTITUTIONS...";
+ "First one: " + Lib.newline + Lib.string_of_list Cssubst.display Lib.newline sobj1.substitutions;
+ "Second one: " + Lib.newline + Lib.string_of_list Cssubst.display Lib.newline sobj2.substitutions;
+ "Result: " + Lib.newline + Lib.string_of_list Cssubst.display Lib.newline substitutions]
+
+ // assemble result and return:
+ let sobj = {
+ translFunc = sobj1.translFunc @ sobj2.translFunc;
+ translFunc1 = sobj1.translFunc1 @ sobj2.translFunc1;
+ translFunc2 = sobj1.translFunc2 @ sobj2.translFunc2;
+ currentMRNA = sobj1.currentMRNA @ sobj2.currentMRNA;
+ currentProt = sobj1.currentProt @ sobj2.currentProt;
+ bbDevices = sobj1.bbDevices @ sobj2.bbDevices;
+ prologConstraints = sobj1.prologConstraints @ sobj2.prologConstraints @ prologConstraints;
+ arithmeticConstraints = sobj1.arithmeticConstraints @ sobj2.arithmeticConstraints;
+ substitutions = substitutions;
+ exclusiveSpecVar = exNamesVar;
+ specNames = sobj1.specNames @ sobj2.specNames;
+ lbsProg = LBSPar(sobj1.lbsProg, sobj2.lbsProg);
+ rateDefs = sobj1.rateDefs @ sobj2.rateDefs;
+ log = sobj1.log @ sobj2.log @ newLog
+ }
+
+ sobj
+
+ | Seq(p1, p2) ->
+ // translate recursively:
+ let sobj1 = translate db p1 env emptySemObj existing
+ let sobj2 = translate db p2 env emptySemObj existing
+
+ // find the a list of names and variables from both components, but with no duplicates:
+ let namesVarsFlat = (List.concat sobj1.specNames)@(List.concat sobj2.specNames)
+ let namesVarsFlatNoDups = namesVarsFlat |> Set.ofList |> Set.toList
+
+ // constraint saying that names for instantiating variables must be fresh, i.e.
+ // the namesVarsNoDups list must remain a set when the variables are instantiated:
+ let freshSubstPrologConstraint = NO_DUPLICATES(namesVarsFlatNoDups)
+
+ // constraint saying that names of programs are disjoint from the respective exclusive names:
+ let specNames1' = sobj1.specNames |> Set.ofList |> Set.toList
+ let specNames2' = sobj2.specNames |> Set.ofList |> Set.toList
+ let disjointPrologConstraint = NAMES_DISJOINT(specNames1', sobj1.exclusiveSpecVar, specNames2', sobj2.exclusiveSpecVar)
+
+ // find the new exclusive names as the union of exclusive names from each component:
+ let exNamesVar = newVar(existing)
+ let exNamesUnionPrologConstraint = UNION(sobj1.exclusiveSpecVar, sobj2.exclusiveSpecVar, exNamesVar)
+
+ // collect new constraints:
+ let prologConstraints' = if !ignoreConsistencyConstraints then []
+ else [freshSubstPrologConstraint; disjointPrologConstraint; exNamesUnionPrologConstraint]
+ let prologConstraints = sobj1.prologConstraints @ sobj2.prologConstraints @ prologConstraints'
+
+ // combine the two templates list (what is the technical word for this operation?)
+ let bbDevices2D = List.map (fun x -> List.map (fun y -> x@y) sobj2.bbDevices) sobj1.bbDevices
+ let bbDevices = List.concat(bbDevices2D)
+
+
+ // ********** END OF BIOBRICK TRANSLATION *************
+ // ********** START OF REACTION TRANSLATION *********
+
+ // check for information about current mrna and update second semantic object accordingly:
+ let sobj2' =
+ match sobj1.currentMRNA with
+ | [] ->
+ sobj2
+ | [mrna] ->
+ // apply partially evaluated translation functions to this mrna to get reactions:
+ let newReacs = sobj2.translFunc1 |> List.map (fun f -> (f mrna))
+ // create lbs parallel prog from list of reactions:
+ let lbsProg = match newReacs with
+ | [] -> LBSNil
+ | [r] -> r
+ | r1::[r2] -> LBSPar(r1,r2)
+ | first::second::remaining ->
+ let firstPar = LBSPar(first,second)
+ List.fold (fun p1 p2 -> LBSPar(p1,p2)) firstPar remaining
+
+ //let lbsProg = List.fold (fun p1 p2 -> LBSPar(p1,p2)) LBSNil newReacs
+
+ // apply non-evaluated translation functions to this mrna to obtain new functions:
+ let newFunc2 = sobj2.translFunc |> List.map (fun f -> (f mrna))
+
+ // and return:
+ {sobj2 with lbsProg = LBSPar(sobj2.lbsProg, lbsProg);
+ translFunc = [];
+ translFunc1 = [];
+ translFunc2 = newFunc2;
+ }
+
+ | _ -> failwith ("Sequential composition is only supported for singleton results, aborting translation [1].\n")
+
+ // check for information about current protein and update first semantic object appropriately:
+ let (sobj1', sobj2'') =
+ match sobj2'.currentProt with
+ | [] ->
+ (sobj1, sobj2')
+ | [prot] ->
+ // apply partially evaluated translation functions to this protein to get reactions:
+ let newReacs = sobj1.translFunc2 |> List.map (fun f -> f prot)
+ // create lbs parallel prog from list of reactions:
+ let lbsProg = match newReacs with
+ | [] -> LBSNil
+ | [r] -> r
+ | r1::[r2] -> LBSPar(r1,r2)
+ | first::second::remaining ->
+ let firstPar = LBSPar(first,second)
+ List.fold (fun p1 p2 -> LBSPar(p1,p2)) firstPar remaining
+ //let lbsProg = Lib.fold_left (fun p1 p2 -> LBSPar(p1,p2)) LBSNil newReacs
+
+ // apply non-evaluated translation functions to this protein to obtain new functions:
+ let newFunc1 = sobj1.translFunc |> List.map (fun f -> (fun mrna -> (f mrna prot)))
+
+ // and return:
+ let sobj1' = { sobj1 with lbsProg = LBSPar(sobj1.lbsProg, lbsProg);
+ translFunc = [];
+ translFunc1 = newFunc1;
+ translFunc2 = []; }
+
+ let sobj2'' = {sobj2' with currentProt = []}
+ (sobj1', sobj2'')
+
+ | _ -> failwith("sequential composition is only supported for singleton results, aborting translation [2].\n")
+
+
+ // propagate the current mrna from the left (this component) to the composite if
+ // none is defined for the right component:
+ let currentMRNA = if sobj2''.currentMRNA.Length = 0 then sobj1'.currentMRNA else sobj2''.currentMRNA
+
+ // propagate the current protein from the right (this component) to the composite if
+ // none is defined for the left component:
+ let currentProt = if sobj1'.currentProt.Length = 0 then sobj2''.currentProt else sobj1'.currentProt
+
+ // combine the two sets of context-sensitive substitutions
+ let substitutions = Cssubst.compose sobj1'.substitutions sobj2'.substitutions
+
+ // combine all results (both biobrick and reaction translation) into a semantic object and return:
+ let sobj = {
+ translFunc = sobj1'.translFunc @ sobj2'.translFunc;
+ translFunc1 = sobj1'.translFunc1 @ sobj2'.translFunc1;
+ translFunc2 = sobj1'.translFunc2 @ sobj2'.translFunc2;
+ currentMRNA = currentMRNA;
+ currentProt = currentProt;
+ bbDevices = bbDevices;
+ prologConstraints = prologConstraints;
+ arithmeticConstraints = sobj1'.arithmeticConstraints @ sobj2.arithmeticConstraints;
+ substitutions = substitutions;
+ exclusiveSpecVar = exNamesVar;
+ specNames = sobj1'.specNames @ sobj2'.specNames;
+ lbsProg = LBSPar(sobj1'.lbsProg, sobj2'.lbsProg);
+ rateDefs = sobj1.rateDefs @ sobj2.rateDefs;
+ log = sobj1.log @ sobj2.log
+ }
+
+ sobj
+
+
+ | Comp(cid, p') ->
+ // translate compartment value (may be under scope of new or formal par)
+ let cid = match transVal (IdVal(cid)) env existing with
+ | [cid'] -> cid'
+ | _ -> failwith("\nType error: non-atomic value used for compartment identifier.\n")
+
+ // translate contained program:
+ let sobj = translate db p' env emptySemObj existing
+
+ // remove the "context" from the context-sensitive substitutions
+ let substitutions = List.map Cssubst.eraseContext sobj.substitutions
+
+ // "forget" exclusive names by creating a fresh variable which unifies with the
+ // empty list, and create an lbs compartment program:
+ let newVar = newVar(existing)
+ {sobj with prologConstraints = sobj.prologConstraints @ [IS_EMPTY_LIST(newVar)];
+ substitutions = substitutions;
+ exclusiveSpecVar = newVar;
+ specNames = [];
+ lbsProg = LBSComp(cid, sobj.lbsProg);
+ }
+
+
+ | New(id, p') ->
+ // create a fresh id and update substitution in environment:
+ let freshId = id + newStr()
+ let subst' = env.subst.Add(id, [freshId])
+ let env' = { env with subst = subst' }
+
+ // translate:
+ let sobj = translate db p' env' emptySemObj existing
+
+ // add a compartment declaration to lbs prog if the id is lower-case, i.e. a name. if
+ // the id is not used as a compartment, this will introduce a redundant
+ // compartment declaration but no harm is done.
+
+ //Websharper compatiblity
+ let isLowerChar (c:char) = (((int) c >= 97) && ((int) c <= 122))
+
+ let lbsProg' = if (isLowerChar(id.Chars 0)) then LBSCompDec(freshId, sobj.lbsProg)
+ else sobj.lbsProg
+
+ // and return.
+ {sobj with lbsProg = lbsProg'}
+
+
+ | Constraint(a1,op,a2) ->
+ // translate values:
+ let a1' = transAExp a1 env
+ let a2' = transAExp a2 env
+
+ let prologConstraint = ARITHMETIC(a1', op, a2')
+ let arithmeticConstraint = (a1', op, a2')
+ let newVar = newVar(existing)
+ {emptySemObj with prologConstraints = prologConstraint::emptySemObj.prologConstraints;
+ arithmeticConstraints = arithmeticConstraint::emptySemObj.arithmeticConstraints;
+ substitutions = [Cssubst.empty]} // Is this OK in the case where the program is "just" constraints? Do we care?
+(*
+ | Constraint(a1,op,a2) ->
+ // translate values:
+ let v1' = transVal v1 env
+ let v2' = transVal v2 env
+
+ // check that values are simple and extract them from lists:
+ let (v1'', v2'') = match (v1', v2') with
+ | ([x],[y]) -> (x,y)
+ | _ -> raise (LBS.Error.CompilerExPos("Type error: complex values are not allowed in constraints.\n", None))
+ let prologConstraint = ARITHMETIC(v1'', op, v2'')
+ let arithmeticConstraint = (v1'', op, v2'')
+ let newVar = newVar()
+ {emptySemObj with prologConstraints = prologConstraint::emptySemObj.prologConstraints;
+ arithmeticConstraints = arithmeticConstraint::emptySemObj.arithmeticConstraints;
+ substitutions = [Cssubst.empty]} // Is this OK in the case where the program is "just" constraints? Do we care?
+*)
+
+ | InitPop(absComp, v) ->
+ // translate initial population statementsn direcly to lbs:
+ let lbsProg = LBSInitPop(transAbstractComplex absComp env existing, v)
+ {emptySemObj with substitutions = [Cssubst.empty];
+ lbsProg = lbsProg}
+
+
+ | Ast.Rate(var, v) ->
+ // translate var and add rate to semantic object:
+ let varStr = match transVal var env existing with
+ | [varStr] -> varStr
+ | _ -> failwith("Type error: use of complex expression where value expected.\n")
+
+ {emptySemObj with substitutions = [Cssubst.empty];
+ rateDefs = [(varStr, v)]}
+
+
+ | Copy(num, p, isPar, simOnly) ->
+ if (num < 1) then
+ failwith("Type error: copy operator must be given a positive argument.\n")
+
+ // define a function for putting p in par or seq a given number of times:
+ let rec build num' =
+ if num' = 1 then
+ p
+ else
+ if isPar then
+ Par(p, (build (num' - 1)))
+ else
+ Seq(p, (build (num' - 1)))
+
+ // build composition num times of prog, but only if simulation-only flag false:
+ let p' = if simOnly then p else build num
+
+ // translate result:
+ let sobj = translate db p' env emptySemObj existing
+
+ // if simulation-only, then contruct a LBSCopy program:
+ // (this avoids copying constraints).
+ let lbsProg' = if simOnly then
+ LBSCopy(num, sobj.lbsProg)
+ else
+ sobj.lbsProg
+
+ {sobj with lbsProg = lbsProg'}
+
+
+ // the following family of functions simply translate values in the given structure
+// to their string representations.
+ and transPropLst propLst (env : tenv) (existing:string list)=
+ propLst |> List.map (fun prop -> transProp prop env existing)
+
+ and transProp prop (env : tenv) (existing:string list)=
+ let (propName, absCompLst) = prop
+ let absCompLst' = transAbstractComplexLst absCompLst env existing
+ (propName, absCompLst')
+
+ and transAbstractComplexLst absCompLst env existing=
+ absCompLst |> List.map (fun absComp -> transAbstractComplex absComp env existing)
+
+ and transAbstractComplex absComp env existing =
+ // translate each value in the abstract complex:
+ let absComp2 = absComp |> List.map (fun v -> transVal v env existing) |> List.concat
+ absComp2
+
+ and transVal v (env : tenv) (existing:string list) =
+ match v with
+ // check if an id is to be substituted (either an actual par or a fresh name):
+ | IdVal(id) ->
+ if (env.subst.ContainsKey(id)) then
+ env.subst.[id]
+ else
+ [id]
+
+ | FloatVal(f) ->
+ [Lib.display_float f]
+
+ // wild cards are just short cuts for fresh vars:
+ | WildCardVal ->
+ [newVar(existing)]
+ | AlgebraicExp _ -> failwith "Unexpected AlgebraicExp"
+
+ and transAExp (a:Ast.aexp) (env : tenv) : Ast.aexp =
+ match a with
+ | FloatAExp v -> FloatAExp v
+ | IdAExp id ->
+ // first check if our environment contains this ID; this is either
+ // for formal -> actual mappings, or for fresh renaming.
+ if (env.subst.ContainsKey(id)) then
+ match env.subst.[id] with
+ | [x] ->
+ // result depends on whether x is a float.
+ (*let f = ref 0.0
+ let isFloat = System.Double.TryParse(x, f)
+
+ if isFloat then
+ FloatAExp(!f)
+ else
+ IdAExp(x)*)
+ NumUtil.case_double FloatAExp (IdAExp x) x
+ (*
+ try
+ FloatAExp(Double.Parse(x))
+ with
+ | _ -> IdAExp(x)
+ *)
+
+
+ | _ -> failwith "Cannot pass a complex expression in module invocations."
+
+ // otherwise check if called in the context of constraint solving; then
+ // the identifier should be in the Subst environment. if it isn't, just
+ // create an identifier expression
+ else
+ match Subst.getFloat id with
+ | Some(f) -> FloatAExp(f)
+ | None -> IdAExp id
+
+
+ | PlusAExp (a1,a2) -> PlusAExp(transAExp a1 env, transAExp a2 env)
+ | MinusAExp (a1,a2) -> MinusAExp(transAExp a1 env, transAExp a2 env)
+ | MulAExp (a1,a2) -> MulAExp(transAExp a1 env, transAExp a2 env)
+ | DivAExp (a1,a2) -> DivAExp(transAExp a1 env, transAExp a2 env)
+ | PowAExp (a1,a2) -> PowAExp(transAExp a1 env, transAExp a2 env)
+
+ // get species names from an abstract complex list:
+ and specNames absCompLst =
+ absCompLst |> List.filter (fun absComp -> absComp |> List.forall (fun s -> not(isNum s)))
+
+ // boolean functions for testing types of strings:
+ and isName (s:string) = Char.IsLower s.[0]
+ and isVar (s:string) = Char.IsUpper s.[0] || s.[0] = '_'
+ and isNum (s:string) = (*let d = ref 0.0 in (Double.TryParse(s, d))*)
+ NumUtil.isNum s
+ (*
+ try
+ Double.Parse(s) |> ignore
+ true
+ with
+ | _ -> false
+ *)
+
+ // concatenates the elements of the string list with seperating commas:
+ and concatWith symbol lst =
+ Lib.fold_left (fun s1 s2 -> if (s1 <> "") then s1 + symbol + s2 else s2) "" lst
+
+ // create a lbs string representing degradation reations from a list of
+// LBS degradation reactions and a list of compartments where these should
+// be put.
+ and createDegReacs degReacs comps varDefs =
+ // function to convert degradation reactions to strings:
+ let toStr degReac =
+ match degReac with
+ | LBSDegReac(complex, rate) ->
+ let lbsReac = LBSReac([],complex,[],rate, true)
+ let (str, _, _) = lbsProgToStr' lbsReac varDefs None // note that parent comp (None) will never be relevant here.
+ str
+ | _ -> ""
+
+ // invoke on list:
+ let degReacStrings = degReacs |> List.map toStr
+
+ // remove duplicates from degradation reactions:
+ let degReacStrings' = degReacStrings |> Set.ofList |> Set.toList
+
+ // remove duplicates from compartment list:
+ let comps' = comps |> Set.ofList |> Set.toList
+
+ // compose into single string seperated by par:
+ let degReacsStr = concatWith " | " degReacStrings'
+
+ // insert degradation reactions into each compartment, concatenate compartements in par:
+ let str = comps' |> List.map (fun c -> newline + c + " [" + degReacsStr + newline + "]") |> (concatWith ("|" + newline))
+
+ // add degradation in no compartment (world) and return:
+ if str <> "" then (str + "|" + newline + degReacsStr) else degReacsStr
+
+
+ // translate an lbs abstract syntax tree to a concrete syntax string.
+ // takes as parameters an LBS AST and variable definitions.
+ and lbsProgToStr lbsProg (varDefs : (string * string) list) =
+ // get a standard program string, and degradation + compartments seperately:
+ let (progStr, degReacs, comps) = lbsProgToStr' lbsProg varDefs None
+
+ // get a string with degradation reactions for each compartment in parallel:
+ let degReacsStr = createDegReacs degReacs comps varDefs
+
+ // append program string to deg string (if any) and return:
+ if (degReacsStr <> "") then
+ progStr + " | " + degReacsStr
+ else
+ progStr
+
+ // translate an lbs program to a string, returning seperately a list of compartments
+// which are not under the scope of any compartment declarations and
+// degradation reactions (non-strings, since we need to remove duplicates later).
+// The latter need to be added to all compartments seperately for
+// systems such as the predator-prey to work -- this
+// unfortunately is non-compositional and not very neat.
+// apart from an lbs prog, the function takes variable definitions and
+// the current parent compartment(a string) as parameters. the former is needed
+// to substitute variables for their solutions, and the latter is needed to
+// translate transport reactions, such as c[s] -> s, to c[s] -> c[s] -> c'[s] where
+// c' is the containing reaction; this respects the LBS compartment semantics.
+ and lbsProgToStr' lbsProg (varDefs : (string * string) list) parentComp =
+
+ // function for substituting vars for defined values in list of value/vars:
+ let substVarVal lst =
+ lst |> List.map (fun x -> match Lib.try_assoc x varDefs with | Some y -> y | None -> x)
+
+
+ match lbsProg with
+ | LBSDevice(d) ->
+ (d,[],[])
+ | LBSReac(enzymes, reactants, products, rate, isMassAction) ->
+
+ let lst2dToLBSSum lst2d =
+ // replace vars for their definitions:
+ let lstVarsReplaced = lst2d |> List.map (fun lst -> lst |> substVarVal)
+ let lst = lstVarsReplaced |> List.map (concatWith "::")
+ (concatWith " + " lst)
+
+ let sum1 = lst2dToLBSSum enzymes
+ let sum2 = lst2dToLBSSum reactants
+ let sum3 = lst2dToLBSSum products
+
+ // replace rate for defined value if necessary:
+ let rate' = match Lib.try_assoc rate varDefs with Some x -> x | None -> rate
+
+ // determine which rate brackets to use:
+ let (bracLeft, bracRight) = if isMassAction then ("{", "}") else ("[", "]")
+
+ // don't print the ~ symbol if there are no enzymes:
+ let prefix = if enzymes = [] then "" else sum1 + " ~ "
+
+ //let str = newline + sprintf "%s%s ->%s%s%s %s " prefix sum2 bracLeft rate' bracRight sum3
+ let str = newline + prefix + sum2 + " ->" + bracLeft + rate' + bracRight + " " + sum3 + " "
+ (str, [], [])
+
+ | LBSReacAbstraction(absReac, program) ->
+ // if abstract reaction has non-0 rate defined in substitution, use this; otherwise use the detailed reactions in program:
+ match absReac with
+ | ( _, _, _, rateVarStr, _) ->
+ let rateStr = match Lib.try_assoc rateVarStr varDefs with Some x -> x | None -> "0.0"
+
+ if (rateStr <> "0.0" && rateStr <> "0") then
+ let p = LBSReac(absReac) in
+ lbsProgToStr' p varDefs parentComp
+ else
+ lbsProgToStr' program varDefs parentComp
+
+
+ | LBSDegReac(complex, rate) ->
+ ("", [lbsProg], [])
+
+ | LBSTrans(complex1, complex2, compartment, rate, direction) ->
+ // replace vars for their defined values:
+ let complex1' = substVarVal complex1
+ let complex2' = substVarVal complex2
+
+ // convert lists to LBS complexes:
+ let complex1Str = concatWith "::" complex1'
+ let complex2Str = concatWith "::" complex2'
+
+ // replace rate for defined value if necessary:
+ let rate' = match Lib.try_assoc rate varDefs with Some x -> x | None -> rate
+
+ // creates a string representation of spec s inside the current parent comp, taking into accound whether
+ // or not this is the empty world compartment:
+ let specInParentComp s =
+ (match parentComp with
+ | None -> s
+ | Some(c') -> c' + "[" + s + "]")
+
+ let str = if direction = In then
+ // we could use a more complex diffusion-style rate (see commented-out def below),
+ // but doing so makes the simulation go slow and weird. don't know why.
+ let arrow = "->{" + rate' + "} " in
+ //let arrow = "->[" + rate' + " * (" + complex1Str + " -- " + compartment + "[" + complex2Str + "])] "
+ newline + complex1Str + arrow + compartment + "[" + complex2Str + "]"
+ else
+ let arrow = "->{" + rate' + "} " in
+ //let arrow = "->[" + rate' + " * (" + compartment + "[" + complex1Str + "] -- " + complex2Str + ")] "
+ newline + compartment + "[" + complex1Str + "] " + arrow + complex2Str
+
+ (str, [], [])
+
+ | LBSComp(cname, p) ->
+ let (pStr, pDeg, pComps) = lbsProgToStr' p varDefs parentComp
+ let cStr = newline + newline + cname + " [" + pStr + newline + "]"
+ (cStr, pDeg, cname::pComps)
+
+ | LBSPar(p1, p2) ->
+ let (p1Str, p1Deg, p1Comps) = lbsProgToStr' p1 varDefs parentComp
+ let (p2Str, p2Deg, p2Comps) = lbsProgToStr' p2 varDefs parentComp
+
+ let isAllWhiteSpace text =
+ not (Seq.exists (fun x -> not (Char.IsWhiteSpace x)) text)
+
+ // don't want to print a lot of empty Nil programs, so ignore parallel
+ // composition sym if one component is Nil (translates to empty string):
+ let parSym = if (isAllWhiteSpace p1Str || isAllWhiteSpace p2Str) then "" else "|"
+
+ //let str = sprintf "%s %s %s" p1Str parSym p2Str
+ let str = p1Str + " " + parSym + " " + p2Str
+ (str, p1Deg@p2Deg, p1Comps@p2Comps)
+
+ | LBSInitPop(lst, pop) ->
+ // creates a string representation of spec s inside the current parent comp, taking into account whether
+ // or not this is the empty world compartment:
+ let specInParentComp s =
+ match parentComp with
+ | None -> s
+ | Some(c') -> c' + "[" + s + "]"
+
+ let lst' = substVarVal lst
+ let str = concatWith "::" lst'
+ let pStr = newline + "init " + str + " " + string pop
+ (pStr, [], [])
+
+ | LBSCompDec(cname, p) ->
+ let (pStr, pDeg, pComps) = lbsProgToStr' p varDefs parentComp
+
+ // create degradation reactions for this compartment
+ // (its important to have them within scope of the compartment declaration):
+ let degReacsStr = createDegReacs pDeg [cname] varDefs
+
+ let str = newline + "comp " + cname + "; " + pStr + " | " + degReacsStr + newline
+
+ // filter the compartment name out of the return compartment list;
+ // we don't want degradation reactions to be created for this compartment
+ // since we already created them locally:
+ let pComps' = List.filter (fun c -> c <> cname) pComps
+
+ // and return:
+ (str, pDeg, pComps')
+
+ | LBSCopy(num, p) ->
+ let (pStr, pDeg, pComps) = lbsProgToStr' p varDefs parentComp
+ let str = newline + "copy " + (string num) + " { " + newline + pStr + " " + newline + "}" + newline
+ (str, pDeg, pComps)
+
+ | LBSNil -> ("", [], [])
+
+
+// returns to lists containing the species variables and rate variables contained in a reaction:
+let rec getVarsFromLBSProg p =
+
+ match p with
+ | LBSReac(enzymes, reactants, products, rate, _) ->
+ let vars1 = getVarsFromLst2d enzymes
+ let vars2 = getVarsFromLst2d reactants
+ let vars3 = getVarsFromLst2d products
+ let varsRate = if isVar rate then [rate] else []
+ (vars1@vars2@vars3, varsRate)
+
+ | LBSDegReac(reactants, rate) ->
+ let p = LBSReac([], reactants, [], rate, true)
+ getVarsFromLBSProg p
+
+ | LBSTrans(complex1, complex2, compartment, rate, direction) ->
+ let vars1 = getVarsFromLst2d [complex1]
+ let vars2 = getVarsFromLst2d [complex2]
+ let varsRate = if isVar rate then [rate] else []
+ (vars1@vars2, varsRate)
+
+ | LBSComp(cname, p) ->
+ getVarsFromLBSProg p
+
+ | LBSPar(p1, p2) ->
+ let (vars1, rateVars1) = (getVarsFromLBSProg p1)
+ let (vars2, rateVars2) = (getVarsFromLBSProg p2)
+ (vars1@vars2, rateVars1@rateVars2)
+
+ | LBSCompDec(c, p) ->
+ getVarsFromLBSProg p
+
+ | LBSCopy(num, p) ->
+ getVarsFromLBSProg p
+
+ | _ -> ([], [])
+
+
+ // returns the variables in a 2d list of strings as a list
+ and getVarsFromLst2d lst2d =
+ lst2d |> List.concat |> List.filter isVar //|> Set.ofList |> Set.toList
+
+// translate0 p simOnlyReacs db
+
+
+
+
+(* NOTES *)
+
+(* OBS: we cannot translate rate declarations directly to LBS rate declarations.
+The reason is that reactions which should be in the scope of such rate declarations
+cannot always be generated locally, specifically for translation reactions.
+
+Here is an example illustrating the problem:
+
+---
+module transl(out) {
+ sim-rate RTransl 0.1; rbs
+};
+
+transl(O1); transl(O2)
+---
+
+This will result in the following output (since nil programs are not printed):
+
+rate RTransl; |
+rate RTransl;
+
+This is certainly not what we want.
+
+So, the current solution is to substitute rates directly into lbs programs or, alternatively,
+collect all rate declarations and prefix the main LBS program with these.
+*)
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNetTests/ClassicGECDotNetTests.fsproj b/ClassicGEC/ClassicGECDotNetTests/ClassicGECDotNetTests.fsproj
new file mode 100644
index 0000000..26392bb
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/ClassicGECDotNetTests.fsproj
@@ -0,0 +1,28 @@
+
+
+
+ netcoreapp3.1
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\Lib\Oslo.FSharp\Oslo.FSharp.dll
+
+
+
+
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNetTests/Program.fs b/ClassicGEC/ClassicGECDotNetTests/Program.fs
new file mode 100644
index 0000000..0695f84
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/ClassicGEC/ClassicGECDotNetTests/database.test.fs b/ClassicGEC/ClassicGECDotNetTests/database.test.fs
new file mode 100644
index 0000000..2ade0e5
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/database.test.fs
@@ -0,0 +1,165 @@
+module Microsoft.Research.GEC.DatabaseTest
+
+open Microsoft.Research.GEC.Database
+open FSBOL
+open FSBOL.SBOLDocument
+open FSBOL.XmlSerializer
+open Xunit
+open FsUnit.Xunit
+open System.Diagnostics
+open System.Xml
+open System.IO
+open System.Text
+
+[]
+let databaseParserText() =
+ let sampledb0 =
+ "i723017,pcr,codes(xylR;0.001)\n"+
+ "i723024,pcr,codes(phzM;0.001)\n"+
+ "e0040,pcr,codes(gfp;0.01)\n"+
+ "c0099,pcr,codes(cviR;0.01)\n"+
+ "i723025,pcr,codes(phzS;0.001)\n"+
+ "i723028,pcr,codes(pca;0.001)\n"+
+ "c0051,pcr,codes(cI;0.01)\n"+
+ "c0040,pcr,codes(tetR;0.01)\n"+
+ "c0080,pcr,codes(araC;0.01)\n"+
+ "c0012,pcr,codes(lacI;0.01)\n"+
+ "cunknown2,pcr,codes(unknown2;0.001)\n"+
+ "c0061,pcr,codes(luxI;0.01)\n"+
+ "c0062,pcr,codes(luxR;0.01)\n"+
+ "c0079,pcr,codes(lasR;0.01)\n"+
+ "c0078,pcr,codes(lasI;0.01)\n"+
+ "cunknown3,pcr,codes(ccdB;0.005)\n"+
+ "cunknown4,pcr,codes(ccdA;0.1)\n"+
+ "i723020,prom,pos(toluene::xylR;0.001;0.001;1.0);con(0.0001)\n"+
+ "r0051,prom,neg(cI;1.0;0.5;0.00005);con(0.12)\n"+
+ "r0040,prom,neg(tetR;1.0;0.5;0.00005);con(0.09)\n"+
+ "runknown1,prom,neg(unknown1;1.0;0.005;0.001);con(0.04)\n"+
+ "b0034,rbs,rate(0.1)\n"+
+ "b0015,ter\n" +
+ "j06504,pcr,codes(mCherry;0.1)"
+
+ let sampledb1 =
+ "i723017,pcr,codes(xylR;0.001)\n"+
+ "i723024,pcr,codes(phzM;0.001)\n"+
+ "e0040,pcr,codes(gfp;0.01)\n"+
+ "c0099,pcr,codes(cviR;0.01)\n"+
+ "i723025,pcr,codes(phzS;0.001)\n"+
+ "i723028,pcr,codes(pca;0.001)\n"+
+ "c0051,pcr,codes(cI;0.01)\n"+
+ "c0040,pcr,codes(tetR;0.01)\n"+
+ "c0080,pcr,codes(araC;0.01)\n"+
+ "c0012,pcr,codes(lacI;0.01)\n"+
+ "cunknown2,pcr,codes(unknown2;0.001)\n"+
+ "c0061,pcr,codes(luxI;0.01)\n"+
+ "c0062,pcr,codes(luxR;0.01)\n"+
+ "c0079,pcr,codes(lasR;0.01)\n"+
+ "c0078,pcr,codes(lasI;0.01)\n"+
+ "cunknown3,pcr,codes(ccdB;0.005)\n"+
+ "cunknown4,pcr,codes(ccdA;0.1)\n"+
+ "i723020,prom,pos(toluene::xylR;0.001;0.001;1.0);con(0.0001)\n"+
+ "r0051,prom,neg(cI;1.0;0.5;0.00005);con(0.12)\n"+
+ "r0040,prom,neg(tetR;1.0;0.5;0.00005);con(0.09)\n"+
+ "runknown1,prom,neg(unknown1;1.0;0.005;0.001);con(0.04)\n"+
+ "b0034,rbs,rate(0.1)\n"+
+ "b0015,ter\n" +
+ "j06504,pcr,codes(mCherry;0.1)\n"+
+ "PRFP,device,components[P;R;RFP;T]\n" +
+ "PTetRS100LuxR,device,components[PTet;RS100;LuxR;T]"
+
+
+ let from_string (s:string) = Parser.from_string parse s
+ let table0 = from_string sampledb0
+ let table1 = from_string sampledb1
+ let sbol = Database.convertTableToSBOLDocument table0
+ //Debug.WriteLine(sbolXmlString sbol)
+
+ let fwsw = new StreamWriter("gecSBOLdb.xml",false)
+ let fwxwSettings = new XmlWriterSettings()
+ fwxwSettings.Indent <- true
+ fwxwSettings.Encoding <- Encoding.UTF8
+ let fwxw = XmlWriter.Create(fwsw,fwxwSettings)
+ (XmlSerializer.sbolToXml sbol).WriteTo(fwxw)
+ fwxw.Close()
+
+ Assert.Equal(table0.parts.Count,24)
+ Assert.True(table0.parts.ContainsKey("b0015"))
+ Assert.True(table0.parts.ContainsKey("b0034"))
+ Assert.True(table0.parts.ContainsKey("i723020"))
+ Assert.True(table0.parts.ContainsKey("r0040"))
+ Assert.True(table0.parts.ContainsKey("c0012"))
+
+ Assert.Equal(table0.devices.Length,0)
+ Assert.Equal(table1.devices.Length,2)
+
+ Debug.WriteLine("END OF TEST")
+
+
+[]
+let ``PCRParserTest``() =
+ let pcrEntry =
+ "i723017,pcr,codes(xylR; 0.001)"
+
+ let from_string (s:string) = Parser.from_string Database.partParser s
+ let dnacomp = from_string pcrEntry
+ let (id,pcr) = match dnacomp with
+ | Part(x,y) -> (x,y)
+ | _ -> failwith "Unexpected Device found"
+
+ Assert.Equal(id,"i723017")
+ match pcr with
+ | Database.PCR(Database.CODES(codes,rate)) ->
+ Assert.Equal(codes.Length,1)
+ Assert.Equal(codes.Head,"xylR")
+ Assert.Equal(rate,0.001)
+ | _ ->
+ Debug.WriteLine("Error")
+ Assert.Equal(true,false)
+
+ Debug.WriteLine("End of Test")
+
+
+[]
+let ``RegulationPromParserTest``() =
+ let negativeRegulation =
+ "r0051,prom,neg(cI;1.0;0.5;0.00005);con(0.12)"
+
+ let from_string (s:string) = Parser.from_string Database.partParser s
+ let dnacomp = from_string negativeRegulation
+ let (id,negProm) =
+ match dnacomp with
+ | Part(x,y) -> (x,y)
+ | _ -> failwith "Unexpected Device found"
+
+ Assert.Equal(id,"r0051")
+ match negProm with
+ | Database.PROM(props) ->
+ Assert.Equal(props.Length,2)
+ match props with
+ first::remaining ->
+ Assert.Equal(props.Head,Database.NEG(["cI"],1.0,0.5,0.00005))
+ Assert.Equal(remaining.Head,Database.CON(0.12))
+ | _ -> failwith ""
+ | _ ->
+ Debug.WriteLine("Unexpected Part type found")
+ Assert.Equal(true,false)
+
+ Debug.WriteLine("End of Test")
+
+[]
+let ``TerminatorParserTest``() =
+ let ter = "b0015,ter"
+
+ let from_string (s:string) = Parser.from_string Database.partParser s
+ let dnacomp = from_string ter
+ let (id,ter) =
+ match dnacomp with
+ | Part(x,y) -> (x,y)
+ | _ -> failwith "Unexpected Device found"
+
+ Assert.Equal(id,"b0015")
+ Assert.Equal(ter,Database.TER)
+
+ Debug.WriteLine("End of Test")
+
+
diff --git a/ClassicGEC/ClassicGECDotNetTests/gecreaction.test.fs b/ClassicGEC/ClassicGECDotNetTests/gecreaction.test.fs
new file mode 100644
index 0000000..8ebd9f5
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/gecreaction.test.fs
@@ -0,0 +1,130 @@
+module Microsoft.Research.GEC.GecreactionTest
+
+open Microsoft.Research.GEC.Gecreaction
+
+open Xunit
+open FsUnit.Xunit
+open System.Diagnostics
+
+
+[]
+let ``TransportParserTest``() =
+ let transportInReaction = "m3OC6HSL->{1.0}c[m3OC6HSL]"
+ let transportOutReaction = "c[m3OC12HSL] -> {1.01}m3OC12HSL"
+ let from_string (s:string) = Parser.from_string parseReaction s
+
+ let tir = from_string transportInReaction
+ let tirProps = Gecreaction.isTransport tir
+ if tirProps.IsSome then
+ let (reactant,product,rate,compartment,direction) = tirProps.Value
+ Assert.Equal(reactant.Head,"m3OC6HSL")
+ Assert.Equal(reactant.Length,1)
+ Assert.Equal(compartment,"c")
+ Assert.Equal(rate,1.0)
+ Assert.Equal(direction,Ast.direction.In)
+ Assert.Equal(product.Length,1)
+ Assert.Equal(product.Head,"m3OC6HSL")
+ else
+ failwith("None encountered. Error.")
+ let tor = from_string transportOutReaction
+ let torProps = Gecreaction.isTransport tor
+ if torProps.IsSome then
+ let (reactant,product,rate,compartment,direction) = torProps.Value
+ Assert.Equal(reactant.Head,"m3OC12HSL")
+ Assert.Equal(reactant.Length,1)
+ Assert.Equal(compartment,"c")
+ Assert.Equal(rate,1.01)
+ Assert.Equal(direction,Ast.direction.Out)
+ Assert.Equal(product.Length,1)
+ Assert.Equal(product.Head,"m3OC12HSL")
+ else
+ failwith("None encountered. Error.")
+ Assert.True(false)
+
+ Debug.WriteLine("END of Test")
+
+
+[]
+let ``NormalParserTest``() =
+ let norNoReactants = "luxI ~ -> {1.0}m3OC6HSL"
+ let from_string (s:string) = Parser.from_string parseReaction s
+ let nnr = from_string norNoReactants
+ let nnrProps = Gecreaction.isNormal nnr
+ if nnrProps.IsSome then
+ let (catalysts,reactants,products,rate) = nnrProps.Value
+ Assert.Equal(catalysts.Length,1)
+ Assert.Equal(catalysts.Head.Head,"luxI")
+ Assert.True(reactants.IsEmpty)
+ Assert.Equal(rate,1.0)
+ Assert.Equal(products.Head.Head,"m3OC6HSL")
+ Assert.Equal(products.Length,1)
+ else
+ failwith("None encountered. Error.")
+ Assert.True(true)
+
+ let nor1Nocat = "lasR + m3OC12HSL->{1.0}lasR::m3OC12HSL"
+ let nor1nc = from_string nor1Nocat
+ let nor1ncProps = Gecreaction.isNormal nor1nc
+ if nor1ncProps.IsSome then
+ let (catalysts,reactants,products,rate) = nor1ncProps.Value
+ Assert.True(catalysts.IsEmpty)
+ Assert.Equal(reactants.Length,2)
+ Assert.Equal(reactants.Head.Head,"lasR")
+ Assert.Equal(rate,1.0)
+ Assert.Equal(products.Head.Item(0),"lasR")
+ Assert.Equal(products.Head.Item(1),"m3OC12HSL")
+ Assert.Equal(products.Length,1)
+ else
+ failwith("None encountered. Error.")
+ Assert.True(true)
+
+ let nor2Nocat = "lasR::m3OC12HSL->{1.0}lasR+m3OC12HSL"
+ let nor2nc = from_string nor2Nocat
+ let nor2ncProps = Gecreaction.isNormal nor2nc
+ if nor2ncProps.IsSome then
+ let (catalysts,reactants,products,rate) = nor2ncProps.Value
+ Assert.True(catalysts.IsEmpty)
+ Assert.Equal(reactants.Length,1)
+ Assert.Equal(reactants.Head.Length,2)
+ Assert.Equal(reactants.Head.Item(0),"lasR")
+ Assert.Equal(reactants.Head.Item(1),"m3OC12HSL")
+ Assert.Equal(rate,1.0)
+ Assert.Equal(products.Item(0).Item(0),"lasR")
+ Assert.Equal(products.Item(1).Item(0),"m3OC12HSL")
+ Assert.Equal(products.Length,2)
+ else
+ failwith("None encountered. Error.")
+ Assert.True(true)
+
+ let nor1 = "a::b+b::c+dc+e::f ~ i::j->{0.9}t::v+y::u"
+ let n1 = from_string nor1
+ let n1Props = Gecreaction.isNormal n1
+ if n1Props.IsSome then
+ let (catalysts,reactants,products,rate) = n1Props.Value
+ Assert.Equal(catalysts.Length,4)
+ Assert.Equal(catalysts.Item(0).Item(0),"a")
+ Assert.Equal(catalysts.Item(0).Item(1),"b")
+ Assert.Equal(catalysts.Item(1).Item(0),"b")
+ Assert.Equal(catalysts.Item(1).Item(1),"c")
+ Assert.Equal(catalysts.Item(2).Item(0),"dc")
+ Assert.Equal(catalysts.Item(3).Item(0),"e")
+ Assert.Equal(catalysts.Item(3).Item(1),"f")
+
+ Assert.Equal(reactants.Length,1)
+ Assert.Equal(reactants.Head.Length,2)
+ Assert.Equal(reactants.Head.Item(0),"i")
+ Assert.Equal(reactants.Head.Item(1),"j")
+ Assert.Equal(rate,0.9)
+ Assert.Equal(products.Length,2)
+ Assert.Equal(products.Item(0).Item(0),"t")
+ Assert.Equal(products.Item(0).Item(1),"v")
+ Assert.Equal(products.Item(1).Item(0),"y")
+ Assert.Equal(products.Item(1).Item(1),"u")
+ else
+ failwith("None encountered. Error.")
+ Assert.True(true)
+
+ Debug.WriteLine("END of Test")
+
+
+
diff --git a/ClassicGEC/ClassicGECDotNetTests/gecspecies.test.fs b/ClassicGEC/ClassicGECDotNetTests/gecspecies.test.fs
new file mode 100644
index 0000000..a2660cd
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/gecspecies.test.fs
@@ -0,0 +1,54 @@
+module Microsoft.Research.GEC.GecSpeciesTest
+
+open Parser
+
+open Xunit
+open System.Diagnostics
+
+
+[]
+let ``speciesToStringTest``() =
+ let species0 = {GecSpecies.t.empty_Species with species = ["a"]}
+ let species1 = {GecSpecies.t.empty_Species with species = ["a";"b"]}
+ let species2 = {GecSpecies.t.empty_Species with species = ["a";"b";"c";"d"]}
+ Assert.Equal(GecSpecies.t.empty_Species.to_string(),"")
+ Assert.Equal(species0.to_string(),"a")
+ Assert.Equal(species1.to_string(),"a::b")
+ Assert.Equal(species2.to_string(),"a::b::c::d")
+
+[]
+let ``speciesToCrnStringTest``() =
+ let species0 = {GecSpecies.t.empty_Species with species = ["a"]}
+ let species1 = {GecSpecies.t.empty_Species with species = ["a";"b"]}
+ let species2 = {GecSpecies.t.empty_Species with species = ["a";"b";"c";"d"]}
+ Assert.Equal(GecSpecies.t.empty_Species.to_string(),"")
+ Assert.Equal(species0.to_crn_string(),"a")
+ Assert.Equal(species1.to_crn_string(),"a_b")
+ Assert.Equal(species2.to_crn_string(),"a_b_c_d")
+
+[]
+let speciesParseTest() =
+ let species0 = "Signal"
+ let species1 = "Receiver::Signal"
+ let species2 = "cell[gfp]"
+ let species3 = "a::b::c"
+ let get_species (s:string) = Parser.from_string GecSpecies.parse s
+ let s0 = get_species species0
+ let s1 = get_species species1
+ let s2 = get_species species2
+ let s3 = get_species species3
+
+ //Compartment tests
+ Assert.Equal(s0.compartment,None)
+ Assert.Equal(s1.compartment,None)
+ Assert.Equal(s2.compartment,Some("cell"))
+ Assert.Equal(s3.compartment,None)
+
+ //Length tests
+ Assert.Equal(s0.species.Length,1)
+ Assert.Equal(s1.species.Length,2)
+ Assert.Equal(s2.species.Length,1)
+ Assert.Equal(s3.species.Length,3)
+
+
+
diff --git a/ClassicGEC/ClassicGECDotNetTests/hypothesis.test.fs b/ClassicGEC/ClassicGECDotNetTests/hypothesis.test.fs
new file mode 100644
index 0000000..c73814e
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/hypothesis.test.fs
@@ -0,0 +1,390 @@
+module Microsoft.Research.GEC.HypothesisTest
+
+open Xunit
+open FsUnit.Xunit
+open System.Diagnostics
+
+open Parser
+open Microsoft.Research.GEC
+open Microsoft.Research.CRNEngine
+
+
+[]
+let ``directivesParser``()=
+ let directiveString = """directive simulator sundials
+//directive simulator deterministic
+//directive deterministic {stiff = true}
+//directive inference {name=target; burnin=400000; samples=400000; thin=50; noise_model=proportional}
+directive inference {name=target; burnin=10; samples=10; thin=1; noise_model=proportional}
+directive sweeps [
+ sweepC6C12 = [
+ (condition,C6,C12) = [
+ (1,25000,0); (2,8333.33333333333,0); (3,2777.77777777778,0); (4,925.925925925926,0); (5,308.641975308642,0); (6,102.880658436214,0); (7,34.2935528120713,0); (8,11.4311842706904,0); (9,3.81039475689681,0); (10,1.27013158563227,0); (11,0.423377195210757,0); (12,0,0);
+ (13,0,25000); (14,0,8333.33333333333); (15,0,2777.77777777778); (16,0,925.925925925926); (17,0,308.641975308642); (18,0,102.880658436214); (19,0,34.2935528120713); (20,0,11.4311842706904); (21,0,3.81039475689681); (22,0,1.27013158563227); (23,0,0.423377195210757); (24,0,0);
+ ];
+ ];
+ sweepC6C12double = [
+ (condition,C6,C12) = [
+ (1,25000,0); (2,8333.33333333333,0); (3,2777.77777777778,0); (4,925.925925925926,0); (5,308.641975308642,0); (6,102.880658436214,0); (7,34.2935528120713,0); (8,11.4311842706904,0); (9,3.81039475689681,0); (10,1.27013158563227,0); (11,0.423377195210757,0); (12,0,0);
+ (13,0,25000); (14,0,8333.33333333333); (15,0,2777.77777777778); (16,0,925.925925925926); (17,0,308.641975308642); (18,0,102.880658436214); (19,0,34.2935528120713); (20,0,11.4311842706904); (21,0,3.81039475689681); (22,0,1.27013158563227); (23,0,0.423377195210757); (24,0,0);
+ (1,25000,0); (2,8333.33333333333,0); (3,2777.77777777778,0); (4,925.925925925926,0); (5,308.641975308642,0); (6,102.880658436214,0); (7,34.2935528120713,0); (8,11.4311842706904,0); (9,3.81039475689681,0); (10,1.27013158563227,0); (11,0.423377195210757,0); (12,0,0);
+ (13,0,25000); (14,0,8333.33333333333); (15,0,2777.77777777778); (16,0,925.925925925926); (17,0,308.641975308642); (18,0,102.880658436214); (19,0,34.2935528120713); (20,0,11.4311842706904); (21,0,3.81039475689681); (22,0,1.27013158563227); (23,0,0.423377195210757); (24,0,0);
+ ];
+ ];
+]
+
+directive simulation { final=20; points=250 }
+
+directive rates [
+ boundLuxR = [luxR]^2 * ((KR6*[c6])^nR + (KR12*[c12])^nR) / ((1.0 + KR6*[c6] + KR12*[c12])^nR);
+ boundLasR = [lasR]^2 * ((KS6*[c6])^nS + (KS12*[c12])^nS) / ((1.0 + KS6*[c6] + KS12*[c12])^nS);
+ P76 = (e76 + KGR_76*[boundLuxR] + KGS_76*[boundLasR]) / (1.0 + KGR_76*[boundLuxR] + KGS_76*[boundLasR]);
+ P81 = (e81 + KGR_81*[boundLuxR] + KGS_81*[boundLasR]) / (1.0 + KGR_81*[boundLuxR] + KGS_81*[boundLasR]);
+ PBad = (Ara^nA+eA*KAra^nA)/(Ara^nA+KAra^nA);
+ PTet = 1/(1+[tetR]^nT);
+ PLac = 1/(1+[lacI]^nL);
+ plot_od = [x]+x0;
+ plot_fp = [x]*[fp]+f0;
+ plot_yfp = [x]*([yfp]+[f500])+yb0;
+ plot_cfp = [x]*([cfp]+[f430])+cb0;
+]
+
+directive parameters [
+ // Background
+ c0 = 0.001, { distribution=Uniform(1e-4,3e-1) };
+ x0 = 0.1, { interval=Real; distribution=Uniform(0,0.2) };
+ f0=5000.0,{ interval=Real; distribution=Uniform(0.0,10000.0) };
+ yb0=1e3, { interval=Real; distribution=Uniform(0.0,5e3) };
+ cb0=1e3, { interval=Real; distribution=Uniform(0.0,1e4) };
+
+ // Autofluorescence
+ dfp=0.1, { distribution=Uniform(1e-3,1e0) };
+ autoYFP=1e0, { distribution=Uniform(1e-3,1e3) };
+ autoCFP=1e0, { distribution=Uniform(1e-3,1e3) };
+
+ // Standard
+ dCFP=1e-2, { distribution=Uniform(1e-3,1e0) };
+ dYFP=1e-2, { distribution=Uniform(1e-3,1e0) };
+
+ // Receivers
+ KR6=1e-2, { distribution=Uniform(1e-8,1e0) };
+ KS6=1e-4, { distribution=Uniform(1e-8,1e0) };
+ KR12=1e-3, { distribution=Uniform(1e-8,1e0) };
+ KS12=1e-2, { distribution=Uniform(1e-8,1e0) };
+ nR=0.797, { interval=Real; distribution=Uniform(0.5,2.0) };
+ nS=0.797, { interval=Real; distribution=Uniform(0.5,2.0) };
+ aR33=1.0, { distribution=Uniform(1e0,1e2) };
+ aS175=1.0, { distribution=Uniform(1e0,1e2) };
+ aRS100=1.0, { distribution=Uniform(1e0,1e2) };
+ aS32=1.0, { distribution=Uniform(1e0,1e2) };
+ nL=0.797, { interval=Real; distribution=Uniform(0.5,2.0) };
+ nT=0.797, { interval=Real; distribution=Uniform(0.5,2.0) };
+
+ dR=0.1, { distribution=Uniform(1e-2,1e1) };
+ //dS=0.1, { distribution=Uniform(1e-2,1e2) };
+ e76=1e-2, { distribution=Uniform(1e-4,1.0) };
+ KGR_76=1e-2,{ distribution=Uniform(1e-4,1e0) };
+ KGS_76=1e-6,{ distribution=Uniform(1e-8,1e0) };
+ e81=1e-2, { distribution=Uniform(1e-4,1.0) };
+ KGR_81=1e-6,{ distribution=Uniform(1e-8,1e0) };
+ KGS_81=1e-2,{ distribution=Uniform(1e-4,1e0) };
+ aCFP=1e3, { distribution=Uniform(1e0,1e5) };
+ aYFP=1e3, { distribution=Uniform(1e0,1e5) };
+
+ // Relays
+ kC6=1e0, { distribution=Uniform(1e0,1e6) };
+ Klux=1.0, { distribution=Uniform(1e0,1e6) };
+ dluxI=0.1,{ distribution=Uniform(1e-3,1e1) };
+ kC12=1e0, { distribution=Uniform(1e0,1e6) };
+ Klas=1.0, { distribution=Uniform(1e0,1e6) };
+ dlasI=0.1,{ distribution=Uniform(1e-3,1e1) };
+
+ // Arabinose
+ KAra=1.0, { distribution=Uniform(1e-2,1e2) };
+ nA=1.0, { interval=Real; distribution=Uniform(0.5,3.0) };
+ eA=0.1, { interval=Real; distribution=Uniform(0.0,0.5) };
+
+ // Degrader
+ dA6=1e-1, { distribution=Uniform(1e-3,1e1) };
+ dA12=1e-1, { distribution=Uniform(1e-3,1e1) };
+ daiiA=0.1, { distribution=Uniform(1e-3,1e1) };
+
+ C6=0.0; C12=0.0; tau=0.0; aR=1.0; aS=1.0; ATC=0.0; IPTG=0.0;
+ aYFP_PL=1000.0; aCFP_PL=1000.0; Ara=0.0; condition = 0;
+]"""
+ let directives = Parser.from_string Hypothesis.parse_crnSettings directiveString
+ Debug.Write(directives.to_string Functional2.to_string Functional2.to_string_plot)
+ ()
+
+[]
+let ``moduleParser``()=
+ let moduleString = """
+module Control(growth,capacity) = {
+//| Growth(growth,tlag)
+ | fp ->[[growth]*[fp]] // Dilution
+ | ->[[capacity]] fp // Transcription/translation
+ | fp ->{dfp} // Degradation
+}
+module cells(growth,tlag,capacity) = {
+ | init luxR 0 | init lasR 0 | init lacI 0 | init tetR 0
+ | init yfp 0 | init cfp 0 | init f430 0 | init f500 0
+ | init c6 C6 @ tau | init c12 C12 @ tau // Hack to prevent greedy evaluation of rates from hurting us
+ | Growth(growth,tlag)
+ // Autofluorescence
+ | ->[[capacity]*autoYFP] f500
+ | f500 ->[[growth]*[f500]]
+ | ->[[capacity]*autoCFP] f430
+ | f430 ->[[growth]*[f430]]
+}
+
+module AiiA(P,aI,growth,capacity) = {
+ | ->[[capacity]*aI*[P]] aiiA
+ | aiiA ->{daiiA}
+ | aiiA ->[[growth]*[aiiA]]
+ //| c6 -> [[x]*dA6*[c6]*[aiiA]/(1+KA6*[c6]+KA12*[c12])]
+ //| c12 -> [[x]*dA12*[c12]*[aiiA]/(1+KA6*[c6]+KA12*[c12])]
+ | c6 -> [[x]*dA6*[c6]*[aiiA]]
+ | c12 -> [[x]*dA12*[c12]*[aiiA]]
+}
+"""
+ let modules = Parser.from_string (Hypothesis.parse_crnModules Crn_settings.defaults) moduleString
+
+ Debug.WriteLine(Hypothesis.modules_to_string 0.0 modules)
+
+ ()
+
+[]
+let ``deviceDirectiveParser``()=
+ let device0 = "device [LuxR]"
+ let device1 = "device [LuxR;pTet]"
+ let device2 = "device [cfp; gfp]"
+ let dev0 = Parser.from_string Hypothesis.parse_hypothesisDirective device0
+ let dev1 = Parser.from_string Hypothesis.parse_hypothesisDirective device1
+ let dev2 = Parser.from_string Hypothesis.parse_hypothesisDirective device2
+
+ ()
+
+[]
+let ``deviceDefinitionParser``()=
+ let device0 = "device PRFP(growth,capacity) = { Control(growth,capacity) }"
+ let device1 = "device PLacYFPCFP(growth,capacity) = { YFP(PLac,aYFP,growth,capacity) | CFP(PLac,aCFP,growth,capacity) }"
+ let dev0 = Parser.from_string Hypothesis.parse_device device0
+ let dev1 = Parser.from_string Hypothesis.parse_device device1
+ Debug.WriteLine(Hypothesis.deviceDefinition_to_string dev0)
+ Debug.WriteLine(Hypothesis.deviceDefinition_to_string dev1)
+ ()
+
+
+[]
+let ``systemParser``()=
+ let system0 = """system growth = {
+ directive simulation { final=20; points=250 }
+ | Growth(growth,tlag)
+}"""
+ let sys0 = Parser.from_string Hypothesis.parse_crn_system system0
+
+ let system1 = """system growth = {
+ directive simulation { final=20; points=250 }
+ directive device [pTet];
+ | Growth(growth,tlag)
+}"""
+
+ let sys1 = Parser.from_string Hypothesis.parse_crn_system system1
+
+ let system2 = """system growth = {
+ control with directive data [R33S175_Y81C76_mRFP1_proc141021]
+ directive device [pTet];
+}"""
+ let sys2 = Parser.from_string Hypothesis.parse_crn_system system2
+ ()
+
+[]
+let ``igElementParser``()=
+ let element0 = """edge Receivers_growth.Receiver0_growth ->[r=Fixed;K=Fixed;tlag=Fixed] Receivers_control.Receiver0_control"""
+ let element1 = """edge Relays ->[KR6;KS6;KR12;KS12;nR;nS;aR33;aS175;dR;e76;KGR_76;KGS_76;e81;KGR_81;KGS_81;aCFP;aYFP;] Degrader"""
+ let element2 = """edge Auto_control ->[dfp] Standard_control"""
+ let element3 = """edge Auto_control ->[r=Fixed;dfp] Standard_control"""
+ let element4 = """node Auto { systems = [Auto] }"""
+ let element5 = """node Receivers_growth { systems = [Receiver0_growth; Receiver1_growth; Receiver2_growth; Receiver3_growth] }"""
+ let element6 = """node Auto_Growth { systems = [growth]; inference = {burnin=1000; samples=1000; partial=true} }"""
+ let element7 = """node Auto_Target { systems = [auto]; inference = {burnin=50000; samples=50000} }"""
+
+ let elem0 = Parser.from_string Hypothesis.parse_igraphElement element0
+ let elem1 = Parser.from_string Hypothesis.parse_igraphElement element1
+ let elem2 = Parser.from_string Hypothesis.parse_igraphElement element2
+ let elem3 = Parser.from_string Hypothesis.parse_igraphElement element3
+ let elem4 = Parser.from_string Hypothesis.parse_igraphElement element4
+ let elem5 = Parser.from_string Hypothesis.parse_igraphElement element5
+ let elem6 = Parser.from_string Hypothesis.parse_igraphElement element6
+ let elem7 = Parser.from_string Hypothesis.parse_igraphElement element7
+
+ ()
+
+[]
+let ``hypothesisTest``()=
+ let database = """i723017,pcr,codes(xylR;0.001)
+i723024,pcr,codes(phzM;0.001)
+e0040,pcr,codes(gfp;0.01)
+c0099,pcr,codes(cviR;0.01)
+i723025,pcr,codes(phzS;0.001)
+i723028,pcr,codes(pca;0.001)
+c0051,pcr,codes(cI;0.01)
+c0040,pcr,codes(tetR;0.01)
+c0080,pcr,codes(araC;0.01)
+c0012,pcr,codes(lacI;0.01)
+cunknown2,pcr,codes(unknown2;0.001)
+c0061,pcr,codes(luxI;0.01)
+c0062,pcr,codes(luxR;0.01)
+c0079,pcr,codes(lasR;0.01)
+c0078,pcr,codes(lasI;0.01)
+cunknown3,pcr,codes(ccdB;0.005)
+cunknown4,pcr,codes(ccdA;0.1)
+i723020,prom,pos(toluene::xylR;0.001;0.001;1.0);con(0.0001)
+r0051,prom,neg(cI;1.0;0.5;0.00005);con(0.12)
+r0040,prom,neg(tetR;1.0;0.5;0.00005);con(0.09)
+runknown1,prom,neg(unknown1;1.0;0.005;0.001);con(0.04)
+b0034,rbs,rate(0.1)
+b0015,ter
+j06504,pcr,codes(mCherry;0.1)
+PRFP,device,components[P;R;RFP;T]
+PTetRS100LuxR,device,components[PTet;RS100;LuxR;T]
+DRR33S175,device,components[PRFP;PTetRS100LuxR]
+DRRS,device,components[DRR33S175|LuxR]
+EC10G,device,components[P]
+PLPL,device,components[P;R;eYFP;T;P;R;eCFP;T]"""
+
+ let hypothesis_content = """directive simulator sundials
+directive parameters [
+ C6=0.0; C12=0.0; c0 = 0.002; r = 1.0; K = 2.0; rc = 1000.0; tlag=0.0; tau=0.0;
+ // Autofluorescence
+ autoYFP=1e0, { interval=Log; distribution=Uniform(1e-3,1e3); variation=Random };
+ autoCFP=1e0, { interval=Log; distribution=Uniform(1e-3,1e3); variation=Random };
+ // FP
+ dRFP=0.1, { interval=Log; distribution=Uniform(1e-3,1e0); variation=Random };
+ dCFP=1e-2, { interval=Log; distribution=Uniform(1e-3,1e0); variation=Random };
+ dYFP=1e-2, { interval=Log; distribution=Uniform(1e-3,1e0); variation=Random };
+]
+directive inference { thin=100; noise_model = proportional }
+directive simulation {multicore=True}
+directive rates [
+ growth = [grow]*r*(1 - [x] / K);
+ capacity = rc;
+]
+
+module CFP(a) = {
+ ->[[capacity]*a] cfp |
+ cfp ->{dCFP} |
+ cfp ->[[growth]*[cfp]]
+}
+module YFP(a) = {
+ ->[[capacity]*a] yfp |
+ yfp ->{dYFP} |
+ yfp ->[[growth]*[yfp]]
+}
+module cells() = {
+ init x c0 |
+ init grow 1 @ tlag |
+ init c6 C6 @ tau |
+ init c12 C12 @ tau |
+ ->[[growth]*[x]] x
+}
+module autofluorescence() = {
+ ->[[capacity]*autoYFP] f530 |
+ f530 ->[[growth]*[f530]] |
+ ->[[capacity]*autoCFP] f480 |
+ f480 ->[[growth]*[f480]]
+}
+module Control() = {
+//| Growth(growth,tlag)
+ | fp ->[[growth]*[fp]] // Dilution
+ | ->[[capacity]] fp // Transcription/translation
+ | fp ->{dRFP} // Degradation
+}
+
+device PRFP() = { Control() }
+device PLPL() = { YFP(aYFP) | CFP(aCFP) }
+
+system growth = {
+ directive simulation { final=36.0; points=250; plots=[[x]+x0] }
+ directive parameters [
+ r = 1, { interval=Real; distribution=Uniform(0.1,10); variation=Multiple };
+ K = 2, { interval=Real; distribution=Uniform(0.1,5); variation=Multiple };
+ tlag = 1, { interval=Real; distribution=Uniform(0,10); variation=Multiple };
+ x0=0.1,{ interval=Real; distribution=Uniform(0.0,0.2); variation=Random };
+ ]
+ directive rates [growth = [grow]*r*(1 - [x] / K)]
+ cells()
+}
+system control = {
+ directive simulation { final=36.0; points=250; plots=[[x]*[fp]+f0]; plotcolours=["#FF0000"] }
+ directive parameters [
+ r = 1, { interval=Real; distribution=Uniform(0.1,10); variation=Multiple };
+ K = 2, { interval=Real; distribution=Uniform(0.1,5); variation=Multiple };
+ tlag = 1, { interval=Real; distribution=Uniform(0,10); variation=Multiple };
+ rc=1e2, { interval=Log; distribution=Uniform(1e0,1e5); variation=Multiple };
+ f0=100.0,{ interval=Real; distribution=Uniform(0.0,10000.0); variation=Random };
+ ]
+ directive rates [growth = [grow]*r*(1 - [x] / K);capacity = rc]
+ directive device [PRFP]
+ cells()
+}
+system auto = {
+ directive simulation { final=36.0; points=250; plots=[[x]*[f530]+yb0; [x]*[f480]+cb0]; plotcolours=["#FFDF00"; "#ADD8E6"] }
+ directive parameters [
+ r = 1, { interval=Real; distribution=Uniform(0.1,10); variation=Multiple };
+ K = 2, { interval=Real; distribution=Uniform(0.1,5); variation=Multiple };
+ tlag = 1, { interval=Real; distribution=Uniform(0,10); variation=Multiple };
+ rc=1e2, { interval=Log; distribution=Uniform(1e0,1e5); variation=Multiple };
+ yb0=1e3, { interval=Real; distribution=Uniform(0.0,5e3); variation=Random };
+ cb0=1e3, { interval=Real; distribution=Uniform(0.0,1e4); variation=Random };
+ ]
+ directive rates [growth = [grow]*r*(1 - [x] / K);capacity = rc]
+ | cells()
+ | autofluorescence()
+}
+system prpr = {
+ directive simulation { final=36.0; points=250; plots=[[x]*([yfp]+[f530])+yb0; [x]*([cfp]+[f480])+cb0]; plotcolours=["#FFDF00"; "#ADD8E6"] }
+ directive parameters [
+ r = 1, { interval=Real; distribution=Uniform(0.1,10); variation=Multiple };
+ K = 2, { interval=Real; distribution=Uniform(0.1,5); variation=Multiple };
+ tlag = 1, { interval=Real; distribution=Uniform(0,10); variation=Multiple };
+ rc=1e2, { interval=Log; distribution=Uniform(1e0,1e5); variation=Multiple };
+ aCFP=1e3, { interval=Log; distribution=Uniform(1e0,1e5); variation=Random };
+ aYFP=1e3, { interval=Log; distribution=Uniform(1e0,1e5); variation=Random };
+ yb0=1e3, { interval=Real; distribution=Uniform(0.0,5e3); variation=Random };
+ cb0=1e3, { interval=Real; distribution=Uniform(0.0,1e4); variation=Random };
+ ]
+ directive rates [growth = [grow]*r*(1 - [x] / K);capacity = rc]
+ directive device [PLPL]
+ | cells()
+ | autofluorescence()
+}
+
+//node Auto_Growth { systems = [growth] }
+//node Auto_Control { systems = [control] }
+
+node Auto_Growth { systems = [growth]; inference = {burnin=1000; samples=1000; partial=true} }
+node Auto_Control { systems = [control]; inference = {burnin=1000; samples=1000; partial=true} }
+node Auto_Target { systems = [auto]; inference = {burnin=50000; samples=50000} }
+
+node PRPR_Growth { systems = [growth]; inference = {burnin=1000; samples=1000; partial=true} }
+node PRPR_Control { systems = [control]; inference = {burnin=100000; samples=100000; partial=true} }
+node PRPR_Target { systems = [prpr]; inference = {burnin=100000; samples=100000} }
+
+edge Auto_Growth.growth ->[r=Fixed;K=Fixed;tlag=Fixed] Auto_Control.control
+edge Auto_Control.control ->[r=Fixed;K=Fixed;tlag=Fixed;rc=Fixed] Auto_Target.auto
+
+edge PRPR_Growth.growth ->[r=Fixed;K=Fixed;tlag=Fixed] PRPR_Control.control
+edge PRPR_Control.control ->[r=Fixed;K=Fixed;tlag=Fixed;rc=Fixed] PRPR_Target.prpr
+
+edge Auto_Control ->[dRFP=TruncatedNormal] PRPR_Control
+edge Auto_Target ->[autoYFP=TruncatedNormal;autoCFP=TruncatedNormal] PRPR_Target
+
+"""
+ let lib = Parser.from_string Database.parse database
+ let hypothesis = Parser.from_string Hypothesis.parse_hypothesis_content hypothesis_content
+
+ Debug.WriteLine(Hypothesis.hypothesis_to_crn_program hypothesis lib.devices)
+
+ ()
+
diff --git a/ClassicGEC/ClassicGECDotNetTests/main.test.fs b/ClassicGEC/ClassicGECDotNetTests/main.test.fs
new file mode 100644
index 0000000..afa7114
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/main.test.fs
@@ -0,0 +1,105 @@
+module Microsoft.Research.GEC.MainTest
+
+open Microsoft.Research.GEC.Program
+
+open Xunit
+open FsUnit.Xunit
+open System.Diagnostics
+
+
+[]
+let ``directivesParserTest``() =
+
+ let sampledir = "directive sample 100000.0"
+ let sampledir2 = "directive sample 100000.0 1"
+ let sampledir3 = "directive sample 100000.0 all"
+ let plotPredprey = "directive plot predator[ccdB]; prey[ccdB]"
+ let plotab = "directive plot A; B; C"
+ let plotcellsig = "directive plot cell[gfp]; Signal"
+ let plotrec = "directive plot receiver[gfp]"
+
+ let parseGECDirective (s:string) = Parser.from_string Program.directiveParser s
+
+ let sampledirfs = parseGECDirective sampledir
+ let sampledir2fs = parseGECDirective sampledir2
+ let sampledir3fs = parseGECDirective sampledir3
+ let plotPredpreyfs = parseGECDirective plotPredprey
+ let plotabfs = parseGECDirective plotab
+ let plotcellsigfs = parseGECDirective plotcellsig
+ let plotrecfs = parseGECDirective plotrec
+
+
+ Debug.WriteLine("Test completed")
+
+
+[]
+let ``expressionParserTest``() =
+ let exp0 = "a+ c"
+ let exp1 = "a+b"
+ let exp2 = "a+b+c"
+ let exp3 = "a+b+c+d"
+ let exp4 = "a+b-c"
+
+ let parseExpression (s:string) = Parser.from_string Program.expressionParser s
+
+ let exp0p = parseExpression exp0
+ let exp1p = parseExpression exp1
+ let exp2p = parseExpression exp2
+ let exp3p = parseExpression exp3
+ let exp4p = parseExpression exp4
+
+ Debug.WriteLine("Test Completed")
+
+[]
+let ``brickParserTest``() =
+ let test (s:string) = Parser.from_string Program.parse_brick s
+ let a = test "r0051:prom"
+ let b = test "rbs"
+ let c = test "pcr"
+ let d = test "r0051:prom"
+ let e = test "ter"
+ let f = test "prom"
+ let g = test "rbs"
+ let h = test "pcr"
+
+ Debug.WriteLine("End of Test")
+
+[]
+let ``newparsertest``()=
+ let prog = "new RB. new RUB.\n" +
+ "prom"
+
+ let test (s:string) = Parser.from_string Program.parse_new_outer s
+ let a = test prog
+ match a with
+ | Ast.New(id1,prog1) ->
+ Assert.Equal(id1,"RB")
+ match prog1 with
+ | Ast.New(id2,prog2) ->
+ Assert.Equal(id2,"RUB")
+ match prog2 with
+ | Ast.Brick(t,v,propLst) ->
+ Debug.WriteLine(v)
+ | _ -> failwith ""
+ | _ -> failwith ""
+ | _ -> failwith ""
+
+ Debug.WriteLine("end of test")
+
+[]
+let ``ReactionCodeParserTest``() =
+
+ let rxn = "luxR + Signal -> luxR::Signal"
+ let test (s:string) = Parser.from_string Program.parse_reaction s
+ let res = test rxn
+ Debug.WriteLine("end of test")
+
+[]
+let modInvTest() =
+ let miprog = "gate(A,B)"
+ let test (s:string) = Parser.from_string Program.parse_ast_template_inv s
+ let a = test miprog
+
+ Debug.WriteLine("End of test")
+
+
diff --git a/ClassicGEC/ClassicGECDotNetTests/paket.references b/ClassicGEC/ClassicGECDotNetTests/paket.references
new file mode 100644
index 0000000..411449c
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/paket.references
@@ -0,0 +1,7 @@
+group DOTNETCORE
+
+FSharp.Core
+FsUnit.xUnit
+xunit.core
+xunit.runner.console
+xunit.runner.visualstudio
\ No newline at end of file
diff --git a/ClassicGEC/ClassicGECDotNetTests/programParser.test.fs b/ClassicGEC/ClassicGECDotNetTests/programParser.test.fs
new file mode 100644
index 0000000..fd8d372
--- /dev/null
+++ b/ClassicGEC/ClassicGECDotNetTests/programParser.test.fs
@@ -0,0 +1,747 @@
+module Microsoft.Research.GEC.ProgramParserTest
+
+open Microsoft.Research.GEC.Program
+
+open Xunit
+open FsUnit.Xunit
+open System.Diagnostics
+
+open Parser
+open Microsoft.Research.CRNEngine
+
+let basic_program = """//solution 1 Y = araC
+directive simulation {final = 100000.0; points = 1000}
+
+prom; rbs; pcr; ter"""
+
+let basic_crn = """directive simulation {final = 100000.0; points = 1000}
+directive crn {
+module g2module(val) = {
+| val g2
+}
+| 1 g4
+| g2module(2)
+}
+
+x1:prom; rbs; pcr; ter
+"""
+
+let repressilator = """directive simulation {final = 100000.0; points = 1000; plots = [A; B; C]}
+
+prom; rbs; pcr; ter;
+prom; rbs; pcr; ter;
+prom; rbs; pcr; ter"""
+
+let repressilator_similar = """directive simulation {final = 100000.0; points = 1000; plots = [A; B; C]}
+
+prom;
+rbs; pcr