Module:Model

From MaRDI portal
Revision as of 14:11, 18 November 2025 by TA4Shehu (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:Model/doc

-- Required modules for SPARQL queries and HTML table generation
-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text") 


-- Main table to hold all functions
local p = {}



-------------------------------- Local Functions -------------------------------

-- Utility: get all P31 values of an entity
local function getInstanceOf(qid)
    local e = mw.wikibase.getEntityObject(qid)
    local result = {}
    if not e or not e.claims or not e.claims["P31"] then
        return result
    end
    for _, claim in pairs(e.claims["P31"]) do
        local id = claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value.id
        if id then
            table.insert(result, id)
        end
    end
    return result
end
-------------------------------- Local Functions -------------------------------


------------------------------- Helper Functions -------------------------------
function p.convertJsonToTable(jsonResults)
	local resultsTable = {}
	if jsonResults and jsonResults.results and jsonResults.results.bindings then
		local bindings = jsonResults.results.bindings
		for j=0, #bindings do
			local row = {}
			for key, value in pairs(bindings[j]) do
				table.insert(row, value.value)
			end
			table.insert(resultsTable, row)
		end
	end
    return resultsTable
end
------------------------------- Helper Functions -------------------------------


-- Function to get model types
function p.getModelTypes(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: used by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?ModelTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?ModelType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?ModelTypeLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
	
	local modelTypes = {}
    -- Get the number of model types
	local totalModelTypes = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalModelTypes  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.ModelTypeLabel and item.ModelTypeLabel.value then
        	local label = item.ModelTypeLabel.value
        	table.insert(modelTypes, label)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(modelTypes, " || ") .. "\n|}"
	return wikitextTable

end


-- Function to get Computational Tasks
function p.getComputationalTasks(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P147: used by property id
    -- P146: series ordinal property id
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label (SAMPLE(?StatementOrdinal) AS ?Ordinal)
	WHERE {
		entityId: p:P147 ?statement.
		?statement ps:P147 ?URL.
		OPTIONAL { ?statement pq:P146 ?StatementOrdinal. }
		?URL rdfs:label ?Label.
		FILTER(LANG(?Label) = "en")
	}
	GROUP BY ?URL ?Label
	ORDER BY
		ASC(COALESCE(xsd:integer(?Ordinal), 999999))
		ASC(?Label)
	]]

--	local sparqlQuery = [[
--	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
--		SELECT ?URL ?URLLabel ?nextURL ?nextURLLabel 
--		WHERE {
--		entityId: p:P147 ?statement.
--		?statement ps:P147 ?URL.
--		OPTIONAL { ?statement pq:P146 ?Ordinal. }
--		OPTIONAL { ?statement pq:P581 ?nextURL. }
--		SERVICE wikibase:label { 
--		bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
--		}
--		ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
--	]]



	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No computational task found"
    end
	
	local computationalTasks = {}
    -- Get the number of computational tasks
	local totalCompTasks = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalCompTasks  do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	local ordinal = item.Ordinal and item.Ordinal.value or nil
			local prefix = ordinal and (ordinal .. ". ") or ""
			table.insert(computationalTasks, "| " .. prefix .. labelWithUrl)
			-- if item.nextURL then
			-- 	local nexturl = item.nextURL.value
			-- 	local nextnumericId = nexturl:match("Q(%d+)")
			-- 	local nextLabel = item.nextURLLabel.value
			-- 	local nexturlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. nextnumericId
			-- 	local nextLabelWithUrl = string.format('[%s %s]', tostring(nexturlRendered), tostring(nextLabel))
			-- 	table.insert(computationalTasks, "| " .. labelWithUrl .. " followed by " .. nextLabelWithUrl)
-- 			else
-- 				table.insert(computationalTasks, "| " .. labelWithUrl)
-- 			end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(computationalTasks, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get Formulations with Quantities
function p.getFormulationsWithQuantities(frame)
	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end

    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1560: contains property id
    -- P989: defining formula property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?Formula ?defining_formulation ?IDFormula ?qualValueLabel ?qualValue
	WHERE {
		# full statement node for P1560
		entityId: p:P1560 ?statement .
		?statement ps:P1560 ?IDFormula .
		FILTER(LANG(?qualValueLabel) = "en")
  
		OPTIONAL { 
    		?IDFormula rdfs:label ?Formula .
    		FILTER(LANG(?Formula) = "en")
		}
		OPTIONAL { ?IDFormula wdt:P989 ?defining_formulation . }

		# qualifiers on this statement
		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers
    		OPTIONAL { 
    		?qualProp rdfs:label ?qualPropLabel .
    		FILTER(LANG(?qualPropLabel) = "en")
    		}
    	OPTIONAL { 
    		?qualValue rdfs:label ?qualValueLabel .
    		FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Formula
]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	
		-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
		return "\"No mathematical expressions found.\""
    end
	
	-- local resultTable = p.convertJsonToTable(jsonResults)
	-- return "<pre>" .. mw.text.nowiki(json.jsonEncode(resultTable)) .. "</pre>"
    -- local jsonString = mw.text.jsonEncode(jsonResults)
    -- return "<pre>" .. mw.text.nowiki(jsonString) .. "</pre>"
	return p.extractDefiningFormulationsWithQuantities(jsonResults)

end


-- Function to extract Formulations with Quantities 
function p.extractDefiningFormulationsWithQuantities(jsonResults)
	local frame = mw.getCurrentFrame()
	-- Table to store contained entities
    local containedEntities = {}
    -- Table to store quantity symbol and name id 
    local quantitySymbolNameIdPairs = {}
    
    local jsonString = mw.text.jsonEncode(jsonResults)
    -- Decode the JSON string into a Lua table
	local data = mw.text.jsonDecode(jsonString)
    
    -- Get the number of contained entities
	local totalContainedEntities = #data.results.bindings

    if totalContainedEntities > 0 then
    	-- Loop through the bindings
		for index = 1, totalContainedEntities  do
    		local item = data.results.bindings[index]
    		local itemLabel = item.Formula.value
    		
        	local equationIDURL = item.IDFormula.value
        	local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
        	local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        table.insert(containedEntities, qualValueWithUrl)
					
        	local instances = getInstanceOf(equationID)
        	for _, id in ipairs(instances) do
        		if(id == "Q6481152") then
        			-- if is about a mathematical expression (Q6481152) that is contained
        			local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
    				local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
    				local equationWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
        			
        			local equation = mw.wikibase.getEntity(equationID)
        	
		    		-- P989 refers to property defining formula 
		    		local definingFormula = equation:getBestStatements('P989')
		    		if definingFormula and #definingFormula > 0 then
    					local value = definingFormula[1].mainsnak.datavalue.value
    					mathTag = frame:extensionTag{
	        				name = "math",
	         				content = value
        				}
	        			local qualValue = item.qualValueLabel or item.qualValue or ""
	        			local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        			local test = "test"
	        			if qualValue ~= "" then
	        				table.insert(containedEntities, 
    						string.format('| %s || %s || %s || %s', equationWithUrl, mathTag, qualValueWithUrl, test))
    					else
    						table.insert(containedEntities, 
    						string.format('| %s || %s', equationWithUrl, mathTag))
						end	
					else
	       				local qualValue = item.qualValueLabel or item.qualValue or ""
	       				local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	       				local test = "test"
	       				if qualValue ~= "" then
							local row = "| " .. equationWithUrl .. " || " ..  qualValueWithUrl .. " || " ..  test
							table.insert(containedEntities, row)
						else
							table.insert(containedEntities, "| " .. equationWithUrl)
						end
					end
   
        	
        			quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        	
        			if type(quantitySymbolNameIdPairs) == "table" then
        				-- Accessing the stored pairs
						for i, pair in ipairs(quantitySymbolNameIdPairs) do
							local pairFirstValue = pair[1]
							local pairFirstValue = mw.text.decode(pairFirstValue or "")
							local quantitySymbolMathTag = frame:extensionTag{
								name = "math",
            					content = pairFirstValue
        					}
        					-- Construct the Portal URL
        					local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        					local instances = getInstanceOf(pair[3])
        					-- Define a set of allowed IDs for Quantity
							local allowedQuantityIds = {
    						Q6534245 = true,
    						Q6534237 = true,
    						}
    						local url = ""
        					for _, id in ipairs(instances) do
        						if allowedQuantityIds[id] then
        							-- if the symbol is a quantity kind or a quantity
        							-- Construct the Portal URL
        							url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        						elseif(id == "Q6481152") then
        							-- if is about a mathematical expression (Q6481152) that is contained
        							url = "https://portal.mardi4nfdi.de/wiki/Formula:"
        						end
        					-- go over values of instances
        					end
        					
        					local fullUrl = url .. numericId
        					local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
        	
            				table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag   ..  " represents "  .. labelWithUrl)
						end
					table.insert(containedEntities, "| " .. " " )
					else
					end
				elseif(id == "Q68663") then
					-- if is about a model (Q68663) that is contained
					local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
					local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
    				local modelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
					table.insert(containedEntities, "| " .. modelWithUrl)
				
				elseif(id == "Q6534237") then
					-- if is about a quantity (Q6534237) that is contained
					local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
					local urlRendered = "https://portal.mardi4nfdi.de/wiki/Quantity:" .. numericId
    				local quantityWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
    				
					-- table.insert(containedEntities, "| " .. quantityWithUrl)
					local equation = mw.wikibase.getEntity(equationID)
        	
		    		-- P989 refers to property defining formula 
		    		local definingFormula = equation:getBestStatements('P989')
		    		if definingFormula and #definingFormula > 0 then
    					local value = definingFormula[1].mainsnak.datavalue.value
    					mathTag = frame:extensionTag{
	        				name = "math",
	         				content = value
        				}
	        			local qualValue = item.qualValueLabel or item.qualValue or ""
	        			local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        			if qualValue ~= "" then
	        				table.insert(containedEntities, 
    						string.format('| %s || %s || %s', quantityWithUrl, mathTag, qualValueWithUrl))
    					else
    						table.insert(containedEntities, 
    						string.format('| %s || %s', quantityWithUrl, mathTag))
						end	
					else
	       				local qualValue = item.qualValueLabel or item.qualValue or ""
	       				local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
						if qualValue ~= "" then
							local row = "| " .. quantityWithUrl .. " || " .. qualValueWithUrl 
    						table.insert(containedEntities, row)
							-- table.insert(containedEntities, "| " .. quantityWithUrl, qualValue.value )
						else
							table.insert(containedEntities, "| " .. quantityWithUrl)
						end
					end
					quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        	
        			if type(quantitySymbolNameIdPairs) == "table" then
        				-- Accessing the stored pairs
						for i, pair in ipairs(quantitySymbolNameIdPairs) do
							local pairFirstValue = pair[1]
							local pairFirstValue = mw.text.decode(pairFirstValue or "")
							local quantitySymbolMathTag = frame:extensionTag{
								name = "math",
            					content = pairFirstValue
        					}
        					-- Construct the Portal URL
        					local url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        					local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        					local fullUrl = url .. numericId
        					local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
        	
            				table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag   ..  " represents "  .. labelWithUrl)
						end
					table.insert(containedEntities, "| " .. " " )
					else
					end
				-- if is about a quantity (Q6534237) that is contained
				end
			-- Loop through the instances	
    		end
        -- Loop through the bindings
		end

		-- Construct the Wikitext table
    	local wikitextTable = [[
{| class="wikitable" style="table-layout: auto;"
]] .. table.concat(containedEntities, "\n|-\n") .. "\n|}"
    	return wikitextTable
    else 
    	return "No mathematical expressions found."
    end
end


function p.extractQuantities(qid)
	-- Property ID for in defining formula 
    local pidInDefiningFormula  = "P983"
    -- Property ID for the (qualifier) symbol represents
    local pidSymbolRepresents = "P984"   

    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(qid)
    if not entity or not entity.claims[pidInDefiningFormula] then
        return "No formulation found"
    end
    
    
    local inDefiningFormulaClaims = entity.claims[pidInDefiningFormula]
    local count = 0
    -- Table to store pairs of quantity symbol and quantity name
    local quantitySymbolNameIdPairs = {}
	for _ in pairs(inDefiningFormulaClaims or {}) do
    	count = count + 1
    	-- Get the quantity symbol
    	local quantitySymbol = inDefiningFormulaClaims[count].mainsnak.datavalue.value
    	if not quantitySymbol then
        	return "No valid symbol found"
    	end
    	quantity = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.text
        quantityId = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.id
	    local quantityName = mw.wikibase.label(quantityId)
	    -- Insert pair into the table
	    table.insert(quantitySymbolNameIdPairs, {quantitySymbol, quantityName, quantityId})
    end
    return quantitySymbolNameIdPairs
end

-- Function to get specialized Models
function p.getSpecializedModels(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1684: specialized by property id
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:P1684 ?statement .
		?statement ps:P1684 ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local specializedModels = {}
    -- Get the number of specialized research fields
	local totalSpecModels = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSpecModels  do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
	        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
	        if qualValue ~= "" then
	        	local qualPropWithUrl = string.format('[%s %s]', tostring(item.qualPropEntity.value), tostring(item.qualPropLabel.value))
	        	local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl .. " || " .. qualPropWithUrl .. " || " ..  qualValueWithUrl
    			table.insert(specializedModels, row)
	        else
        		table.insert(specializedModels, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(specializedModels, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model assumptions
function p.getAssumptions(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1674: assumes property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?AssumptionURL ?AssumptionLabel
	WHERE {
		entityId: p:P1674 ?statement.
		?statement ps:P1674 ?AssumptionURL.
		?AssumptionURL rdfs:label ?AssumptionLabel.
		FILTER(LANG(?AssumptionLabel) = "en")
	}
	ORDER BY ?AssumptionLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No computational task found"
    end
	
	local assumptions = {}
    -- Get the number of computational tasks
	local totalAssumptions = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalAssumptions  do
    	local item = jsonResults.results.bindings[index]
    	if not item.AssumptionLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.AssumptionURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.AssumptionLabel.value
        	local url = item.AssumptionURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	local ordinal = item.Ordinal and item.Ordinal.value or nil
			local prefix = ordinal and (ordinal .. ". ") or ""
			table.insert(assumptions, "| " .. prefix .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(assumptions, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model discretizations
function p.getDiscretizations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1656: discretized property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?DiscretizedURL ?DiscretizedLabel
	WHERE {
		entityId: p:P1656 ?statement.
		?statement ps:P1656 ?DiscretizedURL.
		?DiscretizedURL rdfs:label ?DiscretizedLabel.
		FILTER(LANG(?DiscretizedLabel) = "en")
	}
	ORDER BY ?DiscretizedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local discretizations = {}
    -- Get the number of discretizations
	local totalDiscretizations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalDiscretizations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.DiscretizedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.DiscretizedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.DiscretizedLabel.value
        	local url = item.DiscretizedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(discretizations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(discretizations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model approximations
function p.getApproximations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1655: approximated by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?ApproximatedURL ?ApproximatedLabel
	WHERE {
		entityId: p:P1655 ?statement.
		?statement ps:P1655 ?ApproximatedURL.
		?ApproximatedURL rdfs:label ?ApproximatedLabel.
		FILTER(LANG(?ApproximatedLabel) = "en")
	}
	ORDER BY ?ApproximatedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local approximations = {}
    -- Get the number of approximations
	local totalApproximations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalApproximations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.ApproximatedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.ApproximatedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.ApproximatedLabel.value
        	local url = item.ApproximatedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(approximations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(approximations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model approximations
function p.getSoftware(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1463: describes a project that uses property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?SoftwareURL ?SoftwareLabel
	WHERE {
		entityId: p:P1463 ?statement.
		?statement ps:P1463 ?SoftwareURL.
		?SoftwareURL rdfs:label ?SoftwareLabel.
		FILTER(LANG(?SoftwareLabel) = "en")
	}
	ORDER BY ?SoftwareLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local software = {}
    -- Get the number of software items
	local totalSoftware = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSoftware  do
    	local item = jsonResults.results.bindings[index]
    	if not item.SoftwareLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.SoftwareURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.SoftwareLabel.value
        	local url = item.SoftwareURL.value
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
			table.insert(software, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(software, "\n|-\n") .. "\n|}"
	return wikitextTable

end


-- Function to get model approximations
function p.getLinearizedBy(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1657: linearized by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?LinearizedURL ?LinearizedLabel
	WHERE {
		entityId: p:P1657 ?statement.
		?statement ps:P1657 ?LinearizedURL.
		?LinearizedURL rdfs:label ?LinearizedLabel.
		FILTER(LANG(?LinearizedLabel) = "en")
	}
	ORDER BY ?LinearizedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local linearizations = {}
    -- Get the number of software items
	local totalLlinearizations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalLlinearizations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.LinearizedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.LinearizedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.LinearizedLabel.value
        	local url = item.LinearizedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(linearizations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(linearizations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get similar models
function p.getSimilar(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1691: similar to property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?SimilarURL ?SimilarLabel
	WHERE {
		entityId: p:P1691 ?statement.
		?statement ps:P1691 ?SimilarURL.
		?SimilarURL rdfs:label ?SimilarLabel.
		FILTER(LANG(?SimilarLabel) = "en")
	}
	ORDER BY ?SimilarLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local similar = {}
    -- Get the number of similar expressions
	local totalSimilar = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSimilar  do
    	local item = jsonResults.results.bindings[index]
    	if not item.SimilarLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.SimilarURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.SimilarLabel.value
        	local url = item.SimilarURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(similar, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(similar, "\n|-\n") .. "\n|}"
	return wikitextTable
	
end


return p