Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >约束编程示例【Programming】

约束编程示例【Programming】

作者头像
Potato
修改于 2019-11-18 04:01:36
修改于 2019-11-18 04:01:36
2.5K00
代码可运行
举报
运行总次数:0
代码可运行

通过示例应用程序了解约束编程,该示例应用程序可以转换字符的大小写和ASCII代码。

图片来源:João Trindade. Modified by Jason Baker. CC BY-SA 2.0.
图片来源:João Trindade. Modified by Jason Baker. CC BY-SA 2.0.

解决计算问题的方法有很多种。 您可以通过尽可能多地计算可能性来“蛮力”解决问题,或者您可以采取程序性方法并仔细建立影响正确答案的已知因素。 在约束编程中,问题被视为对可能是有效解决方案的一系列限制。这种范式可以用来有效地解决一组问题,这些问题可以转化为变量和约束,或表示为一个数学方程。 在这种方式下,它与约束满足问题( CSP )有关。

它使用声明式编程风格来描述具有某些属性的通用模型。 与命令式风格相比,它不告诉如何实现目标,而是实现目标。 约束编程不是使用仅一种显而易见的方法来定义一组指令来计算值,而是声明约束内变量之间的关系。 最终模型使计算变量值成为可能,而与方向或变化无关。 因此,一个变量值的任何变化都会影响整个系统(即所有其他变量),并且要满足定义的约束条件,它将导致重新计算其他值。

例如,我们以毕达哥拉斯定理为例: a²+b²=c² 。 约束由该等式表示,该等式具有三个变量 (a,b和c),每个变量都有一个域 (非负)。 如果我们有其他两个变量,则使用命令式编程样式来计算任何变量,我们将需要创建三个不同的函数(因为每个变量是由不同的方程式计算的):

  • c =√(a²+b²)
  • a =√(c²-b²)
  • b =√(c²-a²)

这些函数满足主要约束,并且要检查域,每个函数都应验证输入。 此外,根据所提供的变量来选择合适的功能将需要至少一个另外的功能。 这是一个可能的解决方案:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def pythagoras(*, a=None, b=None, c=None):
 ''' Computes a side of a right triangle '''
 # Validate
 if len([i for i in (a, b, c) if i is None or i <= 0]) != 1:
 raise SystemExit("ERROR: you need to define any of two non-negative variables")
 # Compute
 if a is None:
 return (c**2 - b**2)**0.5
 elif b is None:
 return (c**2 - a**2)**0.5
 else:
 return (a**2 + b**2)**0.5

为了了解与约束编程方法的区别,我将展示一个“问题”的示例,该问题具有四个变量和一个约束,该约束没有用直接的数学方程式表示。 这是一个转换器,可以更改字符的大小写(小写到大写/大写),并返回每个字符的ASCII码。 因此,转换器在任何时候都知道所有四个值,并对任何变化立即做出反应。 创建此示例的想法完全受到John DeNero的Fahrenheit-Celsius转换器的启发。

这是约束系统的图:

表示的“问题”被转换成一个由节点(约束)和连接器(变量)组成的约束系统。连接器提供了一个用于获取和设置值的接口。他们还会检查变量的域。当一个值发生更改时,该特定连接器将更改通知其所有连接的节点。反过来,节点满足约束,计算新值,并通过“请求”它们设置一个新值,将它们传播到系统中的其他连接器。传播是使用消息传递技术完成的,这意味着连接器和节点(同步地)获得消息并相应地作出反应。例如,如果系统在“大写字母”连接器上获得A字母,那么其他三个连接器根据节点上定义的约束提供适当的结果:97、a和65。不允许在该连接器上设置任何其他小写字母(例如,b),因为每个连接器都有自己的域。

当所有连接器都链接到由约束定义的节点时,系统已完全设置并准备好在四个连接器中的任何一个上获取值。 设置完成后,系统会自动计算并设置其余连接器上的值。 无需像命令式方法中那样检查设置了什么变量以及应该调用哪个函数,用几个变量相对容易实现,但在数十个或更多变量的情况下会变得有趣。

工作原理

完整的源代码可在我的GitHub中找到。我将深入一些细节来解释系统是如何构建的。

首先,通过给连接器命名并根据一个参数设置域来定义连接器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import constraint_programming as cp
small_ascii = cp.connector('Small Ascii', lambda x: x >= 97 and x <= 122)
small_letter = cp.connector('Small Letter', lambda x: x >= 'a' and x <= 'z')
capital_ascii = cp.connector('Capital Ascii', lambda x: x >= 65 and x <= 90)
capital_letter = cp.connector('Capital Letter', lambda x: x >= 'A' and x <= 'Z')

其次,将这些连接器链接到节点。 有两种类型: 代码 (将字母来回转换为ASCII码)和aA (将小写字母和大写字母互相转换):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
code(small_letter, small_ascii)
code(capital_letter, capital_ascii)
aA(small_letter, capital_letter)

这两个节点在应调用的函数方面有所不同,但是它们是从常规约束函数派生而来的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def code(conn1, conn2):
 return cp.constraint(conn1, conn2, ord, chr)
def aA(conn1, conn2):
return cp.constraint(conn1, conn2, str.upper, str.lower)

每个节点只有两个连接器。 如果第一个连接器上有更新,则将调用第一个函数来计算另一个连接器(变量)的值。 如果第二个连接器的值更改,也会发生相同的情况。 例如,如果代码节点在conn1连接器上获得A ,则函数ord将用于获取其ASCII代码,同样的,如果aA节点在conn2连接器上获得A ,则它需要使用str.lower函数在conn1上获取正确的小写字母。 每个节点负责计算新值,并将一条消息“发送”到另一个连接器,提示要设置一个新值。 该消息与要求设置新值以及新值的节点的名称一起传送。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def set_value(src_constr, value):
 if (not domain is None) and (not domain(value)):
 raise ValueOutOfDomain(link, value)
 link['value'] = value
 for constraint in constraints:
 if constraint is not src_constr:
 constraint['update'](link)

当连接器收到set消息时,它将运行set_value函数以检查域,设置新值并将“update”消息发送到另一个节点。 通知该连接器上的值已更改。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def update(src_conn):
 if src_conn is conn1:
 conn2['set'](node, constr1(conn1['value']))
 else:
 conn1['set'](node, constr2(conn2['value']))

然后,被通知的节点在连接器上请求此新值,为另一个连接器计算新值,依此类推,直到整个系统发生更改。这就是传播的原理。

但是消息传递是如何发生的?它被实现为访问字典的键。两个函数(连接器和约束)都返回一个调度字典。这样的字典包含作为键的消息和作为值的闭包。比如说,通过访问一个键,一个字典返回一个函数set值(闭包),该函数可以访问“connector”函数的所有本地名称。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# A dispatch dictionary
link = { 'name': name,
 'value': None,
 'connect': connect,
 'set': set_value,
 'constraints': get_constraints }
return link

将字典作为返回值可以创建多个闭包(函数),并且可以访问相同的本地状态。 然后,可以通过使用键作为消息类型来调用这些闭包。

为什么要使用约束编程?

约束编程可以使您对困难的问题有新的认识。并非在每种情况下都可以使用它,但是在某些情况下它可能会为解决方案打开新的机会。如果你发现自己面对的是一个似乎很难在代码中可靠地解决的问题,试着从另一个角度来看待它。 如果最好的角度是约束编程,那么你现在就有了一个如何实现它的例子。


这篇文章最初发表在 Oleksii Tsvietnov的博客,并在他的允许下转载。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python|函数式编程|公式约束器实现
这个公式很简单,写成函数的话,用最简单的一个return即可。然而,如果我想要让他推广,输入华氏度也能求出摄氏度,甚至更广,一个公式里,只要其他的n-1个变量已知,就能自动补全公式,该怎么做呢?
朝闻君
2021/11/22
5280
Python|函数式编程|公式约束器实现
【C语言 字符函数和字符串函数】—— 文本数据的奇幻加工坊,代码世界的魔法编织者
在学习字符和字符串函数之前,我们先认识一下ASCLL码,ASCII 编码是字符处理的基础,了解其规则对编程非常重要!
换一颗红豆
2024/12/23
2750
【C语言 字符函数和字符串函数】—— 文本数据的奇幻加工坊,代码世界的魔法编织者
【Python编程导论】第二章-Python简介
低级编程与高级编程:二者之间的区别是,编写程序时,我们是使用机器层次的指令和数据对象(底层操作),还是使用语言设计者提供的更为抽象的操作(图形用户界面,UI)。
Datawhale
2019/07/08
8040
Python 非线性规划 scipy.optimize.minimize
scipy.optimize.minimize() 是 Python 计算库 Scipy 的一个功能,用于求解函数在某一初始值附近的极值,获取 一个或多个变量的标量函数的最小化结果 ( Minimization of scalar function of one or more variables. )。
为为为什么
2023/03/19
5.1K0
【读码JDK】- java.lang.Character类Api介绍及测试
返回表示指定的char值的Character实例。 如果不需要新的Character实例,则通常应优先使用此方法,而不是构造函数Character(char) 因为此方法可能通过缓存频繁请求的值来显着提高空间和时间性能。
阿提说说
2022/12/02
1.1K0
在Python中优雅地用多进程:进程池 Pool、管道通信 Pipe、队列通信 Queue、共享内存 Manager Value
Python 自带的多进程库 multiprocessing 可实现多进程。我想用这些短例子示范如何优雅地用多线程。中文网络上,有些人只是翻译了旧版的 Python 官网的多进程文档。而我这篇文章会额外讲一讲下方加粗部分的内容。
汀丶人工智能
2023/10/11
9.3K0
在Python中优雅地用多进程:进程池 Pool、管道通信 Pipe、队列通信 Queue、共享内存 Manager Value
ASCII编码介绍与学习总结
描述:上个世纪60年代美国制定了一套字符编码,它就是ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。 它是现今最通用的单字节编码系统(第一个计算机领域通用的字符集),并等同于国际标准 ISO/IEC 646。
全栈工程师修炼指南
2022/09/28
1.3K0
ASCII编码介绍与学习总结
Go语言核心36讲(Go语言实战与应用二十四)--学习笔记
人们常常会使用 Go 语言去编写网络程序(当然了,这方面也是 Go 语言最为擅长的事情)。说到网络编程,我们就不得不提及 socket。
郑子铭
2021/12/09
3950
Go语言核心36讲(Go语言实战与应用二十四)--学习笔记
【C语言】刷题笔记 Day1
1. getchar 为输入函数,EOF(end of file)为文件结束标志,通常为文件结束的末尾。
云边有个稻草人
2024/10/21
770
【C语言】刷题笔记 Day1
Go语言基础语法探索
🔥 Go语言,又称Golang,是由科技巨头Google麾下的一群卓越工程师,包括但不限于罗伯特·格瑞史莫(Robert Griesemer)、罗勃·派克(Rob Pike)和肯·汤普逊(Ken Thompson)等人于21世纪初匠心独运所创设。这一革新性编程语言的孕育始于2007年,并于2009年11月首度公之于众,直至2012年3月28日才正式发布首个稳定版面世。
空白诗
2024/06/14
950
MySQL数据库与JDBC编程
表结构删除,表对象不再存在;表的所有数据被删除;该表所有相关的索引、约束也被删除。
小锋学长生活大爆炸
2020/08/13
3.7K0
C运用练习讲解
2、自信点,智商是没问题的,题目是不算难, 想不到的原因:是不熟悉,不会把实际问题转化成代码的方式来解决!编程思维(需要练习)
用户11015888
2024/03/11
1600
C运用练习讲解
Python升级之路( Lv15 ) 并发编程三剑客: 进程, 线程与协程
第一章 Python 入门 第二章 Python基本概念 第三章 序列 第四章 控制语句 第五章 函数 第六章 面向对象基础 第七章 面向对象深入 第八章 异常机制 第九章 文件操作 第十章 模块 第十一章 GUI图形界面编程 第十二章 pygame游戏开发基础 第十三章 pyinstaller 使用详解 第十四章 并发编程初识 第十五章 并发编程三剑客-进程, 线程与协程
时间静止不是简史
2022/09/27
6570
Python升级之路( Lv15 ) 并发编程三剑客: 进程, 线程与协程
【C语言】字符与字符串---从入门到入土级详解
因为计算机使用数字编码来处理字符,即用特定的整数表示特定的字符。我们最常用的编码就是ASCII编码。我们先定义一个名叫ch的字符变量,再给它赋值为’A‘,如:
修修修也
2024/04/01
5080
【C语言】字符与字符串---从入门到入土级详解
Python全网最全基础课程笔记(十一)——字符串所有操作,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
请注意,title()方法在处理包含标点符号的字符串时,会将标点符号后面的第一个字母也转换为大写,这可能与某些预期不同。比如,在英文中,标点符号(如逗号、句号)后面通常跟随小写字母开始的单词,但title()方法会将这些字母也转换为大写。如果你需要更精细地控制大小写转换,可能需要根据具体情况编写自定义的函数来处理字符串。
小白的大数据之旅
2024/11/20
2700
Python全网最全基础课程笔记(十一)——字符串所有操作,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
【建议收藏】技术面必考题:多线程、多进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
互联网金融打杂
2022/08/01
5880
【建议收藏】技术面必考题:多线程、多进程
c语言每日一练(6)
A、 测字符数组ch的长度 B、 将数字字符串ch转换成十进制数 C、 将字符数组ch中的小写字母转换成大写 D、 将字符数组ch中的大写字母转换成小写
大海里的番茄
2024/01/19
1340
c语言每日一练(6)
[oeasy]python059变量命名有什么规则_惯用法_蛇形命名法_name_convention_snake
local_soil_moisture_value_to_determine_the_amount_of_water_added = 0
oeasy
2025/01/13
960
[oeasy]python059变量命名有什么规则_惯用法_蛇形命名法_name_convention_snake
1.PS编程入门基础语法
描述: 当我第一次开始学习 PowerShell 时,如果无法使用 PowerShell 单行命令完成任务我会回到 GUI 找寻帮助。然后着时间的推移,我逐渐掌握了编写脚本、函数和模块的技能。
全栈工程师修炼指南
2022/09/29
21.1K0
1.PS编程入门基础语法
用欧拉计划学Rust编程(第55~59题)
最近想学习Libra数字货币的MOVE语言,发现它是用Rust编写的,所以先补一下Rust的基础知识。学习了一段时间,发现Rust的学习曲线非常陡峭,不过仍有快速入门的办法。
申龙斌
2019/10/08
7490
用欧拉计划学Rust编程(第55~59题)
推荐阅读
相关推荐
Python|函数式编程|公式约束器实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验